diff options
author | Jeroen Bakker <jeroen@blender.org> | 2021-07-02 12:55:19 +0300 |
---|---|---|
committer | Jeroen Bakker <jeroen@blender.org> | 2021-07-02 12:55:19 +0300 |
commit | cc23dbaa265be6b348d308f48687bc8afc075fd0 (patch) | |
tree | eae3533fa2f1f7128baf1c09ca324905d1b5310f | |
parent | fdda05bf15c12f07ec1b6d813e4e12a0f7a89255 (diff) |
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.
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.cc | 2 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader_converter.cc | 203 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader_converter.hh | 26 |
3 files changed, 156 insertions, 75 deletions
diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 78544035416..9ad9ffebd00 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -149,7 +149,7 @@ 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); converter_.patch(sources); - if (converter_.has_error()) { + if (converter_.has_errors()) { compilation_failed_ = true; return 0; } diff --git a/source/blender/gpu/opengl/gl_shader_converter.cc b/source/blender/gpu/opengl/gl_shader_converter.cc index c2f06b74e31..d055006f2e9 100644 --- a/source/blender/gpu/opengl/gl_shader_converter.cc +++ b/source/blender/gpu/opengl/gl_shader_converter.cc @@ -25,86 +25,169 @@ #include "gl_shader_converter.hh" -namespace blender::gpu { +#include <optional> -void GLShaderConverter::patch(MutableSpan<const char *> sources) -{ - for (int i = 0; i < sources.size(); i++) { - std::string patched_source = patch(sources[i]); - patched_sources_.append(patched_source); - sources[i] = patched_sources_.last().c_str(); - } -} +#include "CLG_log.h" -bool GLShaderConverter::has_error() const -{ - return status != GLShaderConverterState::Ok; -} +static CLG_LogRef LOG = {"gpu.gl.shader.converter"}; -void GLShaderConverter::free() -{ - patched_sources_.clear(); -} +namespace blender::gpu { -std::string GLShaderConverter::patch(StringRef src) +static bool is_error_state(GLShaderConverterState state) { - std::string result = patch_push_constants(src); - return result; + return !ELEM(state, GLShaderConverterState::OkChanged, GLShaderConverterState::OkUnchanged); } -StringRef GLShaderConverter::skip_whitespace(StringRef ref) -{ - static constexpr StringRef WHITESPACES = " \t\n\v\f\r"; - - size_t skip = ref.find_first_not_of(WHITESPACES); - if (skip == blender::StringRef::not_found) { - return ref; +struct GLSLPatchResult { + std::optional<std::string> patched_glsl; + GLShaderConverterState state = GLShaderConverterState::OkUnchanged; + + void merge(const GLSLPatchResult &other, const StringRef unchanged_result) + { + switch (other.state) { + case GLShaderConverterState::OkUnchanged: + patched_glsl = unchanged_result; + break; + case GLShaderConverterState::OkChanged: + patched_glsl = other.patched_glsl; + if (state == GLShaderConverterState::OkUnchanged) { + state = GLShaderConverterState::OkChanged; + } + break; + case GLShaderConverterState::MismatchedPushConstantNames: + state = other.state; + break; + } } - return ref.drop_prefix(skip); -} +}; -StringRef GLShaderConverter::extract_name(StringRef src) -{ - static constexpr StringRef VALID_CHARS = +class GLSLPatch { + private: + static constexpr StringRef WHITESPACES = " \t\n\v\f\r"; + static constexpr StringRef VALID_NAME_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01232456789_"; - StringRef result = src; - size_t skip = result.find_first_not_of(VALID_CHARS); - BLI_assert(skip != StringRef::not_found); - return result.substr(0, skip); -} + public: + virtual GLSLPatchResult patch(PatchContext &context, StringRef source) = 0; -std::string GLShaderConverter::patch_push_constants(StringRef src) -{ + 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)"; - size_t pos = src.find(LAYOUT_PUSH_CONSTANTS); - if (pos == StringRef::not_found) { - return src; + public: + GLSLPatchResult patch(PatchContext &context, StringRef source) override + { + GLSLPatchResult result; + + size_t pos = source.find(LAYOUT_PUSH_CONSTANTS); + if (pos == StringRef::not_found) { + result.state = GLShaderConverterState::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.empty()) { + 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 = GLShaderConverterState::MismatchedPushConstantNames; + return result; + } + + std::string patched_glsl_str = patched_glsl.str(); + result.state = GLShaderConverterState::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(PatchContext &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); } - std::stringstream result; - result << src.substr(0, pos); - result << LAYOUT_STD140; - result << src.substr(pos + LAYOUT_PUSH_CONSTANTS.size()); - - StringRef name = src.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 (push_constants.name.empty()) { - push_constants.name = name; + + public: + GLSLPatchResult patch(PatchContext &context, StringRef source) override + { + GLSLPatchResult result; + PatchPushConstants push_constants; + patch(context, push_constants, source, result); + return result; } - else { - /* Push constant name must be the same across all stages. */ - if (push_constants.name != name) { - status = GLShaderConverterState::NOT_MATCHING_PUSH_CONSTANT_NAME; +}; + +void GLShaderConverter::patch(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); + if (is_error_state(patch_result.state)) { + state = patch_result.state; + return; + } + if (patch_result.state == GLShaderConverterState::OkChanged) { + BLI_assert(patch_result.patched_glsl); + patched_sources_.append(*patch_result.patched_glsl); + sources[i] = patched_sources_.last().c_str(); } } +} - return patch_push_constants(result.str()); +bool GLShaderConverter::has_errors() const +{ + return is_error_state(state); +} + +void GLShaderConverter::free() +{ + patched_sources_.clear(); } } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_shader_converter.hh b/source/blender/gpu/opengl/gl_shader_converter.hh index 0ba58cccf4c..84826fee38a 100644 --- a/source/blender/gpu/opengl/gl_shader_converter.hh +++ b/source/blender/gpu/opengl/gl_shader_converter.hh @@ -29,32 +29,30 @@ namespace blender::gpu { enum class GLShaderConverterState { - Ok, - NOT_MATCHING_PUSH_CONSTANT_NAME, + OkUnchanged, + OkChanged, + MismatchedPushConstantNames, }; -class GLShaderConverter { - public: + +struct PatchContext { struct { std::string name; } push_constants; - GLShaderConverterState status = GLShaderConverterState::Ok; +}; + +class GLShaderConverter { + public: + GLShaderConverterState state = GLShaderConverterState::OkUnchanged; private: Vector<std::string> patched_sources_; + PatchContext context_; public: void patch(MutableSpan<const char *> sources); - bool has_error() const; + bool has_errors() const; void free(); - private: - std::string patch(StringRef src); - bool is_valid_name_char(const char c) const; - StringRef skip_whitespace(StringRef src); - - StringRef extract_name(StringRef src); - std::string patch_push_constants(StringRef src); - MEM_CXX_CLASS_ALLOC_FUNCS("GLShaderConverter"); }; |