[Bf-blender-cvs] [7734b00563b] greasepencil-refactor: GPencil: Refactor: Add basic Material color support via UBO

Clément Foucault noreply at git.blender.org
Tue Dec 10 02:27:44 CET 2019


Commit: 7734b00563ba00389ae1ecf49aba197ed917f92c
Author: Clément Foucault
Date:   Tue Dec 10 01:43:41 2019 +0100
Branches: greasepencil-refactor
https://developer.blender.org/rB7734b00563ba00389ae1ecf49aba197ed917f92c

GPencil: Refactor: Add basic Material color support via UBO

For now there is at least one UBO per object. It is kept relatively small
to avoid overhead. When we implement sharing of UBOs accross objects we
could increase the material count per UBO and reduce the binding overhead.

This also put the BLI_memblocks in the ViewLayer instead of the viewport
storage list. This is because we need to correctly free UBOs when blender
quits. This can become a problem in the future but there are other places
like this in other engines so we should fix them all at once.

===================================================================

M	source/blender/draw/CMakeLists.txt
A	source/blender/draw/engines/gpencil/gpencil_data.c
M	source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
M	source/blender/draw/engines/gpencil/gpencil_engine.c
M	source/blender/draw/engines/gpencil/gpencil_engine.h
M	source/blender/draw/engines/gpencil/gpencil_shader.c
M	source/blender/draw/engines/gpencil/shaders/gpencil_common_lib.glsl
M	source/blender/draw/engines/gpencil/shaders/gpencil_vert.glsl

===================================================================

diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index b465607f102..8d6ed936ca5 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -111,6 +111,7 @@ set(SRC
   engines/workbench/workbench_volume.c
   engines/external/external_engine.c
   engines/gpencil/gpencil_cache_utils.c
+  engines/gpencil/gpencil_data.c
   engines/gpencil/gpencil_draw_cache_impl.c
   engines/gpencil/gpencil_draw_utils.c
   engines/gpencil/gpencil_engine.c
diff --git a/source/blender/draw/engines/gpencil/gpencil_data.c b/source/blender/draw/engines/gpencil/gpencil_data.c
new file mode 100644
index 00000000000..b297fe57443
--- /dev/null
+++ b/source/blender/draw/engines/gpencil/gpencil_data.c
@@ -0,0 +1,117 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Copyright 2019, Blender Foundation.
+ */
+
+/** \file
+ * \ingroup draw_engine
+ */
+
+#include "DRW_render.h"
+
+#include "BLI_memblock.h"
+
+#include "GPU_uniformbuffer.h"
+
+#include "gpencil_engine.h"
+
+static GPENCIL_MaterialPool *gpencil_material_pool_add(GPENCIL_PrivateData *pd)
+{
+  GPENCIL_MaterialPool *matpool = BLI_memblock_alloc(pd->gp_material_pool);
+  matpool->next = NULL;
+  if (matpool->ubo == NULL) {
+    matpool->ubo = GPU_uniformbuffer_create(sizeof(matpool->mat_data), NULL, NULL);
+  }
+  pd->last_material_pool = matpool;
+  return matpool;
+}
+
+/**
+ * Creates a linked list of material pool containing all materials assigned for a given object.
+ * We merge the material pools together if object does not contain a huge amount of materials.
+ * Also return an offset to the first material of the object in the ubo.
+ **/
+GPENCIL_MaterialPool *gpencil_material_pool_create(GPENCIL_PrivateData *pd, Object *ob, int *ofs)
+{
+  GPENCIL_MaterialPool *matpool = pd->last_material_pool;
+
+  /* TODO reuse matpool for objects with small material count. */
+  if (true) {
+    matpool = gpencil_material_pool_add(pd);
+  }
+
+  GPENCIL_MaterialPool *pool = matpool;
+  for (int i = 0; i < ob->totcol; i++) {
+    if ((i > 0) && (i % GPENCIL_MATERIAL_BUFFER_LEN) == 0) {
+      pool->next = gpencil_material_pool_add(pd);
+      pool = pool->next;
+    }
+    gpMaterial *mat_data = &pool->mat_data[i % GPENCIL_MATERIAL_BUFFER_LEN];
+    MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, i + 1);
+    copy_v4_v4(mat_data->stroke_color, gp_style->stroke_rgba);
+    copy_v4_v4(mat_data->fill_color, gp_style->fill_rgba);
+  }
+
+  *ofs = 0;
+
+  return matpool;
+}
+
+GPUUniformBuffer *gpencil_material_ubo_get(GPENCIL_MaterialPool *first_pool, int mat_id)
+{
+  GPENCIL_MaterialPool *matpool = first_pool;
+  int pool_id = mat_id / GPENCIL_MATERIAL_BUFFER_LEN;
+  for (int i = 0; i < pool_id; i++) {
+    matpool = matpool->next;
+  }
+  return matpool->ubo;
+}
+
+void gpencil_material_pool_free(void *storage)
+{
+  GPENCIL_MaterialPool *matpool = (GPENCIL_MaterialPool *)storage;
+  DRW_UBO_FREE_SAFE(matpool->ubo);
+}
+
+static void gpencil_view_layer_data_free(void *storage)
+{
+  GPENCIL_ViewLayerData *vldata = (GPENCIL_ViewLayerData *)storage;
+
+  BLI_memblock_destroy(vldata->gp_material_pool, gpencil_material_pool_free);
+  BLI_memblock_destroy(vldata->gp_object_pool, NULL);
+  BLI_memblock_destroy(vldata->gp_layer_pool, NULL);
+  BLI_memblock_destroy(vldata->gp_vfx_pool, NULL);
+}
+
+GPENCIL_ViewLayerData *GPENCIL_view_layer_data_ensure(void)
+{
+  GPENCIL_ViewLayerData **vldata = (GPENCIL_ViewLayerData **)DRW_view_layer_engine_data_ensure(
+      &draw_engine_gpencil_type, gpencil_view_layer_data_free);
+
+  /* NOTE(fclem) Putting this stuff in viewlayer means it is shared by all viewports.
+   * For now it is ok, but in the future, it could become a problem if we implement
+   * the caching system. */
+  if (*vldata == NULL) {
+    *vldata = MEM_callocN(sizeof(**vldata), "GPENCIL_ViewLayerData");
+
+    (*vldata)->gp_material_pool = BLI_memblock_create(sizeof(GPENCIL_MaterialPool));
+    (*vldata)->gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject));
+    (*vldata)->gp_layer_pool = BLI_memblock_create(sizeof(GPENCIL_tLayer));
+    (*vldata)->gp_vfx_pool = BLI_memblock_create(sizeof(GPENCIL_tVfx));
+  }
+
+  return *vldata;
+}
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
index c8c48e84538..9ba7801b4d4 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_cache_impl.c
@@ -114,13 +114,11 @@ static void gpencil_buffer_add_point(gpStrokeVert *verts,
                                      const bGPDspoint *pt,
                                      bool is_endpoint)
 {
-  // float obscale = mat4_to_scale(ob->obmat);
-  // short lthick = brush->size * obscale;
   /* TODO other attribs */
   copy_v3_v3(verts->pos, &pt->x);
   verts->thickness = gps->thickness * pt->pressure;
   /* Tag endpoint material to -1 so they get discarded by vertex shader. */
-  verts->mat = (is_endpoint) ? -1 : 0;
+  verts->mat = (is_endpoint) ? -1 : (gps->mat_nr % GPENCIL_MATERIAL_BUFFER_LEN);
 }
 
 static void gpencil_buffer_add_stroke(gpStrokeVert *verts, const bGPDstroke *gps)
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 02d2cdbd1a8..e7705bd4b95 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -39,6 +39,7 @@
 #include "DNA_view3d_types.h"
 
 #include "GPU_texture.h"
+#include "GPU_uniformbuffer.h"
 
 #include "gpencil_engine.h"
 
@@ -284,13 +285,19 @@ static void GPENCIL_engine_init_new(void *ved)
     stl->pd = MEM_callocN(sizeof(GPENCIL_PrivateData), "GPENCIL_PrivateData");
   }
 
-  BLI_assert(stl->pd->gp_object_pool == NULL);
-  BLI_assert(stl->pd->gp_layer_pool == NULL);
-  BLI_assert(stl->pd->gp_vfx_pool == NULL);
+  GPENCIL_ViewLayerData *vldata = GPENCIL_view_layer_data_ensure();
 
