[Bf-blender-cvs] [85f96255b25] temp-texture-painting-gpu: Improve performance by making buffers persistent.

Jeroen Bakker noreply at git.blender.org
Tue Oct 4 11:17:33 CEST 2022


Commit: 85f96255b25bbabb8e53d4183adea66a312a4742
Author: Jeroen Bakker
Date:   Tue Oct 4 10:02:59 2022 +0200
Branches: temp-texture-painting-gpu
https://developer.blender.org/rB85f96255b25bbabb8e53d4183adea66a312a4742

Improve performance by making buffers persistent.

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

M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/editors/sculpt_paint/sculpt_paint_color.c
M	source/blender/editors/sculpt_paint/sculpt_paint_image.cc
M	source/blender/gpu/shaders/sculpt_paint/sculpt_paint_image_comp.glsl

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

diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index f19f8e91738..aa3893cf466 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -5511,13 +5511,13 @@ static void sculpt_brush_exit_tex(Sculpt *sd)
 static void sculpt_flush_batches(Sculpt *sd,
                                  Object *ob,
                                  Brush *brush,
-                                 PaintModeSettings *paint_mode_settings)
+                                 PaintModeSettings *paint_mode_settings, const bool is_final)
 {
   if (!sculpt_needs_pbvh_pixels(paint_mode_settings, brush, ob)) {
     return;
   }
   if (brush->sculpt_tool == SCULPT_TOOL_PAINT) {
-    SCULPT_paint_batches_flush(paint_mode_settings, sd, ob);
+    SCULPT_paint_batches_flush(paint_mode_settings, sd, ob, is_final);
   }
 }
 
@@ -5534,14 +5534,11 @@ static void sculpt_stroke_redraw(const bContext *C,
   Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
   Brush *brush = BKE_paint_brush(&sd->paint);
   ToolSettings *tool_settings = CTX_data_tool_settings(C);
-  sculpt_flush_batches(sd, ob, brush, &tool_settings->paint_mode);
+  sculpt_flush_batches(sd, ob, brush, &tool_settings->paint_mode, is_final);
 
   if (!ss->cache) {
     return;
   }
-
-  if (is_final) {
-  }
 }
 
 static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke))
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index d639ff82545..bc22e496013 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -1744,7 +1744,8 @@ void SCULPT_do_paint_brush(struct PaintModeSettings *paint_mode_settings,
                            int totnode) ATTR_NONNULL();
 void SCULPT_paint_batches_flush(struct PaintModeSettings *paint_mode_settings,
                                 struct Sculpt *sd,
-                                struct Object *ob);
+                                struct Object *ob,
+                                const bool is_final);
 
 /**
  * \brief Get the image canvas for painting on the given object.
@@ -1766,6 +1767,9 @@ bool SCULPT_use_image_paint_brush(struct PaintModeSettings *settings, Object *ob
 void SCULPT_paint_image_batches_flush(struct PaintModeSettings *paint_mode_settings,
                                       struct Sculpt *sd,
                                       struct Object *ob);
+void SCULPT_paint_image_batches_finalize(struct PaintModeSettings *paint_mode_settings,
+                                         struct Sculpt *sd,
+                                         struct Object *ob);
 
 /* Smear Brush. */
 void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode);
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_color.c b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
index bc4861f84f3..ccf94aa842e 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_color.c
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_color.c
@@ -395,13 +395,18 @@ void SCULPT_do_paint_brush(
   BLI_task_parallel_range(0, totnode, &data, do_paint_brush_task_cb_ex, &settings);
 }
 
