Compare commits
7 Commits
eevee-rewr
...
temp-gpu-p
Author | SHA1 | Date | |
---|---|---|---|
f4dcad7b24 | |||
fd4652d4f6 | |||
2e7ea42377 | |||
d8d0071367 | |||
2436d36158 | |||
cc23dbaa26 | |||
fdda05bf15 |
Submodule release/datafiles/locale updated: 4833954c0a...78591466c3
Submodule release/scripts/addons updated: f86f25e622...c84f831539
Submodule release/scripts/addons_contrib updated: 5a82baad9f...fd1bed98c9
@@ -445,6 +445,7 @@ void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
|
|||||||
void DRW_shgroup_call_procedural_points(DRWShadingGroup *sh, Object *ob, uint point_count);
|
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_lines(DRWShadingGroup *sh, Object *ob, uint line_count);
|
||||||
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count);
|
void DRW_shgroup_call_procedural_triangles(DRWShadingGroup *sh, Object *ob, uint tri_count);
|
||||||
|
void DRW_shgroup_call_push_constants(DRWShadingGroup *shgroup, GPUUniformBuf *ubo);
|
||||||
/* Warning: Only use with Shaders that have IN_PLACE_INSTANCES defined. */
|
/* Warning: Only use with Shaders that have IN_PLACE_INSTANCES defined. */
|
||||||
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
|
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
|
@@ -192,6 +192,7 @@ typedef enum {
|
|||||||
DRW_CMD_COMPUTE = 8,
|
DRW_CMD_COMPUTE = 8,
|
||||||
|
|
||||||
/* Other Commands */
|
/* Other Commands */
|
||||||
|
DRW_CMD_PUSH_CONSTANTS = 11,
|
||||||
DRW_CMD_CLEAR = 12,
|
DRW_CMD_CLEAR = 12,
|
||||||
DRW_CMD_DRWSTATE = 13,
|
DRW_CMD_DRWSTATE = 13,
|
||||||
DRW_CMD_STENCIL = 14,
|
DRW_CMD_STENCIL = 14,
|
||||||
@@ -234,6 +235,10 @@ typedef struct DRWCommandCompute {
|
|||||||
int groups_z_len;
|
int groups_z_len;
|
||||||
} DRWCommandCompute;
|
} DRWCommandCompute;
|
||||||
|
|
||||||
|
typedef struct DRWCommandPushConstants {
|
||||||
|
GPUUniformBuf *buf;
|
||||||
|
} DRWCommandPushConstants;
|
||||||
|
|
||||||
typedef struct DRWCommandDrawProcedural {
|
typedef struct DRWCommandDrawProcedural {
|
||||||
GPUBatch *batch;
|
GPUBatch *batch;
|
||||||
DRWResourceHandle handle;
|
DRWResourceHandle handle;
|
||||||
@@ -271,6 +276,7 @@ typedef union DRWCommand {
|
|||||||
DRWCommandDrawInstanceRange instance_range;
|
DRWCommandDrawInstanceRange instance_range;
|
||||||
DRWCommandDrawProcedural procedural;
|
DRWCommandDrawProcedural procedural;
|
||||||
DRWCommandCompute compute;
|
DRWCommandCompute compute;
|
||||||
|
DRWCommandPushConstants push_constants;
|
||||||
DRWCommandSetMutableState state;
|
DRWCommandSetMutableState state;
|
||||||
DRWCommandSetStencil stencil;
|
DRWCommandSetStencil stencil;
|
||||||
DRWCommandSetSelectID select_id;
|
DRWCommandSetSelectID select_id;
|
||||||
|
@@ -528,10 +528,10 @@ static void drw_call_obinfos_init(DRWObjectInfos *ob_infos, Object *ob)
|
|||||||
drw_call_calc_orco(ob, ob_infos->orcotexfac);
|
drw_call_calc_orco(ob, ob_infos->orcotexfac);
|
||||||
/* Random float value. */
|
/* Random float value. */
|
||||||
uint random = (DST.dupli_source) ?
|
uint random = (DST.dupli_source) ?
|
||||||
DST.dupli_source->random_id :
|
DST.dupli_source->random_id :
|
||||||
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
|
/* TODO(fclem): this is rather costly to do at runtime. Maybe we can
|
||||||
* put it in ob->runtime and make depsgraph ensure it is up to date. */
|
* put it in ob->runtime and make depsgraph ensure it is up to date. */
|
||||||
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
|
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
|
||||||
ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
|
ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
|
||||||
/* Object State. */
|
/* Object State. */
|
||||||
ob_infos->ob_flag = 1.0f; /* Required to have a correct sign */
|
ob_infos->ob_flag = 1.0f; /* Required to have a correct sign */
|
||||||
@@ -725,6 +725,12 @@ static void drw_command_compute(DRWShadingGroup *shgroup,
|
|||||||
cmd->groups_z_len = groups_z_len;
|
cmd->groups_z_len = groups_z_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void drw_command_push_constants(DRWShadingGroup *shgroup, GPUUniformBuf *ubo)
|
||||||
|
{
|
||||||
|
DRWCommandPushConstants *cmd = drw_command_create(shgroup, DRW_CMD_PUSH_CONSTANTS);
|
||||||
|
cmd->buf = ubo;
|
||||||
|
}
|
||||||
|
|
||||||
static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
|
static void drw_command_draw_procedural(DRWShadingGroup *shgroup,
|
||||||
GPUBatch *batch,
|
GPUBatch *batch,
|
||||||
DRWResourceHandle handle,
|
DRWResourceHandle handle,
|
||||||
@@ -851,6 +857,14 @@ void DRW_shgroup_call_compute(DRWShadingGroup *shgroup,
|
|||||||
drw_command_compute(shgroup, groups_x_len, groups_y_len, groups_z_len);
|
drw_command_compute(shgroup, groups_x_len, groups_y_len, groups_z_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DRW_shgroup_call_push_constants(DRWShadingGroup *shgroup, GPUUniformBuf *ubo)
|
||||||
|
{
|
||||||
|
BLI_assert(ubo);
|
||||||
|
BLI_assert(GPU_compute_shader_support());
|
||||||
|
|
||||||
|
drw_command_push_constants(shgroup, ubo);
|
||||||
|
}
|
||||||
|
|
||||||
static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup,
|
static void drw_shgroup_call_procedural_add_ex(DRWShadingGroup *shgroup,
|
||||||
GPUBatch *geom,
|
GPUBatch *geom,
|
||||||
Object *ob,
|
Object *ob,
|
||||||
|
@@ -1060,6 +1060,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
|
|||||||
cmd->compute.groups_y_len,
|
cmd->compute.groups_y_len,
|
||||||
cmd->compute.groups_z_len);
|
cmd->compute.groups_z_len);
|
||||||
break;
|
break;
|
||||||
|
case DRW_CMD_PUSH_CONSTANTS:
|
||||||
|
GPU_shader_uniform_push_constant(shgroup->shader, cmd->push_constants.buf);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -104,6 +104,7 @@ set(SRC
|
|||||||
opengl/gl_query.cc
|
opengl/gl_query.cc
|
||||||
opengl/gl_shader.cc
|
opengl/gl_shader.cc
|
||||||
opengl/gl_shader_log.cc
|
opengl/gl_shader_log.cc
|
||||||
|
opengl/gl_shader_patcher.cc
|
||||||
opengl/gl_shader_interface.cc
|
opengl/gl_shader_interface.cc
|
||||||
opengl/gl_state.cc
|
opengl/gl_state.cc
|
||||||
opengl/gl_texture.cc
|
opengl/gl_texture.cc
|
||||||
@@ -179,6 +180,7 @@ set(SRC
|
|||||||
opengl/gl_query.hh
|
opengl/gl_query.hh
|
||||||
opengl/gl_shader.hh
|
opengl/gl_shader.hh
|
||||||
opengl/gl_shader_interface.hh
|
opengl/gl_shader_interface.hh
|
||||||
|
opengl/gl_shader_patcher.hh
|
||||||
opengl/gl_state.hh
|
opengl/gl_state.hh
|
||||||
opengl/gl_texture.hh
|
opengl/gl_texture.hh
|
||||||
opengl/gl_uniform_buffer.hh
|
opengl/gl_uniform_buffer.hh
|
||||||
@@ -399,6 +401,7 @@ if(WITH_GTESTS)
|
|||||||
|
|
||||||
tests/gpu_index_buffer_test.cc
|
tests/gpu_index_buffer_test.cc
|
||||||
tests/gpu_shader_builtin_test.cc
|
tests/gpu_shader_builtin_test.cc
|
||||||
|
tests/gpu_shader_push_constants_test.cc
|
||||||
tests/gpu_shader_test.cc
|
tests/gpu_shader_test.cc
|
||||||
|
|
||||||
tests/gpu_testing.hh
|
tests/gpu_testing.hh
|
||||||
|
@@ -29,6 +29,7 @@ extern "C" {
|
|||||||
|
|
||||||
struct GPUIndexBuf;
|
struct GPUIndexBuf;
|
||||||
struct GPUVertBuf;
|
struct GPUVertBuf;
|
||||||
|
struct GPUUniformBuf;
|
||||||
|
|
||||||
/** Opaque type hiding #blender::gpu::Shader */
|
/** Opaque type hiding #blender::gpu::Shader */
|
||||||
typedef struct GPUShader GPUShader;
|
typedef struct GPUShader GPUShader;
|
||||||
@@ -157,7 +158,7 @@ void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4]
|
|||||||
void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]);
|
void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4]);
|
||||||
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]);
|
void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2]);
|
||||||
void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]);
|
void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4]);
|
||||||
|
void GPU_shader_uniform_push_constant(GPUShader *sh, struct GPUUniformBuf *ubo);
|
||||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
||||||
|
|
||||||
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear);
|
void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear);
|
||||||
|
@@ -556,6 +556,16 @@ void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, cons
|
|||||||
GPU_shader_uniform_vector(sh, loc, 4, len, (const float *)val);
|
GPU_shader_uniform_vector(sh, loc, 4, len, (const float *)val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPU_shader_uniform_push_constant(GPUShader *sh, GPUUniformBuf *ubo)
|
||||||
|
{
|
||||||
|
/* According to the specification all platforms should at least support 128 bytes. We should
|
||||||
|
* support only upto the minimum size as some platforms have set this as their max. */
|
||||||
|
static constexpr size_t MAX_PUSH_CONSTANTS_LEN = 128;
|
||||||
|
UniformBuf *buf = unwrap(ubo);
|
||||||
|
BLI_assert(buf->size_in_bytes() < MAX_PUSH_CONSTANTS_LEN);
|
||||||
|
unwrap(sh)->uniform_push_constant(buf);
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "GPU_shader.h"
|
#include "GPU_shader.h"
|
||||||
#include "gpu_shader_interface.hh"
|
#include "gpu_shader_interface.hh"
|
||||||
|
#include "gpu_uniform_buffer_private.hh"
|
||||||
#include "gpu_vertex_buffer_private.hh"
|
#include "gpu_vertex_buffer_private.hh"
|
||||||
|
|
||||||
namespace blender {
|
namespace blender {
|
||||||
@@ -65,6 +66,7 @@ class Shader {
|
|||||||
|
|
||||||
virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
|
virtual void uniform_float(int location, int comp_len, int array_size, const float *data) = 0;
|
||||||
virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
|
virtual void uniform_int(int location, int comp_len, int array_size, const int *data) = 0;
|
||||||
|
virtual void uniform_push_constant(UniformBuf *buf) = 0;
|
||||||
|
|
||||||
virtual void vertformat_from_shader(GPUVertFormat *) const = 0;
|
virtual void vertformat_from_shader(GPUVertFormat *) const = 0;
|
||||||
|
|
||||||
|
@@ -63,6 +63,11 @@ class UniformBuf {
|
|||||||
{
|
{
|
||||||
data_ = data;
|
data_ = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t size_in_bytes() const
|
||||||
|
{
|
||||||
|
return size_in_bytes_;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Syntactic sugar. */
|
/* Syntactic sugar. */
|
||||||
|
@@ -36,6 +36,10 @@
|
|||||||
#include "gl_shader.hh"
|
#include "gl_shader.hh"
|
||||||
#include "gl_shader_interface.hh"
|
#include "gl_shader_interface.hh"
|
||||||
|
|
||||||
|
#include "CLG_log.h"
|
||||||
|
|
||||||
|
static CLG_LogRef LOG = {"gpu.gl.shader"};
|
||||||
|
|
||||||
using namespace blender;
|
using namespace blender;
|
||||||
using namespace blender::gpu;
|
using namespace blender::gpu;
|
||||||
|
|
||||||
@@ -148,6 +152,11 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan<const char *>
|
|||||||
|
|
||||||
/* Patch the shader code using the first source slot. */
|
/* Patch the shader code using the first source slot. */
|
||||||
sources[0] = glsl_patch_get(gl_stage);
|
sources[0] = glsl_patch_get(gl_stage);
|
||||||
|
patch_vulkan_to_opengl(patcher_context_, sources);
|
||||||
|
if (patcher_context_.has_errors()) {
|
||||||
|
compilation_failed_ = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
glShaderSource(shader, sources.size(), sources.data(), nullptr);
|
glShaderSource(shader, sources.size(), sources.data(), nullptr);
|
||||||
glCompileShader(shader);
|
glCompileShader(shader);
|
||||||
@@ -226,7 +235,12 @@ bool GLShader::finalize()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface = new GLShaderInterface(shader_program_);
|
interface = new GLShaderInterface(patcher_context_, shader_program_);
|
||||||
|
|
||||||
|
/* Patched sources are only freed when shader compilation and linking successful completed. In
|
||||||
|
* other cases they are kept for debugging purposes and will be GC'd when the GPUShader is freed.
|
||||||
|
*/
|
||||||
|
patcher_context_.free_patched_sources();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -354,6 +368,18 @@ void GLShader::uniform_int(int location, int comp_len, int array_size, const int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GLShader::uniform_push_constant(UniformBuf *buf)
|
||||||
|
{
|
||||||
|
GLShaderInterface *gl_interface = static_cast<GLShaderInterface *>(interface);
|
||||||
|
const ShaderInput *input = gl_interface->push_constant_get();
|
||||||
|
if (!input) {
|
||||||
|
CLOG_WARN(&LOG, "Cannot bind push_constants, Shader does not have a push constant defined.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf->bind(input->binding);
|
||||||
|
}
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
@@ -29,6 +29,8 @@
|
|||||||
|
|
||||||
#include "gpu_shader_private.hh"
|
#include "gpu_shader_private.hh"
|
||||||
|
|
||||||
|
#include "gl_shader_patcher.hh"
|
||||||
|
|
||||||
namespace blender {
|
namespace blender {
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
|
|
||||||
@@ -49,6 +51,8 @@ class GLShader : public Shader {
|
|||||||
|
|
||||||
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
|
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
|
||||||
|
|
||||||
|
GLShaderPatcherContext patcher_context_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLShader(const char *name);
|
GLShader(const char *name);
|
||||||
~GLShader();
|
~GLShader();
|
||||||
@@ -70,6 +74,7 @@ class GLShader : public Shader {
|
|||||||
|
|
||||||
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
|
void uniform_float(int location, int comp_len, int array_size, const float *data) override;
|
||||||
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
|
void uniform_int(int location, int comp_len, int array_size, const int *data) override;
|
||||||
|
void uniform_push_constant(struct UniformBuf *ubo) override;
|
||||||
|
|
||||||
void vertformat_from_shader(GPUVertFormat *format) const override;
|
void vertformat_from_shader(GPUVertFormat *format) const override;
|
||||||
|
|
||||||
|
@@ -145,7 +145,7 @@ static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
|
|||||||
/** \name Creation / Destruction
|
/** \name Creation / Destruction
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
GLShaderInterface::GLShaderInterface(GLuint program)
|
GLShaderInterface::GLShaderInterface(GLShaderPatcherContext &context, GLuint program)
|
||||||
{
|
{
|
||||||
/* Necessary to make #glUniform works. */
|
/* Necessary to make #glUniform works. */
|
||||||
glUseProgram(program);
|
glUseProgram(program);
|
||||||
@@ -321,6 +321,13 @@ GLShaderInterface::GLShaderInterface(GLuint program)
|
|||||||
// this->debug_print();
|
// this->debug_print();
|
||||||
|
|
||||||
this->sort_inputs();
|
this->sort_inputs();
|
||||||
|
|
||||||
|
/* Push Constant Blocks */
|
||||||
|
/* Push constants are converted by GLShaderPatcher to regular uniform buffers. Here we retrieve
|
||||||
|
* the reference to its binding. */
|
||||||
|
if (context.push_constants.name) {
|
||||||
|
push_constant_input_ = ubo_get(context.push_constants.name->c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLShaderInterface::~GLShaderInterface()
|
GLShaderInterface::~GLShaderInterface()
|
||||||
|
@@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
#include "glew-mx.h"
|
#include "glew-mx.h"
|
||||||
|
|
||||||
|
#include "gl_shader_patcher.hh"
|
||||||
|
|
||||||
#include "gpu_shader_interface.hh"
|
#include "gpu_shader_interface.hh"
|
||||||
|
|
||||||
namespace blender::gpu {
|
namespace blender::gpu {
|
||||||
@@ -48,13 +50,21 @@ class GLShaderInterface : public ShaderInterface {
|
|||||||
/** Reference to VaoCaches using this interface */
|
/** Reference to VaoCaches using this interface */
|
||||||
Vector<GLVaoCache *> refs_;
|
Vector<GLVaoCache *> refs_;
|
||||||
|
|
||||||
|
/* Reference to the ubo binding that is used for push constants. */
|
||||||
|
const ShaderInput *push_constant_input_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GLShaderInterface(GLuint program);
|
GLShaderInterface(GLShaderPatcherContext &context, GLuint program);
|
||||||
~GLShaderInterface();
|
~GLShaderInterface();
|
||||||
|
|
||||||
void ref_add(GLVaoCache *ref);
|
void ref_add(GLVaoCache *ref);
|
||||||
void ref_remove(GLVaoCache *ref);
|
void ref_remove(GLVaoCache *ref);
|
||||||
|
|
||||||
|
inline const ShaderInput *push_constant_get()
|
||||||
|
{
|
||||||
|
return push_constant_input_;
|
||||||
|
}
|
||||||
|
|
||||||
MEM_CXX_CLASS_ALLOC_FUNCS("GLShaderInterface");
|
MEM_CXX_CLASS_ALLOC_FUNCS("GLShaderInterface");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
204
source/blender/gpu/opengl/gl_shader_patcher.cc
Normal file
204
source/blender/gpu/opengl/gl_shader_patcher.cc
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* 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 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup gpu
|
||||||
|
*
|
||||||
|
* Patch GLSL source from Vulkan GLSL to OpenGL GLSL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gl_shader_patcher.hh"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "CLG_log.h"
|
||||||
|
|
||||||
|
static CLG_LogRef LOG = {"gpu.gl.shader.converter"};
|
||||||
|
|
||||||
|
namespace blender::gpu {
|
||||||
|
|
||||||
|
static bool is_error_state(GLShaderPatcherState state)
|
||||||
|
{
|
||||||
|
return !ELEM(state, GLShaderPatcherState::OkChanged, GLShaderPatcherState::OkUnchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct GLSLPatchResult {
|
||||||
|
std::optional<std::string> patched_glsl;
|
||||||
|
GLShaderPatcherState state = GLShaderPatcherState::OkUnchanged;
|
||||||
|
|
||||||
|
void merge(const GLSLPatchResult &other, const StringRef unchanged_result)
|
||||||
|
{
|
||||||
|
switch (other.state) {
|
||||||
|
case GLShaderPatcherState::OkUnchanged:
|
||||||
|
patched_glsl = unchanged_result;
|
||||||
|
break;
|
||||||
|
case GLShaderPatcherState::OkChanged:
|
||||||
|
patched_glsl = other.patched_glsl;
|
||||||
|
if (state == GLShaderPatcherState::OkUnchanged) {
|
||||||
|
state = GLShaderPatcherState::OkChanged;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GLShaderPatcherState::MismatchedPushConstantNames:
|
||||||
|
state = other.state;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLSLPatch {
|
||||||
|
private:
|
||||||
|
static constexpr StringRef WHITESPACES = " \t\n\v\f\r";
|
||||||
|
static constexpr StringRef VALID_NAME_CHARS =
|
||||||
|
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01232456789_";
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual GLSLPatchResult patch(GLShaderPatcherContext &context, StringRef source) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static StringRef skip_whitespace(StringRef ref)
|
||||||
|
{
|
||||||
|
size_t skip = ref.find_first_not_of(WHITESPACES);
|
||||||
|
if (skip == blender::StringRef::not_found) {
|
||||||
|
return ref;
|
||||||
|
}
|
||||||
|
return ref.drop_prefix(skip);
|
||||||
|
}
|
||||||
|
|
||||||
|
static StringRef extract_name(StringRef src)
|
||||||
|
{
|
||||||
|
StringRef result = src;
|
||||||
|
size_t skip = result.find_first_not_of(VALID_NAME_CHARS);
|
||||||
|
BLI_assert(skip != StringRef::not_found);
|
||||||
|
return result.substr(0, skip);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PatchPushConstants : public GLSLPatch {
|
||||||
|
static constexpr StringRef LAYOUT_PUSH_CONSTANTS = "layout(push_constant)";
|
||||||
|
static constexpr StringRef LAYOUT_STD140 = "layout(std140)";
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLSLPatchResult patch(GLShaderPatcherContext &context, StringRef source) override
|
||||||
|
{
|
||||||
|
GLSLPatchResult result;
|
||||||
|
|
||||||
|
size_t pos = source.find(LAYOUT_PUSH_CONSTANTS);
|
||||||
|
if (pos == StringRef::not_found) {
|
||||||
|
result.state = GLShaderPatcherState::OkUnchanged;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stringstream patched_glsl;
|
||||||
|
patched_glsl << source.substr(0, pos);
|
||||||
|
patched_glsl << LAYOUT_STD140;
|
||||||
|
patched_glsl << source.substr(pos + LAYOUT_PUSH_CONSTANTS.size());
|
||||||
|
|
||||||
|
StringRef name = source.substr(pos + LAYOUT_PUSH_CONSTANTS.size());
|
||||||
|
name = skip_whitespace(name);
|
||||||
|
name = name.drop_known_prefix("uniform");
|
||||||
|
name = skip_whitespace(name);
|
||||||
|
name = extract_name(name);
|
||||||
|
|
||||||
|
if (!context.push_constants.name) {
|
||||||
|
context.push_constants.name = name;
|
||||||
|
}
|
||||||
|
else if (context.push_constants.name != name) {
|
||||||
|
CLOG_ERROR(&LOG,
|
||||||
|
"Detected different push_constants binding names ('%s' and '%s'). push_constants "
|
||||||
|
"binding names must be identical across all stages.",
|
||||||
|
context.push_constants.name->c_str(),
|
||||||
|
std::string(name).c_str());
|
||||||
|
result.state = GLShaderPatcherState::MismatchedPushConstantNames;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string patched_glsl_str = patched_glsl.str();
|
||||||
|
result.state = GLShaderPatcherState::OkChanged;
|
||||||
|
GLSLPatchResult recursive_result = patch(context, patched_glsl_str);
|
||||||
|
result.merge(recursive_result, patched_glsl_str);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class GLSLPatcher : public GLSLPatch {
|
||||||
|
private:
|
||||||
|
static void patch(GLShaderPatcherContext &context,
|
||||||
|
GLSLPatch &patch,
|
||||||
|
StringRef source,
|
||||||
|
GLSLPatchResult &r_result)
|
||||||
|
{
|
||||||
|
/* Do not patch when result is in error so the error state won't be rewritten. */
|
||||||
|
if (is_error_state(r_result.state)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLSLPatchResult patch_result = patch.patch(context, source);
|
||||||
|
r_result.merge(patch_result, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
GLSLPatchResult patch(GLShaderPatcherContext &context, StringRef source) override
|
||||||
|
{
|
||||||
|
GLSLPatchResult result;
|
||||||
|
PatchPushConstants push_constants;
|
||||||
|
patch(context, push_constants, source, result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void patch_vulkan_to_opengl(GLShaderPatcherContext &context, MutableSpan<const char *> sources)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < sources.size(); i++) {
|
||||||
|
GLSLPatcher patcher;
|
||||||
|
const char *source = sources[i];
|
||||||
|
GLSLPatchResult patch_result = patcher.patch(context, source);
|
||||||
|
switch (patch_result.state) {
|
||||||
|
case GLShaderPatcherState::OkUnchanged:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLShaderPatcherState::OkChanged:
|
||||||
|
BLI_assert(patch_result.patched_glsl);
|
||||||
|
context.patched_sources.append(*patch_result.patched_glsl);
|
||||||
|
sources[i] = context.patched_sources.last().c_str();
|
||||||
|
|
||||||
|
/* Keep any errors from previous stages. */
|
||||||
|
if (context.state == GLShaderPatcherState::OkUnchanged) {
|
||||||
|
context.state = GLShaderPatcherState::OkChanged;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GLShaderPatcherState::MismatchedPushConstantNames:
|
||||||
|
context.state = patch_result.state;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GLShaderPatcherContext::free_patched_sources()
|
||||||
|
{
|
||||||
|
patched_sources.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GLShaderPatcherContext::has_errors() const
|
||||||
|
{
|
||||||
|
return is_error_state(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender::gpu
|
59
source/blender/gpu/opengl/gl_shader_patcher.hh
Normal file
59
source/blender/gpu/opengl/gl_shader_patcher.hh
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* 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 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \file
|
||||||
|
* \ingroup gpu
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "BLI_string_ref.hh"
|
||||||
|
#include "BLI_vector.hh"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
namespace blender::gpu {
|
||||||
|
|
||||||
|
enum class GLShaderPatcherState {
|
||||||
|
OkUnchanged,
|
||||||
|
OkChanged,
|
||||||
|
MismatchedPushConstantNames,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** State to keep over GLSL compilation stages, linkage and shader_interface building. */
|
||||||
|
struct GLShaderPatcherContext {
|
||||||
|
GLShaderPatcherState state = GLShaderPatcherState::OkUnchanged;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All patched sources. During compilation stage source code is references as `const
|
||||||
|
* char*` These needs to be owned by a `std::string`.
|
||||||
|
*/
|
||||||
|
Vector<std::string> patched_sources;
|
||||||
|
struct {
|
||||||
|
std::optional<std::string> name;
|
||||||
|
} push_constants;
|
||||||
|
|
||||||
|
bool has_errors() const;
|
||||||
|
|
||||||
|
void free_patched_sources();
|
||||||
|
};
|
||||||
|
|
||||||
|
void patch_vulkan_to_opengl(GLShaderPatcherContext &context, MutableSpan<const char *> sources);
|
||||||
|
|
||||||
|
} // namespace blender::gpu
|
238
source/blender/gpu/tests/gpu_shader_push_constants_test.cc
Normal file
238
source/blender/gpu/tests/gpu_shader_push_constants_test.cc
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/* Apache License, Version 2.0 */
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#include "GPU_shader.h"
|
||||||
|
#include "GPU_uniform_buffer.h"
|
||||||
|
|
||||||
|
#include "gpu_testing.hh"
|
||||||
|
|
||||||
|
namespace blender::gpu::tests {
|
||||||
|
|
||||||
|
struct PushConstants {
|
||||||
|
float color[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_gpu_shader_push_constants()
|
||||||
|
{
|
||||||
|
const char *vert_glsl = R"(
|
||||||
|
|
||||||
|
uniform mat4 ModelViewProjectionMatrix;
|
||||||
|
in vec3 pos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 pos_4d = vec4(pos, 1.0);
|
||||||
|
gl_Position = ModelViewProjectionMatrix * pos_4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char *frag_glsl = R"(
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
GPUShader *shader = GPU_shader_create(
|
||||||
|
vert_glsl, frag_glsl, nullptr, nullptr, nullptr, "test_gpu_shader_push_constants");
|
||||||
|
EXPECT_NE(shader, nullptr);
|
||||||
|
|
||||||
|
PushConstants push_constants;
|
||||||
|
GPUUniformBuf *push_constants_buffer = GPU_uniformbuf_create_ex(
|
||||||
|
sizeof(PushConstants), &push_constants, __func__);
|
||||||
|
GPU_shader_uniform_push_constant(shader, push_constants_buffer);
|
||||||
|
GPU_uniformbuf_free(push_constants_buffer);
|
||||||
|
|
||||||
|
GPU_shader_free(shader);
|
||||||
|
}
|
||||||
|
GPU_TEST(gpu_shader_push_constants)
|
||||||
|
|
||||||
|
static void test_gpu_shader_push_constants_2_definitions()
|
||||||
|
{
|
||||||
|
const char *vert_glsl = R"(
|
||||||
|
|
||||||
|
uniform mat4 ModelViewProjectionMatrix;
|
||||||
|
in vec3 pos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 pos_4d = vec4(pos, 1.0);
|
||||||
|
gl_Position = ModelViewProjectionMatrix * pos_4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char *frag_glsl = R"(
|
||||||
|
|
||||||
|
#ifdef NEW
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
GPUShader *shader = GPU_shader_create(
|
||||||
|
vert_glsl, frag_glsl, nullptr, nullptr, nullptr, "gpu_shader_push_constants_2_definitions");
|
||||||
|
EXPECT_NE(shader, nullptr);
|
||||||
|
|
||||||
|
GPU_shader_free(shader);
|
||||||
|
}
|
||||||
|
GPU_TEST(gpu_shader_push_constants_2_definitions)
|
||||||
|
|
||||||
|
static void test_gpu_shader_push_constants_2_stages()
|
||||||
|
{
|
||||||
|
const char *vert_glsl = R"(
|
||||||
|
|
||||||
|
uniform mat4 ModelViewProjectionMatrix;
|
||||||
|
in vec3 pos;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 pos_4d = vec4(pos, 1.0);
|
||||||
|
gl_Position = ModelViewProjectionMatrix * pos_4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char *frag_glsl = R"(
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstants {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
GPUShader *shader = GPU_shader_create(
|
||||||
|
vert_glsl, frag_glsl, nullptr, nullptr, nullptr, "test_gpu_shader_push_constants_2_stages");
|
||||||
|
EXPECT_NE(shader, nullptr);
|
||||||
|
|
||||||
|
GPU_shader_free(shader);
|
||||||
|
}
|
||||||
|
GPU_TEST(gpu_shader_push_constants_2_stages)
|
||||||
|
|
||||||
|
static void test_gpu_shader_push_constants_fail_different_name_2_stages()
|
||||||
|
{
|
||||||
|
const char *vert_glsl = R"(
|
||||||
|
|
||||||
|
uniform mat4 ModelViewProjectionMatrix;
|
||||||
|
in vec3 pos;
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstantsVert {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 pos_4d = vec4(pos, 1.0);
|
||||||
|
gl_Position = ModelViewProjectionMatrix * pos_4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char *frag_glsl = R"(
|
||||||
|
|
||||||
|
layout(push_constant) uniform PushConstantsFrag {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
GPUShader *shader = GPU_shader_create(vert_glsl,
|
||||||
|
frag_glsl,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
"gpu_shader_push_constants_fail_different_name_2_stages");
|
||||||
|
/* Compiling should fail as two differnet binding names are used within a single shader. */
|
||||||
|
EXPECT_EQ(shader, nullptr);
|
||||||
|
|
||||||
|
GPU_shader_free(shader);
|
||||||
|
}
|
||||||
|
GPU_TEST(gpu_shader_push_constants_fail_different_name_2_stages)
|
||||||
|
|
||||||
|
static void test_gpu_shader_push_constants_fail_different_name_1_stage()
|
||||||
|
{
|
||||||
|
const char *vert_glsl = R"(
|
||||||
|
|
||||||
|
uniform mat4 ModelViewProjectionMatrix;
|
||||||
|
flat out vec4 finalColor;
|
||||||
|
in vec3 pos;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 pos_4d = vec4(pos, 1.0);
|
||||||
|
gl_Position = ModelViewProjectionMatrix * pos_4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
const char *frag_glsl = R"(
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
layout(push_constant) uniform PushConstants_new {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
layout(push_constant) uniform PushConstants_old {
|
||||||
|
vec4 color;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
fragColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
)";
|
||||||
|
|
||||||
|
GPUShader *shader = GPU_shader_create(vert_glsl,
|
||||||
|
frag_glsl,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
"gpu_shader_push_constants_fail_different_name_1_stage");
|
||||||
|
/* Compiling should fail as two differnet binding names are used within a single shader. */
|
||||||
|
EXPECT_EQ(shader, nullptr);
|
||||||
|
|
||||||
|
GPU_shader_free(shader);
|
||||||
|
}
|
||||||
|
GPU_TEST(gpu_shader_push_constants_fail_different_name_1_stage)
|
||||||
|
|
||||||
|
} // namespace blender::gpu::tests
|
Submodule source/tools updated: 01f51a0e55...c8579c5cf4
Reference in New Issue
Block a user