static int fluid_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { /* only one bake job at a time */ if (WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_SIM_FLUID)) return OPERATOR_CANCELLED; if (!fluidsimBake(C, op->reports, CTX_data_active_object(C), true)) return OPERATOR_CANCELLED; return OPERATOR_FINISHED; }
static int ptcache_bake_modal(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Scene *scene = (Scene *) op->customdata; /* no running blender, remove handler and pass through */ if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_POINTCACHE)) { return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; } return OPERATOR_PASS_THROUGH; }
static int clip_prefetch_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { /* no running blender, remove handler and pass through */ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_wm_area(C), WM_JOB_TYPE_CLIP_PREFETCH)) return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; /* running render */ switch (event->type) { case ESCKEY: return OPERATOR_RUNNING_MODAL; } return OPERATOR_PASS_THROUGH; }
/* catch esc */ static int screen_render_modal(bContext *C, wmOperator *UNUSED(op), wmEvent *event) { /* no running blender, remove handler and pass through */ if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C))) { return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH; } /* running render */ switch (event->type) { case ESCKEY: return OPERATOR_RUNNING_MODAL; break; } return OPERATOR_PASS_THROUGH; }
static int screencast_exec(bContext *C, wmOperator *op) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); bScreen *screen = CTX_wm_screen(C); wmJob *wm_job; ScreenshotJob *sj; /* if called again, stop the running job */ if (WM_jobs_test(wm, screen, WM_JOB_TYPE_SCREENCAST)) WM_jobs_stop(wm, screen, screenshot_startjob); wm_job = WM_jobs_get(wm, win, screen, "Screencast", 0, WM_JOB_TYPE_SCREENCAST); sj = MEM_callocN(sizeof(ScreenshotJob), "screenshot job"); /* setup sj */ if (RNA_boolean_get(op->ptr, "full")) { sj->x = 0; sj->y = 0; sj->dumpsx = WM_window_pixels_x(win); sj->dumpsy = WM_window_pixels_y(win); } else { ScrArea *curarea = CTX_wm_area(C); sj->x = curarea->totrct.xmin; sj->y = curarea->totrct.ymin; sj->dumpsx = curarea->totrct.xmax - sj->x; sj->dumpsy = curarea->totrct.ymax - sj->y; } sj->bmain = CTX_data_main(C); sj->scene = CTX_data_scene(C); sj->wm = wm; BKE_reports_init(&sj->reports, RPT_PRINT); /* setup job */ WM_jobs_customdata_set(wm_job, sj, screenshot_freejob); WM_jobs_timer(wm_job, 0.1, 0, NC_SCREEN | ND_SCREENCAST); WM_jobs_callbacks(wm_job, screenshot_startjob, NULL, screenshot_updatejob, screenshot_endjob); WM_jobs_start(sj->wm, wm_job); screencast_cursor_toggle(sj->wm, 1); WM_event_add_notifier(C, NC_SCREEN | ND_SCREENCAST, screen); return OPERATOR_FINISHED; }
/* catch esc */ static int screen_render_modal(bContext *C, wmOperator *op, const wmEvent *event) { Scene *scene = (Scene *) op->customdata; /* no running blender, remove handler and pass through */ if (0 == WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) { return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; } /* running render */ switch (event->type) { case ESCKEY: return OPERATOR_RUNNING_MODAL; } return OPERATOR_PASS_THROUGH; }
/* catch esc */ static int bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { /* no running blender, remove handler and pass through */ if (0 == WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_OBJECT_BAKE)) return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH; /* running render */ switch (event->type) { case ESCKEY: { G.is_break = true; return OPERATOR_RUNNING_MODAL; } } return OPERATOR_PASS_THROUGH; }
void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, rcti *rect) { if (idp) { wmWindowManager *wm = CTX_wm_manager(C); ScrArea *sa = CTX_wm_area(C); ID *id = (ID *)idp; ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; SpaceProperties *sbuts = CTX_wm_space_properties(C); ShaderPreview *sp = WM_jobs_customdata(wm, sa); rcti newrect; int ok; int newx = BLI_rcti_size_x(rect); int newy = BLI_rcti_size_y(rect); newrect.xmin = rect->xmin; newrect.xmax = rect->xmin; newrect.ymin = rect->ymin; newrect.ymax = rect->ymin; if (parent) { ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect); ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect); } else { ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect); } if (ok) { *rect = newrect; } /* start a new preview render job if signaled through sbuts->preview, * if no render result was found and no preview render job is running, * or if the job is running and the size of preview changed */ if ((sbuts != NULL && sbuts->preview) || (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW)) || (sp && (ABS(sp->sizex - newx) >= 2 || ABS(sp->sizey - newy) > 2))) { if (sbuts != NULL) { sbuts->preview = 0; } ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER); } } }
static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmJob *wm_job; BakeAPIRender *bkr; Render *re; Scene *scene = CTX_data_scene(C); bake_set_props(op, scene); /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE)) return OPERATOR_CANCELLED; bkr = MEM_mallocN(sizeof(BakeAPIRender), "render bake"); /* init bake render */ bake_init_api_data(op, C, bkr); re = bkr->render; /* setup new render */ RE_test_break_cb(re, NULL, bake_break); RE_progress_cb(re, bkr, bake_progress_update); /* setup job */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake", WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_BAKE); WM_jobs_customdata_set(wm_job, bkr, bake_freejob); WM_jobs_timer(wm_job, 0.5, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */ WM_jobs_callbacks(wm_job, bake_startjob, NULL, NULL, NULL); G.is_break = false; G.is_rendering = true; WM_jobs_start(CTX_wm_manager(C), wm_job); WM_cursor_wait(0); /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); return OPERATOR_RUNNING_MODAL; }
void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, rcti *rect) { if (idp) { wmWindowManager *wm = CTX_wm_manager(C); ScrArea *sa = CTX_wm_area(C); ID *id = (ID *)idp; ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; SpaceButs *sbuts = sa->spacedata.first; rcti newrect; int ok; int newx = BLI_rcti_size_x(rect); int newy = BLI_rcti_size_y(rect); newrect.xmin = rect->xmin; newrect.xmax = rect->xmin; newrect.ymin = rect->ymin; newrect.ymax = rect->ymin; if (parent) { ok = ed_preview_draw_rect(sa, 1, 1, rect, &newrect); ok &= ed_preview_draw_rect(sa, 1, 0, rect, &newrect); } else ok = ed_preview_draw_rect(sa, 0, 0, rect, &newrect); if (ok) *rect = newrect; /* start a new preview render job if signalled through sbuts->preview, * or if no render result was found and no preview render job is running */ if ((sbuts->spacetype == SPACE_BUTS && sbuts->preview) || (!ok && !WM_jobs_test(wm, sa, WM_JOB_TYPE_RENDER_PREVIEW))) { sbuts->preview = 0; ED_preview_shader_job(C, sa, id, parent, slot, newx, newy, PR_BUTS_RENDER); } } }
int thumbnails_running(struct FileList* filelist, const struct bContext* C) { return WM_jobs_test(CTX_wm_manager(C), filelist); }
/* using context, starts job */ static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event) { /* new render clears all callbacks */ Main *mainp; Scene *scene= CTX_data_scene(C); SceneRenderLayer *srl=NULL; bScreen *screen= CTX_wm_screen(C); View3D *v3d= CTX_wm_view3d(C); Render *re; wmJob *steve; RenderJob *rj; Image *ima; int jobflag; const short is_animation= RNA_boolean_get(op->ptr, "animation"); const short is_write_still= RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override= v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; /* only one render job at a time */ if(WM_jobs_test(CTX_wm_manager(C), scene)) return OPERATOR_CANCELLED; if(!RE_is_rendering_allowed(scene, camera_override, op->reports)) { return OPERATOR_CANCELLED; } if(!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.imtype)) { BKE_report(op->reports, RPT_ERROR, "Can't write a single file with an animation format selected."); return OPERATOR_CANCELLED; } /* stop all running jobs, currently previews frustrate Render */ WM_jobs_stop_all(CTX_wm_manager(C)); /* get main */ if(G.rt == 101) { /* thread-safety experiment, copy main from the undo buffer */ mainp= BKE_undo_get_main(&scene); } else mainp= CTX_data_main(C); /* cancel animation playback */ if (screen->animtimer) ED_screen_animation_play(C, 0, 0); /* handle UI stuff */ WM_cursor_wait(1); /* flush multires changes (for sculpt) */ multires_force_render_update(CTX_data_active_object(C)); /* cleanup sequencer caches before starting user triggered render. otherwise, invalidated cache entries can make their way into the output rendering. We can't put that into RE_BlenderFrame, since sequence rendering can call that recursively... (peter) */ seq_stripelem_cache_cleanup(); /* get editmode results */ ED_object_exit_editmode(C, 0); /* 0 = does not exit editmode */ // store spare // get view3d layer, local layer, make this nice api call to render // store spare /* ensure at least 1 area shows result */ render_view_open(C, event->x, event->y); jobflag= WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS; /* single layer re-render */ if(RNA_property_is_set(op->ptr, "layer")) { SceneRenderLayer *rl; Scene *scn; char scene_name[MAX_ID_NAME-2], rl_name[RE_MAXNAME]; RNA_string_get(op->ptr, "layer", rl_name); RNA_string_get(op->ptr, "scene", scene_name); scn = (Scene *)BLI_findstring(&mainp->scene, scene_name, offsetof(ID, name) + 2); rl = (SceneRenderLayer *)BLI_findstring(&scene->r.layers, rl_name, offsetof(SceneRenderLayer, name)); if (scn && rl) { /* camera switch wont have updated */ scn->r.cfra= scene->r.cfra; scene_camera_switch_update(scn); scene = scn; srl = rl; } jobflag |= WM_JOB_SUSPEND; } /* job custom data */ rj= MEM_callocN(sizeof(RenderJob), "render job"); rj->main= mainp; rj->scene= scene; rj->win= CTX_wm_window(C); rj->srl = srl; rj->camera_override = camera_override; rj->lay = (v3d)? v3d->lay: scene->lay; rj->anim= is_animation; rj->write_still= is_write_still && !is_animation; rj->iuser.scene= scene; rj->iuser.ok= 1; rj->reports= op->reports; /* setup job */ steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Render", jobflag); 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, render_endjob); /* get a render result image, and make sure it is empty */ ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(rj->scene, ima); rj->image= ima; /* setup new render */ re= RE_NewRender(scene->id.name); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_draw_cb(re, rj, image_rect_update); RE_stats_draw_cb(re, rj, image_renderinfo_cb); RE_progress_cb(re, rj, render_progress_update); rj->re= re; G.afbreek= 0; WM_jobs_start(CTX_wm_manager(C), steve); WM_cursor_wait(0); WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene); /* we set G.rendering here already instead of only in the job, this ensure main loop or other scene updates are disabled in time, since they may have started before the job thread */ G.rendering = 1; /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; }
/* note: also check undo_history_exec() in bottom if you change notifiers */ static int ed_undo_step(bContext *C, int step, const char *undoname) { wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); ScrArea *sa = CTX_wm_area(C); /* undo during jobs are running can easily lead to freeing data using by jobs, * or they can just lead to freezing job in some other cases */ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY)) { return OPERATOR_CANCELLED; } /* grease pencil can be can be used in plenty of spaces, so check it first */ if (ED_gpencil_session_active()) { return ED_undo_gpencil_step(C, step, undoname); } if (sa && (sa->spacetype == SPACE_IMAGE)) { SpaceImage *sima = (SpaceImage *)sa->spacedata.first; if ((obact && (obact->mode & OB_MODE_TEXTURE_PAINT)) || (sima->mode == SI_MODE_PAINT)) { if (!ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname) && undoname) { if (U.uiflag & USER_GLOBALUNDO) { ED_viewport_render_kill_jobs(C, true); BKE_undo_name(C, undoname); } } WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } } if (sa && (sa->spacetype == SPACE_TEXT)) { ED_text_undo_step(C, step); } else if (obedit) { if (OB_TYPE_SUPPORT_EDITMODE(obedit->type)) { if (undoname) undo_editmode_name(C, undoname); else undo_editmode_step(C, step); WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL); } } else { /* Note: we used to do a fall-through here where if the * mode-specific undo system had no more steps to undo (or * redo), the global undo would run. * * That was inconsistent with editmode, and also makes for * unecessarily tricky interaction with the other undo * systems. */ if (obact && obact->mode & OB_MODE_TEXTURE_PAINT) { ED_undo_paint_step(C, UNDO_PAINT_IMAGE, step, undoname); } else if (obact && obact->mode & OB_MODE_SCULPT) { ED_undo_paint_step(C, UNDO_PAINT_MESH, step, undoname); } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { if (step == 1) PE_undo(scene); else PE_redo(scene); } else if (U.uiflag & USER_GLOBALUNDO) { // note python defines not valid here anymore. //#ifdef WITH_PYTHON // XXX BPY_scripts_clear_pyobjects(); //#endif /* for global undo/redo we should just clear the editmode stack */ /* for example, texface stores image pointers */ undo_editmode_clear(); ED_viewport_render_kill_jobs(C, true); if (undoname) BKE_undo_name(C, undoname); else BKE_undo_step(C, step); scene = CTX_data_scene(C); WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene); } } WM_event_add_notifier(C, NC_WINDOW, NULL); if (win) { win->addmousemove = true; } return OPERATOR_FINISHED; }
static bool screen_opengl_render_init(bContext *C, wmOperator *op) { /* new render clears all callbacks */ wmWindowManager *wm = CTX_wm_manager(C); wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); ScrArea *prevsa = CTX_wm_area(C); ARegion *prevar = CTX_wm_region(C); GPUOffScreen *ofs; OGLRender *oglrender; int sizex, sizey; bool is_view_context = RNA_boolean_get(op->ptr, "view_context"); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); char err_out[256] = "unknown"; if (G.background) { BKE_report(op->reports, RPT_ERROR, "Cannot use OpenGL render in background mode (no opengl context)"); return false; } /* only one render job at a time */ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) return false; if (is_sequencer) { is_view_context = false; } else { /* ensure we have a 3d view */ if (!ED_view3d_context_activate(C)) { RNA_boolean_set(op->ptr, "view_context", false); is_view_context = false; } if (!is_view_context && scene->camera == NULL) { BKE_report(op->reports, RPT_ERROR, "Scene has no camera"); return false; } } if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) { BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected"); return false; } /* stop all running jobs, except screen one. currently previews frustrate Render */ WM_jobs_kill_all_except(wm, CTX_wm_screen(C)); /* create offscreen buffer */ sizex = (scene->r.size * scene->r.xsch) / 100; sizey = (scene->r.size * scene->r.ysch) / 100; /* corrects render size with actual size, not every card supports non-power-of-two dimensions */ ofs = GPU_offscreen_create(sizex, sizey, err_out); if (!ofs) { BKE_reportf(op->reports, RPT_ERROR, "Failed to create OpenGL off-screen buffer, %s", err_out); return false; } /* allocate opengl render */ oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender"); op->customdata = oglrender; oglrender->ofs = ofs; oglrender->sizex = sizex; oglrender->sizey = sizey; oglrender->bmain = CTX_data_main(C); oglrender->scene = scene; oglrender->cfrao = scene->r.cfra; oglrender->write_still = is_write_still && !is_animation; oglrender->is_sequencer = is_sequencer; if (is_sequencer) { oglrender->sseq = CTX_wm_space_seq(C); } oglrender->prevsa = prevsa; oglrender->prevar = prevar; if (is_view_context) { ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->ar); /* so quad view renders camera */ oglrender->rv3d = oglrender->ar->regiondata; /* MUST be cleared on exit */ oglrender->scene->customdata_mask_modal = ED_view3d_datamask(oglrender->scene, oglrender->v3d); /* apply immediately in case we're rendering from a script, * running notifiers again will overwrite */ oglrender->scene->customdata_mask |= oglrender->scene->customdata_mask_modal; if (oglrender->v3d->fx_settings.fx_flag & (GPU_FX_FLAG_DOF | GPU_FX_FLAG_SSAO)) { oglrender->fx = GPU_fx_compositor_create(); } } /* create render */ oglrender->re = RE_NewRender(scene->id.name); /* create image and image user */ oglrender->ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(oglrender->ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(oglrender->scene, oglrender->ima); oglrender->iuser.scene = scene; oglrender->iuser.ok = 1; /* create render result */ RE_InitState(oglrender->re, NULL, &scene->r, NULL, sizex, sizey, NULL); /* create render views */ screen_opengl_views_setup(oglrender); /* wm vars */ oglrender->wm = wm; oglrender->win = win; oglrender->totvideos = 0; oglrender->mh = NULL; oglrender->movie_ctx_arr = NULL; return true; }
/* using context, starts job */ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* new render clears all callbacks */ Main *mainp; Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = NULL; Render *re; wmJob *wm_job; RenderJob *rj; Image *ima; int jobflag; const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport"); View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL; struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; ScrArea *sa; /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) return OPERATOR_CANCELLED; if (RE_force_single_renderlayer(scene)) WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL); if (!RE_is_rendering_allowed(scene, camera_override, op->reports)) { return OPERATOR_CANCELLED; } if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) { BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected"); return OPERATOR_CANCELLED; } /* stop all running jobs, except screen one. currently previews frustrate Render */ WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); /* get main */ if (G.debug_value == 101) { /* thread-safety experiment, copy main from the undo buffer */ mainp = BKE_undo_get_main(&scene); } else mainp = CTX_data_main(C); /* cancel animation playback */ if (ED_screen_animation_playing(CTX_wm_manager(C))) ED_screen_animation_play(C, 0, 0); /* handle UI stuff */ WM_cursor_wait(1); /* flush sculpt and editmode changes */ ED_editors_flush_edits(C, true); /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_BlenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(); // store spare // get view3d layer, local layer, make this nice api call to render // store spare /* ensure at least 1 area shows result */ sa = render_view_open(C, event->x, event->y); jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS; /* custom scene and single layer re-render */ screen_render_scene_layer_set(op, mainp, &scene, &srl); if (RNA_struct_property_is_set(op->ptr, "layer")) jobflag |= WM_JOB_SUSPEND; /* job custom data */ rj = MEM_callocN(sizeof(RenderJob), "render job"); rj->main = mainp; rj->scene = scene; rj->current_scene = rj->scene; rj->srl = srl; rj->camera_override = camera_override; rj->lay_override = 0; rj->anim = is_animation; rj->write_still = is_write_still && !is_animation; rj->iuser.scene = scene; rj->iuser.ok = 1; rj->reports = op->reports; rj->orig_layer = 0; rj->last_layer = 0; rj->sa = sa; BKE_color_managed_display_settings_copy(&rj->display_settings, &scene->display_settings); BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings); if (sa) { SpaceImage *sima = sa->spacedata.first; rj->orig_layer = sima->iuser.layer; } if (v3d) { if (scene->lay != v3d->lay) { rj->lay_override = v3d->lay; rj->v3d_override = true; } else if (camera_override && camera_override != scene->camera) rj->v3d_override = true; if (v3d->localvd) rj->lay_override |= v3d->localvd->lay; } /* Lock the user interface depending on render settings. */ if (scene->r.use_lock_interface) { int renderlay = rj->lay_override ? rj->lay_override : scene->lay; WM_set_locked_interface(CTX_wm_manager(C), true); /* Set flag interface need to be unlocked. * * This is so because we don't have copy of render settings * accessible from render job and copy is needed in case * of non-locked rendering, so we wouldn't try to unlock * anything if option was initially unset but then was * enabled during rendering. */ rj->interface_locked = true; /* Clean memory used by viewport? */ clean_viewport_memory(rj->main, scene, renderlay); } /* setup job */ if (RE_seq_render_active(scene, &scene->r)) name = "Sequence Render"; else name = "Render"; wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag, WM_JOB_TYPE_RENDER); WM_jobs_customdata_set(wm_job, rj, render_freejob); WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob); /* get a render result image, and make sure it is empty */ ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(rj->scene, ima); rj->image = ima; /* setup new render */ re = RE_NewRender(scene->id.name); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_update_cb(re, rj, image_rect_update); RE_current_scene_update_cb(re, rj, current_scene_update); RE_stats_draw_cb(re, rj, image_renderinfo_cb); RE_progress_cb(re, rj, render_progress_update); rj->re = re; G.is_break = false; /* store actual owner of job, so modal operator could check for it, * the reason of this is that active scene could change when rendering * several layers from compositor [#31800] */ op->customdata = scene; WM_jobs_start(CTX_wm_manager(C), wm_job); WM_cursor_wait(0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); /* we set G.is_rendering here already instead of only in the job, this ensure * main loop or other scene updates are disabled in time, since they may * have started before the job thread */ G.is_rendering = true; /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; }
/* using context, starts job */ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *event) { /* new render clears all callbacks */ Main *mainp; Scene *scene = CTX_data_scene(C); SceneRenderLayer *srl = NULL; View3D *v3d = CTX_wm_view3d(C); Render *re; wmJob *wm_job; RenderJob *rj; Image *ima; int jobflag; const short is_animation = RNA_boolean_get(op->ptr, "animation"); const short is_write_still = RNA_boolean_get(op->ptr, "write_still"); struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; const char *name; Object *active_object = CTX_data_active_object(C); /* only one render job at a time */ if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_RENDER)) return OPERATOR_CANCELLED; if (!RE_is_rendering_allowed(scene, camera_override, op->reports)) { return OPERATOR_CANCELLED; } if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) { BKE_report(op->reports, RPT_ERROR, "Cannot write a single file with an animation format selected"); return OPERATOR_CANCELLED; } /* stop all running jobs, except screen one. currently previews frustrate Render */ WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); /* get main */ if (G.debug_value == 101) { /* thread-safety experiment, copy main from the undo buffer */ mainp = BKE_undo_get_main(&scene); } else mainp = CTX_data_main(C); /* cancel animation playback */ if (ED_screen_animation_playing(CTX_wm_manager(C))) ED_screen_animation_play(C, 0, 0); /* handle UI stuff */ WM_cursor_wait(1); /* flush multires changes (for sculpt) */ multires_force_render_update(active_object); /* flush changes from dynamic topology sculpt */ sculptsession_bm_to_me_for_render(active_object); /* cleanup sequencer caches before starting user triggered render. * otherwise, invalidated cache entries can make their way into * the output rendering. We can't put that into RE_BlenderFrame, * since sequence rendering can call that recursively... (peter) */ BKE_sequencer_cache_cleanup(); /* get editmode results */ ED_object_editmode_load(CTX_data_edit_object(C)); // store spare // get view3d layer, local layer, make this nice api call to render // store spare /* ensure at least 1 area shows result */ render_view_open(C, event->x, event->y); jobflag = WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS; /* custom scene and single layer re-render */ screen_render_scene_layer_set(op, mainp, &scene, &srl); if (RNA_struct_property_is_set(op->ptr, "layer")) jobflag |= WM_JOB_SUSPEND; /* job custom data */ rj = MEM_callocN(sizeof(RenderJob), "render job"); rj->main = mainp; rj->scene = scene; rj->win = CTX_wm_window(C); rj->srl = srl; rj->camera_override = camera_override; rj->lay = scene->lay; rj->anim = is_animation; rj->write_still = is_write_still && !is_animation; rj->iuser.scene = scene; rj->iuser.ok = 1; rj->reports = op->reports; if (v3d) { rj->lay = v3d->lay; if (v3d->localvd) rj->lay |= v3d->localvd->lay; } /* setup job */ if (RE_seq_render_active(scene, &scene->r)) name = "Sequence Render"; else name = "Render"; wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, name, jobflag, WM_JOB_TYPE_RENDER); WM_jobs_customdata_set(wm_job, rj, render_freejob); WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob); /* get a render result image, and make sure it is empty */ ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result"); BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE); BKE_image_backup_render(rj->scene, ima); rj->image = ima; /* setup new render */ re = RE_NewRender(scene->id.name); RE_test_break_cb(re, rj, render_breakjob); RE_draw_lock_cb(re, rj, render_drawlock); RE_display_draw_cb(re, rj, image_rect_update); RE_stats_draw_cb(re, rj, image_renderinfo_cb); RE_progress_cb(re, rj, render_progress_update); rj->re = re; G.is_break = FALSE; /* store actual owner of job, so modal operator could check for it, * the reason of this is that active scene could change when rendering * several layers from compositor [#31800] */ op->customdata = scene; WM_jobs_start(CTX_wm_manager(C), wm_job); WM_cursor_wait(0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); /* we set G.is_rendering here already instead of only in the job, this ensure * main loop or other scene updates are disabled in time, since they may * have started before the job thread */ G.is_rendering = TRUE; /* add modal handler for ESC */ WM_event_add_modal_handler(C, op); return OPERATOR_RUNNING_MODAL; }
/* ui callbacks should call this rather than calling WM_operator_repeat() themselves */ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) { int ret = 0; if (op) { wmWindowManager *wm = CTX_wm_manager(C); struct Scene *scene = CTX_data_scene(C); /* keep in sync with logic in view3d_panel_operator_redo() */ ARegion *ar = CTX_wm_region(C); ARegion *ar1 = BKE_area_find_region_active_win(CTX_wm_area(C)); if (ar1) CTX_wm_region_set(C, ar1); if ((WM_operator_repeat_check(C, op)) && (WM_operator_poll(C, op->type)) && /* note, undo/redo cant run if there are jobs active, * check for screen jobs only so jobs like material/texture/world preview * (which copy their data), wont stop redo, see [#29579]], * * note, - WM_operator_check_ui_enabled() jobs test _must_ stay in sync with this */ (WM_jobs_test(wm, scene, WM_JOB_TYPE_ANY) == 0)) { int retval; ED_viewport_render_kill_jobs(C, true); if (G.debug & G_DEBUG) printf("redo_cb: operator redo %s\n", op->type->name); ED_undo_pop_op(C, op); if (op->type->check) { op->type->check(C, op); /* ignore return value since its running again anyway */ } retval = WM_operator_repeat(C, op); if ((retval & OPERATOR_FINISHED) == 0) { if (G.debug & G_DEBUG) printf("redo_cb: operator redo failed: %s, return %d\n", op->type->name, retval); ED_undo_redo(C); } else { ret = 1; } } else { if (G.debug & G_DEBUG) { printf("redo_cb: WM_operator_repeat_check returned false %s\n", op->type->name); } } /* set region back */ CTX_wm_region_set(C, ar); } else { if (G.debug & G_DEBUG) { printf("redo_cb: ED_undo_operator_repeat called with NULL 'op'\n"); } } return ret; }
int thumbnails_running(wmWindowManager *wm, FileList *filelist) { return WM_jobs_test(wm, filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL); }
wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm, struct wmWindow *win, struct Main *bmain, struct ViewLayer *view_layer, struct Scene *scene, int delay, int frame) { EEVEE_LightBake *lbake = NULL; /* only one render job at a time */ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER)) { return NULL; } wmJob *wm_job = WM_jobs_get(wm, win, scene, "Bake Lighting", WM_JOB_EXCL_RENDER | WM_JOB_PRIORITY | WM_JOB_PROGRESS, WM_JOB_TYPE_LIGHT_BAKE); /* If job exists do not recreate context and depsgraph. */ EEVEE_LightBake *old_lbake = (EEVEE_LightBake *)WM_jobs_customdata_get(wm_job); if (old_lbake && (old_lbake->view_layer_input == view_layer) && (old_lbake->bmain == bmain)) { lbake = MEM_callocN(sizeof(EEVEE_LightBake), "EEVEE_LightBake"); /* Cannot reuse depsgraph for now because we cannot get the update from the * main database directly. TODO reuse depsgraph and only update positions. */ /* lbake->depsgraph = old_lbake->depsgraph; */ lbake->depsgraph = DEG_graph_new(scene, view_layer, DAG_EVAL_RENDER); lbake->mutex = BLI_mutex_alloc(); BLI_mutex_lock(old_lbake->mutex); old_lbake->own_resources = false; lbake->scene = scene; lbake->bmain = bmain; lbake->view_layer_input = view_layer; lbake->gl_context = old_lbake->gl_context; lbake->own_resources = true; lbake->delay = delay; lbake->frame = frame; if (lbake->gl_context == NULL) { lbake->gl_context = WM_opengl_context_create(); wm_window_reset_drawable(); } if (old_lbake->stop != NULL) { *old_lbake->stop = 1; } BLI_mutex_unlock(old_lbake->mutex); } else { lbake = EEVEE_lightbake_job_data_alloc(bmain, view_layer, scene, true, frame); lbake->delay = delay; } WM_jobs_customdata_set(wm_job, lbake, EEVEE_lightbake_job_data_free); WM_jobs_timer(wm_job, 0.4, NC_SCENE | NA_EDITED, 0); WM_jobs_callbacks( wm_job, EEVEE_lightbake_job, NULL, EEVEE_lightbake_update, EEVEE_lightbake_update); G.is_break = false; return wm_job; }