Render & Compositing Thread Fixes

* Rendering twice or more could crash layer/pass buttons.
* Compositing would crash while drawing the image.
* Rendering animations could also crash drawing the image.
* Compositing could crash 
* Starting to rendering while preview render / compo was
  still running could crash.
* Exiting while rendering an animation would not abort the
  renderer properly, making Blender seemingly freeze.
* Fixes theoretically possible issue with setting malloc
  lock with nested threads.
* Drawing previews inside nodes could crash when those nodes
  were being rendered at the same time.

There's more crashes, manipulating the scene data or undo can
still crash, this commit only focuses on making sure the image
buffer and render result access is thread safe.


Implementation:
* Rather than assuming the render result does not get freed
  during render, which seems to be quite difficult to do given
  that e.g. the compositor is allowed to change the size of
  the buffer or output different passes, the render result is
  now protected with a read/write mutex.
* The read/write mutex allows multiple readers (and pixel
  writers) at the same time, but only allows one writer to
  manipulate the data structure.
* Added BKE_image_acquire_ibuf/BKE_image_release_ibuf to access
  images being rendered, cases where this is not needed (most
  code) can still use BKE_image_get_ibuf.
* The job manager now allows only one rendering job at the same
  time, rather than the G.rendering check which was not reliable.
This commit is contained in:
Brecht Van Lommel 2009-09-30 18:18:32 +00:00
parent 727745bd49
commit b466286c3e
29 changed files with 595 additions and 214 deletions

View File

@ -688,17 +688,35 @@ static const char *check_memlist(MemHead *memh)
uintptr_t MEM_get_memory_in_use(void)
{
return mem_in_use;
uintptr_t _mem_in_use;
mem_lock_thread();
_mem_in_use= mem_in_use;
mem_unlock_thread();
return _mem_in_use;
}
uintptr_t MEM_get_mapped_memory_in_use(void)
{
return mmap_in_use;
uintptr_t _mmap_in_use;
mem_lock_thread();
_mmap_in_use= mmap_in_use;
mem_unlock_thread();
return _mmap_in_use;
}
int MEM_get_memory_blocks_in_use(void)
{
return totblock;
int _totblock;
mem_lock_thread();
_totblock= totblock;
mem_unlock_thread();
return _totblock;
}
/* eof */

View File

@ -107,6 +107,11 @@ struct RenderResult;
/* always call to make signals work */
struct ImBuf *BKE_image_get_ibuf(struct Image *ima, struct ImageUser *iuser);
/* same as above, but can be used to retrieve images being rendered in
* a thread safe way, always call both acquire and release */
struct ImBuf *BKE_image_acquire_ibuf(struct Image *ima, struct ImageUser *iuser, void **lock_r);
void BKE_image_release_ibuf(struct Image *ima, void *lock);
/* returns existing Image when filename/type is same (frame optional) */
struct Image *BKE_add_image_file(const char *name, int frame);
@ -135,7 +140,8 @@ void BKE_image_user_new_image(struct Image *ima, struct ImageUser *iuser);
struct RenderPass *BKE_image_multilayer_index(struct RenderResult *rr, struct ImageUser *iuser);
/* for multilayer images as well as for render-viewer */
struct RenderResult *BKE_image_get_renderresult(struct Scene *scene, struct Image *ima);
struct RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, struct Image *ima);
void BKE_image_release_renderresult(struct Scene *scene, struct Image *ima);
/* goes over all textures that use images */
void BKE_image_free_all_textures(void);

View File

@ -1564,15 +1564,22 @@ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser)
return rpass;
}
RenderResult *BKE_image_get_renderresult(struct Scene *scene, Image *ima)
RenderResult *BKE_image_acquire_renderresult(struct Scene *scene, Image *ima)
{
if(ima->rr)
return ima->rr;
if(ima->type==IMA_TYPE_R_RESULT)
return RE_GetResult(RE_GetRender(scene->id.name));
else if(ima->type==IMA_TYPE_R_RESULT)
return RE_AcquireResultRead(RE_GetRender(scene->id.name));
return NULL;
}
void BKE_image_release_renderresult(struct Scene *scene, Image *ima)
{
if(ima->rr);
else if(ima->type==IMA_TYPE_R_RESULT)
RE_ReleaseResult(RE_GetRender(scene->id.name));
}
/* after imbuf load, openexr type can return with a exrhandle open */
/* in that case we have to build a render-result */
static void image_create_multilayer(Image *ima, ImBuf *ibuf, int framenr)
@ -1873,16 +1880,25 @@ static ImBuf *image_get_ibuf_multilayer(Image *ima, ImageUser *iuser)
/* showing RGBA result itself (from compo/sequence) or
like exr, using layers etc */
/* always returns a single ibuf, also during render progress */
static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser)
static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser, void **lock_r)
{
Render *re= NULL;
RenderResult *rr= NULL;
/* if we the caller is not going to release the lock, don't give the image */
if(!lock_r)
return NULL;
if(iuser && iuser->scene) {
re= RE_GetRender(iuser->scene->id.name);
rr= RE_GetResult(re);
rr= RE_AcquireResultRead(re);
/* release is done in BKE_image_release_ibuf using lock_r */
*lock_r= re;
}
if(rr==NULL) return NULL;
if(rr==NULL)
return NULL;
if(RE_RenderInProgress(re)) {
ImBuf *ibuf= image_get_ibuf(ima, IMA_NO_INDEX, 0);
@ -1893,6 +1909,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser)
ibuf= IMB_allocImBuf(rr->rectx, rr->recty, 32, IB_rect, 0);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
}
return ibuf;
}
else {
@ -1907,7 +1924,7 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser)
pass= (iuser)? iuser->pass: 0;
/* this gives active layer, composite or seqence result */
RE_GetResultImage(RE_GetRender(iuser->scene->id.name), &rres);
RE_AcquireResultImage(RE_GetRender(iuser->scene->id.name), &rres);
rect= (unsigned int *)rres.rect32;
rectf= rres.rectf;
dither= iuser->scene->r.dither_intensity;
@ -1954,10 +1971,14 @@ static ImBuf *image_get_render_result(Image *ima, ImageUser *iuser)
ibuf->zbuf_float= rres.rectz;
ibuf->flags |= IB_zbuffloat;
ibuf->dither= dither;
RE_ReleaseResultImage(re);
ima->ok= IMA_OK_LOADED;
return ibuf;
}
RE_ReleaseResultImage(re);
}
return NULL;
@ -2011,8 +2032,9 @@ static ImBuf *image_get_ibuf_threadsafe(Image *ima, ImageUser *iuser, int *frame
}
/* Checks optional ImageUser and verifies/creates ImBuf. */
/* returns ibuf */
ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
/* use this one if you want to get a render result in progress,
* if not, use BKE_image_get_ibuf which doesn't require a release */
ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
{
ImBuf *ibuf= NULL;
float color[] = {0, 0, 0, 1};
@ -2028,6 +2050,9 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
* things in a threadsafe way for image_get_ibuf_threadsafe to work correct.
* That means, the last two steps must be, 1) add the ibuf to the list and
* 2) set ima/iuser->ok to 0 to IMA_OK_LOADED */
if(lock_r)
*lock_r= NULL;
/* quick reject tests */
if(ima==NULL)
@ -2103,8 +2128,9 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
}
else if(ima->source == IMA_SRC_VIEWER) {
if(ima->type==IMA_TYPE_R_RESULT) {
/* always verify entirely */
ibuf= image_get_render_result(ima, iuser);
/* always verify entirely, and potentially
returns pointer to release later */
ibuf= image_get_render_result(ima, iuser, lock_r);
}
else if(ima->type==IMA_TYPE_COMPOSITE) {
/* Composite Viewer, all handled in compositor */
@ -2126,6 +2152,17 @@ ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
return ibuf;
}
void BKE_image_release_ibuf(Image *ima, void *lock)
{
/* for getting image during threaded render, need to release */
if(lock)
RE_ReleaseResult(lock);
}
ImBuf *BKE_image_get_ibuf(Image *ima, ImageUser *iuser)
{
return BKE_image_acquire_ibuf(ima, iuser, NULL);
}
void BKE_image_user_calc_imanr(ImageUser *iuser, int cfra, int fieldnr)
{

View File

@ -1953,6 +1953,7 @@ static void composit_end_exec(bNodeTree *ntree, int is_group)
if(ns->data) {
printf("freed leftover buffer from stack\n");
free_compbuf(ns->data);
ns->data= NULL;
}
}
}

