Fix T46646: Point Cloud Density crashes on real time rendering
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 25 Nov 2015 12:38:12 +0000 (17:38 +0500)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 25 Nov 2015 12:43:44 +0000 (17:43 +0500)
The issue was caused by possible use of object->derivedFinal from the render
thread, The patch tries to eliminate (or at least minimize, huh) amount of
access to the derivedFinal of a source object. It's still possible that in
the case of particle source derived mesh will be still unsafely used, but
with the patch applied we can easily change runtime part of the code and
cache derived mesh on the preparation stage.

Some ideas for the future:

- Check whether cache() was called on the point density node when calling
  calc().

- Cache derivedMesh in the runtime part of point density node to avoid
  possible remained thread conflicts.

- NULL the runtime part of the node on .blend load

Reviewers: campbellbarton, plasmasolutions

Reviewed By: plasmasolutions

Differential Revision: https://developer.blender.org/D1614

intern/cycles/blender/blender_shader.cpp
source/blender/makesdna/DNA_node_types.h
source/blender/makesrna/intern/rna_nodetree.c
source/blender/render/extern/include/RE_render_ext.h
source/blender/render/intern/source/pointdensity.c

index 5bbdeb6061bf85b4cb96dc2ddef810ba053a5536..3f4f1bb206b455d5ff875d4d28682149695d2d88 100644 (file)
@@ -184,6 +184,7 @@ static ShaderNode *add_node(Scene *scene,
                             BL::RenderEngine b_engine,
                             BL::BlendData b_data,
                             BL::Scene b_scene,
+                            const bool background,
                             ShaderGraph *graph,
                             BL::ShaderNodeTree b_ntree,
                             BL::ShaderNode b_node)
