void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey) { wmJob *wm_job; IconPreview *ip, *old_ip; /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview", WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, WM_JOB_TYPE_RENDER_PREVIEW); ip = MEM_callocN(sizeof(IconPreview), "icon preview"); /* render all resolutions from suspended job too */ old_ip = WM_jobs_customdata_get(wm_job); if (old_ip) BLI_movelisttolist(&ip->sizes, &old_ip->sizes); /* customdata for preview thread */ ip->scene = CTX_data_scene(C); ip->owner = id; ip->id = id; icon_preview_add_size(ip, rect, sizex, sizey); /* setup job */ WM_jobs_customdata_set(wm_job, ip, icon_preview_free); WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL); WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); }
void clip_start_prefetch_job(const bContext *C) { wmJob *wm_job; PrefetchJob *pj; SpaceClip *sc = CTX_wm_space_clip(C); if (prefetch_check_early_out(C)) return; wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_area(C), "Prefetching", WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_PREFETCH); /* create new job */ pj = MEM_callocN(sizeof(PrefetchJob), "prefetch job"); pj->clip = ED_space_clip_get_clip(sc); pj->start_frame = prefetch_get_start_frame(C); pj->current_frame = sc->user.framenr; pj->end_frame = prefetch_get_final_frame(C); pj->render_size = sc->user.render_size; pj->render_flag = sc->user.render_flag; WM_jobs_customdata_set(wm_job, pj, prefetch_freejob); WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0); WM_jobs_callbacks(wm_job, prefetch_startjob, NULL, NULL, NULL); G.is_break = FALSE; /* and finally start the job */ WM_jobs_start(CTX_wm_manager(C), wm_job); }
static int ptcache_bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { bool all = STREQ(op->type->idname, "PTCACHE_OT_bake_all"); PointCacheJob *job = MEM_mallocN(sizeof(PointCacheJob), "PointCacheJob"); job->baker = ptcache_baker_create(C, op, all); job->baker->bake_job = job; job->baker->update_progress = ptcache_job_update; wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_data_scene(C), "Point Cache", WM_JOB_PROGRESS, WM_JOB_TYPE_POINTCACHE); WM_jobs_customdata_set(wm_job, job, ptcache_job_free); WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_POINTCACHE, NC_OBJECT | ND_POINTCACHE); WM_jobs_callbacks(wm_job, ptcache_job_startjob, NULL, NULL, ptcache_job_endjob); WM_set_locked_interface(CTX_wm_manager(C), true); WM_jobs_start(CTX_wm_manager(C), wm_job); WM_event_add_modal_handler(C, op); /* we must run modal until the bake job is done, otherwise the undo push * happens before the job ends, which can lead to race conditions between * the baking and file writing code */ return OPERATOR_RUNNING_MODAL; }
/* * Bake Dynamic Paint image sequence surface */ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) { DynamicPaintModifierData *pmd = NULL; DynamicPaintCanvasSettings *canvas; Object *ob = ED_object_context(C); Scene *scene = CTX_data_scene(C); DynamicPaintSurface *surface; /* * Get modifier data */ pmd = (DynamicPaintModifierData *)modifiers_findByType(ob, eModifierType_DynamicPaint); if (!pmd) { BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found"); return OPERATOR_CANCELLED; } /* Make sure we're dealing with a canvas */ canvas = pmd->canvas; if (!canvas) { BKE_report(op->reports, RPT_ERROR, "Bake failed: invalid canvas"); return OPERATOR_CANCELLED; } surface = get_activeSurface(canvas); /* Set state to baking and init surface */ canvas->error[0] = '\0'; canvas->flags |= MOD_DPAINT_BAKING; DynamicPaintBakeJob *job = MEM_mallocN(sizeof(DynamicPaintBakeJob), "DynamicPaintBakeJob"); job->bmain = CTX_data_main(C); job->scene = scene; job->ob = ob; job->canvas = canvas; job->surface = surface; wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Dynamic Paint Bake", WM_JOB_PROGRESS, WM_JOB_TYPE_DPAINT_BAKE); WM_jobs_customdata_set(wm_job, job, dpaint_bake_free); WM_jobs_timer(wm_job, 0.1, NC_OBJECT | ND_MODIFIER, NC_OBJECT | ND_MODIFIER); WM_jobs_callbacks(wm_job, dpaint_bake_startjob, NULL, NULL, dpaint_bake_endjob); WM_set_locked_interface(CTX_wm_manager(C), true); /* Bake Dynamic Paint */ WM_jobs_start(CTX_wm_manager(C), wm_job); return OPERATOR_FINISHED; }
static void render_view3d_do(RenderEngine *engine, const bContext *C) { wmJob *wm_job; RenderPreview *rp; Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); int width = ar->winx, height = ar->winy; int divider = 1; int resolution_threshold = scene->r.preview_start_resolution * scene->r.preview_start_resolution; if (CTX_wm_window(C) == NULL) return; if (!render_view3d_flag_changed(engine, C)) return; wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); rp = MEM_callocN(sizeof(RenderPreview), "render preview"); rp->job = wm_job; while (width * height > resolution_threshold) { width = max_ii(1, width / 2); height = max_ii(1, height / 2); divider *= 2; } /* customdata for preview thread */ rp->scene = scene; rp->engine = engine; rp->sa = CTX_wm_area(C); rp->ar = CTX_wm_region(C); rp->v3d = rp->sa->spacedata.first; rp->rv3d = CTX_wm_region_view3d(C); rp->bmain = CTX_data_main(C); rp->resolution_divider = divider; rp->start_resolution_divider = divider; rp->has_freestyle = (scene->r.mode & R_EDGE_FRS) != 0; copy_m4_m4(rp->viewmat, rp->rv3d->viewmat); /* clear info text */ engine->text[0] = '\0'; /* setup job */ WM_jobs_customdata_set(wm_job, rp, render_view3d_free); WM_jobs_timer(wm_job, 0.1, NC_SPACE | ND_SPACE_VIEW3D, NC_SPACE | ND_SPACE_VIEW3D); WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL); WM_jobs_start(CTX_wm_manager(C), wm_job); engine->flag &= ~RE_ENGINE_DO_UPDATE; }
void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, int method) { Object *ob = CTX_data_active_object(C); wmJob *wm_job; ShaderPreview *sp; Scene *scene = CTX_data_scene(C); short id_type = GS(id->name); bool use_new_shading = BKE_scene_use_new_shading_nodes(scene); /* Only texture node preview is supported with Cycles. */ if (use_new_shading && method == PR_NODE_RENDER && id_type != ID_TE) { return; } ED_preview_ensure_dbase(); wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); sp = MEM_callocN(sizeof(ShaderPreview), "shader preview"); /* customdata for preview thread */ sp->scene = scene; sp->owner = owner; sp->sizex = sizex; sp->sizey = sizey; sp->pr_method = method; sp->id = id; sp->parent = parent; sp->slot = slot; sp->bmain = CTX_data_main(C); /* hardcoded preview .blend for cycles/internal, this should be solved * once with custom preview .blend path for external engines */ if ((method != PR_NODE_RENDER) && id_type != ID_TE && use_new_shading) { sp->pr_main = G_pr_main_cycles; } else { sp->pr_main = G_pr_main; } if (ob && ob->totcol) copy_v4_v4(sp->col, ob->col); else sp->col[0] = sp->col[1] = sp->col[2] = sp->col[3] = 1.0f; /* setup job */ WM_jobs_customdata_set(wm_job, sp, shader_preview_free); WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL); WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL); WM_jobs_start(CTX_wm_manager(C), wm_job); }
void ED_preview_icon_job( const bContext *C, void *owner, ID *id, unsigned int *rect, int sizex, int sizey) { wmJob *wm_job; IconPreview *ip, *old_ip; ED_preview_ensure_dbase(); /* suspended start means it starts after 1 timer step, see WM_jobs_timer below */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Icon Preview", WM_JOB_EXCL_RENDER | WM_JOB_SUSPEND, WM_JOB_TYPE_RENDER_PREVIEW); ip = MEM_callocN(sizeof(IconPreview), "icon preview"); /* render all resolutions from suspended job too */ old_ip = WM_jobs_customdata_get(wm_job); if (old_ip) { BLI_movelisttolist(&ip->sizes, &old_ip->sizes); } /* customdata for preview thread */ ip->bmain = CTX_data_main(C); ip->scene = CTX_data_scene(C); ip->depsgraph = CTX_data_depsgraph(C); ip->owner = owner; ip->id = id; ip->id_copy = duplicate_ids(id); icon_preview_add_size(ip, rect, sizex, sizey); /* Special threading hack: * warn main code that this preview is being rendered and cannot be freed... */ { PreviewImage *prv_img = owner; if (prv_img->tag & PRV_TAG_DEFFERED) { prv_img->tag |= PRV_TAG_DEFFERED_RENDERING; } } /* setup job */ WM_jobs_customdata_set(wm_job, ip, icon_preview_free); WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW); WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); }
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; }
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; }
static void render_view3d_do(RenderEngine *engine, const bContext *C, int keep_data) { wmJob *wm_job; RenderPreview *rp; Scene *scene = CTX_data_scene(C); if (CTX_wm_window(C) == NULL) { engine->flag |= RE_ENGINE_DO_UPDATE; return; } wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); rp = MEM_callocN(sizeof(RenderPreview), "render preview"); /* customdata for preview thread */ rp->scene = scene; rp->engine = engine; rp->sa = CTX_wm_area(C); rp->ar = CTX_wm_region(C); rp->v3d = rp->sa->spacedata.first; rp->rv3d = CTX_wm_region_view3d(C); rp->bmain = CTX_data_main(C); rp->keep_data = keep_data; copy_m4_m4(rp->viewmat, rp->rv3d->viewmat); /* dont alloc in threads */ if (engine->text == NULL) engine->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"); /* setup job */ WM_jobs_customdata_set(wm_job, rp, render_view3d_free); WM_jobs_timer(wm_job, 0.1, NC_SPACE | ND_SPACE_VIEW3D, NC_SPACE | ND_SPACE_VIEW3D); WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL); WM_jobs_start(CTX_wm_manager(C), wm_job); engine->flag &= ~RE_ENGINE_DO_UPDATE; }
void sequencer_preview_add_sound(const bContext *C, Sequence *seq) { /* first, get the preview job, if it exists */ wmJob *wm_job; PreviewJob *pj; ScrArea *sa = CTX_wm_area(C); PreviewJobAudio *audiojob = MEM_callocN(sizeof(PreviewJobAudio), "preview_audio"); wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Strip Previews", WM_JOB_PROGRESS, WM_JOB_TYPE_SEQ_BUILD_PREVIEW); pj = WM_jobs_customdata_get(wm_job); if (!pj) { pj = MEM_callocN(sizeof(PreviewJob), "preview rebuild job"); pj->mutex = BLI_mutex_alloc(); pj->scene = CTX_data_scene(C); WM_jobs_customdata_set(wm_job, pj, free_preview_job); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER); WM_jobs_callbacks(wm_job, preview_startjob, NULL, NULL, preview_endjob); } /* attempt to lock mutex of job here */ audiojob->sound = seq->sound; BLI_mutex_lock(pj->mutex); BLI_addtail(&pj->previews, audiojob); pj->total++; BLI_mutex_unlock(pj->mutex); if (!WM_jobs_is_running(wm_job)) { G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); } ED_area_tag_redraw(sa); }
static void render_view3d_do(RenderEngine *engine, const bContext *C) { wmJob *wm_job; RenderPreview *rp; Scene *scene = CTX_data_scene(C); if (CTX_wm_window(C) == NULL) return; if (!render_view3d_flag_changed(engine, C)) return; wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), CTX_wm_region(C), "Render Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); rp = MEM_callocN(sizeof(RenderPreview), "render preview"); rp->job = wm_job; /* customdata for preview thread */ rp->scene = scene; rp->engine = engine; rp->sa = CTX_wm_area(C); rp->ar = CTX_wm_region(C); rp->v3d = rp->sa->spacedata.first; rp->rv3d = CTX_wm_region_view3d(C); rp->bmain = CTX_data_main(C); rp->resolution_divider = START_RESOLUTION_DIVIDER; copy_m4_m4(rp->viewmat, rp->rv3d->viewmat); /* clear info text */ engine->text[0] = '\0'; /* setup job */ WM_jobs_customdata_set(wm_job, rp, render_view3d_free); WM_jobs_timer(wm_job, 0.1, NC_SPACE | ND_SPACE_VIEW3D, NC_SPACE | ND_SPACE_VIEW3D); WM_jobs_callbacks(wm_job, render_view3d_startjob, NULL, NULL, NULL); WM_jobs_start(CTX_wm_manager(C), wm_job); engine->flag &= ~RE_ENGINE_DO_UPDATE; }
static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) { wmJob *wm_job; ProxyJob *pj; Scene *scene = CTX_data_scene(C); ScrArea *sa = CTX_wm_area(C); SpaceClip *sc = CTX_wm_space_clip(C); MovieClip *clip = ED_space_clip_get_clip(sc); if ((clip->flag & MCLIP_USE_PROXY) == 0) return OPERATOR_CANCELLED; wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies", WM_JOB_PROGRESS, WM_JOB_TYPE_CLIP_BUILD_PROXY); pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job"); pj->scene = scene; pj->main = CTX_data_main(C); pj->clip = clip; pj->clip_flag = clip->flag & MCLIP_TIMECODE_FLAGS; if (clip->anim) { pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag, clip->proxy.build_size_flag, clip->proxy.quality, true, NULL); } WM_jobs_customdata_set(wm_job, pj, proxy_freejob); WM_jobs_timer(wm_job, 0.2, NC_MOVIECLIP | ND_DISPLAY, 0); WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob); G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); ED_area_tag_redraw(sa); return OPERATOR_FINISHED; }
void thumbnails_start(FileList *filelist, const bContext *C) { wmJob *wm_job; ThumbnailJob *tj; int idx; /* prepare job data */ tj = MEM_callocN(sizeof(*tj), __func__); tj->filelist = filelist; for (idx = 0; idx < filelist->numfiles; idx++) { if (!filelist->filelist[idx].path) { continue; } if (!filelist->filelist[idx].image) { if (filelist->filelist[idx].flags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_FTFONT | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { FileImage *limg = MEM_callocN(sizeof(*limg), __func__); BLI_strncpy(limg->path, filelist->filelist[idx].path, sizeof(limg->path)); limg->index = idx; limg->flags = filelist->filelist[idx].flags; BLI_addtail(&tj->loadimages, limg); } } } BKE_reports_init(&tj->reports, RPT_PRINT); /* setup job */ wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, "Thumbnails", 0, WM_JOB_TYPE_FILESEL_THUMBNAIL); WM_jobs_customdata_set(wm_job, tj, thumbnails_free); WM_jobs_timer(wm_job, 0.5, NC_WINDOW, NC_WINDOW); WM_jobs_callbacks(wm_job, thumbnails_startjob, NULL, thumbnails_update, thumbnails_endjob); /* start the job */ WM_jobs_start(CTX_wm_manager(C), wm_job); }
/* /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// */ int get_material(Main *bmain, bContext *C, Scene *scene, bNodeTree *ntree, const char *address, int32_t mat_id) { /* Setup job */ wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Get LDB Material", WM_JOB_PROGRESS, WM_JOB_TYPE_RENDER); GetMaterialJob *mj = MEM_callocN(sizeof(GetMaterialJob), "get LDB mat job"); mj->C = C; mj->bmain = bmain; mj->ntree = ntree; mj->mat_id = mat_id; strcpy(mj->address, address); WM_jobs_customdata_set(wm_job, mj, get_material_data_free); WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_RENDER_RESULT, 0); WM_jobs_callbacks(wm_job, get_material_startjob, NULL, NULL, get_material_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); WM_cursor_wait(0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, scene); return 1; } /* get_material() */
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; }
/* 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; }
void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, MTex *slot, int sizex, int sizey, int method) { Object *ob = CTX_data_active_object(C); wmJob *wm_job; ShaderPreview *sp; Scene *scene = CTX_data_scene(C); short id_type = GS(id->name); /* Use workspace render only for buttons Window, * since the other previews are related to the datablock. */ if (!check_engine_supports_preview(scene)) { return; } /* Only texture node preview is supported with Cycles. */ if (method == PR_NODE_RENDER && id_type != ID_TE) { return; } ED_preview_ensure_dbase(); wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); sp = MEM_callocN(sizeof(ShaderPreview), "shader preview"); /* customdata for preview thread */ sp->scene = scene; sp->depsgraph = CTX_data_depsgraph(C); sp->owner = owner; sp->sizex = sizex; sp->sizey = sizey; sp->pr_method = method; sp->id = id; sp->id_copy = duplicate_ids(id); sp->own_id_copy = true; sp->parent = parent; sp->slot = slot; sp->bmain = CTX_data_main(C); Material *ma = NULL; /* hardcoded preview .blend for Eevee + Cycles, this should be solved * once with custom preview .blend path for external engines */ /* grease pencil use its own preview file */ if (GS(id->name) == ID_MA) { ma = (Material *)id; } if ((ma == NULL) || (ma->gp_style == NULL)) { sp->pr_main = G_pr_main; } else { sp->pr_main = G_pr_main_grease_pencil; } if (ob && ob->totcol) { copy_v4_v4(sp->color, ob->color); } else { ARRAY_SET_ITEMS(sp->color, 0.0f, 0.0f, 0.0f, 1.0f); } /* setup job */ WM_jobs_customdata_set(wm_job, sp, shader_preview_free); WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL); WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL); WM_jobs_start(CTX_wm_manager(C), wm_job); }
/* 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; }
static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, short do_job) { Scene *scene= CTX_data_scene(C); int i; FluidsimSettings *domainSettings; char debugStrBuffer[256]; int gridlevels = 0; const char *relbase= modifier_path_relbase(fsDomain); const char *strEnvName = "BLENDER_ELBEEMDEBUG"; // from blendercall.cpp const char *suffixConfigTmp = FLUID_SUFFIX_CONFIG_TMP; const char *suffixSurface = FLUID_SUFFIX_SURFACE; char targetDir[FILE_MAX]; // store & modify output settings char targetFile[FILE_MAX]; // temp. store filename from targetDir for access int outStringsChanged = 0; // modified? copy back before baking float domainMat[4][4]; float invDomMat[4][4]; int noFrames; int origFrame = scene->r.cfra; FluidAnimChannels *channels = MEM_callocN(sizeof(FluidAnimChannels), "fluid domain animation channels"); ListBase *fobjects = MEM_callocN(sizeof(ListBase), "fluid objects"); FluidsimModifierData *fluidmd = NULL; Mesh *mesh = NULL; FluidBakeJob *fb; elbeemSimulationSettings *fsset= MEM_callocN(sizeof(elbeemSimulationSettings), "Fluid sim settings"); fb= MEM_callocN(sizeof(FluidBakeJob), "fluid bake job"); if (getenv(strEnvName)) { int dlevel = atoi(getenv(strEnvName)); elbeemSetDebugLevel(dlevel); BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Debug messages activated due to envvar '%s'\n", strEnvName); elbeemDebugOut(debugStrBuffer); } /* make sure it corresponds to startFrame setting (old: noFrames = scene->r.efra - scene->r.sfra +1) */; noFrames = scene->r.efra - 0; if (noFrames<=0) { BKE_report(reports, RPT_ERROR, "No frames to export (check your animation range settings)"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* check scene for sane object/modifier settings */ if (!fluid_validate_scene(reports, scene, fsDomain)) { fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* these both have to be valid, otherwise we wouldn't be here */ fluidmd = (FluidsimModifierData *)modifiers_findByType(fsDomain, eModifierType_Fluidsim); domainSettings = fluidmd->fss; mesh = fsDomain->data; domainSettings->bakeStart = 1; domainSettings->bakeEnd = scene->r.efra; // calculate bounding box fluid_get_bb(mesh->mvert, mesh->totvert, fsDomain->obmat, domainSettings->bbStart, domainSettings->bbSize); // reset last valid frame domainSettings->lastgoodframe = -1; /* delete old baked files */ fluidsim_delete_until_lastframe(domainSettings, relbase); /* rough check of settings... */ if (domainSettings->previewresxyz > domainSettings->resolutionxyz) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::warning - Preview (%d) >= Resolution (%d)... setting equal.\n", domainSettings->previewresxyz, domainSettings->resolutionxyz); elbeemDebugOut(debugStrBuffer); domainSettings->previewresxyz = domainSettings->resolutionxyz; } // set adaptive coarsening according to resolutionxyz // this should do as an approximation, with in/outflow // doing this more accurate would be overkill // perhaps add manual setting? if (domainSettings->maxRefine <0) { if (domainSettings->resolutionxyz>128) { gridlevels = 2; } else if (domainSettings->resolutionxyz > 64) { gridlevels = 1; } else { gridlevels = 0; } } else { gridlevels = domainSettings->maxRefine; } BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::msg: Baking %s, refine: %d\n", fsDomain->id.name, gridlevels); elbeemDebugOut(debugStrBuffer); /* ******** prepare output file paths ******** */ outStringsChanged = fluid_init_filepaths(fsDomain, targetDir, targetFile, debugStrBuffer); channels->length = scene->r.efra; // DG TODO: why using endframe and not "noFrames" here? .. because "noFrames" is buggy too? (not using sfra) channels->aniFrameTime = (double)((double)domainSettings->animEnd - (double)domainSettings->animStart) / (double)noFrames; /* ******** initialize and allocate animation channels ******** */ fluid_init_all_channels(C, fsDomain, domainSettings, channels, fobjects); /* reset to original current frame */ scene->r.cfra = origFrame; ED_update_for_newframe(CTX_data_main(C), scene, 1); /* ******** init domain object's matrix ******** */ copy_m4_m4(domainMat, fsDomain->obmat); if (!invert_m4_m4(invDomMat, domainMat)) { BLI_snprintf(debugStrBuffer, sizeof(debugStrBuffer), "fluidsimBake::error - Invalid obj matrix?\n"); elbeemDebugOut(debugStrBuffer); BKE_report(reports, RPT_ERROR, "Invalid object matrix"); fluidbake_free_data(channels, fobjects, fsset, fb); return 0; } /* ******** start writing / exporting ******** */ // use .tmp, don't overwrite/delete original file BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixConfigTmp); // make sure these directories exist as well if (outStringsChanged) { BLI_make_existing_file(targetFile); } /* ******** export domain to elbeem ******** */ elbeemResetSettings(fsset); fsset->version = 1; fsset->threads = (domainSettings->threads == 0) ? BKE_scene_num_threads(scene) : domainSettings->threads; // setup global settings copy_v3_v3(fsset->geoStart, domainSettings->bbStart); copy_v3_v3(fsset->geoSize, domainSettings->bbSize); // simulate with 50^3 fsset->resolutionxyz = (int)domainSettings->resolutionxyz; fsset->previewresxyz = (int)domainSettings->previewresxyz; fsset->realsize = get_fluid_size_m(scene, fsDomain, domainSettings); fsset->viscosity = get_fluid_viscosity(domainSettings); get_fluid_gravity(fsset->gravity, scene, domainSettings); // simulate 5 frames, each 0.03 seconds, output to ./apitest_XXX.bobj.gz fsset->animStart = domainSettings->animStart; fsset->aniFrameTime = channels->aniFrameTime; fsset->noOfFrames = noFrames; // is otherwise subtracted in parser BLI_join_dirfile(targetFile, sizeof(targetFile), targetDir, suffixSurface); // defaults for compressibility and adaptive grids fsset->gstar = domainSettings->gstar; fsset->maxRefine = domainSettings->maxRefine; // check <-> gridlevels fsset->generateParticles = domainSettings->generateParticles; fsset->numTracerParticles = domainSettings->generateTracers; fsset->surfaceSmoothing = domainSettings->surfaceSmoothing; fsset->surfaceSubdivs = domainSettings->surfaceSubdivs; fsset->farFieldSize = domainSettings->farFieldSize; BLI_strncpy(fsset->outputPath, targetFile, sizeof(fsset->outputPath)); // domain channels fsset->channelSizeFrameTime = fsset->channelSizeViscosity = fsset->channelSizeGravity = channels->length; fsset->channelFrameTime = channels->DomainTime; fsset->channelViscosity = channels->DomainViscosity; fsset->channelGravity = channels->DomainGravity; fsset->runsimCallback = &runSimulationCallback; fsset->runsimUserData = fb; if (domainSettings->typeFlags & OB_FSBND_NOSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_NOSLIP; else if (domainSettings->typeFlags&OB_FSBND_PARTSLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_PARTSLIP; else if (domainSettings->typeFlags&OB_FSBND_FREESLIP) fsset->domainobsType = FLUIDSIM_OBSTACLE_FREESLIP; fsset->domainobsPartslip = domainSettings->partSlipValue; /* use domainobsType also for surface generation flag (bit: >=64) */ if (domainSettings->typeFlags & OB_FSSG_NOOBS) fsset->mFsSurfGenSetting = FLUIDSIM_FSSG_NOOBS; else fsset->mFsSurfGenSetting = 0; // "normal" mode fsset->generateVertexVectors = (domainSettings->domainNovecgen==0); // init blender domain transform matrix { int j; for (i=0; i<4; i++) { for (j=0; j<4; j++) { fsset->surfaceTrafo[i*4+j] = invDomMat[j][i]; } } } /* ******** init solver with settings ******** */ elbeemInit(); elbeemAddDomain(fsset); /* ******** export all fluid objects to elbeem ******** */ export_fluid_objects(fobjects, scene, channels->length); /* custom data for fluid bake job */ fb->settings = fsset; if (do_job) { wmJob *wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Fluid Simulation", WM_JOB_PROGRESS, WM_JOB_TYPE_OBJECT_SIM_FLUID); /* setup job */ WM_jobs_customdata_set(wm_job, fb, fluidbake_free); WM_jobs_timer(wm_job, 0.1, NC_SCENE|ND_FRAME, NC_SCENE|ND_FRAME); WM_jobs_callbacks(wm_job, fluidbake_startjob, NULL, NULL, fluidbake_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } else { short dummy_stop = 0, dummy_do_update = 0; float dummy_progress = 0.0f; /* blocking, use with exec() */ fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress); fluidbake_endjob((void *)fb); fluidbake_free((void *)fb); } /* ******** free stored animation data ******** */ fluidbake_free_data(channels, fobjects, NULL, NULL); // elbeemFree(); return 1; }