Vulkan: Spirv cache.

This commit is contained in:
Attila Uygun 2021-02-11 01:26:34 +01:00
parent 580ff678ec
commit f332246ea9
2 changed files with 33 additions and 25 deletions

View File

@ -397,20 +397,30 @@ void RendererVulkan::CreateShader(std::shared_ptr<void> impl_data,
Primitive primitive) { Primitive primitive) {
auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get()); auto shader = reinterpret_cast<ShaderVulkan*>(impl_data.get());
VkShaderModule vert_shader_module; auto it = spirv_cache_.find(source->name());
{ if (it == spirv_cache_.end()) {
// TODO: Reuse compiled spirv on context-lost. std::array<std::vector<uint8_t>, 2> spirv;
std::string error; std::string error;
shader->spirv_vertex = spirv[0] = CompileGlsl(EShLangVertex, source->GetVertexSource(), &error);
CompileGlsl(EShLangVertex, source->GetVertexSource(), &error);
if (!error.empty()) if (!error.empty())
DLOG << source->name() << " vertex shader compile error: " << error; DLOG << source->name() << " vertex shader compile error: " << error;
spirv[1] =
CompileGlsl(EShLangFragment, source->GetFragmentSource(), &error);
if (!error.empty())
DLOG << source->name() << " fragment shader compile error: " << error;
it = spirv_cache_.insert({source->name(), spirv}).first;
}
auto& spirv_vertex = it->second[0];
auto& spirv_fragment = it->second[1];
VkShaderModule vert_shader_module;
{
VkShaderModuleCreateInfo shader_module_info{}; VkShaderModuleCreateInfo shader_module_info{};
shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_info.codeSize = shader->spirv_vertex.size(); shader_module_info.codeSize = spirv_vertex.size();
shader_module_info.pCode = shader_module_info.pCode =
reinterpret_cast<const uint32_t*>(shader->spirv_vertex.data()); reinterpret_cast<const uint32_t*>(spirv_vertex.data());
if (vkCreateShaderModule(device_, &shader_module_info, nullptr, if (vkCreateShaderModule(device_, &shader_module_info, nullptr,
&vert_shader_module) != VK_SUCCESS) { &vert_shader_module) != VK_SUCCESS) {
@ -421,18 +431,11 @@ void RendererVulkan::CreateShader(std::shared_ptr<void> impl_data,
VkShaderModule frag_shader_module; VkShaderModule frag_shader_module;
{ {
// TODO: Reuse compiled spirv on context-lost.
std::string error;
shader->spirv_fragment =
CompileGlsl(EShLangFragment, source->GetFragmentSource(), &error);
if (!error.empty())
DLOG << source->name() << " fragment shader compile error: " << error;
VkShaderModuleCreateInfo shader_module_info{}; VkShaderModuleCreateInfo shader_module_info{};
shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
shader_module_info.codeSize = shader->spirv_fragment.size(); shader_module_info.codeSize = spirv_fragment.size();
shader_module_info.pCode = shader_module_info.pCode =
reinterpret_cast<const uint32_t*>(shader->spirv_fragment.data()); reinterpret_cast<const uint32_t*>(spirv_fragment.data());
if (vkCreateShaderModule(device_, &shader_module_info, nullptr, if (vkCreateShaderModule(device_, &shader_module_info, nullptr,
&frag_shader_module) != VK_SUCCESS) { &frag_shader_module) != VK_SUCCESS) {
@ -441,7 +444,7 @@ void RendererVulkan::CreateShader(std::shared_ptr<void> impl_data,
} }
} }
if (!CreatePipelineLayout(shader)) if (!CreatePipelineLayout(shader, spirv_vertex, spirv_fragment))
return; return;
VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; VkPipelineShaderStageCreateInfo vert_shader_stage_info{};
@ -1505,19 +1508,21 @@ void RendererVulkan::ImageMemoryBarrier(VkImage image,
nullptr, 1, &image_mem_barrier); nullptr, 1, &image_mem_barrier);
} }
bool RendererVulkan::CreatePipelineLayout(ShaderVulkan* shader) { bool RendererVulkan::CreatePipelineLayout(
ShaderVulkan* shader,
const std::vector<uint8_t>& spirv_vertex,
const std::vector<uint8_t>& spirv_fragment) {
SpvReflectShaderModule module_vertex; SpvReflectShaderModule module_vertex;
SpvReflectResult result = spvReflectCreateShaderModule( SpvReflectResult result = spvReflectCreateShaderModule(
shader->spirv_vertex.size(), shader->spirv_vertex.data(), &module_vertex); spirv_vertex.size(), spirv_vertex.data(), &module_vertex);
if (result != SPV_REFLECT_RESULT_SUCCESS) { if (result != SPV_REFLECT_RESULT_SUCCESS) {
DLOG << "SPIR-V reflection failed to parse vertex shader."; DLOG << "SPIR-V reflection failed to parse vertex shader.";
return false; return false;
} }
SpvReflectShaderModule module_fragment; SpvReflectShaderModule module_fragment;
result = spvReflectCreateShaderModule(shader->spirv_fragment.size(), result = spvReflectCreateShaderModule(
shader->spirv_fragment.data(), spirv_fragment.size(), spirv_fragment.data(), &module_fragment);
&module_fragment);
if (result != SPV_REFLECT_RESULT_SUCCESS) { if (result != SPV_REFLECT_RESULT_SUCCESS) {
DLOG << "SPIR-V reflection failed to parse fragment shader."; DLOG << "SPIR-V reflection failed to parse fragment shader.";
spvReflectDestroyShaderModule(&module_vertex); spvReflectDestroyShaderModule(&module_vertex);

View File

@ -101,6 +101,9 @@ class RendererVulkan : public Renderer {
using PipelineDeathRow = using PipelineDeathRow =
std::vector<std::tuple<VkPipeline, VkPipelineLayout>>; std::vector<std::tuple<VkPipeline, VkPipelineLayout>>;
std::unordered_map<std::string, std::array<std::vector<uint8_t>, 2>>
spirv_cache_;
struct GeometryVulkan { struct GeometryVulkan {
Buffer<VkBuffer> buffer; Buffer<VkBuffer> buffer;
uint32_t num_vertices = 0; uint32_t num_vertices = 0;
@ -115,8 +118,6 @@ class RendererVulkan : public Renderer {
size_t push_constants_size = 0; size_t push_constants_size = 0;
std::vector<std::string> sampler_uniform_names; std::vector<std::string> sampler_uniform_names;
int desc_set_count = 0; int desc_set_count = 0;
std::vector<uint8_t> spirv_vertex;
std::vector<uint8_t> spirv_fragment;
VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE;
VkPipeline pipeline = VK_NULL_HANDLE; VkPipeline pipeline = VK_NULL_HANDLE;
}; };
@ -248,7 +249,9 @@ class RendererVulkan : public Renderer {
VkImageLayout old_layout, VkImageLayout old_layout,
VkImageLayout new_layout); VkImageLayout new_layout);
bool CreatePipelineLayout(ShaderVulkan* shader); bool CreatePipelineLayout(ShaderVulkan* shader,
const std::vector<uint8_t>& spirv_vertex,
const std::vector<uint8_t>& spirv_fragment);
void DrawListBegin(); void DrawListBegin();
void DrawListEnd(); void DrawListEnd();