-  stl->pd->gp_object_pool = BLI_memblock_create(sizeof(GPENCIL_tObject));
-  stl->pd->gp_layer_pool = BLI_memblock_create(sizeof(GPENCIL_tLayer));
-  stl->pd->gp_vfx_pool = BLI_memblock_create(sizeof(GPENCIL_tVfx));
+  /* Resize and reset memblocks. */
+  BLI_memblock_clear(vldata->gp_material_pool, gpencil_material_pool_free);
+  BLI_memblock_clear(vldata->gp_object_pool, NULL);
+  BLI_memblock_clear(vldata->gp_layer_pool, NULL);
+  BLI_memblock_clear(vldata->gp_vfx_pool, NULL);
+
+  stl->pd->gp_material_pool = vldata->gp_material_pool;
+  stl->pd->gp_object_pool = vldata->gp_object_pool;
+  stl->pd->gp_layer_pool = vldata->gp_layer_pool;
+  stl->pd->gp_vfx_pool = vldata->gp_vfx_pool;
+  stl->pd->last_material_pool = NULL;
 }
 
 void GPENCIL_engine_init(void *vedata)
@@ -728,7 +735,12 @@ typedef struct gpIterPopulateData {
   Object *ob;
   GPENCIL_tObject *tgp_ob;
   GPENCIL_PrivateData *pd;
+  GPENCIL_MaterialPool *matpool;
   DRWShadingGroup *grp;
+  /* Offset in the material pool to the first material of this object. */
+  int mat_ofs;
+  /* Index of last material pool used for drawing. Used to avoid uneeded buffer binding. */
+  int mat_pool_nr;
 } gpIterPopulateData;
 
 static void gp_layer_cache_populate(bGPDlayer *gpl,
@@ -742,6 +754,9 @@ static void gp_layer_cache_populate(bGPDlayer *gpl,
   GPENCIL_tLayer *tgp_layer = gpencil_layer_cache_add_new(iter->pd, iter->ob, gpl);
   BLI_LINKS_APPEND(&iter->tgp_ob->layers, tgp_layer);
 
+  GPUUniformBuffer *ubo_mat = gpencil_material_ubo_get(iter->matpool, 0);
+  iter->mat_pool_nr = 0;
+
   const bool is_screenspace = (gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0;
 
   float object_scale = mat4_to_scale(iter->ob->obmat);
@@ -751,6 +766,7 @@ static void gp_layer_cache_populate(bGPDlayer *gpl,
 
   struct GPUShader *sh = GPENCIL_shader_geometry_get(&en_data);
   iter->grp = DRW_shgroup_create(sh, tgp_layer->geom_ps);
+  DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", ubo_mat);
   DRW_shgroup_uniform_vec4_copy(iter->grp, "gpModelMatrix[0]", iter->ob->obmat[0]);
   DRW_shgroup_uniform_vec4_copy(iter->grp, "gpModelMatrix[1]", iter->ob->obmat[1]);
   DRW_shgroup_uniform_vec4_copy(iter->grp, "gpModelMatrix[2]", iter->ob->obmat[2]);
@@ -776,6 +792,15 @@ static void gp_stroke_cache_populate(bGPDlayer *UNUSED(gpl),
     return;
   }
 
+  int mat_pool_nr = gps->mat_nr / GPENCIL_MATERIAL_BUFFER_LEN;
+  if (mat_pool_nr != iter->mat_pool_nr) {
+    /* Change ubo because material is not from the same pool as previous material. */
+    GPUUniformBuffer *ubo_mat = gpencil_material_ubo_get(iter->matpool, gps->mat_nr);
+    iter->grp = DRW_shgroup_create_sub(iter->grp);
+    DRW_shgroup_uniform_block(iter->grp, "gpMaterialBlock", ubo_mat);
+    iter->mat_pool_nr = mat_pool_nr;
+  }
+
   bool show_stroke = (gp_style->flag & GP_STYLE_STROKE_SHOW) != 0;
   bool show_fill = (gps->tot_triangles > 0) && (gp_style->flag & GP_STYLE_FILL_SHOW) != 0;
 
@@ -807,13 +832,12 @@ static void GPENCIL_cache_populate_new(void *ved, Object *ob)
   }
 
   if (ob->type == OB_GPENCIL && ob->data) {
-    GPENCIL_tObject *tgp_ob = gpencil_object_cache_add_new(pd, ob);
+    gpIterPopulateData iter = {0};
+    iter.ob = ob;
+    iter.pd = pd;
+    iter.tgp_ob = gpencil_object_cache_add_new(pd, ob);
+    iter.matpool = gpencil_material_pool_create(pd, ob, &iter.mat_ofs);
 
-    gpIterPopulateData iter = {
-        .ob = ob,
-        .pd = pd,
-        .tgp_ob = tgp_ob,
-    };
     gpencil_object_visible_stroke_iter(
         ob, gp_layer_ca

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list