From d8d007136719c67e02092b2511bb88f869616f84 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 2 Jul 2021 13:43:01 +0200 Subject: GPU: Added push constants to shader interface --- source/blender/gpu/opengl/gl_shader.cc | 13 ++++++----- source/blender/gpu/opengl/gl_shader.hh | 3 ++- source/blender/gpu/opengl/gl_shader_interface.cc | 9 +++++++- source/blender/gpu/opengl/gl_shader_interface.hh | 12 +++++++++- source/blender/gpu/opengl/gl_shader_patcher.cc | 26 +++++++++++----------- source/blender/gpu/opengl/gl_shader_patcher.hh | 28 ++++++++++++------------ 6 files changed, 55 insertions(+), 36 deletions(-) diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 9ad9ffebd00..b89f59f9557 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -148,8 +148,8 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan /* Patch the shader code using the first source slot. */ sources[0] = glsl_patch_get(gl_stage); - converter_.patch(sources); - if (converter_.has_errors()) { + patch_vulkan_to_opengl(patcher_context_, sources); + if (patcher_context_.has_errors()) { compilation_failed_ = true; return 0; } @@ -231,11 +231,12 @@ bool GLShader::finalize() return false; } - interface = new GLShaderInterface(shader_program_); + interface = new GLShaderInterface(patcher_context_, shader_program_); - /* Only patched sources are only freed when shader compilation and linking succeeds for - * debugging. */ - converter_.free(); + /* 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; } diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index 63dcbcbabae..dfc44119e50 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -50,7 +50,8 @@ class GLShader : public Shader { bool compilation_failed_ = false; eGPUShaderTFBType transform_feedback_type_ = GPU_SHADER_TFB_NONE; - GLShaderPatcher converter_; + + GLShaderPatcherContext patcher_context_; public: GLShader(const char *name); diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index 9cf072b2e8a..b2842020b25 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -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() diff --git a/source/blender/gpu/opengl/gl_shader_interface.hh b/source/blender/gpu/opengl/gl_shader_interface.hh index 89a5b631047..059fedd83c6 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.hh +++ b/source/blender/gpu/opengl/gl_shader_interface.hh @@ -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 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"); }; diff --git a/source/blender/gpu/opengl/gl_shader_patcher.cc b/source/blender/gpu/opengl/gl_shader_patcher.cc index 5d6a766fc6b..15ab4222ae9 100644 --- a/source/blender/gpu/opengl/gl_shader_patcher.cc +++ b/source/blender/gpu/opengl/gl_shader_patcher.cc @@ -68,7 +68,7 @@ class GLSLPatch { "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01232456789_"; public: - virtual GLSLPatchResult patch(GLShaderPatchState &context, StringRef source) = 0; + virtual GLSLPatchResult patch(GLShaderPatcherContext &context, StringRef source) = 0; protected: static StringRef skip_whitespace(StringRef ref) @@ -94,7 +94,7 @@ class PatchPushConstants : public GLSLPatch { static constexpr StringRef LAYOUT_STD140 = "layout(std140)"; public: - GLSLPatchResult patch(GLShaderPatchState &context, StringRef source) override + GLSLPatchResult patch(GLShaderPatcherContext &context, StringRef source) override { GLSLPatchResult result; @@ -115,14 +115,14 @@ class PatchPushConstants : public GLSLPatch { name = skip_whitespace(name); name = extract_name(name); - if (context.push_constants.name.empty()) { + 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(), + context.push_constants.name->c_str(), std::string(name).c_str()); result.state = GLShaderPatcherState::MismatchedPushConstantNames; return result; @@ -138,7 +138,7 @@ class PatchPushConstants : public GLSLPatch { class GLSLPatcher : public GLSLPatch { private: - static void patch(GLShaderPatchState &context, + static void patch(GLShaderPatcherContext &context, GLSLPatch &patch, StringRef source, GLSLPatchResult &r_result) @@ -153,7 +153,7 @@ class GLSLPatcher : public GLSLPatch { } public: - GLSLPatchResult patch(GLShaderPatchState &context, StringRef source) override + GLSLPatchResult patch(GLShaderPatcherContext &context, StringRef source) override { GLSLPatchResult result; PatchPushConstants push_constants; @@ -162,7 +162,7 @@ class GLSLPatcher : public GLSLPatch { } }; -void GLShaderPatcher::patch(MutableSpan sources) +void patch_vulkan_to_opengl(GLShaderPatcherContext &context, MutableSpan sources) { for (int i = 0; i < sources.size(); i++) { GLSLPatcher patcher; @@ -174,8 +174,8 @@ void GLShaderPatcher::patch(MutableSpan sources) case GLShaderPatcherState::OkChanged: BLI_assert(patch_result.patched_glsl); - patched_sources_.append(*patch_result.patched_glsl); - sources[i] = patched_sources_.last().c_str(); + 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) { @@ -191,14 +191,14 @@ void GLShaderPatcher::patch(MutableSpan sources) } } -bool GLShaderPatcher::has_errors() const +void GLShaderPatcherContext::free_patched_sources() { - return is_error_state(context.state); + patched_sources.clear(); } -void GLShaderPatcher::free() +bool GLShaderPatcherContext::has_errors() const { - patched_sources_.clear(); + return is_error_state(state); } } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_shader_patcher.hh b/source/blender/gpu/opengl/gl_shader_patcher.hh index 854de2b9ab2..7578600df53 100644 --- a/source/blender/gpu/opengl/gl_shader_patcher.hh +++ b/source/blender/gpu/opengl/gl_shader_patcher.hh @@ -26,6 +26,8 @@ #include "BLI_string_ref.hh" #include "BLI_vector.hh" +#include + namespace blender::gpu { enum class GLShaderPatcherState { @@ -34,26 +36,24 @@ enum class GLShaderPatcherState { MismatchedPushConstantNames, }; -struct GLShaderPatchState { +/** 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 patched_sources; struct { - std::string name; + std::optional name; } push_constants; -}; -class GLShaderPatcher { - public: - GLShaderPatchState context; - - private: - Vector patched_sources_; - - public: - void patch(MutableSpan sources); bool has_errors() const; - void free(); - MEM_CXX_CLASS_ALLOC_FUNCS("GLShaderPatcher"); + void free_patched_sources(); }; +void patch_vulkan_to_opengl(GLShaderPatcherContext &context, MutableSpan sources); + } // namespace blender::gpu -- cgit v1.2.3