Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/render')
-rw-r--r--source/blender/render/RE_engine.h4
-rw-r--r--source/blender/render/RE_pipeline.h19
-rw-r--r--source/blender/render/intern/engine.c137
-rw-r--r--source/blender/render/intern/pipeline.c273
-rw-r--r--source/blender/render/intern/render_result.c2
-rw-r--r--source/blender/render/intern/render_types.h2
-rw-r--r--source/blender/render/intern/zbuf.c2
7 files changed, 227 insertions, 212 deletions
diff --git a/source/blender/render/RE_engine.h b/source/blender/render/RE_engine.h
index c31a41f66d5..7352ac7b12e 100644
--- a/source/blender/render/RE_engine.h
+++ b/source/blender/render/RE_engine.h
@@ -195,7 +195,7 @@ float RE_engine_get_camera_shift_x(RenderEngine *engine,
void RE_engine_get_camera_model_matrix(RenderEngine *engine,
struct Object *camera,
bool use_spherical_stereo,
- float *r_modelmat);
+ float r_modelmat[16]);
bool RE_engine_get_spherical_stereo(RenderEngine *engine, struct Object *camera);
bool RE_engine_test_break(RenderEngine *engine);
@@ -224,6 +224,8 @@ void RE_engine_register_pass(struct RenderEngine *engine,
const char *chanid,
eNodeSocketDatatype type);
+bool RE_engine_use_persistent_data(struct RenderEngine *engine);
+
/* Engine Types */
void RE_engines_init(void);
diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h
index 27dcd9e70ed..4534c86f7f7 100644
--- a/source/blender/render/RE_pipeline.h
+++ b/source/blender/render/RE_pipeline.h
@@ -184,14 +184,14 @@ void RE_InitRenderCB(struct Render *re);
void RE_FreeRender(struct Render *re);
/* only called on exit */
void RE_FreeAllRender(void);
-/* Free memory used by persistent data.
- * Invoked when loading new file.
- */
-void RE_FreeAllPersistentData(void);
-/* only call on file load */
+
+/* On file load, free render results. */
void RE_FreeAllRenderResults(void);
-/* for external render engines that can keep persistent data */
-void RE_FreePersistentData(void);
+/* On file load or changes engines, free persistent render data.
+ * Assumes no engines are currently rendering. */
+void RE_FreeAllPersistentData(void);
+/* Free persistent render data, optionally only for the given scene. */
+void RE_FreePersistentData(const Scene *scene);
/* get results and statistics */
void RE_FreeRenderResult(struct RenderResult *rr);
@@ -245,8 +245,6 @@ void RE_InitState(struct Render *re,
int winx,
int winy,
rcti *disprect);
-void RE_ChangeResolution(struct Render *re, int winx, int winy, rcti *disprect);
-void RE_ChangeModeFlag(struct Render *re, int flag, bool clear);
/* set up the viewplane/perspective matrix, three choices */
struct Object *RE_GetCamera(struct Render *re); /* return camera override if set */
@@ -297,9 +295,6 @@ void RE_RenderFreestyleStrokes(struct Render *re,
void RE_RenderFreestyleExternal(struct Render *re);
#endif
-/* Free memory and clear runtime data which is only needed during rendering. */
-void RE_CleanAfterRender(struct Render *re);
-
void RE_SetActiveRenderView(struct Render *re, const char *viewname);
const char *RE_GetActiveRenderView(struct Render *re);
diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c
index a43a78f5d3d..306d144f79d 100644
--- a/source/blender/render/intern/engine.c
+++ b/source/blender/render/intern/engine.c
@@ -140,6 +140,24 @@ RenderEngine *RE_engine_create(RenderEngineType *type)
return engine;
}
+static void engine_depsgraph_free(RenderEngine *engine)
+{
+ if (engine->depsgraph) {
+ /* Need GPU context since this might free GPU buffers. */
+ const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
+ if (use_gpu_context) {
+ DRW_render_context_enable(engine->re);
+ }
+
+ DEG_graph_free(engine->depsgraph);
+ engine->depsgraph = NULL;
+
+ if (use_gpu_context) {
+ DRW_render_context_disable(engine->re);
+ }
+ }
+}
+
void RE_engine_free(RenderEngine *engine)
{
#ifdef WITH_PYTHON
@@ -148,6 +166,8 @@ void RE_engine_free(RenderEngine *engine)
}
#endif
+ engine_depsgraph_free(engine);
+
BLI_mutex_end(&engine->update_render_passes_mutex);
MEM_freeN(engine);
@@ -526,7 +546,7 @@ float RE_engine_get_camera_shift_x(RenderEngine *engine, Object *camera, bool us
void RE_engine_get_camera_model_matrix(RenderEngine *engine,
Object *camera,
bool use_spherical_stereo,
- float *r_modelmat)
+ float r_modelmat[16])
{
/* When using spherical stereo, get model matrix without multiview,
* leaving stereo to be handled by the engine. */
@@ -598,34 +618,94 @@ RenderData *RE_engine_get_render_data(Render *re)
return &re->r;
}
+bool RE_engine_use_persistent_data(RenderEngine *engine)
+{
+ /* Re-rendering is not supported with GPU contexts, since the GPU context
+ * is destroyed when the render thread exists. */
+ return (engine->re->r.mode & R_PERSISTENT_DATA) && !(engine->type->flag & RE_USE_GPU_CONTEXT);
+}
+
+static bool engine_keep_depsgraph(RenderEngine *engine)
+{
+ /* For persistent data or GPU engines like Eevee, reuse the depsgraph between
+ * view layers and animation frames. For renderers like Cycles that create
+ * their own copy of the scene, persistent data must be explicitly enabled to
+ * keep memory usage low by default. */
+ return (engine->re->r.mode & R_PERSISTENT_DATA) || (engine->type->flag & RE_USE_GPU_CONTEXT);
+}
+
/* Depsgraph */
static void engine_depsgraph_init(RenderEngine *engine, ViewLayer *view_layer)
{
Main *bmain = engine->re->main;
Scene *scene = engine->re->scene;
+ bool reuse_depsgraph = false;
+
+ /* Reuse depsgraph from persistent data if possible. */
+ if (engine->depsgraph) {
+ if (DEG_get_bmain(engine->depsgraph) != bmain ||
+ DEG_get_input_scene(engine->depsgraph) != scene) {
+ /* If bmain or scene changes, we need a completely new graph. */
+ engine_depsgraph_free(engine);
+ }
+ else if (DEG_get_input_view_layer(engine->depsgraph) != view_layer) {
+ /* If only view layer changed, reuse depsgraph in the hope of reusing
+ * objects shared between view layers. */
+ DEG_graph_replace_owners(engine->depsgraph, bmain, scene, view_layer);
+ DEG_graph_tag_relations_update(engine->depsgraph);
+ }
+
+ reuse_depsgraph = true;
+ }
+
+ if (!engine->depsgraph) {
+ /* Ensure we only use persistent data for one scene / view layer at a time,
+ * to avoid excessive memory usage. */
+ RE_FreePersistentData(NULL);
- engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
- DEG_debug_name_set(engine->depsgraph, "RENDER");
+ /* Create new depsgraph if not cached with persistent data. */
+ engine->depsgraph = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER);
+ DEG_debug_name_set(engine->depsgraph, "RENDER");
+ }
if (engine->re->r.scemode & R_BUTS_PREVIEW) {
+ /* Update for preview render. */
Depsgraph *depsgraph = engine->depsgraph;
DEG_graph_relations_update(depsgraph);
+
+ /* Need GPU context since this might free GPU buffers. */
+ const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT) && reuse_depsgraph;
+ if (use_gpu_context) {
+ DRW_render_context_enable(engine->re);
+ }
+
DEG_evaluate_on_framechange(depsgraph, CFRA);
- DEG_ids_check_recalc(bmain, depsgraph, scene, view_layer, true);
- DEG_ids_clear_recalc(bmain, depsgraph);
+
+ if (use_gpu_context) {
+ DRW_render_context_disable(engine->re);
+ }
}
else {
- BKE_scene_graph_update_for_newframe(engine->depsgraph);
+ /* Go through update with full Python callbacks for regular render. */
+ BKE_scene_graph_update_for_newframe_ex(engine->depsgraph, false);
}
engine->has_grease_pencil = DRW_render_check_grease_pencil(engine->depsgraph);
}
-static void engine_depsgraph_free(RenderEngine *engine)
+static void engine_depsgraph_exit(RenderEngine *engine)
{
- DEG_graph_free(engine->depsgraph);
-
- engine->depsgraph = NULL;
+ if (engine->depsgraph) {
+ if (engine_keep_depsgraph(engine)) {
+ /* Clear recalc flags since the engine should have handled the updates for the currently
+ * rendered framed by now. */
+ DEG_ids_clear_recalc(engine->depsgraph, false);
+ }
+ else {
+ /* Free immediately to save memory. */
+ engine_depsgraph_free(engine);
+ }
+ }
}
void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
@@ -634,12 +714,15 @@ void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
return;
}
+ /* Clear recalc flags before update so engine can detect what changed. */
+ DEG_ids_clear_recalc(engine->depsgraph, false);
+
Render *re = engine->re;
double cfra = (double)frame + (double)subframe;
CLAMP(cfra, MINAFRAME, MAXFRAME);
BKE_scene_frame_set(re->scene, cfra);
- BKE_scene_graph_update_for_newframe(engine->depsgraph);
+ BKE_scene_graph_update_for_newframe_ex(engine->depsgraph, false);
BKE_scene_camera_switch_update(re->scene);
}
@@ -670,7 +753,6 @@ bool RE_bake_engine(Render *re,
{
RenderEngineType *type = RE_engines_find(re->r.engine);
RenderEngine *engine;
- bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
/* set render info */
re->i.cfra = re->scene->r.cfra;
@@ -729,13 +811,13 @@ bool RE_bake_engine(Render *re,
engine->tile_y = 0;
engine->flag &= ~RE_ENGINE_RENDERING;
+ /* Free depsgraph outside of parts mutex lock, since this locks OpenGL context
+ * while the the UI drawing might also lock the OpenGL context and parts mutex. */
+ engine_depsgraph_free(engine);
BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
- /* re->engine becomes zero if user changed active render engine during render */
- if (!persistent_data || !re->engine) {
- RE_engine_free(engine);
- re->engine = NULL;
- }
+ RE_engine_free(engine);
+ re->engine = NULL;
RE_parts_free(re);
BLI_rw_mutex_unlock(&re->partsmutex);
@@ -778,13 +860,14 @@ static void engine_render_view_layer(Render *re,
/* Perform render with engine. */
if (use_engine) {
- if (engine->type->flag & RE_USE_GPU_CONTEXT) {
+ const bool use_gpu_context = (engine->type->flag & RE_USE_GPU_CONTEXT);
+ if (use_gpu_context) {
DRW_render_context_enable(engine->re);
}
engine->type->render(engine, engine->depsgraph);
- if (engine->type->flag & RE_USE_GPU_CONTEXT) {
+ if (use_gpu_context) {
DRW_render_context_disable(engine->re);
}
}
@@ -800,13 +883,12 @@ static void engine_render_view_layer(Render *re,
}
/* Free dependency graph, if engine has not done it already. */
- engine_depsgraph_free(engine);
+ engine_depsgraph_exit(engine);
}
bool RE_engine_render(Render *re, bool do_all)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
- bool persistent_data = (re->r.mode & R_PERSISTENT_DATA) != 0;
/* verify if we can render */
if (!type->render) {
@@ -953,7 +1035,13 @@ bool RE_engine_render(Render *re, bool do_all)
}
/* re->engine becomes zero if user changed active render engine during render */
- if (!persistent_data || !re->engine) {
+ if (!engine_keep_depsgraph(engine) || !re->engine) {
+ /* Free depsgraph outside of parts mutex lock, since this locks OpenGL context
+ * while the the UI drawing might also lock the OpenGL context and parts mutex. */
+ BLI_rw_mutex_unlock(&re->partsmutex);
+ engine_depsgraph_free(engine);
+ BLI_rw_mutex_lock(&re->partsmutex, THREAD_LOCK_WRITE);
+
RE_engine_free(engine);
re->engine = NULL;
}
@@ -1023,9 +1111,8 @@ void RE_engine_free_blender_memory(RenderEngine *engine)
*
* TODO(sergey): Find better solution for this.
*/
- if (engine->has_grease_pencil) {
+ if (engine->has_grease_pencil || engine_keep_depsgraph(engine)) {
return;
}
- DEG_graph_free(engine->depsgraph);
- engine->depsgraph = NULL;
+ engine_depsgraph_free(engine);
}
diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c
index 92bec9c6fd4..a39214b609d 100644
--- a/source/blender/render/intern/pipeline.c
+++ b/source/blender/render/intern/pipeline.c
@@ -662,17 +662,6 @@ void RE_FreeAllRender(void)
#endif
}
-void RE_FreeAllPersistentData(void)
-{
- Render *re;
- for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) {
- if ((re->r.mode & R_PERSISTENT_DATA) != 0 && re->engine != NULL) {
- RE_engine_free(re->engine);
- re->engine = NULL;
- }
- }
-}
-
/* on file load, free all re */
void RE_FreeAllRenderResults(void)
{
@@ -687,19 +676,39 @@ void RE_FreeAllRenderResults(void)
}
}
-void RE_FreePersistentData(void)
+void RE_FreeAllPersistentData(void)
{
Render *re;
+ for (re = RenderGlobal.renderlist.first; re != NULL; re = re->next) {
+ if (re->engine != NULL) {
+ BLI_assert(!(re->engine->flag & RE_ENGINE_RENDERING));
+ RE_engine_free(re->engine);
+ re->engine = NULL;
+ }
+ }
+}
- /* render engines can be kept around for quick re-render, this clears all */
- for (re = RenderGlobal.renderlist.first; re; re = re->next) {
- if (re->engine) {
- /* if engine is currently rendering, just tag it to be freed when render is finished */
- if (!(re->engine->flag & RE_ENGINE_RENDERING)) {
- RE_engine_free(re->engine);
- }
+static void re_free_persistent_data(Render *re)
+{
+ /* If engine is currently rendering, just wait for it to be freed when it finishes rendering. */
+ if (re->engine && !(re->engine->flag & RE_ENGINE_RENDERING)) {
+ RE_engine_free(re->engine);
+ re->engine = NULL;
+ }
+}
- re->engine = NULL;
+void RE_FreePersistentData(const Scene *scene)
+{
+ /* Render engines can be kept around for quick re-render, this clears all or one scene. */
+ if (scene) {
+ Render *re = RE_GetSceneRender(scene);
+ if (re) {
+ re_free_persistent_data(re);
+ }
+ }
+ else {
+ for (Render *re = RenderGlobal.renderlist.first; re; re = re->next) {
+ re_free_persistent_data(re);
}
}
}
@@ -732,7 +741,7 @@ static void re_init_resolution(Render *re, Render *source, int winx, int winy, r
re->winy = winy;
if (source && (source->r.mode & R_BORDER)) {
/* eeh, doesn't seem original bordered disprect is storing anywhere
- * after insertion on black happening in do_render(),
+ * after insertion on black happening in do_render_engine(),
* so for now simply re-calculate disprect using border from source
* renderer (sergey)
*/
@@ -884,82 +893,6 @@ void RE_InitState(Render *re,
RE_point_density_fix_linking();
}
-/* This function is only called by view3d rendering, which doesn't support
- * multiview at the moment. so handle only one view here */
-static void render_result_rescale(Render *re)
-{
- RenderResult *result = re->result;
- RenderView *rv;
- int x, y;
- float scale_x, scale_y;
- float *src_rectf;
-
- rv = RE_RenderViewGetById(result, 0);
- src_rectf = rv->rectf;
-
- if (src_rectf == NULL) {
- RenderLayer *rl = render_get_active_layer(re, re->result);
- if (rl != NULL) {
- src_rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, NULL);
- }
- }
-
- if (src_rectf != NULL) {
- float *dst_rectf = NULL;
- re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, "");
-
- if (re->result != NULL) {
- dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf;
- if (dst_rectf == NULL) {
- RenderLayer *rl;
- rl = render_get_active_layer(re, re->result);
- if (rl != NULL) {
- dst_rectf = RE_RenderLayerGetPass(rl, RE_PASSNAME_COMBINED, NULL);
- }
- }
-
- scale_x = (float)result->rectx / re->result->rectx;
- scale_y = (float)result->recty / re->result->recty;
- for (x = 0; x < re->result->rectx; x++) {
- for (y = 0; y < re->result->recty; y++) {
- int src_x = x * scale_x;
- int src_y = y * scale_y;
- int dst_index = y * re->result->rectx + x;
- int src_index = src_y * result->rectx + src_x;
- copy_v4_v4(dst_rectf + dst_index * 4, src_rectf + src_index * 4);
- }
- }
- }
- render_result_free(result);
- }
-}
-
-void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect)
-{
- re_init_resolution(re, NULL, winx, winy, disprect);
- RE_parts_clamp(re);
-
- if (re->result) {
- BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_rescale(re);
- BLI_rw_mutex_unlock(&re->resultmutex);
- }
-}
-
-/* TODO(sergey): This is a bit hackish, used to temporary disable freestyle when
- * doing viewport render. Needs some better integration of BI viewport rendering
- * into the pipeline.
- */
-void RE_ChangeModeFlag(Render *re, int flag, bool clear)
-{
- if (clear) {
- re->r.mode &= ~flag;
- }
- else {
- re->r.mode |= flag;
- }
-}
-
/* update some variables that can be animated, and otherwise wouldn't be due to
* RenderData getting copied once at the start of animation render */
void render_update_anim_renderdata(Render *re, RenderData *rd, ListBase *render_layers)
@@ -1068,24 +1001,8 @@ void *RE_gpu_context_get(Render *re)
return re->gpu_context;
}
-/* ********* add object data (later) ******** */
-
-/* object is considered fully prepared on correct time etc */
-/* includes lights */
-#if 0
-void RE_AddObject(Render *UNUSED(re), Object *UNUSED(ob))
-{
-}
-#endif
-
/* ************ This part uses API, for rendering Blender scenes ********** */
-static void do_render_3d(Render *re)
-{
- re->current_scene_update(re->suh, re->scene);
- RE_engine_render(re, false);
-}
-
/* make sure disprect is not affected by the render border */
static void render_result_disprect_to_full_resolution(Render *re)
{
@@ -1146,8 +1063,8 @@ static void render_result_uncrop(Render *re)
}
}
-/* main render routine, no compositing */
-static void do_render(Render *re)
+/* Render scene into render result, with a render engine. */
+static void do_render_engine(Render *re)
{
Object *camera = RE_GetCamera(re);
/* also check for camera here */
@@ -1160,16 +1077,16 @@ static void do_render(Render *re)
/* now use renderdata and camera to set viewplane */
RE_SetCamera(re, camera);
- do_render_3d(re);
+ re->current_scene_update(re->suh, re->scene);
+ RE_engine_render(re, false);
/* when border render, check if we have to insert it in black */
render_result_uncrop(re);
}
-/* within context of current Render *re, render another scene.
- * it uses current render image size and disprect, but doesn't execute composite
- */
-static void render_scene(Render *re, Scene *sce, int cfra)
+/* Render scene into render result, within a compositor node tree.
+ * Uses the same image dimensions, does not recursively perform compositing. */
+static void do_render_compositor_scene(Render *re, Scene *sce, int cfra)
{
Render *resc = RE_NewSceneRender(sce);
int winx = re->winx, winy = re->winy;
@@ -1204,12 +1121,12 @@ static void render_scene(Render *re, Scene *sce, int cfra)
resc->current_scene_update = re->current_scene_update;
resc->suh = re->suh;
- do_render(resc);
+ do_render_engine(resc);
}
/* helper call to detect if this scene needs a render,
* or if there's a any render layer to render. */
-static int composite_needs_render(Scene *sce, int this_scene)
+static int compositor_needs_render(Scene *sce, int this_scene)
{
bNodeTree *ntree = sce->nodetree;
bNode *node;
@@ -1234,19 +1151,8 @@ static int composite_needs_render(Scene *sce, int this_scene)
return 0;
}
-bool RE_allow_render_generic_object(Object *ob)
-{
- /* override not showing object when duplis are used with particles */
- if (ob->transflag & OB_DUPLIPARTS) {
- /* pass */ /* let particle system(s) handle showing vs. not showing */
- }
- else if (ob->transflag & OB_DUPLI) {
- return false;
- }
- return true;
-}
-
-static void ntree_render_scenes(Render *re)
+/* Render all scenes within a compositor node tree. */
+static void do_render_compositor_scenes(Render *re)
{
bNode *node;
int cfra = re->scene->r.cfra;
@@ -1265,7 +1171,7 @@ static void ntree_render_scenes(Render *re)
Scene *scene = (Scene *)node->id;
if (!BLI_gset_haskey(scenes_rendered, scene) &&
render_scene_has_layers_to_render(scene, false)) {
- render_scene(re, scene, cfra);
+ do_render_compositor_scene(re, scene, cfra);
BLI_gset_add(scenes_rendered, scene);
nodeUpdate(restore_scene->nodetree, node);
}
@@ -1276,7 +1182,7 @@ static void ntree_render_scenes(Render *re)
}
/* bad call... need to think over proper method still */
-static void render_composit_stats(void *arg, const char *str)
+static void render_compositor_stats(void *arg, const char *str)
{
Render *re = (Render *)arg;
@@ -1286,13 +1192,14 @@ static void render_composit_stats(void *arg, const char *str)
re->stats_draw(re->sdh, &i);
}
-/* returns fully composited render-result on given time step (in RenderData) */
-static void do_render_composite(Render *re)
+/* Render compositor nodes, along with any scenes required for them.
+ * The result will be output into a compositing render layer in the render result. */
+static void do_render_compositor(Render *re)
{
bNodeTree *ntree = re->pipeline_scene_eval->nodetree;
int update_newframe = 0;
- if (composite_needs_render(re->pipeline_scene_eval, 1)) {
+ if (compositor_needs_render(re->pipeline_scene_eval, 1)) {
/* save memory... free all cached images */
ntreeFreeCache(ntree);
@@ -1300,7 +1207,7 @@ static void do_render_composite(Render *re)
* it could be optimized to render only the needed view
* but what if a scene has a different number of views
* than the main scene? */
- do_render(re);
+ do_render_engine(re);
}
else {
re->i.cfra = re->r.cfra;
@@ -1336,11 +1243,11 @@ static void do_render_composite(Render *re)
if (ntree && re->scene->use_nodes && re->r.scemode & R_DOCOMP) {
/* checks if there are render-result nodes that need scene */
if ((re->r.scemode & R_SINGLE_LAYER) == 0) {
- ntree_render_scenes(re);
+ do_render_compositor_scenes(re);
}
if (!re->test_break(re->tbh)) {
- ntree->stats_draw = render_composit_stats;
+ ntree->stats_draw = render_compositor_stats;
ntree->test_break = re->test_break;
ntree->progress = re->progress;
ntree->sdh = re;
@@ -1423,7 +1330,8 @@ int RE_seq_render_active(Scene *scene, RenderData *rd)
return 0;
}
-static void do_render_seq(Render *re)
+/* Render sequencer strips into render result. */
+static void do_render_sequencer(Render *re)
{
static int recurs_depth = 0;
struct ImBuf *out;
@@ -1537,8 +1445,8 @@ static void do_render_seq(Render *re)
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
-/* main loop: doing sequence + 3d render + compositing */
-static void do_render_all_options(Render *re)
+/* Render full pipeline, using render engine, sequencer and compositing nodes. */
+static void do_render_full_pipeline(Render *re)
{
bool render_seq = false;
@@ -1556,9 +1464,9 @@ static void do_render_all_options(Render *re)
/* in this case external render overrides all */
}
else if (RE_seq_render_active(re->scene, &re->r)) {
- /* note: do_render_seq() frees rect32 when sequencer returns float images */
+ /* note: do_render_sequencer() frees rect32 when sequencer returns float images */
if (!re->test_break(re->tbh)) {
- do_render_seq(re);
+ do_render_sequencer(re);
render_seq = true;
}
@@ -1566,7 +1474,7 @@ static void do_render_all_options(Render *re)
re->display_update(re->duh, re->result, NULL);
}
else {
- do_render_composite(re);
+ do_render_compositor(re);
}
re->i.lastframetime = PIL_check_seconds_timer() - re->i.starttime;
@@ -1701,7 +1609,7 @@ static int check_valid_camera(Scene *scene, Object *camera_override, ReportList
return true;
}
-static bool node_tree_has_composite_output(bNodeTree *ntree)
+static bool node_tree_has_compositor_output(bNodeTree *ntree)
{
bNode *node;
@@ -1711,7 +1619,7 @@ static bool node_tree_has_composite_output(bNodeTree *ntree)
}
if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) {
if (node->id) {
- if (node_tree_has_composite_output((bNodeTree *)node->id)) {
+ if (node_tree_has_compositor_output((bNodeTree *)node->id)) {
return true;
}
}
@@ -1721,9 +1629,9 @@ static bool node_tree_has_composite_output(bNodeTree *ntree)
return false;
}
-static int check_composite_output(Scene *scene)
+static int check_compositor_output(Scene *scene)
{
- return node_tree_has_composite_output(scene->nodetree);
+ return node_tree_has_compositor_output(scene->nodetree);
}
bool RE_is_rendering_allowed(Scene *scene,
@@ -1766,13 +1674,13 @@ bool RE_is_rendering_allowed(Scene *scene,
return 0;
}
- if (!check_composite_output(scene)) {
+ if (!check_compositor_output(scene)) {
BKE_report(reports, RPT_ERROR, "No render output node in scene");
return 0;
}
if (scemode & R_FULL_SAMPLE) {
- if (composite_needs_render(scene, 0) == 0) {
+ if (compositor_needs_render(scene, 0) == 0) {
BKE_report(reports, RPT_ERROR, "Full sample AA not supported without 3D rendering");
return 0;
}
@@ -1941,6 +1849,22 @@ static void render_init_depsgraph(Render *re)
re->pipeline_scene_eval = DEG_get_evaluated_scene(re->pipeline_depsgraph);
}
+/* Free data only needed during rendering operation. */
+static void render_pipeline_free(Render *re)
+{
+ if (re->engine && !RE_engine_use_persistent_data(re->engine)) {
+ RE_engine_free(re->engine);
+ re->engine = NULL;
+ }
+ if (re->pipeline_depsgraph != NULL) {
+ DEG_graph_free(re->pipeline_depsgraph);
+ re->pipeline_depsgraph = NULL;
+ re->pipeline_scene_eval = NULL;
+ }
+ /* Destroy the opengl context in the correct thread. */
+ RE_gl_context_destroy(re);
+}
+
/* general Blender frame render call */
void RE_RenderFrame(Render *re,
Main *bmain,
@@ -1966,7 +1890,7 @@ void RE_RenderFrame(Render *re,
render_init_depsgraph(re);
- do_render_all_options(re);
+ do_render_full_pipeline(re);
if (write_still && !G.is_break) {
if (BKE_imtype_is_movie(rd.im_format.imtype)) {
@@ -2001,7 +1925,7 @@ void RE_RenderFrame(Render *re,
&scene->id,
G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
- RE_CleanAfterRender(re);
+ render_pipeline_free(re);
/* UGLY WARNING */
G.is_rendering = false;
@@ -2038,7 +1962,7 @@ void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render
change_renderdata_engine(re, RE_engine_id_BLENDER_EEVEE);
}
- do_render_3d(re);
+ RE_engine_render(re, false);
change_renderdata_engine(re, scene_engine);
}
@@ -2444,7 +2368,7 @@ void RE_RenderAnim(Render *re,
if (is_error) {
/* report is handled above */
re_movie_free_all(re, mh, i + 1);
- RE_CleanAfterRender(re);
+ render_pipeline_free(re);
return;
}
}
@@ -2568,7 +2492,7 @@ void RE_RenderAnim(Render *re,
/* run callbacks before rendering, before the scene is updated */
render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_PRE);
- do_render_all_options(re);
+ do_render_full_pipeline(re);
totrendered++;
if (re->test_break(re->tbh) == 0) {
@@ -2642,7 +2566,7 @@ void RE_RenderAnim(Render *re,
G.is_break ? BKE_CB_EVT_RENDER_CANCEL : BKE_CB_EVT_RENDER_COMPLETE);
BKE_sound_reset_scene_specs(re->pipeline_scene_eval);
- RE_CleanAfterRender(re);
+ render_pipeline_free(re);
/* UGLY WARNING */
G.is_rendering = false;
@@ -2664,18 +2588,13 @@ void RE_PreviewRender(Render *re, Main *bmain, Scene *sce)
camera = RE_GetCamera(re);
RE_SetCamera(re, camera);
- do_render_3d(re);
-}
+ RE_engine_render(re, false);
-void RE_CleanAfterRender(Render *re)
-{
- /* Destroy the opengl context in the correct thread. */
- RE_gl_context_destroy(re);
- if (re->pipeline_depsgraph != NULL) {
- DEG_graph_free(re->pipeline_depsgraph);
+ /* No persistent data for preview render. */
+ if (re->engine) {
+ RE_engine_free(re->engine);
+ re->engine = NULL;
}
- re->pipeline_depsgraph = NULL;
- re->pipeline_scene_eval = NULL;
}
/* note; repeated win/disprect calc... solve that nicer, also in compo */
@@ -2917,3 +2836,15 @@ RenderPass *RE_create_gp_pass(RenderResult *rr, const char *layername, const cha
/* create a totally new pass */
return render_layer_add_pass(rr, rl, 4, RE_PASSNAME_COMBINED, viewname, "RGBA");
}
+
+bool RE_allow_render_generic_object(Object *ob)
+{
+ /* override not showing object when duplis are used with particles */
+ if (ob->transflag & OB_DUPLIPARTS) {
+ /* pass */ /* let particle system(s) handle showing vs. not showing */
+ }
+ else if (ob->transflag & OB_DUPLI) {
+ return false;
+ }
+ return true;
+}
diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c
index f73a200f3c6..74c96392d48 100644
--- a/source/blender/render/intern/render_result.c
+++ b/source/blender/render/intern/render_result.c
@@ -126,7 +126,7 @@ void render_result_free(RenderResult *rr)
MEM_freeN(rr);
}
-/* version that's compatible with fullsample buffers */
+/** Version that's compatible with full-sample buffers. */
void render_result_free_list(ListBase *lb, RenderResult *rr)
{
RenderResult *rrnext;
diff --git a/source/blender/render/intern/render_types.h b/source/blender/render/intern/render_types.h
index 0488bf6e87a..9f399971049 100644
--- a/source/blender/render/intern/render_types.h
+++ b/source/blender/render/intern/render_types.h
@@ -79,7 +79,7 @@ struct Render {
RenderResult *result;
/* if render with single-layer option, other rendered layers are stored here */
RenderResult *pushedresult;
- /* a list of RenderResults, for fullsample */
+ /** A list of #RenderResults, for full-samples. */
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
diff --git a/source/blender/render/intern/zbuf.c b/source/blender/render/intern/zbuf.c
index 33af3bbaf29..242c8a199fb 100644
--- a/source/blender/render/intern/zbuf.c
+++ b/source/blender/render/intern/zbuf.c
@@ -175,7 +175,7 @@ static void zbuf_add_to_span(ZSpan *zspan, const float v1[2], const float v2[2])
/* Functions */
/*-----------------------------------------------------------*/
-/* Scanconvert for strand triangles, calls func for each x, y coordinate
+/* Scan-convert for strand triangles, calls function for each x, y coordinate
* and gives UV barycentrics and z. */
void zspan_scanconvert(ZSpan *zspan,