diff options
author | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-11-15 19:59:58 +0400 |
---|---|---|
committer | Sergey Sharybin <sergey.vfx@gmail.com> | 2012-11-15 19:59:58 +0400 |
commit | 5c6f6301b02a68c6569e14a70b3968a69fa099e7 (patch) | |
tree | 2245e539979eb97feb3931639b38bf91061bc5a7 /source/blender/render | |
parent | 613cf7ae376b0994c9bd7c57b13123d72831bd3a (diff) |
Image thread safe improvements
This commit makes BKE_image_acquire_ibuf referencing result, which means once
some area requested for image buffer, it'll be guaranteed this buffer wouldn't
be freed by image signal.
To de-reference buffer BKE_image_release_ibuf should now always be used.
To make referencing working correct we can not rely on result of
image_get_ibuf_threadsafe called outside from thread lock. This is so because
we need to guarantee getting image buffer from list of loaded buffers and it's
referencing happens atomic. Without lock here it is possible that between call
of image_get_ibuf_threadsafe and referencing the buffer IMA_SIGNAL_FREE would
be called. Image signal handling too is blocking now to prevent such a
situation.
Threads are locking by spinlock, which are faster than mutexes. There were some
slowdown reports in the past about render slowdown when using OSX on Xeon CPU.
It shouldn't happen with spin locks, but more tests on different hardware would
be really welcome. So far can not see speed regressions on own computers.
This commit also removes BKE_image_get_ibuf, because it was not so intuitive
when get_ibuf and acquire_ibuf should be used.
Thanks to Ton and Brecht for discussion/review :)
Diffstat (limited to 'source/blender/render')
-rw-r--r-- | source/blender/render/intern/source/envmap.c | 3 | ||||
-rw-r--r-- | source/blender/render/intern/source/imagetexture.c | 81 | ||||
-rw-r--r-- | source/blender/render/intern/source/pipeline.c | 1 | ||||
-rw-r--r-- | source/blender/render/intern/source/render_texture.c | 30 | ||||
-rw-r--r-- | source/blender/render/intern/source/rendercore.c | 28 | ||||
-rw-r--r-- | source/blender/render/intern/source/voxeldata.c | 11 |
6 files changed, 121 insertions, 33 deletions
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index 28f70211a9c..c3126e57b53 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -687,11 +687,12 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o env->ima = tex->ima; if (env->ima && env->ima->ok) { if (env->cube[1] == NULL) { - ImBuf *ibuf_ima = BKE_image_get_ibuf(env->ima, NULL); + ImBuf *ibuf_ima = BKE_image_acquire_ibuf(env->ima, NULL, NULL); if (ibuf_ima) envmap_split_ima(env, ibuf_ima); else env->ok = 0; + BKE_image_release_ibuf(env->ima, ibuf_ima, NULL); } } } diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c index db1454fd82f..cd06839b004 100644 --- a/source/blender/render/intern/source/imagetexture.c +++ b/source/blender/render/intern/source/imagetexture.c @@ -124,13 +124,16 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul /* hack for icon render */ if (ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval; - - ibuf= BKE_image_get_ibuf(ima, &tex->iuser); + + ibuf= BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); ima->flag|= IMA_USED_FOR_RENDER; } - if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) + if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; + } /* setup mapping */ if (tex->imaflag & TEX_IMAROT) { @@ -155,11 +158,17 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul /* pass */ } else { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; } } if ( (tex->flag & TEX_CHECKER_EVEN)==0) { - if ((xs+ys) & 1) return retval; + if ((xs+ys) & 1) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + return retval; + } } /* scale around center, (0.5, 0.5) */ if (tex->checkerdist<1.0f) { @@ -173,11 +182,15 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul if (tex->extend == TEX_CLIPCUBE) { if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y || texvec[2]<-1.0f || texvec[2]>1.0f) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; } } else if ( tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) { if (x<0 || y<0 || x>=ibuf->x || y>=ibuf->y) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; } } @@ -287,6 +300,9 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul texres->tb*= fx; } + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + BRICONTRGB; return retval; @@ -1056,10 +1072,14 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex if (ima) { /* hack for icon render */ if ((ima->ibufs.first == NULL) && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval; - ibuf = BKE_image_get_ibuf(ima, &tex->iuser); + ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); } - if ((ibuf == NULL) || ((ibuf->rect == NULL) && (ibuf->rect_float == NULL))) return retval; + if ((ibuf == NULL) || ((ibuf->rect == NULL) && (ibuf->rect_float == NULL))) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + return retval; + } if (ima) { ima->flag |= IMA_USED_FOR_RENDER; @@ -1172,8 +1192,16 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex } } else { - if ((tex->flag & TEX_CHECKER_ODD) == 0 && ((xs + ys) & 1) == 0) return retval; - if ((tex->flag & TEX_CHECKER_EVEN) == 0 && (xs + ys) & 1) return retval; + if ((tex->flag & TEX_CHECKER_ODD) == 0 && ((xs + ys) & 1) == 0) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + return retval; + } + if ((tex->flag & TEX_CHECKER_EVEN) == 0 && (xs + ys) & 1) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + return retval; + } fx -= xs; fy -= ys; } @@ -1189,10 +1217,18 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex } if (tex->extend == TEX_CLIPCUBE) { - if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f || texvec[2] < -1.f || texvec[2] > 1.f) return retval; + if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f || texvec[2] < -1.f || texvec[2] > 1.f) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + return retval; + } } else if (tex->extend == TEX_CLIP || tex->extend == TEX_CHECKER) { - if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f) return retval; + if ((fx + minx) < 0.f || (fy + miny) < 0.f || (fx - minx) > 1.f || (fy - miny) > 1.f) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + return retval; + } } else { if (tex->extend == TEX_EXTEND) { @@ -1413,6 +1449,9 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex texres->tb *= fx; } + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + BRICONTRGB; return retval; @@ -1449,12 +1488,15 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (ima->ibufs.first==NULL && (R.r.scemode & R_NO_IMAGE_LOAD)) return retval; - ibuf= BKE_image_get_ibuf(ima, &tex->iuser); + ibuf= BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); ima->flag|= IMA_USED_FOR_RENDER; } - if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) + if (ibuf==NULL || (ibuf->rect==NULL && ibuf->rect_float==NULL)) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; + } /* mipmap test */ image_mipmap_test(tex, ibuf); @@ -1565,11 +1607,15 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const /* pass */ } else { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; } } if ( (tex->flag & TEX_CHECKER_EVEN)==0) { if ((xs + ys) & 1) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; } } @@ -1605,11 +1651,15 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const if (tex->extend == TEX_CLIPCUBE) { if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f || texvec[2]<-1.0f || texvec[2]>1.0f) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; } } else if (tex->extend==TEX_CLIP || tex->extend==TEX_CHECKER) { if (fx+minx<0.0f || fy+miny<0.0f || fx-minx>1.0f || fy-miny>1.0f) { + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); return retval; } } @@ -1804,6 +1854,9 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const mul_v3_fl(&texres->tr, 1.0f / texres->ta); } + if (ima) + BKE_image_release_ibuf(ima, ibuf, NULL); + BRICONTRGB; return retval; @@ -1812,7 +1865,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const void image_sample(Image *ima, float fx, float fy, float dx, float dy, float result[4]) { TexResult texres; - ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); + ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); if (UNLIKELY(ibuf == NULL)) { zero_v4(result); @@ -1830,6 +1883,8 @@ void image_sample(Image *ima, float fx, float fy, float dx, float dy, float resu ibuf->rect-= (ibuf->x*ibuf->y); ima->flag|= IMA_USED_FOR_RENDER; + + BKE_image_release_ibuf(ima, ibuf, NULL); } void ibuf_sample(ImBuf *ibuf, float fx, float fy, float dx, float dy, float result[4]) diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index f2549f04659..1b237d61e81 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -63,6 +63,7 @@ #include "BLI_string.h" #include "BLI_path_util.h" #include "BLI_fileops.h" +#include "BLI_threads.h" #include "BLI_rand.h" #include "BLI_callbacks.h" diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index c507d6595e0..e6daa5f9094 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -1233,11 +1233,13 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output); if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) { - ImBuf *ibuf = BKE_image_get_ibuf(tex->ima, &tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres->tr, ibuf->rect_colorspace); + + BKE_image_release_ibuf(tex->ima, ibuf, NULL); } } else { @@ -1264,11 +1266,13 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os rgbnor= multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output); { - ImBuf *ibuf = BKE_image_get_ibuf(tex->ima, &tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres->tr, ibuf->rect_colorspace); + + BKE_image_release_ibuf(tex->ima, ibuf, NULL); } } @@ -1723,11 +1727,12 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, if (!shi->osatex && (tex->type == TEX_IMAGE) && tex->ima) { /* in case we have no proper derivatives, fall back to * computing du/dv it based on image size */ - ImBuf *ibuf = BKE_image_get_ibuf(tex->ima, &tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); if (ibuf) { du = 1.f/(float)ibuf->x; dv = 1.f/(float)ibuf->y; } + BKE_image_release_ibuf(tex->ima, ibuf, NULL); } else if (shi->osatex) { /* we have derivatives, can compute proper du/dv */ @@ -1900,12 +1905,13 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T /* resolve image dimensions */ if (found_deriv_map || (mtex->texflag&MTEX_BUMP_TEXTURESPACE)!=0) { - ImBuf *ibuf = BKE_image_get_ibuf(tex->ima, &tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); if (ibuf) { dimx = ibuf->x; dimy = ibuf->y; aspect = ((float) dimy) / dimx; } + BKE_image_release_ibuf(tex->ima, ibuf, NULL); } if (found_deriv_map) { @@ -2396,11 +2402,13 @@ void do_material_tex(ShadeInput *shi, Render *re) /* inverse gamma correction */ if (tex->type==TEX_IMAGE) { Image *ima = tex->ima; - ImBuf *ibuf = BKE_image_get_ibuf(ima, &tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace); + + BKE_image_release_ibuf(ima, ibuf, NULL); } if (mtex->mapto & MAP_COL) { @@ -2928,11 +2936,13 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4]) /* inverse gamma correction */ if (mtex->tex->type==TEX_IMAGE) { Image *ima = mtex->tex->ima; - ImBuf *ibuf = BKE_image_get_ibuf(ima, &mtex->tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &mtex->tex->iuser, NULL); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace); + + BKE_image_release_ibuf(ima, ibuf, NULL); } fact= texres.tin*mtex->colfac; @@ -3147,11 +3157,13 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h /* inverse gamma correction */ if (tex->type==TEX_IMAGE) { Image *ima = tex->ima; - ImBuf *ibuf = BKE_image_get_ibuf(ima, &tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(tcol, ibuf->rect_colorspace); + + BKE_image_release_ibuf(ima, ibuf, NULL); } if (mtex->mapto & WOMAP_HORIZ) { @@ -3361,11 +3373,13 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r /* inverse gamma correction */ if (tex->type==TEX_IMAGE) { Image *ima = tex->ima; - ImBuf *ibuf = BKE_image_get_ibuf(ima, &tex->iuser); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &tex->iuser, NULL); /* don't linearize float buffers, assumed to be linear */ if (ibuf && !(ibuf->rect_float) && R.scene_color_manage) IMB_colormanagement_colorspace_to_scene_linear_v3(&texres.tr, ibuf->rect_colorspace); + + BKE_image_release_ibuf(ima, ibuf, NULL); } /* lamp colors were premultiplied with this */ diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c index 9fe2620747c..3431c3ff5de 100644 --- a/source/blender/render/intern/source/rendercore.c +++ b/source/blender/render/intern/source/rendercore.c @@ -2506,21 +2506,26 @@ static int get_next_bake_face(BakeShade *bs) if (tface && tface->tpage) { Image *ima= tface->tpage; - ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); + ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); const float vec_alpha[4]= {0.0f, 0.0f, 0.0f, 0.0f}; const float vec_solid[4]= {0.0f, 0.0f, 0.0f, 1.0f}; if (ibuf==NULL) continue; - if (ibuf->rect==NULL && ibuf->rect_float==NULL) + if (ibuf->rect==NULL && ibuf->rect_float==NULL) { + BKE_image_release_ibuf(ima, ibuf, NULL); continue; + } - if (ibuf->rect_float && !(ibuf->channels==0 || ibuf->channels==4)) + if (ibuf->rect_float && !(ibuf->channels==0 || ibuf->channels==4)) { + BKE_image_release_ibuf(ima, ibuf, NULL); continue; + } if (ima->flag & IMA_USED_FOR_RENDER) { ima->id.flag &= ~LIB_DOIT; + BKE_image_release_ibuf(ima, ibuf, NULL); continue; } @@ -2548,6 +2553,9 @@ static int get_next_bake_face(BakeShade *bs) v++; BLI_unlock_thread(LOCK_CUSTOM1); + + BKE_image_release_ibuf(ima, ibuf, NULL); + return 1; } } @@ -2571,8 +2579,10 @@ static void shade_tface(BakeShade *bs) /* check valid zspan */ if (ima!=bs->ima) { + BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); + bs->ima= ima; - bs->ibuf= BKE_image_get_ibuf(ima, NULL); + bs->ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); /* note, these calls only free/fill contents of zspan struct, not zspan itself */ zbuf_free_span(bs->zspan); zbuf_alloc_span(bs->zspan, bs->ibuf->x, bs->ibuf->y, R.clipcrop); @@ -2638,7 +2648,9 @@ static void *do_bake_thread(void *bs_v) *bs->do_update= TRUE; } bs->ready= 1; - + + BKE_image_release_ibuf(bs->ima, bs->ibuf, NULL); + return NULL; } @@ -2689,12 +2701,13 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up /* baker uses this flag to detect if image was initialized */ for (ima= G.main->image.first; ima; ima= ima->id.next) { - ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); + ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); ima->id.flag |= LIB_DOIT; ima->flag&= ~IMA_USED_FOR_RENDER; if (ibuf) { ibuf->userdata = NULL; /* use for masking if needed */ } + BKE_image_release_ibuf(ima, ibuf, NULL); } BLI_init_threads(&threads, do_bake_thread, re->r.threads); @@ -2747,7 +2760,7 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up /* filter and refresh images */ for (ima= G.main->image.first; ima; ima= ima->id.next) { if ((ima->id.flag & LIB_DOIT)==0) { - ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL); + ImBuf *ibuf= BKE_image_acquire_ibuf(ima, NULL, NULL); if (ima->flag & IMA_USED_FOR_RENDER) result= BAKE_RESULT_FEEDBACK_LOOP; @@ -2758,6 +2771,7 @@ int RE_bake_shade_all_selected(Render *re, int type, Object *actob, short *do_up RE_bake_ibuf_filter(ibuf, (char *)ibuf->userdata, re->r.bake_filter); ibuf->userflags |= IB_BITMAPDIRTY; + BKE_image_release_ibuf(ima, ibuf, NULL); } } diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c index 42849a01971..77d6644479a 100644 --- a/source/blender/render/intern/source/voxeldata.c +++ b/source/blender/render/intern/source/voxeldata.c @@ -157,10 +157,10 @@ static void load_frame_image_sequence(VoxelData *vd, Tex *tex) /* find the first valid ibuf and use it to initialize the resolution of the data set */ /* need to do this in advance so we know how much memory to allocate */ - ibuf = BKE_image_get_ibuf(ima, &iuser); + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); while (!ibuf && (iuser.framenr < iuser.frames)) { iuser.framenr++; - ibuf = BKE_image_get_ibuf(ima, &iuser); + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); } if (!ibuf) return; if (!ibuf->rect_float) IMB_float_from_rect(ibuf); @@ -175,7 +175,8 @@ static void load_frame_image_sequence(VoxelData *vd, Tex *tex) /* get a new ibuf for each frame */ if (z > 0) { iuser.framenr++; - ibuf = BKE_image_get_ibuf(ima, &iuser); + BKE_image_release_ibuf(ima, ibuf, NULL); + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); if (!ibuf) break; if (!ibuf->rect_float) IMB_float_from_rect(ibuf); } @@ -191,7 +192,9 @@ static void load_frame_image_sequence(VoxelData *vd, Tex *tex) BKE_image_free_anim_ibufs(ima, iuser.framenr); } - + + BKE_image_release_ibuf(ima, ibuf, NULL); + vd->ok = 1; return; } |