View File

@ -2067,7 +2067,7 @@ static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int
if(rendering)
BLI_strncpy(sce->id.name+2, scenename, 64);
RE_GetResultImage(re, &rres);
RE_AcquireResultImage(re, &rres);
if(rres.rectf) {
se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rectfloat, 0);
@ -2080,6 +2080,8 @@ static void do_build_seq_ibuf(Scene *scene, Sequence * seq, TStripElem *se, int
se->ibuf= IMB_allocImBuf(rres.rectx, rres.recty, 32, IB_rect, 0);
memcpy(se->ibuf->rect, rres.rect32, 4*rres.rectx*rres.recty);
}
RE_ReleaseResultImage(re);
BIF_end_render_callbacks();

View File

@ -31,14 +31,15 @@
#ifndef BLI_THREADS_H
#define BLI_THREADS_H
/* one custom lock available now. can be extended */
#define LOCK_IMAGE 0
#define LOCK_CUSTOM1 1
#include <pthread.h>
/* for tables, button in UI, etc */
#define BLENDER_MAX_THREADS 8
struct ListBase;
/* Threading API */
void BLI_init_threads (struct ListBase *threadbase, void *(*do_thread)(void *), int tot);
int BLI_available_threads(struct ListBase *threadbase);
int BLI_available_thread_index(struct ListBase *threadbase);
@ -48,18 +49,46 @@ void BLI_remove_thread_index(struct ListBase *threadbase, int index);
void BLI_remove_threads(struct ListBase *threadbase);
void BLI_end_threads (struct ListBase *threadbase);
void BLI_lock_thread (int type);
void BLI_unlock_thread (int type);
/* System Information */
int BLI_system_thread_count( void ); /* gets the number of threads the system can make use of */
int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */
/* exported by preview render, it has to ensure render buffers are not freed while draw */
void BLI_lock_malloc_thread(void);
void BLI_unlock_malloc_thread(void);
/* Global Mutex Locks
*
* One custom lock available now. can be extended. */
/* ThreadedWorker is a simple tool for dispatching work to a limited number of threads in a transparent
* fashion from the caller's perspective
* */
#define LOCK_IMAGE 0
#define LOCK_PREVIEW 1
#define LOCK_CUSTOM1 2
void BLI_lock_thread(int type);
void BLI_unlock_thread(int type);
/* Mutex Lock */
typedef pthread_mutex_t ThreadMutex;
void BLI_mutex_init(ThreadMutex *mutex);
void BLI_mutex_lock(ThreadMutex *mutex);
void BLI_mutex_unlock(ThreadMutex *mutex);
void BLI_mutex_end(ThreadMutex *mutex);
/* Read/Write Mutex Lock */
#define THREAD_LOCK_READ 1
#define THREAD_LOCK_WRITE 2
typedef pthread_rwlock_t ThreadRWMutex;
void BLI_rw_mutex_init(ThreadRWMutex *mutex);
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode);
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex);
void BLI_rw_mutex_end(ThreadRWMutex *mutex);
/* ThreadedWorker
*
* A simple tool for dispatching work to a limited number of threads
* in a transparent fashion from the caller's perspective. */
struct ThreadedWorker;

View File

@ -98,6 +98,7 @@ A sample loop can look like this (pseudo c);
************************************************ */
static pthread_mutex_t _malloc_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _image_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _preview_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t _custom1_lock = PTHREAD_MUTEX_INITIALIZER;
static int thread_levels= 0; /* threads can be invoked inside threads */
@ -112,12 +113,12 @@ typedef struct ThreadSlot {
int avail;
} ThreadSlot;
void BLI_lock_malloc_thread(void)
static void BLI_lock_malloc_thread(void)
{
pthread_mutex_lock(&_malloc_lock);
}
void BLI_unlock_malloc_thread(void)
static void BLI_unlock_malloc_thread(void)
{
pthread_mutex_unlock(&_malloc_lock);
}
@ -143,7 +144,9 @@ void BLI_init_threads(ListBase *threadbase, void *(*do_thread)(void *), int tot)
tslot->avail= 1;
}
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
if(thread_levels == 0)
MEM_set_lock_callback(BLI_lock_malloc_thread, BLI_unlock_malloc_thread);
thread_levels++;
}
}
@ -252,21 +255,7 @@ void BLI_end_threads(ListBase *threadbase)
}
}
void BLI_lock_thread(int type)
{
if (type==LOCK_IMAGE)
pthread_mutex_lock(&_image_lock);
else if (type==LOCK_CUSTOM1)
pthread_mutex_lock(&_custom1_lock);
}
void BLI_unlock_thread(int type)
{
if (type==LOCK_IMAGE)
pthread_mutex_unlock(&_image_lock);
else if(type==LOCK_CUSTOM1)
pthread_mutex_unlock(&_custom1_lock);
}
/* System Information */
/* how many threads are native on this system? */
int BLI_system_thread_count( void )
@ -300,6 +289,75 @@ int BLI_system_thread_count( void )
return t;
}
/* Global Mutex Locks */
void BLI_lock_thread(int type)
{
if (type==LOCK_IMAGE)
pthread_mutex_lock(&_image_lock);
else if (type==LOCK_PREVIEW)
pthread_mutex_lock(&_preview_lock);
else if (type==LOCK_CUSTOM1)
pthread_mutex_lock(&_custom1_lock);
}
void BLI_unlock_thread(int type)
{
if (type==LOCK_IMAGE)
pthread_mutex_unlock(&_image_lock);
else if (type==LOCK_PREVIEW)
pthread_mutex_unlock(&_preview_lock);
else if(type==LOCK_CUSTOM1)
pthread_mutex_unlock(&_custom1_lock);
}
/* Mutex Locks */
void BLI_mutex_init(ThreadMutex *mutex)
{
pthread_mutex_init(mutex, NULL);
}
void BLI_mutex_lock(ThreadMutex *mutex)
{
pthread_mutex_lock(mutex);
}
void BLI_mutex_unlock(ThreadMutex *mutex)
{
pthread_mutex_unlock(mutex);
}
void BLI_mutex_end(ThreadMutex *mutex)
{
pthread_mutex_destroy(mutex);
}
/* Read/Write Mutex Lock */
void BLI_rw_mutex_init(ThreadRWMutex *mutex)
{
pthread_rwlock_init(mutex, NULL);
}
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
{
if(mode == THREAD_LOCK_READ)
pthread_rwlock_rdlock(mutex);
else
pthread_rwlock_wrlock(mutex);
}
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
{
pthread_rwlock_unlock(mutex);
}
void BLI_rw_mutex_end(ThreadRWMutex *mutex)
{
pthread_rwlock_destroy(mutex);
}
/* ************************************************ */
typedef struct ThreadedWorker {

View File

@ -38,7 +38,10 @@ struct uiBlock;
struct Image *ED_space_image(struct SpaceImage *sima);
void ED_space_image_set(struct bContext *C, struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima);
struct ImBuf *ED_space_image_buffer(struct SpaceImage *sima);
struct ImBuf *ED_space_image_acquire_buffer(struct SpaceImage *sima, void **lock_r);
void ED_space_image_release_buffer(struct SpaceImage *sima, void *lock);
int ED_space_image_has_buffer(struct SpaceImage *sima);
void ED_space_image_size(struct SpaceImage *sima, int *width, int *height);
void ED_space_image_aspect(struct SpaceImage *sima, float *aspx, float *aspy);
void ED_space_image_zoom(struct SpaceImage *sima, struct ARegion *ar, float *zoomx, float *zoomy);

View File

@ -446,6 +446,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
/* uses ROUNDBOX button in block to get the rect */
static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int first, rcti *rect, rcti *newrect)
{
Render *re;
RenderResult rres;
char name[32];
int gamma_correct=0;
@ -470,7 +471,8 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int
}
}
RE_GetResultImage(RE_GetRender(name), &rres);
re= RE_GetRender(name);
RE_AcquireResultImage(re, &rres);
if(rres.rectf) {
@ -482,10 +484,13 @@ static int ed_preview_draw_rect(ScrArea *sa, Scene *sce, ID *id, int split, int
glTranslatef(offx, 0, 0);
glaDrawPixelsSafe_to32(rect->xmin, rect->ymin, rres.rectx, rres.recty, rres.rectx, rres.rectf, gamma_correct);
glPopMatrix();
RE_ReleaseResultImage(re);
return 1;
}
}
RE_ReleaseResultImage(re);
return 0;
}
@ -1100,13 +1105,7 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r
wmJob *steve;
ShaderPreview *sp;
/* XXX ugly global still, but we can't do preview while rendering */
if(G.rendering) {
printf("abort icon because rendering\n");
return;
}
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, WM_JOB_EXCL_RENDER);
sp= MEM_callocN(sizeof(ShaderPreview), "shader preview");
/* customdata for preview thread */
@ -1131,13 +1130,7 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
wmJob *steve;
ShaderPreview *sp;
/* XXX ugly global still, but we can't do preview while rendering */
if(G.rendering) {
printf("abort shader because rendering\n");
return;
}
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, WM_JOB_EXCL_RENDER);
sp= MEM_callocN(sizeof(ShaderPreview), "shader preview");
/* customdata for preview thread */

