DRW: Add DRW_duplidata_get to create fast path for duplis
authorClément Foucault <foucault.clem@gmail.com>
Tue, 7 May 2019 18:56:20 +0000 (20:56 +0200)
committerClément Foucault <foucault.clem@gmail.com>
Wed, 8 May 2019 15:52:48 +0000 (17:52 +0200)
This is in order to create less shading group when using duplis.

Data for dupli objects keep in draw manager state until the source object
changes so retrieval is fast.

Note that this system could be extended to all meshes.

source/blender/draw/intern/DRW_render.h
source/blender/draw/intern/draw_manager.c
source/blender/draw/intern/draw_manager.h

index 82584eb..db5bab3 100644 (file)
@@ -631,6 +631,7 @@ DrawData *DRW_drawdata_ensure(ID *id,
                               size_t size,
                               DrawDataInitCb init_cb,
                               DrawDataFreeCb free_cb);
+void **DRW_duplidata_get(void *vedata);
 
 /* Settings */
 bool DRW_object_is_renderable(const struct Object *ob);
index 6afb1fd..95f34fe 100644 (file)
@@ -789,6 +789,69 @@ void DRW_viewport_request_redraw(void)
 
 /** \} */
 
+/* -------------------------------------------------------------------- */
+/** \name Duplis
+ * \{ */
+
+static void drw_duplidata_load(DupliObject *dupli)
+{
+  if (dupli == NULL) {
+    return;
+  }
+
+  if (DST.dupli_origin != dupli->ob) {
+    DST.dupli_origin = dupli->ob;
+  }
+  else {
+    /* Same data as previous iter. No need to poll ghash for this. */
+    return;
+  }
+
+  if (DST.dupli_ghash == NULL) {
+    DST.dupli_ghash = BLI_ghash_ptr_new(__func__);
+  }
+
+  void **value;
+  if (!BLI_ghash_ensure_p(DST.dupli_ghash, DST.dupli_origin, &value)) {
+    *value = MEM_callocN(sizeof(void *) * DST.enabled_engine_count, __func__);
+  }
+  DST.dupli_datas = *(void ***)value;
+}
+
+static void duplidata_value_free(void *val)
+{
+  void **dupli_datas = val;
+  for (int i = 0; i < DST.enabled_engine_count; i++) {
+    MEM_SAFE_FREE(dupli_datas[i]);
+  }
+  MEM_freeN(val);
+}
+
+static void drw_duplidata_free(void)
+{
+  if (DST.dupli_ghash != NULL) {
+    BLI_ghash_free(DST.dupli_ghash, NULL, duplidata_value_free);
+    DST.dupli_ghash = NULL;
+  }
+}
+
+/* Return NULL if not a dupli or a pointer of pointer to the engine data */
+void **DRW_duplidata_get(void *vedata)
+{
+  if (DST.dupli_source == NULL) {
+    return NULL;
+  }
+  /* XXX Search engine index by using vedata array */
+  for (int i = 0; i < DST.enabled_engine_count; i++) {
+    if (DST.vedata_array[i] == vedata) {
+      return &DST.dupli_datas[i];
+    }
+  }
+  return NULL;
+}
+
+/** \} */
+
 /* -------------------------------------------------------------------- */
 /** \name ViewLayers (DRW_scenelayer)
  * \{ */
@@ -1045,8 +1108,8 @@ static void drw_engines_init(void)
 
 static void drw_engines_cache_init(void)
 {
-  int enabled_engine_count = BLI_listbase_count(&DST.enabled_engines);
-  DST.vedata_array = MEM_mallocN(sizeof(void *) * enabled_engine_count, __func__);
+  DST.enabled_engine_count = BLI_listbase_count(&DST.enabled_engines);
+  DST.vedata_array = MEM_mallocN(sizeof(void *) * DST.enabled_engine_count, __func__);
 
   int i = 0;
   for (LinkData *link = DST.enabled_engines.first; link; link = link->next, i++) {
@@ -1586,11 +1649,13 @@ void DRW_draw_render_loop_ex(struct Depsgraph *depsgraph,
         }
         DST.dupli_parent = data_.dupli_parent;
         DST.dupli_source = data_.dupli_object_current;
+        drw_duplidata_load(DST.dupli_source);
         drw_engines_cache_populate(ob);
       }
       DEG_OBJECT_ITER_END;
     }
 
+    drw_duplidata_free();
     drw_engines_cache_finish();
 
     DRW_render_instance_buffer_finish();
@@ -2304,12 +2369,14 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph,
           }
           DST.dupli_parent = data_.dupli_parent;
           DST.dupli_source = data_.dupli_object_current;
+          drw_duplidata_load(DST.dupli_source);
           drw_engines_cache_populate(ob);
         }
       }
       DEG_OBJECT_ITER_END;
     }
 
+    drw_duplidata_free();
     drw_engines_cache_finish();
 
     DRW_render_instance_buffer_finish();
@@ -2404,10 +2471,12 @@ static void drw_draw_depth_loop_imp(void)
 
       DST.dupli_parent = data_.dupli_parent;
       DST.dupli_source = data_.dupli_object_current;
+      drw_duplidata_load(DST.dupli_source);
       drw_engines_cache_populate(ob);
     }
     DEG_OBJECT_ITER_END;
 
+    drw_duplidata_free();
     drw_engines_cache_finish();
 
     DRW_render_instance_buffer_finish();
index 6dd112e..e592101 100644 (file)
@@ -329,6 +329,9 @@ typedef struct DRWManager {
   uchar state_cache_id; /* Could be larger but 254 view changes is already a lot! */
   struct DupliObject *dupli_source;
   struct Object *dupli_parent;
+  struct Object *dupli_origin;
+  struct GHash *dupli_ghash;
+  void **dupli_datas; /* Array of dupli_data (one for each enabled engine) to handle duplis. */
 
   /* Rendering state */
   GPUShader *shader;
@@ -365,6 +368,7 @@ typedef struct DRWManager {
 
   ListBase enabled_engines; /* RenderEngineType */
   void **vedata_array;      /* ViewportEngineData */
+  int enabled_engine_count; /* Length of enabled_engines list. */
 
   bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */