From 4ac026756752ab21e697a228478a041d0d57b21d Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Fri, 12 Jan 2024 14:28:50 +0100 Subject: [PATCH] OpenGL: Specialization Constants This PR adds support for specialization constants for the OpenGL backend. The minimum OpenGL version we are targetting doesn't have native support for specialization constants. We simulate this by keeping track of shader programs for each set of specialization constants that are being used. Specialization constants can be used to reduce shader complexity and improve performance as less registry and/or spilling is done. This requires the ability to recompile GLShaders. In order to do this we need to keep track of the sources that are used when the shader was compiled. For static sources we only store references (`GLSource::source_ref`), for dynamically generated sources we keep a copy of the source (`GLSource::source`). When recompiling the shader GLSL source-code is generated for the constants stored in `Shader::constants`. When compiling the previous GLSource that contains specialization constants is then replaced by the new version. Pull Request: https://projects.blender.org/blender/blender/pulls/116926 --- source/blender/gpu/intern/gpu_shader.cc | 36 ++- .../blender/gpu/intern/gpu_shader_private.hh | 17 ++ source/blender/gpu/metal/mtl_shader.hh | 2 + source/blender/gpu/metal/mtl_shader.mm | 6 +- source/blender/gpu/opengl/gl_shader.cc | 287 ++++++++++++++---- source/blender/gpu/opengl/gl_shader.hh | 115 ++++++- source/blender/gpu/vulkan/vk_shader.cc | 2 +- source/blender/gpu/vulkan/vk_shader.hh | 2 + 8 files changed, 388 insertions(+), 79 deletions(-) diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index bb0ace8d63e..acf655db008 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -65,8 +65,10 @@ Shader::~Shader() static void standard_defines(Vector &sources) { BLI_assert(sources.is_empty()); - /* Version needs to be first. Exact values will be added by implementation. */ + /* Version and specialization constants needs to be first. + * Exact values will be added by implementation. */ sources.append("version"); + sources.append("/* specialization_constants */"); /* Define to identify code usage in shading language. */ sources.append("#define GPU_SHADER\n"); /* some useful defines to detect GPU type */ @@ -297,7 +299,7 @@ GPUShader *GPU_shader_create_from_info(const GPUShaderCreateInfo *_info) } Shader *shader = GPUBackend::get()->shader_alloc(info.name_.c_str()); - + shader->init(info); shader->specialization_constants_init(info); std::string defines = shader->defines_declare(info); @@ -462,8 +464,13 @@ void GPU_shader_bind(GPUShader *gpu_shader) shader->bind(); GPU_matrix_bind(gpu_shader); Shader::set_srgb_uniform(gpu_shader); + shader->constants.is_dirty = false; } else { + if (shader->constants.is_dirty) { + shader->bind(); + shader->constants.is_dirty = false; + } if (Shader::srgb_uniform_dirty_get()) { Shader::set_srgb_uniform(gpu_shader); } @@ -557,27 +564,36 @@ void Shader::specialization_constants_init(const shader::ShaderCreateInfo &info) constants.types.append(sc.type); constants.values.append(sc.default_value); } + constants.is_dirty = true; } void GPU_shader_constant_int_ex(GPUShader *sh, int location, int value) { - BLI_assert(unwrap(sh)->constants.types[location] == gpu::shader::Type::INT); - unwrap(sh)->constants.values[location].i = value; + Shader &shader = *unwrap(sh); + BLI_assert(shader.constants.types[location] == gpu::shader::Type::INT); + shader.constants.values[location].i = value; + shader.constants.is_dirty = true; } void GPU_shader_constant_uint_ex(GPUShader *sh, int location, uint value) { - BLI_assert(unwrap(sh)->constants.types[location] == gpu::shader::Type::UINT); - unwrap(sh)->constants.values[location].u = value; + Shader &shader = *unwrap(sh); + BLI_assert(shader.constants.types[location] == gpu::shader::Type::UINT); + shader.constants.values[location].u = value; + shader.constants.is_dirty = true; } void GPU_shader_constant_float_ex(GPUShader *sh, int location, float value) { - BLI_assert(unwrap(sh)->constants.types[location] == gpu::shader::Type::FLOAT); - unwrap(sh)->constants.values[location].f = value; + Shader &shader = *unwrap(sh); + BLI_assert(shader.constants.types[location] == gpu::shader::Type::FLOAT); + shader.constants.values[location].f = value; + shader.constants.is_dirty = true; } void GPU_shader_constant_bool_ex(GPUShader *sh, int location, bool value) { - BLI_assert(unwrap(sh)->constants.types[location] == gpu::shader::Type::BOOL); - unwrap(sh)->constants.values[location].u = value; + Shader &shader = *unwrap(sh); + BLI_assert(shader.constants.types[location] == gpu::shader::Type::BOOL); + shader.constants.values[location].u = value; + shader.constants.is_dirty = true; } void GPU_shader_constant_int(GPUShader *sh, const char *name, int value) diff --git a/source/blender/gpu/intern/gpu_shader_private.hh b/source/blender/gpu/intern/gpu_shader_private.hh index 0b0ea10c0b6..a698de6b6bb 100644 --- a/source/blender/gpu/intern/gpu_shader_private.hh +++ b/source/blender/gpu/intern/gpu_shader_private.hh @@ -25,6 +25,14 @@ namespace gpu { class GPULogParser; +/** + * Compilation is done on a list of GLSL sources. This list contains placeholders that should be + * provided by the backend shader. These defines contains the locations where the backend can patch + * the sources. + */ +#define SOURCES_INDEX_VERSION 0 +#define SOURCES_INDEX_SPECIALIZATION_CONSTANTS 1 + /** * Implementation of shader compilation and uniforms handling. * Base class which is then specialized for each implementation (GL, VK, ...). @@ -44,6 +52,13 @@ class Shader { /* Current values set by `GPU_shader_constant_*()` call. The backend can choose to interpret * that however it wants (i.e: bind another shader instead). */ Vector values; + + /** + * OpenGL needs to know if a different program needs to be attached when constants are + * changed. Vulkan and Metal uses pipelines and don't have this issue. Attribute can be + * removed after the OpenGL backend has been phased out. + */ + bool is_dirty; } constants; protected: @@ -60,6 +75,8 @@ class Shader { Shader(const char *name); virtual ~Shader(); + virtual void init(const shader::ShaderCreateInfo &info) = 0; + virtual void vertex_shader_from_glsl(MutableSpan sources) = 0; virtual void geometry_shader_from_glsl(MutableSpan sources) = 0; virtual void fragment_shader_from_glsl(MutableSpan sources) = 0; diff --git a/source/blender/gpu/metal/mtl_shader.hh b/source/blender/gpu/metal/mtl_shader.hh index 27e527a2913..36cc395456c 100644 --- a/source/blender/gpu/metal/mtl_shader.hh +++ b/source/blender/gpu/metal/mtl_shader.hh @@ -274,6 +274,8 @@ class MTLShader : public Shader { NSString *fragment_function_name_); ~MTLShader(); + void init(const shader::ShaderCreateInfo & /*info*/) override {} + /* Assign GLSL source. */ void vertex_shader_from_glsl(MutableSpan sources) override; void geometry_shader_from_glsl(MutableSpan sources) override; diff --git a/source/blender/gpu/metal/mtl_shader.mm b/source/blender/gpu/metal/mtl_shader.mm index 3de77ddfc64..1ca3bd558d2 100644 --- a/source/blender/gpu/metal/mtl_shader.mm +++ b/source/blender/gpu/metal/mtl_shader.mm @@ -181,7 +181,7 @@ void MTLShader::vertex_shader_from_glsl(MutableSpan sources) shd_builder_->source_from_msl_ = false; /* Remove #version tag entry. */ - sources[0] = ""; + sources[SOURCES_INDEX_VERSION] = ""; /* Consolidate GLSL vertex sources. */ std::stringstream ss; @@ -203,7 +203,7 @@ void MTLShader::fragment_shader_from_glsl(MutableSpan sources) shd_builder_->source_from_msl_ = false; /* Remove #version tag entry. */ - sources[0] = ""; + sources[SOURCES_INDEX_VERSION] = ""; /* Consolidate GLSL fragment sources. */ std::stringstream ss; @@ -231,7 +231,7 @@ void MTLShader::compute_shader_from_glsl(MutableSpan sources) shd_builder_->source_from_msl_ = false; /* Remove #version tag entry. */ - sources[0] = ""; + sources[SOURCES_INDEX_VERSION] = ""; /* Consolidate GLSL compute sources. */ std::stringstream ss; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index dd2e1b96847..1879ece01e4 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -15,6 +15,7 @@ #include "GPU_capabilities.h" #include "GPU_platform.h" +#include "gpu_shader_dependency_private.h" #include "gl_debug.hh" #include "gl_vertex_buffer.hh" @@ -40,9 +41,6 @@ GLShader::GLShader(const char *name) : Shader(name) * does not have a GPUContext. */ BLI_assert(GLContext::get() != nullptr); #endif - shader_program_ = glCreateProgram(); - - debug::object_label(GL_PROGRAM, shader_program_, name); } GLShader::~GLShader() @@ -51,12 +49,14 @@ GLShader::~GLShader() * does not have a GPUContext. */ BLI_assert(GLContext::get() != nullptr); #endif - /* Invalid handles are silently ignored. */ - glDeleteShader(vert_shader_); - glDeleteShader(geom_shader_); - glDeleteShader(frag_shader_); - glDeleteShader(compute_shader_); - glDeleteProgram(shader_program_); +} + +void GLShader::init(const shader::ShaderCreateInfo &info) +{ + /* Extract the constants names from info and store them locally. */ + for (const ShaderCreateInfo::SpecializationConstant &constant : info.specialization_constants_) { + specialization_constant_names_.append(constant.name.c_str()); + } } /** \} */ @@ -618,30 +618,6 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const /* NOTE: We define macros in GLSL to trigger compilation error if the resource names * are reused for local variables. This is to match other backend behavior which needs accessors * macros. */ - - ss << "\n/* Specialization Constants (pass-through). */\n"; - for (const ShaderCreateInfo::SpecializationConstant &sc : info.specialization_constants_) { - switch (sc.type) { - case Type::INT: - ss << "const int " << sc.name << "=" << std::to_string(sc.default_value.i) << ";\n"; - break; - case Type::UINT: - ss << "const uint " << sc.name << "=" << std::to_string(sc.default_value.u) << "u;\n"; - break; - case Type::BOOL: - ss << "const bool " << sc.name << "=" << (sc.default_value.u ? "true" : "false") << ";\n"; - break; - case Type::FLOAT: - /* Use uint representation to allow exact same bit pattern even if NaN. */ - ss << "const float " << sc.name << "= uintBitsToFloat(" - << std::to_string(sc.default_value.u) << "u);\n"; - break; - default: - BLI_assert_unreachable(); - break; - } - } - ss << "\n/* Pass Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { print_resource(ss, res, info.auto_resource_location_); @@ -675,6 +651,39 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const return ss.str(); } +std::string GLShader::constants_declare() const +{ + std::stringstream ss; + + ss << "/* Specialization Constants. */\n"; + for (int constant_index : IndexRange(constants.types.size())) { + const StringRefNull name = specialization_constant_names_[constant_index]; + gpu::shader::Type constant_type = constants.types[constant_index]; + const shader::ShaderCreateInfo::SpecializationConstant::Value &value = + constants.values[constant_index]; + + switch (constant_type) { + case Type::INT: + ss << "const int " << name << "=" << std::to_string(value.i) << ";\n"; + break; + case Type::UINT: + ss << "const uint " << name << "=" << std::to_string(value.u) << "u;\n"; + break; + case Type::BOOL: + ss << "const bool " << name << "=" << (value.u ? "true" : "false") << ";\n"; + break; + case Type::FLOAT: + /* Use uint representation to allow exact same bit pattern even if NaN. */ + ss << "const float " << name << "= uintBitsToFloat(" << std::to_string(value.u) << "u);\n"; + break; + default: + BLI_assert_unreachable(); + break; + } + } + return ss.str(); +} + static std::string main_function_wrapper(std::string &pre_main, std::string &post_main) { std::stringstream ss; @@ -1168,7 +1177,9 @@ const char *GLShader::glsl_patch_get(GLenum gl_stage) return glsl_patch_default_get(); } -GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan sources) +GLuint GLShader::create_shader_stage(GLenum gl_stage, + MutableSpan sources, + const GLSources &gl_sources) { GLuint shader = glCreateShader(gl_stage); if (shader == 0) { @@ -1176,8 +1187,21 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan return 0; } + /* Patch the shader sources to include specialization constants. */ + std::string constants_source; + Vector recreated_sources; + const bool has_specialization_constants = !constants.types.is_empty(); + if (has_specialization_constants) { + constants_source = constants_declare(); + if (sources.is_empty()) { + recreated_sources = gl_sources.sources_get(); + sources = recreated_sources; + } + } + /* Patch the shader code using the first source slot. */ - sources[0] = glsl_patch_get(gl_stage); + sources[SOURCES_INDEX_VERSION] = glsl_patch_get(gl_stage); + sources[SOURCES_INDEX_SPECIALIZATION_CONSTANTS] = constants_source.c_str(); glShaderSource(shader, sources.size(), sources.data(), nullptr); glCompileShader(shader); @@ -1213,28 +1237,47 @@ GLuint GLShader::create_shader_stage(GLenum gl_stage, MutableSpan debug::object_label(gl_stage, shader, name); - glAttachShader(shader_program_, shader); + glAttachShader(program_active_->program_id, shader); return shader; } +void GLShader::update_program_and_sources(GLSources &stage_sources, + MutableSpan sources) +{ + const bool has_specialization_constants = !constants.types.is_empty(); + if (has_specialization_constants && stage_sources.is_empty()) { + stage_sources = sources; + } + + init_program(); +} + void GLShader::vertex_shader_from_glsl(MutableSpan sources) { - vert_shader_ = this->create_shader_stage(GL_VERTEX_SHADER, sources); + update_program_and_sources(vertex_sources_, sources); + program_active_->vert_shader = this->create_shader_stage( + GL_VERTEX_SHADER, sources, vertex_sources_); } void GLShader::geometry_shader_from_glsl(MutableSpan sources) { - geom_shader_ = this->create_shader_stage(GL_GEOMETRY_SHADER, sources); + update_program_and_sources(geometry_sources_, sources); + program_active_->geom_shader = this->create_shader_stage( + GL_GEOMETRY_SHADER, sources, geometry_sources_); } void GLShader::fragment_shader_from_glsl(MutableSpan sources) { - frag_shader_ = this->create_shader_stage(GL_FRAGMENT_SHADER, sources); + update_program_and_sources(fragment_sources_, sources); + program_active_->frag_shader = this->create_shader_stage( + GL_FRAGMENT_SHADER, sources, fragment_sources_); } void GLShader::compute_shader_from_glsl(MutableSpan sources) { - compute_shader_ = this->create_shader_stage(GL_COMPUTE_SHADER, sources); + update_program_and_sources(compute_sources_, sources); + program_active_->compute_shader = this->create_shader_stage( + GL_COMPUTE_SHADER, sources, compute_sources_); } bool GLShader::finalize(const shader::ShaderCreateInfo *info) @@ -1249,26 +1292,21 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info) sources.append("version"); sources.append(source.c_str()); geometry_shader_from_glsl(sources); + if (!constants.types.is_empty()) { + geometry_sources_ = sources; + } } - glLinkProgram(shader_program_); - - GLint status; - glGetProgramiv(shader_program_, GL_LINK_STATUS, &status); - if (!status) { - char log[5000]; - glGetProgramInfoLog(shader_program_, sizeof(log), nullptr, log); - Span sources; - GLLogParser parser; - this->print_log(sources, log, "Linking", true, &parser); + if (!program_link()) { return false; } + GLuint program_id = program_get(); if (info != nullptr && info->legacy_resource_location_ == false) { - interface = new GLShaderInterface(shader_program_, *info); + interface = new GLShaderInterface(program_id, *info); } else { - interface = new GLShaderInterface(shader_program_); + interface = new GLShaderInterface(program_id); } return true; @@ -1282,8 +1320,8 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info) void GLShader::bind() { - BLI_assert(shader_program_ != 0); - glUseProgram(shader_program_); + GLuint program_id = program_get(); + glUseProgram(program_id); } void GLShader::unbind() @@ -1305,7 +1343,7 @@ void GLShader::transform_feedback_names_set(Span name_list, const eGPUShaderTFBType geom_type) { glTransformFeedbackVaryings( - shader_program_, name_list.size(), name_list.data(), GL_INTERLEAVED_ATTRIBS); + program_get(), name_list.size(), name_list.data(), GL_INTERLEAVED_ATTRIBS); transform_feedback_type_ = geom_type; } @@ -1408,7 +1446,144 @@ void GLShader::uniform_int(int location, int comp_len, int array_size, const int int GLShader::program_handle_get() const { - return int(this->shader_program_); + BLI_assert(program_active_); + return program_active_->program_id; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sources + * \{ */ +GLSource::GLSource(const char *other) +{ + if (!gpu_shader_dependency_get_filename_from_source_string(other).is_empty()) { + source = ""; + source_ref = StringRefNull(other); + } + else { + source = other; + source_ref = StringRefNull(source); + } +} + +GLSources &GLSources::operator=(Span other) +{ + clear(); + reserve(other.size()); + + for (const char *other_source : other) { + /* Don't store empty string as compilers can optimize these away and result in pointing to a + * string that isn't c-str compliant anymore. */ + if (other_source[0] == '\0') { + continue; + } + append(GLSource(other_source)); + } + + return *this; +} + +Vector GLSources::sources_get() const +{ + Vector result; + result.reserve(size()); + + for (const GLSource &source : *this) { + result.append(source.source_ref.c_str()); + } + return result; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Specialization Constants + * \{ */ + +GLShader::GLProgram::~GLProgram() +{ + /* Invalid handles are silently ignored. */ + glDeleteShader(vert_shader); + glDeleteShader(geom_shader); + glDeleteShader(frag_shader); + glDeleteShader(compute_shader); + glDeleteProgram(program_id); +} + +bool GLShader::program_link() +{ + GLuint program_id = program_active_->program_id; + glLinkProgram(program_id); + + GLint status; + glGetProgramiv(program_id, GL_LINK_STATUS, &status); + if (!status) { + char log[5000]; + glGetProgramInfoLog(program_id, sizeof(log), nullptr, log); + Span sources; + GLLogParser parser; + print_log(sources, log, "Linking", true, &parser); + } + + return bool(status); +} + +void GLShader::init_program() +{ + if (program_active_) { + return; + } + + program_active_ = &program_cache_.lookup_or_add_default(constants.values); + if (!program_active_->program_id) { + program_active_->program_id = glCreateProgram(); + debug::object_label(GL_PROGRAM, program_active_->program_id, name); + } +} + +GLuint GLShader::program_get() +{ + if (constants.types.is_empty()) { + /* Early exit for shaders that doesn't use specialization constants. The active shader should + * already be setup. */ + BLI_assert(program_active_ && program_active_->program_id); + return program_active_->program_id; + } + + if (!constants.is_dirty) { + /* Early exit when constants didn't change since the last call. */ + BLI_assert(program_active_ && program_active_->program_id); + return program_active_->program_id; + } + + program_active_ = &program_cache_.lookup_or_add_default(constants.values); + if (!program_active_->program_id) { + program_active_->program_id = glCreateProgram(); + debug::object_label(GL_PROGRAM, program_active_->program_id, name); + MutableSpan no_sources; + if (!vertex_sources_.is_empty()) { + program_active_->vert_shader = create_shader_stage( + GL_VERTEX_SHADER, no_sources, vertex_sources_); + } + if (!geometry_sources_.is_empty()) { + program_active_->geom_shader = create_shader_stage( + GL_GEOMETRY_SHADER, no_sources, geometry_sources_); + } + if (!fragment_sources_.is_empty()) { + program_active_->frag_shader = create_shader_stage( + GL_FRAGMENT_SHADER, no_sources, fragment_sources_); + } + if (!compute_sources_.is_empty()) { + program_active_->compute_shader = create_shader_stage( + GL_COMPUTE_SHADER, no_sources, compute_sources_); + } + + program_link(); + } + + constants.is_dirty = false; + return program_active_->program_id; } /** \} */ diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index f5f25c8da5d..c9084d92012 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -12,12 +12,50 @@ #include +#include "BLI_map.hh" + #include "gpu_shader_create_info.hh" #include "gpu_shader_private.hh" namespace blender { +template<> +struct DefaultHash> { + uint64_t operator()( + const Vector &key) const + { + uint64_t hash = 0; + for (const gpu::shader::ShaderCreateInfo::SpecializationConstant::Value &value : key) { + hash = hash * 33 + value.u; + } + return hash; + } +}; + namespace gpu { +/** + * Shaders that uses specialization constants must keep track of the sources in order to rebuild + * shader stages. + * + * Some sources are shared and won't be copied. For example for dependencies. In this case we + * would only store the source_ref. + * + * Other sources would be stored in the #source attribute. #source_ref + * would still be updated. + */ +struct GLSource { + std::string source; + StringRefNull source_ref; + + GLSource() = default; + GLSource(const char *other_source); +}; +class GLSources : public Vector { + public: + GLSources &operator=(Span other); + Vector sources_get() const; +}; + /** * Implementation of shader compilation and uniforms handling using OpenGL. */ @@ -26,13 +64,61 @@ class GLShader : public Shader { friend shader::StageInterfaceInfo; private: - /** Handle for full program (links shader stages below). */ - GLuint shader_program_ = 0; - /** Individual shader stages. */ - GLuint vert_shader_ = 0; - GLuint geom_shader_ = 0; - GLuint frag_shader_ = 0; - GLuint compute_shader_ = 0; + struct GLProgram { + /** Handle for program. */ + GLuint program_id = 0; + /** Handle for individual shader stages. */ + GLuint vert_shader = 0; + GLuint geom_shader = 0; + GLuint frag_shader = 0; + GLuint compute_shader = 0; + ~GLProgram(); + }; + + using GLProgramCacheKey = Vector; + Map program_cache_; + + /** + * Points to the active program. When binding a shader the active program is + * setup. + */ + GLProgram *program_active_ = nullptr; + + /** + * When the shader uses Specialization Constants these attribute contains the sources to + * rebuild shader stages. When Specialization Constants aren't used they are empty to + * reduce memory needs. + */ + GLSources vertex_sources_; + GLSources geometry_sources_; + GLSources fragment_sources_; + GLSources compute_sources_; + + Vector specialization_constant_names_; + + /** + * Initialize an this instance. + * + * - Ensures that program_cache at least has a default GLProgram. + * - Ensures that active program is set. + * - Active GLProgram has a shader_program (at least in creation state). + * - Does nothing when instance was already initialized. + */ + void init_program(); + + void update_program_and_sources(GLSources &stage_sources, MutableSpan sources); + + /** + * Link the active program. + */ + bool program_link(); + + /** + * Return a GLProgram program id that reflects the current state of shader.constants.values. + * The returned program_id is in linked state, or an error happened during linking. + */ + GLuint program_get(); + /** True if any shader failed to compile. */ bool compilation_failed_ = false; @@ -42,6 +128,8 @@ class GLShader : public Shader { GLShader(const char *name); ~GLShader(); + void init(const shader::ShaderCreateInfo &info) override; + /** Return true on success. */ void vertex_shader_from_glsl(MutableSpan sources) override; void geometry_shader_from_glsl(MutableSpan sources) override; @@ -51,6 +139,7 @@ class GLShader : public Shader { void warm_cache(int /*limit*/) override{}; std::string resources_declare(const shader::ShaderCreateInfo &info) const override; + std::string constants_declare() const; std::string vertex_interface_declare(const shader::ShaderCreateInfo &info) const override; std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override; std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override; @@ -84,14 +173,22 @@ class GLShader : public Shader { bool is_compute() const { - return compute_shader_ != 0; + if (!vertex_sources_.is_empty()) { + return false; + } + if (!compute_sources_.is_empty()) { + return true; + } + return program_active_->compute_shader != 0; } private: const char *glsl_patch_get(GLenum gl_stage); /** Create, compile and attach the shader stage to the shader program. */ - GLuint create_shader_stage(GLenum gl_stage, MutableSpan sources); + GLuint create_shader_stage(GLenum gl_stage, + MutableSpan sources, + const GLSources &gl_sources); /** * \brief features available on newer implementation such as native barycentric coordinates diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index e825fd4d8ad..87d29dbc528 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -610,7 +610,7 @@ void VKShader::build_shader_module(MutableSpan sources, shaderc_compute_shader), "Only forced ShaderC shader kinds are supported."); const VKDevice &device = VKBackend::get().device_get(); - sources[0] = device.glsl_patch_get(); + sources[SOURCES_INDEX_VERSION] = device.glsl_patch_get(); Vector spirv_module = compile_glsl_to_spirv(sources, stage); build_shader_module(spirv_module, r_shader_module); } diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index c2939e57db4..4abf860eed7 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -36,6 +36,8 @@ class VKShader : public Shader { VKShader(const char *name); virtual ~VKShader(); + void init(const shader::ShaderCreateInfo & /*info*/) override {} + void vertex_shader_from_glsl(MutableSpan sources) override; void geometry_shader_from_glsl(MutableSpan sources) override; void fragment_shader_from_glsl(MutableSpan sources) override;