[Bf-blender-cvs] [6b03621c018] master: DrawManager: Use Compute Shader to Update Hair.

Jeroen Bakker noreply at git.blender.org
Fri May 28 08:25:49 CEST 2021


Commit: 6b03621c018acc3b343caa1d8d2aad746fcffc08
Author: Jeroen Bakker
Date:   Fri May 28 08:16:26 2021 +0200
Branches: master
https://developer.blender.org/rB6b03621c018acc3b343caa1d8d2aad746fcffc08

DrawManager: Use Compute Shader to Update Hair.

This patch will use compute shaders to create the VBO for hair.
The previous implementation uses transform feedback.

Timings before: between 0.000069s and 0.000362s.
Timings after:  between 0.000032s and 0.000092s.

Speedup isn't noticeable by end-users. The patch is used to test
the new compute shader pipeline and integrate it with the draw
manager. Allowing EEVEE, Workbench and other draw engines to
use compute shaders with the introduction of `DRW_shgroup_call_compute`
and `DRW_shgroup_vertex_buffer`.

Future improvements are possible by generating the index buffer
of hair directly on the GPU.

NOTE: that compute shaders aren't supported by Apple and still use
the transform feedback workaround.

Reviewed By: fclem

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

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

M	source/blender/draw/CMakeLists.txt
M	source/blender/draw/intern/DRW_render.h
M	source/blender/draw/intern/draw_cache_impl_hair.c
M	source/blender/draw/intern/draw_hair.c
M	source/blender/draw/intern/draw_manager.h
M	source/blender/draw/intern/draw_manager_data.c
M	source/blender/draw/intern/draw_manager_exec.c
M	source/blender/draw/intern/shaders/common_hair_lib.glsl
A	source/blender/draw/intern/shaders/common_hair_refine_comp.glsl
M	source/blender/draw/intern/shaders/common_hair_refine_vert.glsl
M	source/blender/gpu/GPU_capabilities.h
M	source/blender/gpu/intern/gpu_capabilities.cc
M	source/blender/gpu/intern/gpu_capabilities_private.hh
M	source/blender/gpu/opengl/gl_backend.cc

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

diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt
index afb0f613290..0541aa982f3 100644
--- a/source/blender/draw/CMakeLists.txt
+++ b/source/blender/draw/CMakeLists.txt
@@ -322,6 +322,7 @@ data_to_c_simple(intern/shaders/common_globals_lib.glsl SRC)
 data_to_c_simple(intern/shaders/common_pointcloud_lib.glsl SRC)
 data_to_c_simple(intern/shaders/common_hair_lib.glsl SRC)
 data_to_c_simple(intern/shaders/common_hair_refine_vert.glsl SRC)
+data_to_c_simple(intern/shaders/common_hair_refine_comp.glsl SRC)
 data_to_c_simple(intern/shaders/common_math_lib.glsl SRC)
 data_to_c_simple(intern/shaders/common_math_geom_lib.glsl SRC)
 data_to_c_simple(intern/shaders/common_view_lib.glsl SRC)
diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 2545cfa65dc..5071658fd82 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -438,6 +438,10 @@ void DRW_shgroup_call_range(
 void DRW_shgroup_call_instance_range(
     DRWShadingGroup *shgroup, Object *ob, struct GPUBatch *geom, uint i_sta, uint i_ct);
 
+void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
+                              int groups_x_len,
+                              int groups_y_len,
+                              int groups_z_len);
 void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count);
 void DRW_shgroup_call_procedural_lines(DRWShadingGroup *sh, Object *ob, uint line_count);
 void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count);
@@ -575,6 +579,9 @@ void DRW_shgroup_uniform_vec4_array_copy(DRWShadingGroup *shgroup,
                                          const char *name,
                                          const float (*value)[4],
                                          int arraysize);
+void DRW_shgroup_vertex_buffer(DRWShadingGroup *shgroup,
+                               const char *name,
+                               struct GPUVertBuf *vertex_buffer);
 
 bool DRW_shgroup_is_empty(DRWShadingGroup *shgroup);
 
diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.c
index fd28ac00186..6424b21666d 100644
--- a/source/blender/draw/intern/draw_cache_impl_hair.c
+++ b/source/blender/draw/intern/draw_cache_impl_hair.c
@@ -243,7 +243,8 @@ static void hair_batch_cache_ensure_procedural_final_points(ParticleHairCache *c
   GPUVertFormat format = {0};
   GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
 
-  cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format(&format);
+  cache->final[subdiv].proc_buf = GPU_vertbuf_create_with_format_ex(&format,
+                                                                    GPU_USAGE_DEVICE_ONLY);
 
   /* Create a destination buffer for the transform feedback. Sized appropriately */
   /* Those are points! not line segments. */
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index bca227a24e2..bf3b10bccd3 100644
--- a/source/blender/draw/intern/draw_hair.c
+++ b/source/blender/draw/intern/draw_hair.c
@@ -36,15 +36,28 @@
 #include "BKE_duplilist.h"
 
 #include "GPU_batch.h"
+#include "GPU_capabilities.h"
+#include "GPU_compute.h"
 #include "GPU_shader.h"
+#include "GPU_texture.h"
 #include "GPU_vertex_buffer.h"
 
 #include "draw_hair_private.h"
 
 #ifndef __APPLE__
 #  define USE_TRANSFORM_FEEDBACK
+#  define USE_COMPUTE_SHADERS
 #endif
 
+BLI_INLINE bool drw_hair_use_compute_shaders(void)
+{
+#ifdef USE_COMPUTE_SHADERS
+  return GPU_compute_shader_support();
+#else
+  return false;
+#endif
+}
+
 typedef enum ParticleRefineShader {
   PART_REFINE_CATMULL_ROM = 0,
   PART_REFINE_MAX_SHADER,
@@ -71,38 +84,89 @@ static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in t
 
 extern char datatoc_common_hair_lib_glsl[];
 extern char datatoc_common_hair_refine_vert_glsl[];
+extern char datatoc_common_hair_refine_comp_glsl[];
 extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
 
-static GPUShader *hair_refine_shader_get(ParticleRefineShader sh)
+/* TODO(jbakker): move shader creation to `draw_shaders` and add test cases. */
+/* TODO(jbakker): replace defines with `constexpr` to check compilation on all OSs. Currently the
+ * APPLE codepath does not compile on other platforms and vice versa. */
+#ifdef USE_COMPUTE_SHADERS
+static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement))
 {
-  if (g_refine_shaders[sh]) {
-    return g_refine_shaders[sh];
-  }
-
-  char *vert_with_lib = BLI_string_joinN(datatoc_common_hair_lib_glsl,
-                                         datatoc_common_hair_refine_vert_glsl);
+  GPUShader *sh = NULL;
+  sh = GPU_shader_create_compute(datatoc_common_hair_refine_comp_glsl,
+                                 datatoc_common_hair_lib_glsl,
+                                 "#define HAIR_PHASE_SUBDIV\n",
+                                 __func__);
+  return sh;
+}
+#endif
 
 #ifdef USE_TRANSFORM_FEEDBACK
+static GPUShader *hair_refine_shader_transform_feedback_create(
+    ParticleRefineShader UNUSED(refinement))
+{
+  GPUShader *sh = NULL;
+
+  char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
+                                      datatoc_common_hair_refine_vert_glsl);
   const char *var_names[1] = {"finalColor"};
-  g_refine_shaders[sh] = DRW_shader_create_with_transform_feedback(
-      vert_with_lib, NULL, "#define HAIR_PHASE_SUBDIV\n", GPU_SHADER_TFB_POINTS, var_names, 1);
-#else
-  g_refine_shaders[sh] = DRW_shader_create(vert_with_lib,
-                                           NULL,
-                                           datatoc_gpu_shader_3D_smooth_color_frag_glsl,
-                                           "#define blender_srgb_to_framebuffer_space(a) a\n"
-                                           "#define HAIR_PHASE_SUBDIV\n"
-                                           "#define TF_WORKAROUND\n");
+  sh = DRW_shader_create_with_transform_feedback(
+      shader_src, NULL, "#define HAIR_PHASE_SUBDIV\n", GPU_SHADER_TFB_POINTS, var_names, 1);
+  MEM_freeN(shader_src);
+
+  return sh;
+}
 #endif
 
