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;