Compare commits
7 Commits
temp-scale
...
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_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_push_constants(DRWShadingGroup *shgroup, GPUUniformBuf *ubo);
|
||||
/* Warning: Only use with Shaders that have IN_PLACE_INSTANCES defined. */
|
||||
void DRW_shgroup_call_instances(DRWShadingGroup *shgroup,
|
||||
Object *ob,
|
||||
|
@@ -192,6 +192,7 @@ typedef enum {
|
||||
DRW_CMD_COMPUTE = 8,
|
||||
|
||||
/* Other Commands */
|
||||
DRW_CMD_PUSH_CONSTANTS = 11,
|
||||
DRW_CMD_CLEAR = 12,
|
||||
DRW_CMD_DRWSTATE = 13,
|
||||
DRW_CMD_STENCIL = 14,
|
||||
@@ -234,6 +235,10 @@ typedef struct DRWCommandCompute {
|
||||
int groups_z_len;
|
||||
} DRWCommandCompute;
|
||||
|
||||
typedef struct DRWCommandPushConstants {
|
||||
GPUUniformBuf *buf;
|
||||
} DRWCommandPushConstants;
|
||||
|
||||
typedef struct DRWCommandDrawProcedural {
|
||||
GPUBatch *batch;
|
||||
DRWResourceHandle handle;
|
||||
@@ -271,6 +276,7 @@ typedef union DRWCommand {
|
||||
DRWCommandDrawInstanceRange instance_range;
|
||||
DRWCommandDrawProcedural procedural;
|
||||
DRWCommandCompute compute;
|
||||
DRWCommandPushConstants push_constants;
|
||||
DRWCommandSetMutableState state;
|
||||
DRWCommandSetStencil stencil;
|
||||
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);
|
||||
/* Random float value. */
|
||||
uint random = (DST.dupli_source) ?
|
||||
DST.dupli_source->random_id :
|
||||
/* 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. */
|
||||
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
|
||||
DST.dupli_source->random_id :
|
||||
/* 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. */
|
||||
BLI_hash_int_2d(BLI_hash_string(ob->id.name + 2), 0);
|
||||
ob_infos->ob_random = random * (1.0f / (float)0xFFFFFFFF);
|
||||
/* Object State. */
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
GPUBatch *batch,
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
GPUBatch *geom,
|
||||
Object *ob,
|
||||
|
@@ -1060,6 +1060,9 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state)
|
||||
cmd->compute.groups_y_len,
|
||||
cmd->compute.groups_z_len);
|
||||
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_shader.cc
|
||||
opengl/gl_shader_log.cc
|
||||
opengl/gl_shader_patcher.cc
|
||||
opengl/gl_shader_interface.cc
|
||||
opengl/gl_state.cc
|
||||
opengl/gl_texture.cc
|
||||
@@ -179,6 +180,7 @@ set(SRC
|
||||
opengl/gl_query.hh
|
||||
opengl/gl_shader.hh
|
||||
opengl/gl_shader_interface.hh
|
||||
opengl/gl_shader_patcher.hh
|
||||
opengl/gl_state.hh
|
||||
opengl/gl_texture.hh
|
||||
opengl/gl_uniform_buffer.hh
|
||||
@@ -399,6 +401,7 @@ if(WITH_GTESTS)
|
||||
|
||||
tests/gpu_index_buffer_test.cc
|
||||
tests/gpu_shader_builtin_test.cc
|
||||
tests/gpu_shader_push_constants_test.cc
|
||||
tests/gpu_shader_test.cc
|
||||
|
||||
tests/gpu_testing.hh
|
||||
|
@@ -29,6 +29,7 @@ extern "C" {
|
||||
|
||||
struct GPUIndexBuf;
|
||||
struct GPUVertBuf;
|
||||
struct GPUUniformBuf;
|
||||
|
||||
/** Opaque type hiding #blender::gpu::Shader */
|
||||
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_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_push_constant(GPUShader *sh, struct GPUUniformBuf *ubo);
|
||||
int GPU_shader_get_attribute(GPUShader *shader, const char *name);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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_interface.hh"
|
||||
#include "gpu_uniform_buffer_private.hh"
|
||||
#include "gpu_vertex_buffer_private.hh"
|
||||
|
||||
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_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;
|
||||
|
||||
|
@@ -63,6 +63,11 @@ class UniformBuf {
|
||||
{
|
||||
data_ = data;
|
||||
}
|
||||
|
||||
size_t size_in_bytes() const
|
||||
{
|
||||
return size_in_bytes_;
|
||||
}
|
||||
};
|
||||
|
||||
/* Syntactic sugar. */
|
||||
|
@@ -36,6 +36,10 @@
|
||||
#include "gl_shader.hh"
|
||||
#include "gl_shader_interface.hh"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
static CLG_LogRef LOG = {"gpu.gl.shader"};
|
||||
|
||||
using namespace blender;
|
||||
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. */
|
||||
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);
|
||||
glCompileShader(shader);
|
||||
@@ -226,7 +235,12 @@ bool GLShader::finalize()
|
||||
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;
|
||||
}
|
||||
@@ -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 "gl_shader_patcher.hh"
|
||||
|
||||
namespace blender {
|
||||
namespace gpu {
|
||||
|
||||
@@ -49,6 +51,8 @@ class GLShader : public Shader {
|
||||
|
||||
eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE;
|
||||
|
||||
GLShaderPatcherContext patcher_context_;
|
||||
|
||||
public:
|
||||
GLShader(const char *name);
|
||||
~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_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;
|
||||
|
||||
|
@@ -145,7 +145,7 @@ static inline int ssbo_binding(int32_t program, uint32_t ssbo_index)
|
||||
/** \name Creation / Destruction
|
||||
* \{ */
|
||||
|
||||
GLShaderInterface::GLShaderInterface(GLuint program)
|
||||
GLShaderInterface::GLShaderInterface(GLShaderPatcherContext &context, GLuint program)
|
||||
{
|
||||
/* Necessary to make #glUniform works. */
|
||||
glUseProgram(program);
|
||||
@@ -321,6 +321,13 @@ GLShaderInterface::GLShaderInterface(GLuint program)
|
||||
// this->debug_print();
|
||||
|
||||
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()
|
||||
|
@@ -34,6 +34,8 @@
|
||||
|
||||
#include "glew-mx.h"
|
||||
|
||||
#include "gl_shader_patcher.hh"
|
||||
|
||||
#include "gpu_shader_interface.hh"
|
||||
|
||||
namespace blender::gpu {
|
||||
@@ -48,13 +50,21 @@ class GLShaderInterface : public ShaderInterface {
|
||||
/** Reference to VaoCaches using this interface */
|
||||
Vector<GLVaoCache *> refs_;
|
||||
|
||||
/* Reference to the ubo binding that is used for push constants. */
|
||||
const ShaderInput *push_constant_input_ = nullptr;
|
||||
|
||||
public:
|
||||
GLShaderInterface(GLuint program);
|
||||
GLShaderInterface(GLShaderPatcherContext &context, GLuint program);
|
||||
~GLShaderInterface();
|
||||
|
||||
void ref_add(GLVaoCache *ref);
|
||||
void ref_remove(GLVaoCache *ref);
|
||||
|
||||
inline const ShaderInput *push_constant_get()
|
||||
{
|
||||
return push_constant_input_;
|
||||
}
|
||||
|
||||
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