Draw: Added testcases for hair refine shaders.

This commit is contained in:
Jeroen Bakker 2021-06-22 11:10:59 +02:00
parent ad9fd47d7b
commit 3f1111b2a8
7 changed files with 220 additions and 95 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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();

View File

@ -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]);
}
}

View File

@ -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

View File

@ -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