View File

@ -2703,18 +2703,13 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs)
}
/* called inside thread! */
static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
static void image_buffer_rect_update(RenderJob *rj, RenderResult *rr, ImBuf *ibuf, volatile rcti *renrect)
{
RenderJob *rj= rjv;
ImBuf *ibuf;
float x1, y1, *rectf= NULL;
int ymin, ymax, xmin, xmax;
int rymin, rxmin;
char *rectc;
ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
if(ibuf==NULL) return;
/* if renrect argument, we only refresh scanlines */
if(renrect) {
/* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
@ -2814,6 +2809,18 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec
*(rj->do_update)= 1;
}
static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
{
RenderJob *rj= rjv;
ImBuf *ibuf;
void *lock;
ibuf= BKE_image_acquire_ibuf(rj->image, &rj->iuser, &lock);
if(ibuf)
image_buffer_rect_update(rj, rr, ibuf, renrect);
BKE_image_release_ibuf(rj->image, lock);
}
static void render_startjob(void *rjv, short *stop, short *do_update)
{
RenderJob *rj= rjv;
@ -2897,7 +2904,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
rj->iuser.ok= 1;
/* setup job */
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY);
WM_jobs_customdata(steve, rj, render_freejob);
WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
WM_jobs_callbacks(steve, render_startjob, NULL, NULL);

View File

@ -284,7 +284,7 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update)
static int screencast_exec(bContext *C, wmOperator *op)
{
bScreen *screen= CTX_wm_screen(C);
wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen);
wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), screen, 0);
ScreenshotJob *sj= MEM_callocN(sizeof(ScreenshotJob), "screenshot job");
/* setup sj */

View File

@ -115,15 +115,18 @@ static void save_rendered_image_cb_real(char *name, int confirm)
if(overwrite) {
if(scene->r.imtype==R_MULTILAYER) {
RenderResult *rr= RE_GetResult(RE_GetRender(scene->id.name));
Render *re= RE_GetRender(scene->id.name);
RenderResult *rr= RE_AcquireResultRead(re);
if(rr)
RE_WriteRenderResult(rr, str, scene->r.quality);
RE_ReleaseResult(re);
}
else {
Render *re= RE_GetRender(scene->id.name);
RenderResult rres;
ImBuf *ibuf;
RE_GetResultImage(RE_GetRender(scene->id.name), &rres);
RE_AcquireResultImage(re, &rres);
waitcursor(1); /* from screen.c */
@ -137,6 +140,8 @@ static void save_rendered_image_cb_real(char *name, int confirm)
BKE_write_ibuf(scene, ibuf, str, scene->r.imtype, scene->r.subimtype, scene->r.quality);
IMB_freeImBuf(ibuf); /* imbuf knows rects are not part of ibuf */
RE_ReleaseResultImage(re);
}
strcpy(G.ima, name);
@ -231,9 +236,10 @@ void BIF_save_rendered_image(char *name)
/* calls fileselect */
void BIF_save_rendered_image_fs(Scene *scene)
{
Render *re= RE_GetRender(scene->id.name);
RenderResult rres;
RE_GetResultImage(RE_GetRender(scene->id.name), &rres);
RE_AcquireResultImage(re, &rres);
if(!rres.rectf && !rres.rect32) {
error("No image rendered");
@ -250,6 +256,8 @@ void BIF_save_rendered_image_fs(Scene *scene)
save_image_filesel_str(scene, str);
activate_fileselect(FILE_SPECIAL, str, G.ima, save_rendered_image_cb);
}
RE_ReleaseResultImage(re);
}

View File

@ -204,11 +204,7 @@ struct ImageUser *ntree_get_active_iuser(bNodeTree *ntree)
/* this function gets the values for cursor and vertex number buttons */
static void image_transform_but_attr(SpaceImage *sima, int *imx, int *imy, int *step, int *digits) /*, float *xcoord, float *ycoord)*/
{
ImBuf *ibuf= ED_space_image_buffer(sima);
if(ibuf) {
*imx= ibuf->x;
*imy= ibuf->y;
}
ED_space_image_size(sima, imx, imy);
if (sima->flag & SI_COORDFLOATS) {
*step= 1;
@ -497,9 +493,8 @@ void brush_buttons(const bContext *C, uiBlock *block, short fromsima,
static int image_panel_poll(const bContext *C, PanelType *pt)
{
SpaceImage *sima= CTX_wm_space_image(C);
ImBuf *ibuf= ED_space_image_buffer(sima);
return (ibuf != NULL);
return ED_space_image_has_buffer(sima);
}
static void image_panel_curves(const bContext *C, Panel *pa)
@ -509,8 +504,9 @@ static void image_panel_curves(const bContext *C, Panel *pa)
ImBuf *ibuf;
PointerRNA simaptr;
int levels;
void *lock;
ibuf= ED_space_image_buffer(sima);
ibuf= ED_space_image_acquire_buffer(sima, &lock);
if(ibuf) {
if(sima->cumap==NULL)
@ -522,6 +518,8 @@ static void image_panel_curves(const bContext *C, Panel *pa)
RNA_pointer_create(&sc->id, &RNA_SpaceImageEditor, sima, &simaptr);
uiTemplateCurveMapping(pa->layout, &simaptr, "curves", 'c', levels);
}
ED_space_image_release_buffer(sima, lock);
}
#if 0
@ -923,6 +921,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn
uiBlock *block;
uiBut *but;
char str[128];
void *lock;
if(!ptr->data)
return;
@ -953,8 +952,9 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn
uiBlockSetNFunc(block, rna_update_cb, MEM_dupallocN(cb), NULL);
if(ima->source == IMA_SRC_VIEWER) {
ibuf= BKE_image_get_ibuf(ima, iuser);
ibuf= BKE_image_acquire_ibuf(ima, iuser, &lock);
image_info(ima, ibuf, str);
BKE_image_release_ibuf(ima, lock);
uiItemL(layout, ima->id.name+2, 0);
uiItemL(layout, str, 0);
@ -981,7 +981,10 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn
}
else if(ima->type==IMA_TYPE_R_RESULT) {
/* browse layer/passes */
uiblock_layer_pass_arrow_buttons(layout, RE_GetResult(RE_GetRender(scene->id.name)), iuser);
Render *re= RE_GetRender(scene->id.name);
RenderResult *rr= RE_AcquireResultRead(re);
uiblock_layer_pass_arrow_buttons(layout, rr, iuser);
RE_ReleaseResult(re);
}
}
else {
@ -1010,8 +1013,9 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, char *propn
uiblock_layer_pass_arrow_buttons(layout, ima->rr, iuser);
}
else if(ima->source != IMA_SRC_GENERATED) {
ibuf= BKE_image_get_ibuf(ima, iuser);
ibuf= BKE_image_acquire_ibuf(ima, iuser, &lock);
image_info(ima, ibuf, str);
BKE_image_release_ibuf(ima, lock);
uiItemL(layout, str, 0);
}
@ -1081,10 +1085,12 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser
/* render layers and passes */
if(ima && iuser) {
rr= BKE_image_get_renderresult(scene, ima);
rr= BKE_image_acquire_renderresult(scene, ima);
if(rr)
uiblock_layer_pass_buttons(layout, rr, iuser, 160);
BKE_image_release_renderresult(scene, ima);
}
}

View File

@ -533,11 +533,14 @@ void draw_image_grease_pencil(bContext *C, short onlyv2d)
if (onlyv2d) {
/* assume that UI_view2d_ortho(C) has been called... */
SpaceImage *sima= (SpaceImage *)CTX_wm_space_data(C);
ImBuf *ibuf= ED_space_image_buffer(sima);
void *lock;
ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
/* draw grease-pencil ('image' strokes) */
//if (sima->flag & SI_DISPGP)
draw_gpencil_2dimage(C, ibuf);
ED_space_image_release_buffer(sima, lock);
}
else {
/* assume that UI_view2d_restore(C) has been called... */
@ -654,6 +657,7 @@ void draw_image_main(SpaceImage *sima, ARegion *ar, Scene *scene)
ImBuf *ibuf;
float zoomx, zoomy;
int show_viewer, show_render;
void *lock;
/* XXX can we do this in refresh? */
#if 0
@ -675,11 +679,9 @@ void draw_image_main(SpaceImage *sima, ARegion *ar, Scene *scene)
}
#endif
/* put scene context variable in iuser */
sima->iuser.scene= scene;
/* retrieve the image and information about it */
ima= ED_space_image(sima);
ibuf= ED_space_image_buffer(sima);
ibuf= ED_space_image_acquire_buffer(sima, &lock);
ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
show_viewer= (ima && ima->source == IMA_SRC_VIEWER);
@ -718,5 +720,7 @@ void draw_image_main(SpaceImage *sima, ARegion *ar, Scene *scene)
}
}
#endif
ED_space_image_release_buffer(sima, lock);
}

