WIP: Vulkan: Reuse shader modules. #122044

Draft
Jeroen Bakker wants to merge 3 commits from Jeroen-Bakker/blender:vulkan/shader-modules into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
3 changed files with 102 additions and 53 deletions
Showing only changes of commit d4f38c14be - Show all commits

View File

@ -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) {

View File

@ -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<const char *> 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<uint32_t> 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<const char *> 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<uint32_t> 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<const char *> 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();
}

View File

@ -8,6 +8,8 @@
#pragma once
#include <BLI_map.hh>
#include "GPU_shader.hh"
#include "vk_common.hh"
@ -30,9 +32,13 @@ class ShaderCreateInfo;
*/
class VKShaderModules {
private:
Map<uint64_t, VkShaderModule> cache_;
Set<VkShaderModule> 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: