From 3f1111b2a82fe975fdb55114943009e8ef0a2c43 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 22 Jun 2021 11:10:59 +0200 Subject: Draw: Added testcases for hair refine shaders. --- source/blender/draw/CMakeLists.txt | 2 + source/blender/draw/intern/draw_hair.c | 106 +++------------------ source/blender/draw/intern/draw_hair_private.h | 13 +++ source/blender/draw/intern/draw_manager.c | 2 + source/blender/draw/intern/draw_shader.c | 122 +++++++++++++++++++++++++ source/blender/draw/intern/draw_shader.h | 47 ++++++++++ source/blender/draw/tests/shaders_test.cc | 23 ++++- 7 files changed, 220 insertions(+), 95 deletions(-) create mode 100644 source/blender/draw/intern/draw_shader.c create mode 100644 source/blender/draw/intern/draw_shader.h (limited to 'source/blender/draw') diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index e99bf1f5b0c..4f68c3fdc7e 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -85,6 +85,7 @@ set(SRC intern/draw_manager_text.c intern/draw_manager_texture.c intern/draw_select_buffer.c + intern/draw_shader.c intern/draw_view.c engines/basic/basic_engine.c engines/image/image_engine.c @@ -185,6 +186,7 @@ set(SRC intern/draw_manager_testing.h intern/draw_manager_text.h intern/draw_view.h + intern/draw_shader.h intern/smaa_textures.h engines/basic/basic_engine.h engines/eevee/eevee_engine.h diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 585e171adc5..d101df737ff 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -43,26 +43,26 @@ #include "GPU_vertex_buffer.h" #include "draw_hair_private.h" +#include "draw_shader.h" #ifndef __APPLE__ # define USE_TRANSFORM_FEEDBACK # define USE_COMPUTE_SHADERS #endif -BLI_INLINE bool drw_hair_use_compute_shaders(void) +BLI_INLINE eParticleRefineShaderType drw_hair_shader_type_get(void) { #ifdef USE_COMPUTE_SHADERS - return GPU_compute_shader_support(); -#else - return false; + if (GPU_compute_shader_support()) { + return PART_REFINE_SHADER_COMPUTE; + } #endif +#ifdef USE_TRANSFORM_FEEDBACK + return PART_REFINE_SHADER_TRANSFORM_FEEDBACK; +#endif + return PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND; } -typedef enum ParticleRefineShader { - PART_REFINE_CATMULL_ROM = 0, - PART_REFINE_MAX_SHADER, -} ParticleRefineShader; - #ifndef USE_TRANSFORM_FEEDBACK typedef struct ParticleRefineCall { struct ParticleRefineCall *next; @@ -79,89 +79,11 @@ static int g_tf_target_height; static GPUVertBuf *g_dummy_vbo = NULL; static GPUTexture *g_dummy_texture = NULL; -static GPUShader *g_refine_shaders[PART_REFINE_MAX_SHADER] = {NULL}; static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */ -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[]; - -/* 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)) -{ - 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"}; - 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 - -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 - - g_refine_shaders[refinement] = hair_refine_shader_transform_feedback_workaround_create( - refinement); - return g_refine_shaders[refinement]; + return DRW_shader_hair_refine_get(refinement, drw_hair_shader_type_get()); } void DRW_hair_init(void) @@ -265,7 +187,7 @@ static ParticleHairCache *drw_hair_particle_cache_get( } if (update) { - if (drw_hair_use_compute_shaders()) { + if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) { drw_hair_particle_cache_update_compute(cache, subdiv); } else { @@ -473,7 +395,7 @@ void DRW_hair_update(void) #else /* Just render the pass when using compute shaders or transform feedback. */ DRW_draw_pass(g_tf_pass); - if (drw_hair_use_compute_shaders()) { + if (drw_hair_shader_type_get() == PART_REFINE_SHADER_COMPUTE) { GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE); } #endif @@ -481,10 +403,6 @@ void DRW_hair_update(void) void DRW_hair_free(void) { - for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) { - DRW_SHADER_FREE_SAFE(g_refine_shaders[i]); - } - GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo); DRW_TEXTURE_FREE_SAFE(g_dummy_texture); } diff --git a/source/blender/draw/intern/draw_hair_private.h b/source/blender/draw/intern/draw_hair_private.h index 28bd5d4dfb5..1f58d8d0ead 100644 --- a/source/blender/draw/intern/draw_hair_private.h +++ b/source/blender/draw/intern/draw_hair_private.h @@ -23,11 +23,20 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + #define MAX_LAYER_NAME_CT 4 /* u0123456789, u, au, a0123456789 */ #define MAX_LAYER_NAME_LEN (GPU_MAX_SAFE_ATTR_NAME + 2) #define MAX_THICKRES 2 /* see eHairType */ #define MAX_HAIR_SUBDIV 4 /* see hair_subdiv rna */ +typedef enum ParticleRefineShader { + PART_REFINE_CATMULL_ROM = 0, + PART_REFINE_MAX_SHADER, +} ParticleRefineShader; + struct ModifierData; struct Object; struct ParticleHairCache; @@ -91,3 +100,7 @@ bool hair_ensure_procedural_data(struct Object *object, struct ParticleHairCache **r_hair_cache, int subdiv, int thickness_res); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 37f6bbf52b5..8a805409b27 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -87,6 +87,7 @@ #include "draw_manager_profiling.h" #include "draw_manager_testing.h" #include "draw_manager_text.h" +#include "draw_shader.h" /* only for callbacks */ #include "draw_cache_impl.h" @@ -2987,6 +2988,7 @@ void DRW_engines_free(void) DRW_TEXTURE_FREE_SAFE(g_select_buffer.texture_depth); GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer_depth_only); + DRW_shaders_free(); DRW_hair_free(); DRW_shape_cache_free(); DRW_stats_free(); diff --git a/source/blender/draw/intern/draw_shader.c b/source/blender/draw/intern/draw_shader.c new file mode 100644 index 00000000000..9c756065353 --- /dev/null +++ b/source/blender/draw/intern/draw_shader.c @@ -0,0 +1,122 @@ +/* + * 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 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BLI_dynstr.h" +#include "BLI_string_utils.h" + +#include "GPU_batch.h" +#include "GPU_index_buffer.h" +#include "GPU_vertex_buffer.h" + +#include "draw_shader.h" + +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 struct { + struct GPUShader *hair_refine_sh[PART_REFINE_MAX_SHADER]; +} e_data = {{NULL}}; + +/* -------------------------------------------------------------------- */ +/** \name Hair refinement + * \{ */ + +static GPUShader *hair_refine_shader_compute_create(ParticleRefineShader UNUSED(refinement)) +{ + 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; +} + +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"}; + 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; +} + +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; +} + +GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement, + eParticleRefineShaderType sh_type) +{ + if (e_data.hair_refine_sh[refinement] == NULL) { + GPUShader *sh = NULL; + switch (sh_type) { + case PART_REFINE_SHADER_COMPUTE: + sh = hair_refine_shader_compute_create(refinement); + break; + case PART_REFINE_SHADER_TRANSFORM_FEEDBACK: + sh = hair_refine_shader_transform_feedback_create(refinement); + break; + case PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND: + sh = hair_refine_shader_transform_feedback_workaround_create(refinement); + break; + default: + BLI_assert(!"Incorrect shader type"); + } + e_data.hair_refine_sh[refinement] = sh; + } + + return e_data.hair_refine_sh[refinement]; +} + +/** \} */ + +void DRW_shaders_free(void) +{ + for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) { + DRW_SHADER_FREE_SAFE(e_data.hair_refine_sh[i]); + } +} diff --git a/source/blender/draw/intern/draw_shader.h b/source/blender/draw/intern/draw_shader.h new file mode 100644 index 00000000000..f9fa452671b --- /dev/null +++ b/source/blender/draw/intern/draw_shader.h @@ -0,0 +1,47 @@ +/* + * 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. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup draw + */ + +#pragma once + +#include "draw_hair_private.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct GPUShader; + +typedef enum eParticleRefineShaderType { + PART_REFINE_SHADER_TRANSFORM_FEEDBACK, + PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND, + PART_REFINE_SHADER_COMPUTE, +} eParticleRefineShaderType; + +/* draw_shader.c */ +struct GPUShader *DRW_shader_hair_refine_get(ParticleRefineShader refinement, + eParticleRefineShaderType sh_type); +void DRW_shaders_free(void); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index c96f22859ca..cce69714f5e 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -3,17 +3,22 @@ #include "testing/testing.h" #include "draw_testing.hh" -#include "intern/draw_manager_testing.h" #include "GPU_context.h" +#include "GPU_index_buffer.h" #include "GPU_init_exit.h" #include "GPU_shader.h" +#include "GPU_texture.h" +#include "GPU_vertex_buffer.h" + +#include "intern/draw_manager_testing.h" #include "engines/eevee/eevee_private.h" #include "engines/gpencil/gpencil_engine.h" #include "engines/image/image_private.h" #include "engines/overlay/overlay_private.h" #include "engines/workbench/workbench_private.h" +#include "intern/draw_shader.h" namespace blender::draw { @@ -366,4 +371,20 @@ TEST_F(DrawTest, eevee_glsl_shaders_static) EEVEE_shaders_free(); } +static void test_draw_shaders(eParticleRefineShaderType sh_type) +{ + DRW_shaders_free(); + EXPECT_NE(DRW_shader_hair_refine_get(PART_REFINE_CATMULL_ROM, sh_type), nullptr); + DRW_shaders_free(); +} + +TEST_F(DrawTest, draw_glsl_shaders) +{ +#ifndef __APPLE__ + test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK); + test_draw_shaders(PART_REFINE_SHADER_COMPUTE); +#endif + test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND); +} + } // namespace blender::draw -- cgit v1.2.3