View File

@ -112,7 +112,7 @@ static int space_image_poll(bContext *C)
{
SpaceImage *sima= CTX_wm_space_image(C);
if(sima && sima->spacetype==SPACE_IMAGE)
if(ED_space_image_buffer(sima))
if(ED_space_image_has_buffer(sima))
return 1;
return 0;
}
@ -121,10 +121,15 @@ static int space_image_file_exists_poll(bContext *C)
{
if(space_image_poll(C)) {
SpaceImage *sima= CTX_wm_space_image(C);
ImBuf *ibuf= ED_space_image_buffer(sima);
ImBuf *ibuf;
void *lock;
int poll;
if(ibuf && BLI_exists(ibuf->name) && BLI_is_writable(ibuf->name))
return 1;
ibuf= ED_space_image_acquire_buffer(sima, &lock);
poll= (ibuf && BLI_exists(ibuf->name) && BLI_is_writable(ibuf->name));
ED_space_image_release_buffer(sima, lock);
return poll;
}
return 0;
}
@ -388,7 +393,6 @@ static int view_all_exec(bContext *C, wmOperator *op)
ARegion *ar;
Scene *scene;
Object *obedit;
ImBuf *ibuf;
float aspx, aspy, zoomx, zoomy, w, h;
int width, height;
@ -398,7 +402,6 @@ static int view_all_exec(bContext *C, wmOperator *op)
scene= (Scene*)CTX_data_scene(C);
obedit= CTX_data_edit_object(C);
ibuf= ED_space_image_buffer(sima);
ED_space_image_size(sima, &width, &height);
ED_space_image_aspect(sima, &aspx, &aspy);
@ -445,7 +448,6 @@ static int view_selected_exec(bContext *C, wmOperator *op)
Scene *scene;
Object *obedit;
Image *ima;
ImBuf *ibuf;
float size, min[2], max[2], d[2];
int width, height;
@ -456,7 +458,6 @@ static int view_selected_exec(bContext *C, wmOperator *op)
obedit= CTX_data_edit_object(C);
ima= ED_space_image(sima);
ibuf= ED_space_image_buffer(sima);
ED_space_image_size(sima, &width, &height);
/* get bounds */
@ -730,7 +731,8 @@ void IMAGE_OT_replace(wmOperatorType *ot)
static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOperator *op, char *name)
{
Image *ima= ED_space_image(sima);
ImBuf *ibuf= ED_space_image_buffer(sima);
void *lock;
ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
int len;
if (ibuf) {
@ -751,7 +753,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOpera
WM_cursor_wait(1);
if(sima->imtypenr==R_MULTILAYER) {
RenderResult *rr= BKE_image_get_renderresult(scene, ima);
RenderResult *rr= BKE_image_acquire_renderresult(scene, ima);
if(rr) {
RE_WriteRenderResult(rr, name, scene->r.quality);
@ -765,6 +767,7 @@ static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOpera
}
else
BKE_report(op->reports, RPT_ERROR, "Did not write, no Multilayer Image");
BKE_image_release_renderresult(scene, ima);
}
else if (BKE_write_ibuf(scene, ibuf, name, sima->imtypenr, scene->r.subimtype, scene->r.quality)) {
BLI_strncpy(ima->name, name, sizeof(ima->name));
@ -792,6 +795,8 @@ static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOpera
WM_cursor_wait(0);
}
ED_space_image_release_buffer(sima, lock);
}
static int save_as_exec(bContext *C, wmOperator *op)
@ -816,8 +821,9 @@ static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
SpaceImage *sima= CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
ImBuf *ibuf= ED_space_image_buffer(sima);
Scene *scene= CTX_data_scene(C);
ImBuf *ibuf;
void *lock;
if(RNA_property_is_set(op->ptr, "path"))
return save_as_exec(C, op);
@ -826,6 +832,8 @@ static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
return OPERATOR_CANCELLED;
/* always opens fileselect */
ibuf= ED_space_image_acquire_buffer(sima, &lock);
if(ibuf) {
/* cant save multilayer sequence, ima->rr isn't valid for a specific frame */
if(ima->rr && !(ima->source==IMA_SRC_SEQUENCE && ima->type==IMA_TYPE_MULTILAYER))
@ -842,10 +850,14 @@ static int save_as_invoke(bContext *C, wmOperator *op, wmEvent *event)
// XXX note: we can give default menu enums to operator for this
image_filesel(C, op, ibuf->name);
ED_space_image_release_buffer(sima, lock);
return OPERATOR_RUNNING_MODAL;
}
ED_space_image_release_buffer(sima, lock);
return OPERATOR_CANCELLED;
}
@ -874,12 +886,16 @@ static int save_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima= CTX_wm_space_image(C);
Image *ima = ED_space_image(sima);
ImBuf *ibuf= ED_space_image_buffer(sima);
void *lock;
ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
Scene *scene= CTX_data_scene(C);
RenderResult *rr;
char name[FILE_MAX];
if(!ima || !ibuf)
if(!ima || !ibuf) {
ED_space_image_release_buffer(sima, lock);
return OPERATOR_CANCELLED;
}
/* if exists, saves over without fileselect */
@ -888,14 +904,21 @@ static int save_exec(bContext *C, wmOperator *op)
BLI_strncpy(name, G.ima, FILE_MAX);
if(BLI_exists(name) && BLI_is_writable(name)) {
if(BKE_image_get_renderresult(scene, ima))
rr= BKE_image_acquire_renderresult(scene, ima);
if(rr)
sima->imtypenr= R_MULTILAYER;
else
sima->imtypenr= BKE_ftype_to_imtype(ibuf->ftype);
BKE_image_release_renderresult(scene, ima);
ED_space_image_release_buffer(sima, lock);
save_image_doit(C, sima, scene, op, name);
}
else {
ED_space_image_release_buffer(sima, lock);
BKE_report(op->reports, RPT_ERROR, "Can not save image.");
return OPERATOR_CANCELLED;
}
@ -1110,9 +1133,8 @@ static int pack_test(bContext *C, wmOperator *op)
static int pack_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima= CTX_wm_space_image(C);
Image *ima= ED_space_image(sima);
ImBuf *ibuf= ED_space_image_buffer(sima);
Image *ima= CTX_data_edit_image(C);
ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
int as_png= RNA_boolean_get(op->ptr, "as_png");
if(!pack_test(C, op))
@ -1133,8 +1155,8 @@ static int pack_exec(bContext *C, wmOperator *op)
static int pack_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
SpaceImage *sima= CTX_wm_space_image(C);
ImBuf *ibuf= ED_space_image_buffer(sima);
Image *ima= CTX_data_edit_image(C);
ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
uiPopupMenu *pup;
uiLayout *layout;
int as_png= RNA_boolean_get(op->ptr, "as_png");
@ -1294,6 +1316,7 @@ typedef struct ImageSampleInfo {
ARegionType *art;
void *draw_handle;
int x, y;
int channels;
char col[4];
float colf[4];
@ -1310,14 +1333,9 @@ typedef struct ImageSampleInfo {
static void sample_draw(const bContext *C, ARegion *ar, void *arg_info)
{
SpaceImage *sima= CTX_wm_space_image(C);
ImBuf *ibuf= ED_space_image_buffer(sima);
ImageSampleInfo *info= arg_info;
if(ibuf == NULL)
return;
draw_image_info(ar, ibuf->channels, info->x, info->y, info->colp,
draw_image_info(ar, info->channels, info->x, info->y, info->colp,
info->colfp, info->zp, info->zfp);
}
@ -1325,13 +1343,16 @@ static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
{
SpaceImage *sima= CTX_wm_space_image(C);
ARegion *ar= CTX_wm_region(C);
ImBuf *ibuf= ED_space_image_buffer(sima);
void *lock;
ImBuf *ibuf= ED_space_image_acquire_buffer(sima, &lock);
ImageSampleInfo *info= op->customdata;
float fx, fy;
int x, y;
if(ibuf == NULL)
if(ibuf == NULL) {
ED_space_image_release_buffer(sima, lock);
return;
}
x= event->x - ar->winrct.xmin;
y= event->y - ar->winrct.ymin;
@ -1348,6 +1369,7 @@ static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
info->x= x;
info->y= y;
info->draw= 1;
info->channels= ibuf->channels;
info->colp= NULL;
info->colfp= NULL;
@ -1424,6 +1446,7 @@ static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
else
info->draw= 0;
ED_space_image_release_buffer(sima, lock);
ED_area_tag_redraw(CTX_wm_area(C));
}
@ -1440,10 +1463,9 @@ static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
SpaceImage *sima= CTX_wm_space_image(C);
ARegion *ar= CTX_wm_region(C);
ImBuf *ibuf= ED_space_image_buffer(sima);
ImageSampleInfo *info;
if(ibuf == NULL)
if(!ED_space_image_has_buffer(sima))
return OPERATOR_CANCELLED;
info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");

View File

@ -328,7 +328,7 @@ static int image_context(const bContext *C, const char *member, bContextDataResu
/************************** main region ***************************/
/* sets up the fields of the View2D from zoom and offset */
static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar, Scene *scene)
static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar)
{
Image *ima= ED_space_image(sima);
float x1, y1, w, h;
@ -336,24 +336,9 @@ static void image_main_area_set_view2d(SpaceImage *sima, ARegion *ar, Scene *sce
#if 0
if(image_preview_active(curarea, &width, &height));
#endif
if(sima->image) {
ImBuf *ibuf= ED_space_image_buffer(sima);
if(ibuf) {
width= ibuf->x;
height= ibuf->y;
}
else if(sima->image->type==IMA_TYPE_R_RESULT) {
/* not very important, just nice */
width= (scene->r.xsch*scene->r.size)/100;
height= (scene->r.ysch*scene->r.size)/100;
}
else
ED_space_image_size(sima, &width, &height);
}
else
ED_space_image_size(sima, &width, &height);
#endif
ED_space_image_size(sima, &width, &height);
w= width;
h= height;
@ -431,9 +416,12 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
UI_GetThemeColor3fv(TH_BACK, col);
glClearColor(col[0], col[1], col[2], 0.0);
glClear(GL_COLOR_BUFFER_BIT);
/* put scene context variable in iuser */
sima->iuser.scene= scene;
/* we set view2d from own zoom and offset each time */
image_main_area_set_view2d(sima, ar, scene);
image_main_area_set_view2d(sima, ar);
/* we draw image in pixelspace */
draw_image_main(sima, ar, scene);
@ -621,7 +609,7 @@ void ED_space_image_set(bContext *C, SpaceImage *sima, Scene *scene, Object *obe
}
}
ImBuf *ED_space_image_buffer(SpaceImage *sima)
ImBuf *ED_space_image_acquire_buffer(SpaceImage *sima, void **lock_r)
{
ImBuf *ibuf;
@ -631,7 +619,7 @@ ImBuf *ED_space_image_buffer(SpaceImage *sima)
return BIF_render_spare_imbuf();
else
#endif
ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
ibuf= BKE_image_acquire_ibuf(sima->image, &sima->iuser, lock_r);
if(ibuf && (ibuf->rect || ibuf->rect_float))
return ibuf;
@ -640,11 +628,32 @@ ImBuf *ED_space_image_buffer(SpaceImage *sima)
return NULL;
}
void ED_image_size(Image *ima, int *width, int *height)
void ED_space_image_release_buffer(SpaceImage *sima, void *lock)
{
if(sima && sima->image)
BKE_image_release_ibuf(sima->image, lock);
}
int ED_space_image_has_buffer(SpaceImage *sima)
{
ImBuf *ibuf;
void *lock;
int has_buffer;
ibuf= (ima)? BKE_image_get_ibuf(ima, NULL): NULL;
ibuf= ED_space_image_acquire_buffer(sima, &lock);
has_buffer= (ibuf != NULL);
ED_space_image_release_buffer(sima, lock);
return has_buffer;
}
void ED_image_size(Image *ima, int *width, int *height)
{
ImBuf *ibuf= NULL;
void *lock;
if(ima)
ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
if(ibuf && ibuf->x > 0 && ibuf->y > 0) {
*width= ibuf->x;
@ -654,24 +663,36 @@ void ED_image_size(Image *ima, int *width, int *height)
*width= 256;
*height= 256;
}
if(ima)
BKE_image_release_ibuf(ima, lock);
}
void ED_space_image_size(SpaceImage *sima, int *width, int *height)
{
Scene *scene= sima->iuser.scene;
ImBuf *ibuf;
void *lock;
ibuf= ED_space_image_buffer(sima);
ibuf= ED_space_image_acquire_buffer(sima, &lock);
if(ibuf && ibuf->x > 0 && ibuf->y > 0) {
*width= ibuf->x;
*height= ibuf->y;
}
else if(sima->image && sima->image->type==IMA_TYPE_R_RESULT && scene) {
/* not very important, just nice */
*width= (scene->r.xsch*scene->r.size)/100;
*height= (scene->r.ysch*scene->r.size)/100;
}
/* I know a bit weak... but preview uses not actual image size */
// XXX else if(image_preview_active(sima, width, height));
else {
*width= 256;
*height= 256;
}
ED_space_image_release_buffer(sima, lock);
}
void ED_image_aspect(Image *ima, float *aspx, float *aspy)

View File

@ -48,8 +48,9 @@
#include "DNA_text_types.h"
#include "DNA_userdef_types.h"
#include "BLI_blenlib.h"
#include "BLI_arithb.h"
#include "BLI_blenlib.h"
#include "BLI_threads.h"
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
@ -187,6 +188,8 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
/* preview rect? */
if(node->flag & NODE_PREVIEW) {
/* only recalculate size when there's a preview actually, otherwise we use stored result */
BLI_lock_thread(LOCK_PREVIEW);
if(node->preview && node->preview->rect) {
float aspect= 1.0f;
@ -222,6 +225,8 @@ static void node_update(const bContext *C, bNodeTree *ntree, bNode *node)
node->prvr.ymin= dy - oldh;
dy= node->prvr.ymin - NODE_DYS/2;
}
BLI_unlock_thread(LOCK_PREVIEW);
}
/* XXX ugly hack, typeinfo for group is generated */
@ -836,9 +841,12 @@ static void node_draw_basis(const bContext *C, ARegion *ar, SpaceNode *snode, bN
}
/* preview */
if(node->flag & NODE_PREVIEW)
if(node->flag & NODE_PREVIEW) {
BLI_lock_thread(LOCK_PREVIEW);
if(node->preview && node->preview->rect)
node_draw_preview(node->preview, &node->prvr);
BLI_unlock_thread(LOCK_PREVIEW);
}
uiEndBlock(C, node->block);
uiDrawBlock(C, node->block);

View File

@ -152,7 +152,7 @@ static void compo_startjob(void *cjv, short *stop, short *do_update)
{
CompoJob *cj= cjv;
bNodeTree *ntree= cj->localtree;
if(cj->scene->use_nodes==0)
return;
@ -176,8 +176,11 @@ static void compo_startjob(void *cjv, short *stop, short *do_update)
void snode_composite_job(const bContext *C, ScrArea *sa)
{
SpaceNode *snode= sa->spacedata.first;
wmJob *steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa);
CompoJob *cj= MEM_callocN(sizeof(CompoJob), "compo job");
wmJob *steve;
CompoJob *cj;
steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, WM_JOB_EXCL_RENDER);
cj= MEM_callocN(sizeof(CompoJob), "compo job");
/* customdata for preview thread */
cj->scene= CTX_data_scene(C);

View File

@ -84,8 +84,9 @@ static void rna_Image_fields_update(bContext *C, PointerRNA *ptr)
{
Image *ima= ptr->id.data;
ImBuf *ibuf;
void *lock;
ibuf= BKE_image_get_ibuf(ima, NULL);
ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
if(ibuf) {
short nr= 0;
@ -96,6 +97,8 @@ static void rna_Image_fields_update(bContext *C, PointerRNA *ptr)
if(nr)
BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
}
BKE_image_release_ibuf(ima, lock);
}
static void rna_Image_reload_update(bContext *C, PointerRNA *ptr)
@ -157,14 +160,22 @@ static int rna_Image_has_data_get(PointerRNA *ptr)
static int rna_Image_depth_get(PointerRNA *ptr)
{
Image *im= (Image*)ptr->data;
ImBuf *ibuf= BKE_image_get_ibuf(im, NULL);
ImBuf *ibuf;
void *lock;
int depth;
ibuf= BKE_image_acquire_ibuf(im, NULL, &lock);
if (!ibuf) return 0;
if(!ibuf)
depth= 0;
else if(ibuf->rect_float)
depth= 128;
else
depth= ibuf->depth;
if (ibuf->rect_float)
return 128;
BKE_image_release_ibuf(im, lock);
return ibuf->depth;
return depth;
}
#else

View File

@ -191,7 +191,8 @@ static EnumPropertyItem dc_z_items[] = {DC_RGB, DC_Z, DC_LCMS, DC_ZERO};
static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *C, PointerRNA *ptr, int *free)
{
SpaceImage *sima= (SpaceImage*)ptr->data;
ImBuf *ibuf= ED_space_image_buffer(sima);
ImBuf *ibuf;
void *lock;
int zbuf, alpha;
if(C==NULL) {
@ -199,9 +200,13 @@ static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *C, P
return dc_all_items;
}
ibuf= ED_space_image_acquire_buffer(sima, &lock);
alpha= ibuf && (ibuf->channels == 4);
zbuf= ibuf && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels==1));
ED_space_image_release_buffer(sima, lock);
if(alpha && zbuf)
return dc_all_items;
else if(alpha)
@ -215,8 +220,13 @@ static EnumPropertyItem *rna_SpaceImageEditor_draw_channels_itemf(bContext *C, P
static void rna_SpaceImageEditor_curves_update(bContext *C, PointerRNA *ptr)
{
SpaceImage *sima= (SpaceImage*)ptr->data;
ImBuf *ibuf;
void *lock;
ibuf= ED_space_image_acquire_buffer(sima, &lock);
curvemapping_do_ibuf(sima->cumap, ibuf);
ED_space_image_release_buffer(sima, lock);
curvemapping_do_ibuf(sima->cumap, ED_space_image_buffer(sima));
WM_event_add_notifier(C, NC_IMAGE, sima->image);
}

View File

@ -50,7 +50,8 @@ static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **i
RenderData *rd= data;
if(scene && (rd->scemode & R_DOCOMP)) {
RenderResult *rr= RE_GetResult(RE_GetRender(scene->id.name));
Render *re= RE_GetRender(scene->id.name);
RenderResult *rr= RE_AcquireResultWrite(re);
if(rr) {
CompBuf *outbuf, *zbuf=NULL;
@ -78,11 +79,15 @@ static void node_composit_exec_composite(void *data, bNode *node, bNodeStack **i
rr->rectf= outbuf->rect;
outbuf->malloc= 0;
free_compbuf(outbuf);
RE_ReleaseResult(re);
/* signal for imageviewer to refresh (it converts to byte rects...) */
BKE_image_signal(BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"), NULL, IMA_SIGNAL_FREE);
return;
}
else
RE_ReleaseResult(re);
}
}
if(in[0]->data)

View File

@ -350,11 +350,12 @@ void node_composit_rlayers_out(RenderData *rd, RenderLayer *rl, bNodeStack **out
static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
{
Scene *sce= (Scene *)node->id;
Render *re= (sce)? RE_GetRender(sce->id.name): NULL;
RenderData *rd= data;
RenderResult *rr= NULL;
if(sce)
rr= RE_GetResult(RE_GetRender(sce->id.name));
if(re)
rr= RE_AcquireResultRead(re);
if(rr) {
SceneRenderLayer *srl= BLI_findlink(&sce->r.layers, node->custom1);
@ -389,7 +390,10 @@ static void node_composit_exec_rlayers(void *data, bNode *node, bNodeStack **in,
}
}
}
}
}
if(re)
RE_ReleaseResult(re);
};

View File

@ -614,7 +614,9 @@ void generate_preview(bNode *node, CompBuf *stackbuf)
if(stackbuf->rect==NULL && stackbuf->rect_procedural==NULL) return;
stackbuf_use= typecheck_compbuf(stackbuf, CB_RGBA);
BLI_lock_thread(LOCK_PREVIEW);
if(stackbuf->x > stackbuf->y) {
preview->xsize= 140;
preview->ysize= (140*stackbuf->y)/stackbuf->x;
@ -628,14 +630,15 @@ void generate_preview(bNode *node, CompBuf *stackbuf)
cbuf= generate_procedural_preview(stackbuf_use, preview->xsize, preview->ysize);
else
cbuf= scalefast_compbuf(stackbuf_use, preview->xsize, preview->ysize);
/* this ensures free-compbuf does the right stuff */
SWAP(float *, cbuf->rect, node->preview->rect);
BLI_unlock_thread(LOCK_PREVIEW);
free_compbuf(cbuf);
if(stackbuf_use!=stackbuf)
free_compbuf(stackbuf_use);
}
}

