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:
authorSergey Sharybin <sergey.vfx@gmail.com>2013-12-26 15:24:42 +0400
committerSergey Sharybin <sergey.vfx@gmail.com>2013-12-26 15:24:42 +0400
commit709041ed0b7e1848068c9d53543ed114229a9f5b (patch)
treeedf2cd930e6bcfd9bbc9ab7fd21490effb069e09 /source/blender/render
parent7025a1bd7830c3bb58ea7f6a3dba8089869591eb (diff)
Threaded object update and EvaluationContext
Summary: Made objects update happening from multiple threads. It is a task-based scheduling system which uses current dependency graph for spawning new tasks. This means threading happens on object level, but the system is flexible enough for higher granularity. Technical details: - Uses task scheduler which was recently committed to trunk (that one which Brecht ported from Cycles). - Added two utility functions to dependency graph: * DAG_threaded_update_begin, which is called to initialize threaded objects update. It will also schedule root DAG node to the queue, hence starting evaluation process. Initialization will calculate how much parents are to be evaluation before current DAG node can be scheduled. This value is used by task threads for faster detecting which nodes might be scheduled. * DAG_threaded_update_handle_node_updated which is called from task thread function when node was fully handled. This function decreases num_pending_parents of node children and schedules children with zero valency. As it might have become clear, task thread receives DAG nodes and decides which callback to call for it. Currently only BKE_object_handle_update is called for object nodes. In the future it'll call node->callback() from Ali's new DAG. - This required adding some workarounds to the render pipeline. Mainly to stop using get_object_dm() from modifiers' apply callback. Such a call was only a workaround for dependency graph glitch when rendering scene with, say, boolean modifiers before displaying this scene. Such change moves workaround from one place to another, so overall hackentropy remains the same. - Added paradigm of EvaluaitonContext. Currently it's more like just a more reliable replacement for G.is_rendering which fails in some circumstances. Future idea of this context is to also store all the local data needed for objects evaluation such as local time, Copy-on-Write data and so. There're two types of EvaluationContext: * Context used for viewport updated and owned by Main. In the future this context might be easily moved to Window or Screen to allo per-window/per-screen local time. * Context used by render engines to evaluate objects for render purposes. Render engine is an owner of this context. This context is passed to all object update routines. Reviewers: brecht, campbellbarton Reviewed By: brecht CC: lukastoenne Differential Revision: https://developer.blender.org/D94
Diffstat (limited to 'source/blender/render')
-rw-r--r--source/blender/render/intern/include/render_types.h2
-rw-r--r--source/blender/render/intern/source/convertblender.c13
-rw-r--r--source/blender/render/intern/source/external_engine.c2
-rw-r--r--source/blender/render/intern/source/pipeline.c129
4 files changed, 126 insertions, 20 deletions
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 2a43cab7bce..02a9f1eb347 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -52,6 +52,7 @@
#include "BLI_sys_types.h" // for intptr_t support
+struct EvaluationContext;
struct Object;
struct MemArena;
struct VertTableNode;
@@ -270,6 +271,7 @@ struct Render
struct ReportList *reports;
struct ImagePool *pool;
+ struct EvaluationContext *eval_ctx;
};
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 1f3e961c151..e3a8c57de66 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -39,8 +39,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
+#include "BLI_task.h"
#include "BLI_memarena.h"
-#include "BLI_ghash.h"
#include "BLI_linklist.h"
#ifdef WITH_FREESTYLE
# include "BLI_edgehash.h"
@@ -79,6 +79,7 @@
#include "BKE_constraint.h"
#include "BKE_displist.h"
#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
#include "BKE_global.h"
@@ -2221,7 +2222,7 @@ static void init_render_mball(Render *re, ObjectRen *obr)
need_orco= 1;
}
- BKE_displist_make_mball_forRender(re->scene, ob, &dispbase);
+ BKE_displist_make_mball_forRender(re->eval_ctx, re->scene, ob, &dispbase);
dl= dispbase.first;
if (dl == NULL) return;
@@ -4981,7 +4982,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
/* create list of duplis generated by this object, particle
* system need to have render settings set for dupli particles */
dupli_render_particle_set(re, ob, timeoffset, 0, 1);
- lb= object_duplilist(re->scene, ob, TRUE);
+ lb= object_duplilist(re->eval_ctx, re->scene, ob);
dupli_render_particle_set(re, ob, timeoffset, 0, 0);
for (dob= lb->first; dob; dob= dob->next) {
@@ -5133,12 +5134,12 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
/* applies changes fully */
if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
- BKE_scene_update_for_newframe(re->main, re->scene, lay);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
/* if no camera, viewmat should have been set! */
if (use_camera_view && camera) {
/* called before but need to call again in case of lens animation from the
- * above call to BKE_scene_update_for_newframe, fixes bug. [#22702].
+ * above call to BKE_scene_update_for_newframe_render, fixes bug. [#22702].
* following calls don't depend on 'RE_SetCamera' */
RE_SetCamera(re, camera);
@@ -5310,7 +5311,7 @@ static void database_fromscene_vectors(Render *re, Scene *scene, unsigned int la
/* applies changes fully */
scene->r.cfra += timeoffset;
- BKE_scene_update_for_newframe(re->main, re->scene, lay);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
/* if no camera, viewmat should have been set! */
if (camera) {
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index c3628e99d04..cccfeed6e47 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -459,7 +459,7 @@ int RE_engine_render(Render *re, int do_all)
lay &= non_excluded_lay;
}
- BKE_scene_update_for_newframe(re->main, re->scene, lay);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
}
/* create render result */
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index ba8265a83fe..4ec7ce1c0d2 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -59,9 +59,11 @@
#include "BKE_animsys.h" /* <------ should this be here?, needed for sequencer update */
#include "BKE_camera.h"
+#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
#include "BKE_node.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
@@ -373,6 +375,8 @@ Render *RE_NewRender(const char *name)
BLI_addtail(&RenderGlobal.renderlist, re);
BLI_strncpy(re->name, name, RE_MAXNAME);
BLI_rw_mutex_init(&re->resultmutex);
+ re->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "re->eval_ctx");
+ re->eval_ctx->for_render = true;
}
RE_InitRenderCB(re);
@@ -420,6 +424,7 @@ void RE_FreeRender(Render *re)
render_result_free(re->pushedresult);
BLI_remlink(&RenderGlobal.renderlist, re);
+ MEM_freeN(re->eval_ctx);
MEM_freeN(re);
}
@@ -1320,8 +1325,9 @@ static void do_render_blur_3d(Render *re)
re->i.curblur = 0; /* stats */
/* make sure motion blur changes get reset to current frame */
- if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
- BKE_scene_update_for_newframe(re->main, re->scene, re->lay);
+ if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay);
+ }
/* weak... the display callback wants an active renderlayer pointer... */
re->result->renlay = render_get_active_layer(re, re->result);
@@ -1590,21 +1596,117 @@ static bool rlayer_node_uses_alpha(bNodeTree *ntree, bNode *node)
return false;
}
+/* Issue here is that it's possible that object which is used by boolean,
+ * array or shrinkwrap modifiers weren't displayed in the viewport before
+ * rendering. This leads to situations when apply() of this modifiers
+ * could not get ob->derivedFinal and modifiers are not being applied.
+ *
+ * This was worked around by direct call of get_derived_final() from those
+ * modifiers, but such approach leads to write conflicts with threaded
+ * update.
+ *
+ * Here we make sure derivedFinal will be calculated by update_for_newframe
+ * function later in the pipeline and all the modifiers are applied
+ * properly without hacks from their side.
+ * - sergey -
+ */
+#define DEPSGRAPH_WORKAROUND_HACK
+
+#ifdef DEPSGRAPH_WORKAROUND_HACK
+static bool allow_render_mesh_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) && !(ob->transflag & OB_DUPLIFRAMES)) {
+ return false;
+ }
+ return true;
+}
+
+static void tag_dependend_objects_for_render(Scene *scene, int renderlay)
+{
+ Scene *sce_iter;
+ Base *base;
+ for (SETLOOPER(scene, sce_iter, base)) {
+ Object *object = base->object;
+
+ if ((base->lay & renderlay) == 0) {
+ continue;
+ }
+
+ if (object->type == OB_MESH) {
+ if (allow_render_mesh_object(object)) {
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
+
+ for (md = modifiers_getVirtualModifierList(object, &virtualModifierData);
+ md;
+ md = md->next)
+ {
+ if (!modifier_isEnabled(scene, md, eModifierMode_Render)) {
+ continue;
+ }
+
+ if (md->type == eModifierType_Boolean) {
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+ if (bmd->object && bmd->object->type == OB_MESH) {
+ DAG_id_tag_update(&bmd->object->id, OB_RECALC_DATA);
+ }
+ }
+ else if (md->type == eModifierType_Array) {
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+ if (amd->start_cap && amd->start_cap->type == OB_MESH) {
+ DAG_id_tag_update(&amd->start_cap->id, OB_RECALC_DATA);
+ }
+ if (amd->end_cap && amd->end_cap->type == OB_MESH) {
+ DAG_id_tag_update(&amd->end_cap->id, OB_RECALC_DATA);
+ }
+ }
+ else if (md->type == eModifierType_Shrinkwrap) {
+ ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
+ if (smd->target && smd->target->type == OB_MESH) {
+ DAG_id_tag_update(&smd->target->id, OB_RECALC_DATA);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
static void tag_scenes_for_render(Render *re)
{
bNode *node;
Scene *sce;
+#ifdef DEPSGRAPH_WORKAROUND_HACK
+ int renderlay = re->lay;
+#endif
- for (sce = re->main->scene.first; sce; sce = sce->id.next)
+ for (sce = re->main->scene.first; sce; sce = sce->id.next) {
sce->id.flag &= ~LIB_DOIT;
+#ifdef DEPSGRAPH_WORKAROUND_HACK
+ tag_dependend_objects_for_render(sce, renderlay);
+#endif
+ }
#ifdef WITH_FREESTYLE
- for (sce = re->freestyle_bmain.scene.first; sce; sce = sce->id.next)
+ for (sce = re->freestyle_bmain.scene.first; sce; sce = sce->id.next) {
sce->id.flag &= ~LIB_DOIT;
+#ifdef DEPSGRAPH_WORKAROUND_HACK
+ tag_dependend_objects_for_render(sce, renderlay);
+#endif
+ }
#endif
- if (RE_GetCamera(re) && composite_needs_render(re->scene, 1))
+ if (RE_GetCamera(re) && composite_needs_render(re->scene, 1)) {
re->scene->id.flag |= LIB_DOIT;
+#ifdef DEPSGRAPH_WORKAROUND_HACK
+ tag_dependend_objects_for_render(re->scene, renderlay);
+#endif
+ }
if (re->scene->nodetree == NULL) return;
@@ -1632,6 +1734,9 @@ static void tag_scenes_for_render(Render *re)
if ((node->id->flag & LIB_DOIT) == 0) {
node->flag |= NODE_TEST;
node->id->flag |= LIB_DOIT;
+#ifdef DEPSGRAPH_WORKAROUND_HACK
+ tag_dependend_objects_for_render((Scene *) node->id, renderlay);
+#endif
}
}
}
@@ -2020,7 +2125,7 @@ static void do_render_composite_fields_blur_3d(Render *re)
R.stats_draw = re->stats_draw;
if (update_newframe)
- BKE_scene_update_for_newframe(re->main, re->scene, re->lay);
+ BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, re->lay);
if (re->r.scemode & R_FULL_SAMPLE)
do_merge_fullsample(re, ntree);
@@ -2095,14 +2200,12 @@ static void do_render_seq(Render *re)
if ((re->r.mode & R_BORDER) && (re->r.mode & R_CROP) == 0) {
/* if border rendering is used and cropping is disabled, final buffer should
* be as large as the whole frame */
- context = BKE_sequencer_new_render_data(re->main, re->scene,
- re->winx, re->winy,
- 100);
+ context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene,
+ re->winx, re->winy, 100);
}
else {
- context = BKE_sequencer_new_render_data(re->main, re->scene,
- re->result->rectx, re->result->recty,
- 100);
+ context = BKE_sequencer_new_render_data(re->eval_ctx, re->main, re->scene,
+ re->result->rectx, re->result->recty, 100);
}
out = BKE_sequencer_give_ibuf(context, cfra, 0);
@@ -2704,7 +2807,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
else
updatelay = re->lay;
- BKE_scene_update_for_newframe(bmain, scene, updatelay);
+ BKE_scene_update_for_newframe(re->eval_ctx, bmain, scene, updatelay);
continue;
}
else