Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw/intern/draw_hair.c')
-rw-r--r--source/blender/draw/intern/draw_hair.c200
1 files changed, 153 insertions, 47 deletions
diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c
index bca227a24e2..585e171adc5 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 OS's.
+ * Currently the `__APPLE__` code-path 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_shgrp = DRW_shgroup_transform_feedback_create(
+ tf_shader, g_tf_pass, cache->final[subdiv].proc_buf);
+#else
+ DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
+
+ ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
+ pr_call->next = g_tf_calls;
+ pr_call->vbo = cache->final[subdiv].proc_buf;
+ pr_call->shgrp = tf_shgrp;
+ pr_call->vert_len = final_points_len;
+ g_tf_calls = pr_call;
+ DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
+ DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
+#endif
+
+ drw_hair_particle_cache_shgrp_attach_resources(tf_shgrp, cache, subdiv);
+ DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ }
+}
+
static ParticleHairCache *drw_hair_particle_cache_get(
Object *object, ParticleSystem *psys, ModifierData *md, int subdiv, int thickness_res)
{
@@ -140,32 +265,11 @@ static ParticleHairCache *drw_hair_particle_cache_get(
}
if (update) {
- 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_shgrp = DRW_shgroup_transform_feedback_create(
- tf_shader, g_tf_pass, cache->final[subdiv].proc_buf);
-#else
- DRWShadingGroup *tf_shgrp = DRW_shgroup_create(tf_shader, g_tf_pass);
-
- ParticleRefineCall *pr_call = MEM_mallocN(sizeof(*pr_call), __func__);
- pr_call->next = g_tf_calls;
- pr_call->vbo = cache->final[subdiv].proc_buf;
- pr_call->shgrp = tf_shgrp;
- pr_call->vert_len = final_points_len;
- g_tf_calls = pr_call;
- DRW_shgroup_uniform_int(tf_shgrp, "targetHeight", &g_tf_target_height, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "targetWidth", &g_tf_target_width, 1);
- DRW_shgroup_uniform_int(tf_shgrp, "idOffset", &g_tf_id_offset, 1);
-#endif
-
- DRW_shgroup_uniform_texture(tf_shgrp, "hairPointBuffer", cache->point_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandBuffer", cache->strand_tex);
- DRW_shgroup_uniform_texture(tf_shgrp, "hairStrandSegBuffer", cache->strand_seg_tex);
- DRW_shgroup_uniform_int(tf_shgrp, "hairStrandsRes", &cache->final[subdiv].strands_res, 1);
- DRW_shgroup_call_procedural_points(tf_shgrp, NULL, final_points_len);
+ if (drw_hair_use_compute_shaders()) {
+ drw_hair_particle_cache_update_compute(cache, subdiv);
+ }
+ else {
+ drw_hair_particle_cache_update_transform_feedback(cache, subdiv);
}
}
return cache;
@@ -367,9 +471,11 @@ void DRW_hair_update(void)
MEM_freeN(data);
GPU_framebuffer_free(fb);
#else
- /* TODO(fclem): replace by compute shader. */
- /* Just render using transform feedback. */
+ /* Just render the pass when using compute shaders or transform feedback. */
DRW_draw_pass(g_tf_pass);
+ if (drw_hair_use_compute_shaders()) {
+ GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE);
+ }
#endif
}