-void SCULPT_paint_batches_flush(PaintModeSettings *paint_mode_settings, Sculpt *sd, Object *ob)
+void SCULPT_paint_batches_flush(PaintModeSettings *paint_mode_settings,
+                                Sculpt *sd,
+                                Object *ob,
+                                const bool is_final)
 {
   if (!SCULPT_use_image_paint_brush(paint_mode_settings, ob)) {
     return;
   }
-
   SCULPT_paint_image_batches_flush(paint_mode_settings, sd, ob);
+  if (is_final) {
+    SCULPT_paint_image_batches_finalize(paint_mode_settings, sd, ob);
+  }
 }
 
 static void do_smear_brush_task_cb_exec(void *__restrict userdata,
diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
index 14ea5bad8b3..3bb2db62932 100644
--- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
+++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc
@@ -14,6 +14,8 @@
 #include "BLI_math_color_blend.h"
 #include "BLI_task.h"
 
+#include "PIL_time_utildefines.h"
+
 #include "GPU_capabilities.h"
 #include "GPU_compute.h"
 #include "GPU_debug.h"
@@ -489,9 +491,140 @@ static void do_mark_dirty_regions(void *__restrict userdata,
 /* -------------------------------------------------------------------- */
 /** \name GPU
  * \{ */
+static GPUStorageBuf *gpu_painting_vert_coord_create(SculptSession &ss)
+{
+  Vector<float4> vert_coords;
+
+  vert_coords.reserve(ss.totvert);
+  for (const MVert &mvert : Span<MVert>(ss.mvert, ss.totvert)) {
+    float3 co(mvert.co);
+    vert_coords.append(float4(co.x, co.y, co.z, 0.0f));
+  }
+  GPUStorageBuf *result = GPU_storagebuf_create_ex(
+      sizeof(float4) * ss.totvert, vert_coords.data(), GPU_USAGE_STATIC, __func__);
+  return result;
+}
+
+static void init_paint_brush_color(const SculptSession &ss,
+                                   const Brush &brush,
+                                   PaintBrushData &r_paint_brush)
+{
+  if (ss.cache->invert) {
+    copy_v3_v3(r_paint_brush.color, BKE_brush_secondary_color_get(ss.scene, &brush));
+  }
+  else {
+    copy_v3_v3(r_paint_brush.color, BKE_brush_color_get(ss.scene, &brush));
+  }
+  /* NOTE: Brush colors are stored in sRGB. We use math color to follow other areas that use
+       brush colors. */
+  srgb_to_linearrgb_v3_v3(r_paint_brush.color, r_paint_brush.color);
+  r_paint_brush.color[3] = 1.0f;
+}
+
+static void init_paint_brush_strength(const SculptSession &ss, PaintBrushData &r_paint_brush)
+{
+  r_paint_brush.strength = ss.cache->bstrength;
+}
+
+/* TODO: Currently only spherical is supported. */
+static void init_paint_brush_test(const SculptSession &ss, PaintBrushData &r_paint_brush)
+{
+  r_paint_brush.test.symm_rot_mat_inv = ss.cache->symm_rot_mat_inv;
+}
+
+static void init_paint_brush(const SculptSession &ss,
+                             const Brush &brush,
+                             PaintBrushData &r_paint_brush)
+{
+  init_paint_brush_color(ss, brush, r_paint_brush);
+  init_paint_brush_strength(ss, r_paint_brush);
+  init_paint_brush_test(ss, r_paint_brush);
+}
 
 struct GPUSculptPaintData {
   Vector<PaintStepData> steps;
+  GPUStorageBuf *step_buf = nullptr;
+  size_t step_buf_alloc_size = 0;
+  GPUStorageBuf *vert_coord_buf = nullptr;
+  GPUUniformBuf *paint_brush_buf = nullptr;
+
+  GPUTexture *tile_texture = nullptr;
+
+  ~GPUSculptPaintData()
+  {
+    if (vert_coord_buf) {
+      GPU_storagebuf_free(vert_coord_buf);
+      vert_coord_buf = nullptr;
+    }
+
+    if (paint_brush_buf) {
+      GPU_uniformbuf_free(paint_brush_buf);
+      paint_brush_buf = nullptr;
+    }
+
+    if (step_buf) {
+      GPU_storagebuf_free(step_buf);
+      step_buf = nullptr;
+    }
+
+    if (tile_texture) {
+      GPU_texture_free(tile_texture);
+      tile_texture = nullptr;
+    }
+  }
+
+  void update_step_buf()
+  {
+    int requested_size = sizeof(PaintStepData) * steps.size();
+
+    if (step_buf && requested_size > step_buf_alloc_size) {
+      GPU_storagebuf_free(step_buf);
+      step_buf = nullptr;
+    }
+
+    if (step_buf == nullptr) {
+      step_buf = GPU_storagebuf_create_ex(
+          requested_size, nullptr, GPU_USAGE_STATIC, "PaintStepData");
+      step_buf_alloc_size = requested_size;
+    }
+
+    BLI_assert_msg(sizeof(PaintStepData) * steps.capacity() > step_buf_alloc_size,
+                   "Possible read from unallocated memory as storage buffer is larger than the "
+                   "step capacity.");
+    GPU_storagebuf_update(step_buf, steps.data());
+  }
+
+  void ensure_vert_coord_buf(SculptSession &ss)
+  {
+    if (!vert_coord_buf) {
+      vert_coord_buf = gpu_painting_vert_coord_create(ss);
+    }
+  }
+
+  void ensure_paint_brush_buf(SculptSession &ss, Brush &brush)
+  {
+    PaintBrushData paint_brush;
+    init_paint_brush(ss, brush, paint_brush);
+
+    if (!paint_brush_buf) {
+      paint_brush_buf = GPU_uniformbuf_create_ex(
+          sizeof(PaintBrushData), nullptr, "PaintBrushData");
+    }
+
+    GPU_uniformbuf_update(paint_brush_buf, &paint_brush);
+  }
+
+  void ensure_tile_texture(const int2 resolution)
+  {
+    if (tile_texture == nullptr || GPU_texture_width(tile_texture) != resolution.x ||
+        GPU_texture_height(tile_texture) != resolution.y) {
+      if (tile_texture) {
+        GPU_texture_free(tile_texture);
+        tile_texture = nullptr;
+      }
+      tile_texture = GPU_texture_create_2d(__func__, UNPACK2(resolution), 1, GPU_RGBA32F, nullptr);
+    }
+  }
 };
 
 static void ensure_gpu_buffers(TexturePaintingUserData &data)
@@ -499,6 +632,11 @@ static void ensure_gpu_buffers(TexturePaintingUserData &data)
   SculptSession &ss = *data.ob->sculpt;
   if (!ss.mode.texture_paint.gpu_data) {
     ss.mode.texture_paint.gpu_data = MEM_new<GPUSculptPaintData>(__func__);
+  }
+
+  GPUSculptPaintData &paint_data = *static_cast<GPUSculptPaintData *>(
+      ss.mode.texture_paint.gpu_data);
+  if (paint_data.steps.is_empty()) {
     PBVH *pbvh = ss.pbvh;
     BKE_pbvh_frame_selection_clear(pbvh);
   }
@@ -510,40 +648,19 @@ static void ensure_gpu_buffers(TexturePaintingUserData &data)
 }
 
 static void gpu_painting_paint_step(TexturePaintingUserData &data,
+                                    GPUSculptPaintData &batches,
                                     TileNumber tile_number,
                                     ImBuf *image_buffer,
-                                    GPUTexture **tex_ptr,
-                                    GPUUniformBuf *paint_brush_buf,
-                                    GPUStorageBuf *paint_step_buf,
-                                    int2 paint_step_range,
-                                    GPUStorageBuf *vert_coord_buf)
+                                    int2 paint_step_range)
 {
   GPUShader *shader = SCULPT_shader_paint_image_get();
-  bool texture_needs_clearing = true;
-
-  GPUTexture *tex = *tex_ptr;
 
-  /* Ensure that texture size is same as tile size. */


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list