WIP: Vulkan: Reuse shader modules. #122044
@ -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
|
||||
|
@ -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_);
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -479,113 +479,37 @@ 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<const char *> 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<uint32_t> VKShader::compile_glsl_to_spirv(Span<const char *> 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<char> 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<uint32_t>();
|
||||
}
|
||||
|
||||
return Vector<uint32_t>(module.cbegin(), module.cend());
|
||||
}
|
||||
|
||||
void VKShader::build_shader_module(Span<uint32_t> 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();
|
||||
}
|
||||
|
||||
void VKShader::init(const shader::ShaderCreateInfo &info)
|
||||
{
|
||||
create_info_ = &info;
|
||||
VKShaderInterface *vk_interface = new VKShaderInterface();
|
||||
vk_interface->init(info);
|
||||
interface = vk_interface;
|
||||
}
|
||||
|
||||
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 +518,16 @@ VKShader::~VKShader()
|
||||
}
|
||||
/* Reset not owning handles. */
|
||||
vk_descriptor_set_layout_ = VK_NULL_HANDLE;
|
||||
create_info_ = nullptr;
|
||||
}
|
||||
|
||||
void VKShader::build_shader_module(MutableSpan<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.");
|
||||
const VKDevice &device = VKBackend::get().device_get();
|
||||
VKDevice &device = VKBackend::get().device_get();
|
||||
sources[SOURCES_INDEX_VERSION] = device.glsl_patch_get();
|
||||
Vector<uint32_t> 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<const char *> sources)
|
||||
@ -651,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) {
|
||||
@ -686,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;
|
||||
}
|
||||
@ -798,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";
|
||||
@ -830,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) {
|
||||
|
@ -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<const char *> sources) override;
|
||||
void geometry_shader_from_glsl(MutableSpan<const char *> sources) override;
|
||||
@ -128,8 +134,6 @@ class VKShader : public Shader {
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<uint32_t> compile_glsl_to_spirv(Span<const char *> sources, shaderc_shader_kind kind);
|
||||
void build_shader_module(Span<uint32_t> spirv_module, VkShaderModule *r_shader_module);
|
||||
void build_shader_module(MutableSpan<const char *> sources,
|
||||
shaderc_shader_kind stage,
|
||||
VkShaderModule *r_shader_module);
|
||||
|
215
source/blender/gpu/vulkan/vk_shader_modules.cc
Normal file
215
source/blender/gpu/vulkan/vk_shader_modules.cc
Normal file
@ -0,0 +1,215 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#include "BLI_hash.hh"
|
||||
#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 <sstream>
|
||||
|
||||
namespace blender::gpu {
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
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());
|
||||
std::string result(sources_combined);
|
||||
MEM_freeN(sources_combined);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool VKShaderModules::compile_glsl_to_spirv(VKShader &shader,
|
||||
Span<const char *> sources,
|
||||
shaderc_shader_kind stage,
|
||||
Vector<uint32_t> &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<char> 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<uint32_t> 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(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();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
} // namespace blender::gpu
|
65
source/blender/gpu/vulkan/vk_shader_modules.hh
Normal file
65
source/blender/gpu/vulkan/vk_shader_modules.hh
Normal file
@ -0,0 +1,65 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup gpu
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <BLI_map.hh>
|
||||
|
||||
#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:
|
||||
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:
|
||||
bool construct(VKShader &shader,
|
||||
const shader::ShaderCreateInfo &info,
|
||||
Span<const char *> 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<const char *> sources,
|
||||
shaderc_shader_kind stage,
|
||||
Vector<uint32_t> &r_compiled_spirv);
|
||||
bool build_shader_module(const VKShader &shader,
|
||||
Span<uint32_t> spirv_module,
|
||||
VkShaderModule *r_shader_module);
|
||||
};
|
||||
|
||||
} // namespace blender::gpu
|
Loading…
Reference in New Issue
Block a user