From 8e23c216d7b9260bde3e339a11a3e56bdb8502f1 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 21 May 2024 12:29:08 +0200 Subject: [PATCH 1/3] Vulkan: Reuse shader modules. Before the patch performing frontend compilation of all static shaders. ``` VKShaderModules(glsl_spirv_time=35.9324s, spirv_shader_module_time0.00639725s) ``` --- source/blender/gpu/CMakeLists.txt | 2 + source/blender/gpu/vulkan/vk_device.cc | 1 + source/blender/gpu/vulkan/vk_device.hh | 2 + source/blender/gpu/vulkan/vk_shader.cc | 27 ++- source/blender/gpu/vulkan/vk_shader.hh | 8 +- .../blender/gpu/vulkan/vk_shader_modules.cc | 174 ++++++++++++++++++ .../blender/gpu/vulkan/vk_shader_modules.hh | 59 ++++++ 7 files changed, 258 insertions(+), 15 deletions(-) create mode 100644 source/blender/gpu/vulkan/vk_shader_modules.cc create mode 100644 source/blender/gpu/vulkan/vk_shader_modules.hh diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index fb0ecd791ae..3770e3fb9b8 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -232,6 +232,7 @@ set(VULKAN_SRC vulkan/vk_shader.cc vulkan/vk_shader_interface.cc vulkan/vk_shader_log.cc + vulkan/vk_shader_modules.cc vulkan/vk_staging_buffer.cc vulkan/vk_state_manager.cc vulkan/vk_storage_buffer.cc @@ -299,6 +300,7 @@ set(VULKAN_SRC vulkan/vk_shader.hh vulkan/vk_shader_interface.hh vulkan/vk_shader_log.hh + vulkan/vk_shader_modules.hh vulkan/vk_staging_buffer.hh vulkan/vk_state_manager.hh vulkan/vk_storage_buffer.hh diff --git a/source/blender/gpu/vulkan/vk_device.cc b/source/blender/gpu/vulkan/vk_device.cc index 17019fd9a58..2d1d59fafc0 100644 --- a/source/blender/gpu/vulkan/vk_device.cc +++ b/source/blender/gpu/vulkan/vk_device.cc @@ -49,6 +49,7 @@ void VKDevice::deinit() samplers_.free(); destroy_discarded_resources(); pipelines.free_data(); + shader_modules.free_data(); vkDestroyPipelineCache(vk_device_, vk_pipeline_cache_, vk_allocation_callbacks); descriptor_set_layouts_.deinit(); vmaDestroyAllocator(mem_allocator_); diff --git a/source/blender/gpu/vulkan/vk_device.hh b/source/blender/gpu/vulkan/vk_device.hh index ceaeda95aa1..fd6aeb28374 100644 --- a/source/blender/gpu/vulkan/vk_device.hh +++ b/source/blender/gpu/vulkan/vk_device.hh @@ -19,6 +19,7 @@ #include "vk_descriptor_set_layouts.hh" #include "vk_pipeline_pool.hh" #include "vk_samplers.hh" +#include "vk_shader_modules.hh" #include "vk_timeline_semaphore.hh" namespace blender::gpu { @@ -112,6 +113,7 @@ class VKDevice : public NonCopyable { public: render_graph::VKResourceStateTracker resources; + VKShaderModules shader_modules; VKPipelinePool pipelines; /** diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 5e2bcd3d750..64076c6f035 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -568,24 +568,29 @@ VKShader::VKShader(const char *name) : Shader(name) context_ = VKContext::get(); } +void VKShader::init(const shader::ShaderCreateInfo &info) +{ + create_info_ = &info; +} + VKShader::~VKShader() { VK_ALLOCATION_CALLBACKS - const VKDevice &device = VKBackend::get().device_get(); + VKDevice &device = VKBackend::get().device_get(); if (vertex_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device.device_get(), vertex_module_, vk_allocation_callbacks); + device.shader_modules.destruct(vertex_module_); vertex_module_ = VK_NULL_HANDLE; } if (geometry_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device.device_get(), geometry_module_, vk_allocation_callbacks); + device.shader_modules.destruct(geometry_module_); geometry_module_ = VK_NULL_HANDLE; } if (fragment_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device.device_get(), fragment_module_, vk_allocation_callbacks); + device.shader_modules.destruct(fragment_module_); fragment_module_ = VK_NULL_HANDLE; } if (compute_module_ != VK_NULL_HANDLE) { - vkDestroyShaderModule(device.device_get(), compute_module_, vk_allocation_callbacks); + device.shader_modules.destruct(compute_module_); compute_module_ = VK_NULL_HANDLE; } if (vk_pipeline_layout_ != VK_NULL_HANDLE) { @@ -594,22 +599,16 @@ VKShader::~VKShader() } /* Reset not owning handles. */ vk_descriptor_set_layout_ = VK_NULL_HANDLE; + create_info_ = nullptr; } void VKShader::build_shader_module(MutableSpan sources, shaderc_shader_kind stage, VkShaderModule *r_shader_module) { - BLI_assert_msg(ELEM(stage, - shaderc_vertex_shader, - shaderc_geometry_shader, - shaderc_fragment_shader, - shaderc_compute_shader), - "Only forced ShaderC shader kinds are supported."); - const VKDevice &device = VKBackend::get().device_get(); + VKDevice &device = VKBackend::get().device_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); + device.shader_modules.construct(*this, *create_info_, sources, stage, r_shader_module); } void VKShader::vertex_shader_from_glsl(MutableSpan sources) diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index 3776abf6163..28e94837ceb 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -18,8 +18,11 @@ namespace blender::gpu { class VKShaderInterface; +class VKShaderModules; class VKShader : public Shader { + friend class VKShaderModules; + private: VKContext *context_ = nullptr; VkShaderModule vertex_module_ = VK_NULL_HANDLE; @@ -43,13 +46,16 @@ class VKShader : public Shader { */ VkPipeline vk_pipeline_ = VK_NULL_HANDLE; + /** Create info used to construct this shader. */ + const shader::ShaderCreateInfo *create_info_ = nullptr; + public: VKPushConstants push_constants; VKShader(const char *name); virtual ~VKShader(); - void init(const shader::ShaderCreateInfo & /*info*/) override {} + void init(const shader::ShaderCreateInfo &info) override; void vertex_shader_from_glsl(MutableSpan sources) override; void geometry_shader_from_glsl(MutableSpan sources) override; diff --git a/source/blender/gpu/vulkan/vk_shader_modules.cc b/source/blender/gpu/vulkan/vk_shader_modules.cc new file mode 100644 index 00000000000..388039b0110 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_modules.cc @@ -0,0 +1,174 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#include "BLI_string_utils.hh" +#include "BLI_time.h" + +#include "gpu_shader_create_info.hh" + +#include "vk_backend.hh" +#include "vk_memory.hh" +#include "vk_shader.hh" +#include "vk_shader_log.hh" +#include "vk_shader_modules.hh" + +#include + +namespace blender::gpu { +bool VKShaderModules::construct(VKShader &shader, + const shader::ShaderCreateInfo & /*info*/, + Span sources, + shaderc_shader_kind stage, + VkShaderModule *r_shader_module) +{ + BLI_assert_msg(ELEM(stage, + shaderc_vertex_shader, + shaderc_geometry_shader, + shaderc_fragment_shader, + shaderc_compute_shader), + "Only forced ShaderC shader kinds are supported."); + Vector spirv_module; + if (!compile_glsl_to_spirv(shader, sources, stage, spirv_module)) { + r_shader_module = VK_NULL_HANDLE; + return false; + } + return build_shader_module(shader, spirv_module, r_shader_module); +} + +/* -------------------------------------------------------------------- */ +/** \name Frontend compilation (GLSL -> SpirV) + * + * \{ */ + +static const std::string to_stage_name(shaderc_shader_kind stage) +{ + switch (stage) { + case shaderc_vertex_shader: + return std::string("vertex"); + case shaderc_geometry_shader: + return std::string("geometry"); + case shaderc_fragment_shader: + return std::string("fragment"); + case shaderc_compute_shader: + return std::string("compute"); + + default: + BLI_assert_msg(false, "Do not know how to convert shaderc_shader_kind to stage name."); + break; + } + return std::string("unknown stage"); +} + +static std::string combine_sources(Span sources) +{ + char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size()); + std::string result(sources_combined); + MEM_freeN(sources_combined); + return result; +} + +bool VKShaderModules::compile_glsl_to_spirv(VKShader &shader, + Span sources, + shaderc_shader_kind stage, + Vector &r_compiled_spirv) +{ + const double start_time = BLI_time_now_seconds(); + std::string combined_sources = combine_sources(sources); + VKBackend &backend = VKBackend::get(); + shaderc::Compiler &compiler = backend.get_shaderc_compiler(); + shaderc::CompileOptions options; + options.SetOptimizationLevel(shaderc_optimization_level_performance); + options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); + if (G.debug & G_DEBUG_GPU_RENDERDOC) { + options.SetOptimizationLevel(shaderc_optimization_level_zero); + options.SetGenerateDebugInfo(); + } + + shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv( + combined_sources, stage, shader.name, options); + if (module.GetNumErrors() != 0 || module.GetNumWarnings() != 0) { + std::string log = module.GetErrorMessage(); + Vector logcstr(log.c_str(), log.c_str() + log.size() + 1); + + VKLogParser parser; + shader.print_log(sources, + logcstr.data(), + to_stage_name(stage).c_str(), + module.GetCompilationStatus() != shaderc_compilation_status_success, + &parser); + } + stats_.glsl_to_spirv_time += BLI_time_now_seconds() - start_time; + r_compiled_spirv.clear(); + if (module.GetCompilationStatus() != shaderc_compilation_status_success) { + return false; + } + + r_compiled_spirv.extend(module.cbegin(), module.cend()); + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Frontend compilation (SpirV -> ShaderModule) + * + * \{ */ +bool VKShaderModules::build_shader_module(const VKShader &shader, + Span spirv_module, + VkShaderModule *r_shader_module) +{ + const double start_time = BLI_time_now_seconds(); + VK_ALLOCATION_CALLBACKS; + + VkShaderModuleCreateInfo create_info = {}; + create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + create_info.codeSize = spirv_module.size() * sizeof(uint32_t); + create_info.pCode = spirv_module.data(); + + const VKDevice &device = VKBackend::get().device_get(); + VkResult result = vkCreateShaderModule( + device.device_get(), &create_info, vk_allocation_callbacks, r_shader_module); + stats_.spirv_to_shader_module_time += BLI_time_now_seconds() - start_time; + if (result == VK_SUCCESS) { + debug::object_label(*r_shader_module, shader.name); + return true; + } + else { + *r_shader_module = VK_NULL_HANDLE; + return false; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Debugging and statistics + * + * \{ */ +void VKShaderModules::debug_print() const +{ + std::stringstream ss; + ss << "VKShaderModules(glsl_spirv_time=" << stats_.glsl_to_spirv_time << "s" + << ", spirv_shader_module_time" << stats_.spirv_to_shader_module_time << "s)\n"; + std::cout << ss.str(); +} +/** \} */ + +void VKShaderModules::destruct(VkShaderModule vk_shader_module) +{ + VK_ALLOCATION_CALLBACKS + const VKDevice &device = VKBackend::get().device_get(); + vkDestroyShaderModule(device.device_get(), vk_shader_module, vk_allocation_callbacks); +} + +void VKShaderModules::free_data() +{ + debug_print(); +} + +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_shader_modules.hh b/source/blender/gpu/vulkan/vk_shader_modules.hh new file mode 100644 index 00000000000..05e3d2763b6 --- /dev/null +++ b/source/blender/gpu/vulkan/vk_shader_modules.hh @@ -0,0 +1,59 @@ +/* SPDX-FileCopyrightText: 2024 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup gpu + */ + +#pragma once + +#include "GPU_shader.hh" + +#include "vk_common.hh" + +#include "shaderc/shaderc.hpp" + +namespace blender::gpu { +class VKShader; +namespace shader { +class ShaderCreateInfo; +} + +/** + * Pool of shader modules. + * + * Responsibility of VKShaderModules: + * - Reusing of VkShaderModule between shaders to reduce compilation and pipeline creation + * times. + * - Loading of precompiled spirv bytecode. + */ +class VKShaderModules { + private: + struct { + double glsl_to_spirv_time = 0.0; + double spirv_to_shader_module_time = 0.0; + } stats_; + + public: + bool construct(VKShader &shader, + const shader::ShaderCreateInfo &info, + Span sources, + shaderc_shader_kind stage, + VkShaderModule *r_shader_module); + void destruct(VkShaderModule vk_shader_module); + void free_data(); + + void debug_print() const; + + private: + bool compile_glsl_to_spirv(VKShader &shader, + Span sources, + shaderc_shader_kind stage, + Vector &r_compiled_spirv); + bool build_shader_module(const VKShader &shader, + Span spirv_module, + VkShaderModule *r_shader_module); +}; + +} // namespace blender::gpu -- 2.30.2 From fb0f0fe4214eb7ca52bb4629803371fe4b07b9fa Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 21 May 2024 12:37:13 +0200 Subject: [PATCH 2/3] Remove unused code --- source/blender/gpu/vulkan/vk_shader.cc | 84 ------------------- source/blender/gpu/vulkan/vk_shader.hh | 2 - .../blender/gpu/vulkan/vk_shader_modules.cc | 27 +++--- 3 files changed, 15 insertions(+), 98 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index 64076c6f035..bfa4aab781e 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -479,90 +479,6 @@ static std::string main_function_wrapper(std::string &pre_main, std::string &pos return ss.str(); } -static const std::string to_stage_name(shaderc_shader_kind stage) -{ - switch (stage) { - case shaderc_vertex_shader: - return std::string("vertex"); - case shaderc_geometry_shader: - return std::string("geometry"); - case shaderc_fragment_shader: - return std::string("fragment"); - case shaderc_compute_shader: - return std::string("compute"); - - default: - BLI_assert_msg(false, "Do not know how to convert shaderc_shader_kind to stage name."); - break; - } - return std::string("unknown stage"); -} - -static std::string combine_sources(Span sources) -{ - char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size()); - std::string result(sources_combined); - MEM_freeN(sources_combined); - return result; -} - -Vector VKShader::compile_glsl_to_spirv(Span sources, - shaderc_shader_kind stage) -{ - std::string combined_sources = combine_sources(sources); - VKBackend &backend = VKBackend::get(); - shaderc::Compiler &compiler = backend.get_shaderc_compiler(); - shaderc::CompileOptions options; - options.SetOptimizationLevel(shaderc_optimization_level_performance); - options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_2); - if (G.debug & G_DEBUG_GPU_RENDERDOC) { - options.SetOptimizationLevel(shaderc_optimization_level_zero); - options.SetGenerateDebugInfo(); - } - - shaderc::SpvCompilationResult module = compiler.CompileGlslToSpv( - combined_sources, stage, name, options); - if (module.GetNumErrors() != 0 || module.GetNumWarnings() != 0) { - std::string log = module.GetErrorMessage(); - Vector logcstr(log.c_str(), log.c_str() + log.size() + 1); - - VKLogParser parser; - print_log(sources, - logcstr.data(), - to_stage_name(stage).c_str(), - module.GetCompilationStatus() != shaderc_compilation_status_success, - &parser); - } - - if (module.GetCompilationStatus() != shaderc_compilation_status_success) { - compilation_failed_ = true; - return Vector(); - } - - return Vector(module.cbegin(), module.cend()); -} - -void VKShader::build_shader_module(Span spirv_module, VkShaderModule *r_shader_module) -{ - VK_ALLOCATION_CALLBACKS; - - VkShaderModuleCreateInfo create_info = {}; - create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - create_info.codeSize = spirv_module.size() * sizeof(uint32_t); - create_info.pCode = spirv_module.data(); - - const VKDevice &device = VKBackend::get().device_get(); - VkResult result = vkCreateShaderModule( - device.device_get(), &create_info, vk_allocation_callbacks, r_shader_module); - if (result == VK_SUCCESS) { - debug::object_label(*r_shader_module, name); - } - else { - compilation_failed_ = true; - *r_shader_module = VK_NULL_HANDLE; - } -} - VKShader::VKShader(const char *name) : Shader(name) { context_ = VKContext::get(); diff --git a/source/blender/gpu/vulkan/vk_shader.hh b/source/blender/gpu/vulkan/vk_shader.hh index 28e94837ceb..7e825e2b3a9 100644 --- a/source/blender/gpu/vulkan/vk_shader.hh +++ b/source/blender/gpu/vulkan/vk_shader.hh @@ -134,8 +134,6 @@ class VKShader : public Shader { } private: - Vector compile_glsl_to_spirv(Span sources, shaderc_shader_kind kind); - void build_shader_module(Span spirv_module, VkShaderModule *r_shader_module); void build_shader_module(MutableSpan sources, shaderc_shader_kind stage, VkShaderModule *r_shader_module); diff --git a/source/blender/gpu/vulkan/vk_shader_modules.cc b/source/blender/gpu/vulkan/vk_shader_modules.cc index 388039b0110..8e7638e15a9 100644 --- a/source/blender/gpu/vulkan/vk_shader_modules.cc +++ b/source/blender/gpu/vulkan/vk_shader_modules.cc @@ -20,6 +20,7 @@ #include namespace blender::gpu { + bool VKShaderModules::construct(VKShader &shader, const shader::ShaderCreateInfo & /*info*/, Span sources, @@ -40,6 +41,18 @@ bool VKShaderModules::construct(VKShader &shader, return build_shader_module(shader, spirv_module, r_shader_module); } +void VKShaderModules::destruct(VkShaderModule vk_shader_module) +{ + VK_ALLOCATION_CALLBACKS + const VKDevice &device = VKBackend::get().device_get(); + vkDestroyShaderModule(device.device_get(), vk_shader_module, vk_allocation_callbacks); +} + +void VKShaderModules::free_data() +{ + debug_print(); +} + /* -------------------------------------------------------------------- */ /** \name Frontend compilation (GLSL -> SpirV) * @@ -150,6 +163,7 @@ bool VKShaderModules::build_shader_module(const VKShader &shader, /** \name Debugging and statistics * * \{ */ + void VKShaderModules::debug_print() const { std::stringstream ss; @@ -157,18 +171,7 @@ void VKShaderModules::debug_print() const << ", spirv_shader_module_time" << stats_.spirv_to_shader_module_time << "s)\n"; std::cout << ss.str(); } + /** \} */ -void VKShaderModules::destruct(VkShaderModule vk_shader_module) -{ - VK_ALLOCATION_CALLBACKS - const VKDevice &device = VKBackend::get().device_get(); - vkDestroyShaderModule(device.device_get(), vk_shader_module, vk_allocation_callbacks); -} - -void VKShaderModules::free_data() -{ - debug_print(); -} - } // namespace blender::gpu -- 2.30.2 From d4f38c14be9877c1e73e8bebcb50de04309fa976 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 21 May 2024 14:35:08 +0200 Subject: [PATCH 3/3] Check spirv --- source/blender/gpu/vulkan/vk_shader.cc | 35 +++--- .../blender/gpu/vulkan/vk_shader_modules.cc | 114 ++++++++++++------ .../blender/gpu/vulkan/vk_shader_modules.hh | 6 + 3 files changed, 102 insertions(+), 53 deletions(-) diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index bfa4aab781e..f71127cb08f 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -487,6 +487,9 @@ VKShader::VKShader(const char *name) : Shader(name) void VKShader::init(const shader::ShaderCreateInfo &info) { create_info_ = &info; + VKShaderInterface *vk_interface = new VKShaderInterface(); + vk_interface->init(info); + interface = vk_interface; } VKShader::~VKShader() @@ -566,18 +569,23 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) geometry_shader_from_glsl(sources); } - VKShaderInterface *vk_interface = new VKShaderInterface(); - vk_interface->init(*info); + /* Create infos of none static compilation shaders can be destructed after the shader are + * compiled. Better to reset the value to not confuse developers during debugging. */ + if (!create_info_->do_static_compilation_) { + create_info_ = nullptr; + } + + const VKShaderInterface &vk_interface = interface_get(); VKDevice &device = VKBackend::get().device_get(); - if (!finalize_descriptor_set_layouts(device, *vk_interface)) { + if (!finalize_descriptor_set_layouts(device, vk_interface)) { return false; } - if (!finalize_pipeline_layout(device.device_get(), *vk_interface)) { + if (!finalize_pipeline_layout(device.device_get(), vk_interface)) { return false; } - push_constants = VKPushConstants(&vk_interface->push_constants_layout_get()); + push_constants = VKPushConstants(&vk_interface.push_constants_layout_get()); bool result; if (use_render_graph) { @@ -601,11 +609,9 @@ bool VKShader::finalize(const shader::ShaderCreateInfo *info) } } - if (result) { - interface = vk_interface; - } - else { - delete vk_interface; + if (!result) { + delete interface; + interface = nullptr; } return result; } @@ -713,8 +719,7 @@ void VKShader::uniform_int(int location, int comp_len, int array_size, const int std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) const { - VKShaderInterface interface; - interface.init(info); + const VKShaderInterface &vk_interface = interface_get(); std::stringstream ss; ss << "\n/* Specialization Constants (pass-through). */\n"; @@ -745,16 +750,16 @@ std::string VKShader::resources_declare(const shader::ShaderCreateInfo &info) co ss << "\n/* Pass Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { - print_resource(ss, interface, res); + print_resource(ss, vk_interface, res); } ss << "\n/* Batch Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { - print_resource(ss, interface, res); + print_resource(ss, vk_interface, res); } /* Push constants. */ - const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get(); + const VKPushConstants::Layout &push_constants_layout = vk_interface.push_constants_layout_get(); const VKPushConstants::StorageType push_constants_storage = push_constants_layout.storage_type_get(); if (push_constants_storage != VKPushConstants::StorageType::NONE) { diff --git a/source/blender/gpu/vulkan/vk_shader_modules.cc b/source/blender/gpu/vulkan/vk_shader_modules.cc index 8e7638e15a9..995080c275f 100644 --- a/source/blender/gpu/vulkan/vk_shader_modules.cc +++ b/source/blender/gpu/vulkan/vk_shader_modules.cc @@ -6,6 +6,7 @@ * \ingroup gpu */ +#include "BLI_hash.hh" #include "BLI_string_utils.hh" #include "BLI_time.h" @@ -21,43 +22,6 @@ namespace blender::gpu { -bool VKShaderModules::construct(VKShader &shader, - const shader::ShaderCreateInfo & /*info*/, - Span sources, - shaderc_shader_kind stage, - VkShaderModule *r_shader_module) -{ - BLI_assert_msg(ELEM(stage, - shaderc_vertex_shader, - shaderc_geometry_shader, - shaderc_fragment_shader, - shaderc_compute_shader), - "Only forced ShaderC shader kinds are supported."); - Vector spirv_module; - if (!compile_glsl_to_spirv(shader, sources, stage, spirv_module)) { - r_shader_module = VK_NULL_HANDLE; - return false; - } - return build_shader_module(shader, spirv_module, r_shader_module); -} - -void VKShaderModules::destruct(VkShaderModule vk_shader_module) -{ - VK_ALLOCATION_CALLBACKS - const VKDevice &device = VKBackend::get().device_get(); - vkDestroyShaderModule(device.device_get(), vk_shader_module, vk_allocation_callbacks); -} - -void VKShaderModules::free_data() -{ - debug_print(); -} - -/* -------------------------------------------------------------------- */ -/** \name Frontend compilation (GLSL -> SpirV) - * - * \{ */ - static const std::string to_stage_name(shaderc_shader_kind stage) { switch (stage) { @@ -77,6 +41,79 @@ static const std::string to_stage_name(shaderc_shader_kind stage) return std::string("unknown stage"); } +bool VKShaderModules::construct(VKShader &shader, + const shader::ShaderCreateInfo &info, + Span sources, + shaderc_shader_kind stage, + VkShaderModule *r_shader_module) +{ + BLI_assert_msg(ELEM(stage, + shaderc_vertex_shader, + shaderc_geometry_shader, + shaderc_fragment_shader, + shaderc_compute_shader), + "Only forced ShaderC shader kinds are supported."); + + Vector spirv_module; + if (!compile_glsl_to_spirv(shader, sources, stage, spirv_module)) { + r_shader_module = VK_NULL_HANDLE; + return false; + } + + const bool use_module_cache = !info.do_static_compilation_; + uint64_t cache_key = 0; + if (use_module_cache) { + cache_key = spirv_module.hash(); + VkShaderModule *shader_module = cache_.lookup_ptr(cache_key); + if (shader_module) { + printf("%s: %s.%s\n", __func__, info.name_.c_str(), to_stage_name(stage).c_str()); + stats_.shader_modules_reused += 1; + *r_shader_module = *shader_module; + return true; + } + } + + if (!build_shader_module(shader, spirv_module, r_shader_module)) { + r_shader_module = VK_NULL_HANDLE; + return false; + } + + if (use_module_cache) { + cache_.add_new(cache_key, *r_shader_module); + cached_values_.add_new(*r_shader_module); + } + return true; +} + +void VKShaderModules::destruct(VkShaderModule vk_shader_module) +{ + if (cached_values_.contains(vk_shader_module)) { + return; + } + + VK_ALLOCATION_CALLBACKS + const VKDevice &device = VKBackend::get().device_get(); + vkDestroyShaderModule(device.device_get(), vk_shader_module, vk_allocation_callbacks); +} + +void VKShaderModules::free_data() +{ + debug_print(); + + VK_ALLOCATION_CALLBACKS + const VKDevice &device = VKBackend::get().device_get(); + for (VkShaderModule vk_shader_module : cached_values_) { + vkDestroyShaderModule(device.device_get(), vk_shader_module, vk_allocation_callbacks); + } + cache_.clear(); + cached_values_.clear(); +} + +/* -------------------------------------------------------------------- */ +/** \name Frontend compilation (GLSL -> SpirV) + * + * \{ */ + static std::string combine_sources(Span sources) { char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size()); @@ -167,7 +204,8 @@ bool VKShaderModules::build_shader_module(const VKShader &shader, void VKShaderModules::debug_print() const { std::stringstream ss; - ss << "VKShaderModules(glsl_spirv_time=" << stats_.glsl_to_spirv_time << "s" + ss << "VKShaderModules(reused_shader_modules=" << stats_.shader_modules_reused + << ", glsl_spirv_time=" << stats_.glsl_to_spirv_time << "s" << ", spirv_shader_module_time" << stats_.spirv_to_shader_module_time << "s)\n"; std::cout << ss.str(); } diff --git a/source/blender/gpu/vulkan/vk_shader_modules.hh b/source/blender/gpu/vulkan/vk_shader_modules.hh index 05e3d2763b6..a5f5922db3b 100644 --- a/source/blender/gpu/vulkan/vk_shader_modules.hh +++ b/source/blender/gpu/vulkan/vk_shader_modules.hh @@ -8,6 +8,8 @@ #pragma once +#include + #include "GPU_shader.hh" #include "vk_common.hh" @@ -30,9 +32,13 @@ class ShaderCreateInfo; */ class VKShaderModules { private: + Map cache_; + Set cached_values_; + struct { double glsl_to_spirv_time = 0.0; double spirv_to_shader_module_time = 0.0; + int64_t shader_modules_reused = 0; } stats_; public: -- 2.30.2