1
1

Compare commits

...

7 Commits

Author SHA1 Message Date
f4dcad7b24 GPU: Sizecheck for push constants buffer.
According to the specs platforms should at least support push constants
of 128 bytes. As there are known platforms that have set this as their
maximum (Mesa for example) we should use this as the maximum as well.
2021-07-02 16:38:23 +02:00
fd4652d4f6 DrawManager: Add push constants command. 2021-07-02 16:25:13 +02:00
2e7ea42377 GPU: Binding uniformbuffer as push constant. 2021-07-02 16:06:15 +02:00
d8d0071367 GPU: Added push constants to shader interface 2021-07-02 13:43:01 +02:00
2436d36158 Cleanup: Renamed converter to patcher. 2021-07-02 12:11:03 +02:00
cc23dbaa26 Refactored GLSL patching for future extension.
Every patch would be its own class this would keep the data and logic contained.
When a source is unchained during patching it would reuse the original source.
2021-07-02 11:55:19 +02:00
fdda05bf15 [WIP] GPU: Push Constants.
See T89553 for more details.
2021-06-30 17:10:47 +02:00
20 changed files with 606 additions and 12 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -63,6 +63,11 @@ class UniformBuf {
{
data_ = data;
}
size_t size_in_bytes() const
{
return size_in_bytes_;
}
};
/* Syntactic sugar. */

View File

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

View File

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

View File

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

View File

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

View 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

View 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

View 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