-  MEM_freeN(vert_with_lib);
+static GPUShader *hair_refine_shader_transform_feedback_workaround_create(
+    ParticleRefineShader UNUSED(refinement))
+{
+  GPUShader *sh = NULL;
+
+  char *shader_src = BLI_string_joinN(datatoc_common_hair_lib_glsl,
+                                      datatoc_common_hair_refine_vert_glsl);
+  sh = DRW_shader_create(shader_src,
+                         NULL,
+                         datatoc_gpu_shader_3D_smooth_color_frag_glsl,
+                         "#define blender_srgb_to_framebuffer_space(a) a\n"
+                         "#define HAIR_PHASE_SUBDIV\n"
+                         "#define TF_WORKAROUND\n");
+  MEM_freeN(shader_src);
+
+  return sh;
+}
+
+static GPUShader *hair_refine_shader_get(ParticleRefineShader refinement)
+{
+  if (g_refine_shaders[refinement]) {
+    return g_refine_shaders[refinement];
+  }
+
+#ifdef USE_COMPUTE_SHADERS
+  if (drw_hair_use_compute_shaders()) {
+    g_refine_shaders[refinement] = hair_refine_shader_compute_create(refinement);
+    if (g_refine_shaders[refinement]) {
+      return g_refine_shaders[refinement];
+    }
+  }
+#endif
+
+#ifdef USE_TRANSFORM_FEEDBACK
+  g_refine_shaders[refinement] = hair_refine_shader_transform_feedback_create(refinement);
+  if (g_refine_shaders[refinement]) {
+    return g_refine_shaders[refinement];
+  }
+#endif
 
-  return g_refine_shaders[sh];
+  g_refine_shaders[refinement] = hair_refine_shader_transform_feedback_workaround_create(
+      refinement);
+  return g_refine_shaders[refinement];
 }
 
 void DRW_hair_init(void)
 {
-#ifdef USE_TRANSFORM_FEEDBACK
+#if defined(USE_TRANSFORM_FEEDBACK) || defined(USE_COMPUTE_SHADERS)
   g_tf_pass = DRW_pass_create("Update Hair Pass", 0);
 #else
   g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR);
@@ -125,6 +189,67 @@ void DRW_hair_init(void)
   }
 }
 
+static void drw_hair_particle_cache_shgrp_attach_resources(DRWShadingGroup *shgrp,
+                                                           ParticleHairCache *cache,
+                                                           const int subdiv)
+{
+  DRW_shgroup_uniform_texture(shgrp, "hairPointBuffer", cache->point_tex);
+  DRW_shgroup_uniform_texture(shgrp, "hairStrandBuffer", cache->strand_tex);
+  DRW_shgroup_uniform_texture(shgrp, "hairStrandSegBuffer", cache->strand_seg_tex);
+  DRW_shgroup_uniform_int(shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1);
+}
+
+static void drw_hair_particle_cache_update_compute(ParticleHairCache *cache, const int subdiv)
+{
+  const int strands_len = cache->strands_len;
+  const int final_points_len = cache->final[subdiv].strands_res * strands_len;
+  if (final_points_len > 0) {
+    GPUShader *shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
+    DRWShadingGroup *shgrp = DRW_shgroup_create(shader, g_tf_pass);
+    drw_hair_particle_cache_shgrp_attach_resources(shgrp, cache, subdiv);
+    DRW_shgroup_vertex_buffer(shgrp, "hairPointOutputBuffer", cache->final[subdiv].proc_buf);
+
+    const int max_strands_per_call = GPU_max_work_group_count(0);
+    int strands_start = 0;
+    while (strands_start < strands_len) {
+      int batch_strands_len = MIN2(strands_len - strands_start, max_strands_per_call);
+      DRWShadingGroup *subgroup = DRW_shgroup_create_sub(shgrp);
+      DRW_shgroup_uniform_int_copy(subgroup, "hairStrandOffset", strands_start);
+      DRW_shgroup_call_compute(subgroup, batch_strands_len, cache->final[subdiv].strands_res, 1);
+      strands_start += batch_strands_len;
+    }
+  }
+}
+
+static void drw_hair_particle_cache_update_transform_feedback(ParticleHairCache *cache,
+                                                              const int subdiv)
+{
+  const int final_points_len = cache->final[subdiv].strands_res * cache->strands_len;
+  if (final_points_len > 0) {
+    GPUShader *tf_shader = hair_refine_shader_get(PART_REFINE_CATMULL_ROM);
+
+#ifdef USE_TRANSFORM_FEEDBACK
+    DRWShadingGroup *tf_shg

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list