View File

@ -157,8 +157,11 @@ void RE_FreeAllRender (void);
/* get results and statistics */
void RE_FreeRenderResult(struct RenderResult *rr);
struct RenderResult *RE_GetResult(struct Render *re);
void RE_GetResultImage(struct Render *re, struct RenderResult *rr);
struct RenderResult *RE_AcquireResultRead(struct Render *re);
struct RenderResult *RE_AcquireResultWrite(struct Render *re);
void RE_ReleaseResult(struct Render *re);
void RE_AcquireResultImage(struct Render *re, struct RenderResult *rr);
void RE_ReleaseResultImage(struct Render *re);
struct RenderStats *RE_GetStats(struct Render *re);
void RE_ResultGet32(struct Render *re, unsigned int *rect);
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name);

View File

@ -121,6 +121,10 @@ struct Render
RenderResult *pushedresult;
/* a list of RenderResults, for fullsample */
ListBase fullresult;
/* read/write mutex, all internal code that writes to re->result must use a
write lock, all external code must use a read lock. internal code is assumed
to not conflict with writes, so no lock used for that */
ThreadRWMutex resultmutex;
/* window size, display rect, viewplane */
int winx, winy;

View File

@ -213,11 +213,15 @@ static void free_render_result(ListBase *lb, RenderResult *rr)
/* all layers except the active one get temporally pushed away */
static void push_render_result(Render *re)
{
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
/* officially pushed result should be NULL... error can happen with do_seq */
RE_FreeRenderResult(re->pushedresult);
re->pushedresult= re->result;
re->result= NULL;
BLI_rw_mutex_unlock(&re->resultmutex);
}
/* if scemode is R_SINGLE_LAYER, at end of rendering, merge the both render results */
@ -229,6 +233,8 @@ static void pop_render_result(Render *re)
return;
}
if(re->pushedresult) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(re->pushedresult->rectx==re->result->rectx && re->pushedresult->recty==re->result->recty) {
/* find which layer in pushedresult should be replaced */
SceneRenderLayer *srl;
@ -255,6 +261,8 @@ static void pop_render_result(Render *re)
RE_FreeRenderResult(re->pushedresult);
re->pushedresult= NULL;
BLI_rw_mutex_unlock(&re->resultmutex);
}
}
@ -920,6 +928,8 @@ static void read_render_result(Render *re, int sample)
{
char str[FILE_MAX];
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
RE_FreeRenderResult(re->result);
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
@ -928,6 +938,8 @@ static void read_render_result(Render *re, int sample)
if(!read_render_result_from_file(str, re->result))
printf("cannot read: %s\n", str);
BLI_rw_mutex_unlock(&re->resultmutex);
}
/* *************************************************** */
@ -946,11 +958,30 @@ Render *RE_GetRender(const char *name)
}
/* if you want to know exactly what has been done */
RenderResult *RE_GetResult(Render *re)
RenderResult *RE_AcquireResultRead(Render *re)
{
if(re) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ);
return re->result;
}
return NULL;
}
RenderResult *RE_AcquireResultWrite(Render *re)
{
if(re) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
return re->result;
}
return NULL;
}
void RE_ReleaseResult(Render *re)
{
if(re)
return re->result;
return NULL;
BLI_rw_mutex_unlock(&re->resultmutex);
}
/* displist.c util.... */
@ -973,38 +1004,49 @@ RenderLayer *render_get_active_layer(Render *re, RenderResult *rr)
/* fill provided result struct with what's currently active or done */
void RE_GetResultImage(Render *re, RenderResult *rr)
void RE_AcquireResultImage(Render *re, RenderResult *rr)
{
memset(rr, 0, sizeof(RenderResult));
if(re && re->result) {
RenderLayer *rl;
rr->rectx= re->result->rectx;
rr->recty= re->result->recty;
rr->rectf= re->result->rectf;
rr->rectz= re->result->rectz;
rr->rect32= re->result->rect32;
/* active layer */
rl= render_get_active_layer(re, re->result);
if(re) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_READ);
if(rl) {
if(rr->rectf==NULL)
rr->rectf= rl->rectf;
if(rr->rectz==NULL)
rr->rectz= RE_RenderLayerGetPass(rl, SCE_PASS_Z);
if(re->result) {
RenderLayer *rl;
rr->rectx= re->result->rectx;
rr->recty= re->result->recty;
rr->rectf= re->result->rectf;
rr->rectz= re->result->rectz;
rr->rect32= re->result->rect32;
/* active layer */
rl= render_get_active_layer(re, re->result);
if(rl) {
if(rr->rectf==NULL)
rr->rectf= rl->rectf;
if(rr->rectz==NULL)
rr->rectz= RE_RenderLayerGetPass(rl, SCE_PASS_Z);
}
}
}
}
void RE_ReleaseResultImage(Render *re)
{
if(re)
BLI_rw_mutex_unlock(&re->resultmutex);
}
/* caller is responsible for allocating rect in correct size! */
void RE_ResultGet32(Render *re, unsigned int *rect)
{
RenderResult rres;
RE_GetResultImage(re, &rres);
RE_AcquireResultImage(re, &rres);
if(rres.rect32)
memcpy(rect, rres.rect32, sizeof(int)*rres.rectx*rres.recty);
else if(rres.rectf) {
@ -1022,6 +1064,8 @@ void RE_ResultGet32(Render *re, unsigned int *rect)
else
/* else fill with black */
memset(rect, 0, sizeof(int)*re->rectx*re->recty);
RE_ReleaseResultImage(re);
}
@ -1042,12 +1086,15 @@ Render *RE_NewRender(const char *name)
re= MEM_callocN(sizeof(Render), "new render");
BLI_addtail(&RenderList, re);
strncpy(re->name, name, RE_MAXNAME);
BLI_rw_mutex_init(&re->resultmutex);
}
/* prevent UI to draw old results */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
RE_FreeRenderResult(re->result);
re->result= NULL;
re->result_ok= 0;
BLI_rw_mutex_unlock(&re->resultmutex);
/* set default empty callbacks */
re->display_init= result_nothing;
@ -1072,6 +1119,7 @@ Render *RE_NewRender(const char *name)
/* only call this while you know it will remove the link too */
void RE_FreeRender(Render *re)
{
BLI_rw_mutex_end(&re->resultmutex);
free_renderdata_tables(re);
free_sample_tables(re);
@ -1153,6 +1201,8 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, int winx, int winy
make_sample_tables(re);
/* if preview render, we try to keep old result */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(re->r.scemode & R_PREVIEWBUTS) {
if(re->result && re->result->rectx==re->rectx && re->result->recty==re->recty);
else {
@ -1168,6 +1218,8 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, int winx, int winy
re->result->rectx= re->rectx;
re->result->recty= re->recty;
}
BLI_rw_mutex_unlock(&re->resultmutex);
/* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
re->clipcrop= 1.0f + 2.0f/(float)(re->winx>re->winy?re->winy:re->winx);
@ -1184,8 +1236,12 @@ void RE_SetDispRect (struct Render *re, rcti *disprect)
re->recty= disprect->ymax-disprect->ymin;
/* initialize render result */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
RE_FreeRenderResult(re->result);
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
BLI_rw_mutex_unlock(&re->resultmutex);
}
void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend)
@ -1345,11 +1401,15 @@ static void render_tile_processor(Render *re, int firsttile)
if(re->test_break(re->tbh))
return;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
/* hrmf... exception, this is used for preview render, re-entrant, so render result has to be re-used */
if(re->result==NULL || re->result->layers.first==NULL) {
if(re->result) RE_FreeRenderResult(re->result);
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
}
BLI_rw_mutex_unlock(&re->resultmutex);
re->stats_draw(re->sdh, &re->i);
@ -1357,7 +1417,7 @@ static void render_tile_processor(Render *re, int firsttile)
return;
initparts(re);
/* assuming no new data gets added to dbase... */
R= *re;
@ -1384,7 +1444,7 @@ static void render_tile_processor(Render *re, int firsttile)
break;
}
}
freeparts(re);
}
@ -1522,6 +1582,8 @@ static void threaded_tile_processor(Render *re)
rctf viewplane= re->viewplane;
int rendering=1, counter= 1, drawtimer=0, hasdrawn, minx=0;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
/* first step; free the entire render result, make new, and/or prepare exr buffer saving */
if(re->result==NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
RE_FreeRenderResult(re->result);
@ -1533,6 +1595,8 @@ static void threaded_tile_processor(Render *re)
else
re->result= new_render_result(re, &re->disprect, 0, re->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE));
}
BLI_rw_mutex_unlock(&re->resultmutex);
if(re->result==NULL)
return;
@ -1540,7 +1604,7 @@ static void threaded_tile_processor(Render *re)
/* warning; no return here without closing exr file */
initparts(re);
if(re->result->exrhandle) {
RenderResult *rr;
char str[FILE_MAX];
@ -1629,6 +1693,8 @@ static void threaded_tile_processor(Render *re)
}
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(re->result->exrhandle) {
RenderResult *rr;
@ -1644,6 +1710,8 @@ static void threaded_tile_processor(Render *re)
read_render_result(re, 0);
}
BLI_rw_mutex_unlock(&re->resultmutex);
/* unset threadsafety */
g_break= 0;
@ -1823,8 +1891,10 @@ static void do_render_blur_3d(Render *re)
}
/* swap results */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
RE_FreeRenderResult(re->result);
re->result= rres;
BLI_rw_mutex_unlock(&re->resultmutex);
set_mblur_offs(0.0f);
re->i.curblur= 0; /* stats */
@ -1894,8 +1964,11 @@ static void do_render_fields_3d(Render *re)
do_render_blur_3d(re);
else
do_render_3d(re);
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
rr1= re->result;
re->result= NULL;
BLI_rw_mutex_unlock(&re->resultmutex);
/* second field */
if(!re->test_break(re->tbh)) {
@ -1921,8 +1994,11 @@ static void do_render_fields_3d(Render *re)
re->recty *= 2;
re->disprect.ymin *= 2;
re->disprect.ymax *= 2;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
re->result= new_render_result(re, &re->disprect, 0, RR_USEMEM);
RE_FreeRenderResult(rr1);
if(rr2) {
if(re->r.mode & R_ODDFIELD)
merge_renderresult_fields(re->result, rr2, rr1);
@ -1931,12 +2007,14 @@ static void do_render_fields_3d(Render *re)
RE_FreeRenderResult(rr2);
}
RE_FreeRenderResult(rr1);
re->i.curfield= 0; /* stats */
/* weak... the display callback wants an active renderlayer pointer... */
re->result->renlay= render_get_active_layer(re, re->result);
BLI_rw_mutex_unlock(&re->resultmutex);
re->display_draw(re->ddh, re->result, NULL);
}
@ -2000,6 +2078,8 @@ static void do_render_fields_blur_3d(Render *re)
if((re->r.mode & R_CROP)==0) {
RenderResult *rres;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
/* sub-rect for merge call later on */
re->result->tilerect= re->disprect;
@ -2020,6 +2100,8 @@ static void do_render_fields_blur_3d(Render *re)
/* weak... the display callback wants an active renderlayer pointer... */
re->result->renlay= render_get_active_layer(re, re->result);
BLI_rw_mutex_unlock(&re->resultmutex);
re->display_init(re->dih, re->result);
re->display_draw(re->ddh, re->result, NULL);
}
@ -2176,7 +2258,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
}
/* ensure we get either composited result or the active layer */
RE_GetResultImage(re, &rres);
RE_AcquireResultImage(re, &rres);
/* accumulate with filter, and clip */
mask= (1<<sample);
@ -2195,6 +2277,8 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
}
}
RE_ReleaseResultImage(re);
/* show stuff */
if(sample!=re->osa-1) {
/* weak... the display callback wants an active renderlayer pointer... */
@ -2206,9 +2290,11 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
break;
}
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(re->result->rectf)
MEM_freeN(re->result->rectf);
re->result->rectf= rectf;
BLI_rw_mutex_unlock(&re->resultmutex);
}
void RE_MergeFullSample(Render *re, Scene *sce, bNodeTree *ntree)
@ -2309,9 +2395,12 @@ static void do_render_composite_fields_blur_3d(Render *re)
static void renderresult_stampinfo(Scene *scene)
{
RenderResult rres;
Render *re= RE_GetRender(scene->id.name);
/* this is the basic trick to get the displayed float or char rect from render result */
RE_GetResultImage(RE_GetRender(scene->id.name), &rres);
RE_AcquireResultImage(re, &rres);
BKE_stamp_buf(scene, (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
RE_ReleaseResultImage(re);
}
static void do_render_seq(Render * re)
@ -2327,6 +2416,8 @@ static void do_render_seq(Render * re)
recurs_depth--;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(ibuf) {
if(ibuf->rect_float) {
if (!rr->rectf)
@ -2369,6 +2460,8 @@ static void do_render_seq(Render * re)
else
rr->rect32= MEM_callocN(sizeof(int)*rr->rectx*rr->recty, "render_seq rect");
}
BLI_rw_mutex_unlock(&re->resultmutex);
}
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
@ -2388,14 +2481,15 @@ static void do_render_all_options(Render *re)
re->stats_draw(re->sdh, &re->i);
re->display_draw(re->ddh, re->result, NULL);
}
else {
do_render_composite_fields_blur_3d(re);
}
/* for UI only */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
renderresult_add_names(re->result);
BLI_rw_mutex_unlock(&re->resultmutex);
re->i.lastframetime= PIL_check_seconds_timer()- re->i.starttime;
@ -2622,7 +2716,7 @@ static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
char name[FILE_MAX];
RenderResult rres;
RE_GetResultImage(re, &rres);
RE_AcquireResultImage(re, &rres);
/* write movie or image */
if(BKE_imtype_is_movie(scene->r.imtype)) {
@ -2686,6 +2780,8 @@ static void do_write_image_or_movie(Render *re, Scene *scene, bMovieHandle *mh)
}
}
RE_ReleaseResultImage(re);
BLI_timestr(re->i.lastframetime, name);
printf(" Time: %s\n", name);
fflush(stdout); /* needed for renderd !! (not anymore... (ton)) */
@ -2723,7 +2819,8 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
do_write_image_or_movie(re, scene, mh);
}
} else {
re->test_break(re->tbh);
if(re->test_break(re->tbh))
G.afbreek= 1;
}
}
} else {
@ -2769,9 +2866,10 @@ void RE_BlenderAnim(Render *re, Scene *scene, int sfra, int efra, int tfra)
do_render_all_options(re);
if(re->test_break(re->tbh) == 0) {
if(re->test_break(re->tbh) == 0)
do_write_image_or_movie(re, scene, mh);
}
else
G.afbreek= 1;
if(G.afbreek==1) {
/* remove touched file */
@ -3006,6 +3104,7 @@ static void external_render_3d(Render *re, RenderEngineType *type)
{
RenderEngine engine;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(re->result==NULL || !(re->r.scemode & R_PREVIEWBUTS)) {
RE_FreeRenderResult(re->result);
@ -3014,6 +3113,7 @@ static void external_render_3d(Render *re, RenderEngineType *type)
else
re->result= new_render_result(re, &re->disprect, 0, 0); // XXX re->r.scemode & (R_EXR_TILE_FILE|R_FULL_SAMPLE));
}
BLI_rw_mutex_unlock(&re->resultmutex);
if(re->result==NULL)
return;
@ -3027,6 +3127,7 @@ static void external_render_3d(Render *re, RenderEngineType *type)
free_render_result(&engine.fullresult, engine.fullresult.first);
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(re->result->exrhandle) {
RenderResult *rr;
@ -3042,5 +3143,6 @@ static void external_render_3d(Render *re, RenderEngineType *type)
read_render_result(re, 0);
}
BLI_rw_mutex_unlock(&re->resultmutex);
}

View File

@ -862,6 +862,7 @@ static void sss_create_tree_mat(Render *re, Material *mat)
setting them back, maybe we need to create our own Render? */
/* do SSS preprocessing render */
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
rr= re->result;
osa= re->osa;
osaflag= re->r.mode & R_OSA;
@ -875,13 +876,16 @@ static void sss_create_tree_mat(Render *re, Material *mat)
if(!(re->r.scemode & R_PREVIEWBUTS))
re->result= NULL;
BLI_rw_mutex_unlock(&re->resultmutex);
RE_TileProcessor(re, 0, 1);
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
if(!(re->r.scemode & R_PREVIEWBUTS)) {
RE_FreeRenderResult(re->result);
re->result= rr;
}
BLI_rw_mutex_unlock(&re->resultmutex);
re->i.partsdone= partsdone;
re->sss_mat= NULL;

View File

@ -226,8 +226,10 @@ void WM_set_framebuffer_index_color(int index);
int WM_framebuffer_to_index(unsigned int col);
/* threaded Jobs Manager */
#define WM_JOB_PRIORITY 1
#define WM_JOB_EXCL_RENDER 2
struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void *owner);
struct wmJob *WM_jobs_get(struct wmWindowManager *wm, struct wmWindow *win, void *owner, int flag);
int WM_jobs_test(struct wmWindowManager *wm, void *owner);

View File

@ -107,6 +107,7 @@ struct wmJob {
/* internal */
void *owner;
int flag;
short suspended, running, ready, do_update, stop;
/* once running, we store this separately */
@ -123,7 +124,7 @@ struct wmJob {
/* returns current or adds new job, but doesnt run it */
/* every owner only gets a single job, adding a new one will stop running stop and
when stopped it starts the new one */
wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner)
wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner, int flag)
{
wmJob *steve;
@ -137,6 +138,7 @@ wmJob *WM_jobs_get(wmWindowManager *wm, wmWindow *win, void *owner)
BLI_addtail(&wm->jobs, steve);
steve->win= win;
steve->owner= owner;
steve->flag= flag;
}
return steve;
@ -198,20 +200,25 @@ static void *do_job_thread(void *job_v)
}
/* dont allow same startjob to be executed twice */
static void wm_jobs_test_suspend(wmWindowManager *wm, wmJob *test)
static void wm_jobs_test_suspend_stop(wmWindowManager *wm, wmJob *test)
{
wmJob *steve;
int suspend= 0;
for(steve= wm->jobs.first; steve; steve= steve->next)
if(steve!=test)
if(steve->running)
if(steve->startjob==test->startjob)
break;
if(steve)
test->suspended= 1;
else
test->suspended= 0;
for(steve= wm->jobs.first; steve; steve= steve->next) {
if(steve==test || !steve->running) continue;
if(steve->startjob!=test->startjob && !(test->flag & WM_JOB_EXCL_RENDER)) continue;
if((test->flag & WM_JOB_EXCL_RENDER) && !(steve->flag & WM_JOB_EXCL_RENDER)) continue;
suspend= 1;
/* if this job has higher priority, stop others */
if(test->flag & WM_JOB_PRIORITY)
steve->stop= 1;
}
/* possible suspend ourselfs, waiting for other jobs, or de-suspend */
test->suspended= suspend;
}
/* if job running, the same owner gave it a new job */
@ -225,7 +232,7 @@ void WM_jobs_start(wmWindowManager *wm, wmJob *steve)
else {
if(steve->customdata && steve->startjob) {
wm_jobs_test_suspend(wm, steve);
wm_jobs_test_suspend_stop(wm, steve);
if(steve->suspended==0) {
/* copy to ensure proper free in end */