@@ -763,6 +764,8 @@ static ShaderNode *add_node(Scene *scene,
 
                /* TODO(sergey): Use more proper update flag. */
                if(true) {
+                       int settings = background ? 1 : 0;  /* 1 - render settings, 0 - vewport settings. */
+                       b_point_density_node.cache_point_density(b_scene, settings);
                        scene->image_manager->tag_reload_image(
                                point_density->filename,
                                point_density->builtin_data,
@@ -852,6 +855,7 @@ static void add_nodes(Scene *scene,
                       BL::RenderEngine b_engine,
                       BL::BlendData b_data,
                       BL::Scene b_scene,
+                      const bool background,
                       ShaderGraph *graph,
                       BL::ShaderNodeTree b_ntree,
                       const ProxyMap &proxy_input_map,
@@ -937,6 +941,7 @@ static void add_nodes(Scene *scene,
                                          b_engine,
                                          b_data,
                                          b_scene,
+                                         background,
                                          graph,
                                          b_group_ntree,
                                          group_proxy_input_map,
@@ -984,6 +989,7 @@ static void add_nodes(Scene *scene,
                                                b_engine,
                                                b_data,
                                                b_scene,
+                                               background,
                                                graph,
                                                b_ntree,
                                                BL::ShaderNode(*b_node));
@@ -1046,6 +1052,7 @@ static void add_nodes(Scene *scene,
                       BL::RenderEngine b_engine,
                       BL::BlendData b_data,
                       BL::Scene b_scene,
+                      const bool background,
                       ShaderGraph *graph,
                       BL::ShaderNodeTree b_ntree)
 {
@@ -1054,6 +1061,7 @@ static void add_nodes(Scene *scene,
                  b_engine,
                  b_data,
                  b_scene,
+                 background,
                  graph,
                  b_ntree,
                  empty_proxy_map,
@@ -1083,7 +1091,7 @@ void BlenderSync::sync_materials(bool update_all)
                        if(b_mat->use_nodes() && b_mat->node_tree()) {
                                BL::ShaderNodeTree b_ntree(b_mat->node_tree());
 
-                               add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
+                               add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
                        }
                        else {
                                ShaderNode *closure, *out;
@@ -1126,7 +1134,7 @@ void BlenderSync::sync_world(bool update_all)
                if(b_world && b_world.use_nodes() && b_world.node_tree()) {
                        BL::ShaderNodeTree b_ntree(b_world.node_tree());
 
-                       add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
+                       add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
 
                        /* volume */
                        PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
@@ -1217,7 +1225,7 @@ void BlenderSync::sync_lamps(bool update_all)
 
                                BL::ShaderNodeTree b_ntree(b_lamp->node_tree());
 
-                               add_nodes(scene, b_engine, b_data, b_scene, graph, b_ntree);
+                               add_nodes(scene, b_engine, b_data, b_scene, !preview, graph, b_ntree);
                        }
                        else {
                                ShaderNode *closure, *out;
index 6d282f4ece90c74d4faabdd11e11b6b4f545ce06..86713d7dcc870e7ec700b72f8eb42a7687f92217 100644 (file)
@@ -807,6 +807,7 @@ typedef struct NodeShaderTexPointDensity {
        short interpolation;
        short color_source;
        short pad2;
+       PointDensity pd;
 } NodeShaderTexPointDensity;
 
 /* TEX_output */
index 2d412bf778b8ca155cfa49abaf9936c02c327c73..e7e8f6d6121d39773e134f4209b9c43179ffefb6 100644 (file)
@@ -3016,6 +3016,39 @@ static int point_density_color_source_from_shader(NodeShaderTexPointDensity *sha
        }
 }
 
+void rna_ShaderNodePointDensity_density_cache(bNode *self,
+                                              Scene *scene,
+                                              int settings)
+{
+       NodeShaderTexPointDensity *shader_point_density = self->storage;
+       PointDensity *pd = &shader_point_density->pd;
+       if (scene == NULL) {
+               return;
+       }
+
+       /* Create PointDensity structure from node for sampling. */
+       memset(pd, 0, sizeof(*pd));
+       BKE_texture_pointdensity_init_data(pd);
+       pd->object = (Object *)self->id;
+       pd->radius = shader_point_density->radius;
+       if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
+               pd->source = TEX_PD_PSYS;
+               pd->psys = shader_point_density->particle_system;
+               pd->psys_cache_space = TEX_PD_OBJECTSPACE;
+       }
+       else {
+               BLI_assert(shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_OBJECT);
+               pd->source = TEX_PD_OBJECT;
+               pd->ob_cache_space = TEX_PD_OBJECTSPACE;
+       }
+       pd->color_source = point_density_color_source_from_shader(shader_point_density);
+
+       /* Single-threaded sampling of the voxel domain. */
+       RE_cache_point_density(scene,
+                              pd,
+                              settings == 1);
+}
+
 void rna_ShaderNodePointDensity_density_calc(bNode *self,
                                              Scene *scene,
                                              int settings,
@@ -3023,7 +3056,7 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
                                              float **values)
 {
        NodeShaderTexPointDensity *shader_point_density = self->storage;
-       PointDensity pd;
+       PointDensity *pd = &shader_point_density->pd;
 
        if (scene == NULL) {
                *length = 0;
@@ -3038,30 +3071,14 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self,
                *values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array");
        }
 
-       /* Create PointDensity structure from node for sampling. */
-       BKE_texture_pointdensity_init_data(&pd);
-       pd.object = (Object *)self->id;
-       pd.radius = shader_point_density->radius;
-       if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) {
-               pd.source = TEX_PD_PSYS;
-               pd.psys = shader_point_density->particle_system;
-               pd.psys_cache_space = TEX_PD_OBJECTSPACE;
-       }
-       else {
-               BLI_assert(shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_OBJECT);
-               pd.source = TEX_PD_OBJECT;
-               pd.ob_cache_space = TEX_PD_OBJECTSPACE;
-       }
-       pd.color_source = point_density_color_source_from_shader(shader_point_density);
-
        /* Single-threaded sampling of the voxel domain. */
-       RE_sample_point_density(scene, &pd,
+       RE_sample_point_density(scene, pd,
                                shader_point_density->resolution,
                                settings == 1,
                                *values);
 
        /* We're done, time to clean up. */
-       BKE_texture_pointdensity_free_data(&pd);
+       BKE_texture_pointdensity_free_data(pd);
 }
 
 #else
@@ -3993,6 +4010,11 @@ static void def_sh_tex_pointdensity(StructRNA *srna)
        RNA_def_property_ui_text(prop, "Color Source", "Data to derive color results from");
        RNA_def_property_update(prop, 0, "rna_Node_update");
 
+       func = RNA_def_function(srna, "cache_point_density", "rna_ShaderNodePointDensity_density_cache");
+       RNA_def_function_ui_description(func, "Cache point density data for later calculation");
+       RNA_def_pointer(func, "scene", "Scene", "", "");
+       RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering");
+
        func = RNA_def_function(srna, "calc_point_density", "rna_ShaderNodePointDensity_density_calc");
        RNA_def_function_ui_description(func, "Calculate point density");
        RNA_def_pointer(func, "scene", "Scene", "", "");
index 85a9dc9fccd3e3d75e07d9e6952a066f862011d4..81d1a00702d1992f36bfd2f57fc8ab8407d6dbec 100644 (file)
@@ -63,6 +63,10 @@ void RE_sample_material_color(
 
 struct PointDensity;
 
+void RE_cache_point_density(struct Scene *scene,
+                            struct PointDensity *pd,
+                            const bool use_render_params);
+
 void RE_sample_point_density(struct Scene *scene,
                              struct PointDensity *pd,
                              const int resolution,
index 9b58bde730aa325b946070b24cd198d93a53b877..4028d80fd86ef24dd477e817936bf0227f55f119 100644 (file)
@@ -715,6 +715,21 @@ static void particle_system_minmax(Scene *scene,
        }
 }
 
+void RE_cache_point_density(Scene *scene,
+                            PointDensity *pd,
+                            const bool use_render_params)
+{
+       float mat[4][4];
+       /* Same matricies/resolution as dupli_render_particle_set(). */
+       unit_m4(mat);
+       BLI_mutex_lock(&sample_mutex);
+       cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params);
+       BLI_mutex_unlock(&sample_mutex);
+}
+
+/* NOTE 1: Requires RE_cache_point_density() to be called first.
+ * NOTE 2: Frees point density structure after sampling.
+ */
 void RE_sample_point_density(Scene *scene,
                              PointDensity *pd,
                              const int resolution,
@@ -724,7 +739,11 @@ void RE_sample_point_density(Scene *scene,
        const size_t resolution2 = resolution * resolution;
        Object *object = pd->object;
        size_t x, y, z;
-       float min[3], max[3], dim[3], mat[4][4];
+       float min[3], max[3], dim[3];
+
+       /* TODO(sergey): Implement some sort of assert() that point density
+        * was cached already.
+        */
 
        if (object == NULL) {
                sample_dummy_point_density(resolution, values);
@@ -766,11 +785,7 @@ void RE_sample_point_density(Scene *scene,
                return;
        }
 
-       /* Same matricies/resolution as dupli_render_particle_set(). */
-       unit_m4(mat);
-
        BLI_mutex_lock(&sample_mutex);
-       cache_pointdensity_ex(scene, pd, mat, mat, 1, 1, use_render_params);
        for (z = 0; z < resolution; ++z) {
                for (y = 0; y < resolution; ++y) {
                        for (x = 0; x < resolution; ++x) {