From f332246ea95122c9f95af5e24d361050c5483087 Mon Sep 17 00:00:00 2001 From: Attila Uygun Date: Thu, 11 Feb 2021 01:26:34 +0100 Subject: [PATCH] Vulkan: Spirv cache. --- src/engine/renderer/vulkan/renderer_vulkan.cc | 49 ++++++++++--------- src/engine/renderer/vulkan/renderer_vulkan.h | 9 ++-- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/engine/renderer/vulkan/renderer_vulkan.cc b/src/engine/renderer/vulkan/renderer_vulkan.cc index 095f43a..ecdce95 100644 --- a/src/engine/renderer/vulkan/renderer_vulkan.cc +++ b/src/engine/renderer/vulkan/renderer_vulkan.cc @@ -397,20 +397,30 @@ void RendererVulkan::CreateShader(std::shared_ptr impl_data, Primitive primitive) { auto shader = reinterpret_cast(impl_data.get()); - VkShaderModule vert_shader_module; - { - // TODO: Reuse compiled spirv on context-lost. + auto it = spirv_cache_.find(source->name()); + if (it == spirv_cache_.end()) { + std::array, 2> spirv; std::string error; - shader->spirv_vertex = - CompileGlsl(EShLangVertex, source->GetVertexSource(), &error); + spirv[0] = CompileGlsl(EShLangVertex, source->GetVertexSource(), &error); if (!error.empty()) 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{}; 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 = - reinterpret_cast(shader->spirv_vertex.data()); + reinterpret_cast(spirv_vertex.data()); if (vkCreateShaderModule(device_, &shader_module_info, nullptr, &vert_shader_module) != VK_SUCCESS) { @@ -421,18 +431,11 @@ void RendererVulkan::CreateShader(std::shared_ptr impl_data, 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{}; 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 = - reinterpret_cast(shader->spirv_fragment.data()); + reinterpret_cast(spirv_fragment.data()); if (vkCreateShaderModule(device_, &shader_module_info, nullptr, &frag_shader_module) != VK_SUCCESS) { @@ -441,7 +444,7 @@ void RendererVulkan::CreateShader(std::shared_ptr impl_data, } } - if (!CreatePipelineLayout(shader)) + if (!CreatePipelineLayout(shader, spirv_vertex, spirv_fragment)) return; VkPipelineShaderStageCreateInfo vert_shader_stage_info{}; @@ -1505,19 +1508,21 @@ void RendererVulkan::ImageMemoryBarrier(VkImage image, nullptr, 1, &image_mem_barrier); } -bool RendererVulkan::CreatePipelineLayout(ShaderVulkan* shader) { +bool RendererVulkan::CreatePipelineLayout( + ShaderVulkan* shader, + const std::vector& spirv_vertex, + const std::vector& spirv_fragment) { SpvReflectShaderModule module_vertex; 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) { DLOG << "SPIR-V reflection failed to parse vertex shader."; return false; } SpvReflectShaderModule module_fragment; - result = spvReflectCreateShaderModule(shader->spirv_fragment.size(), - shader->spirv_fragment.data(), - &module_fragment); + result = spvReflectCreateShaderModule( + spirv_fragment.size(), spirv_fragment.data(), &module_fragment); if (result != SPV_REFLECT_RESULT_SUCCESS) { DLOG << "SPIR-V reflection failed to parse fragment shader."; spvReflectDestroyShaderModule(&module_vertex); diff --git a/src/engine/renderer/vulkan/renderer_vulkan.h b/src/engine/renderer/vulkan/renderer_vulkan.h index 2e182c4..1fa4ad1 100644 --- a/src/engine/renderer/vulkan/renderer_vulkan.h +++ b/src/engine/renderer/vulkan/renderer_vulkan.h @@ -101,6 +101,9 @@ class RendererVulkan : public Renderer { using PipelineDeathRow = std::vector>; + std::unordered_map, 2>> + spirv_cache_; + struct GeometryVulkan { Buffer buffer; uint32_t num_vertices = 0; @@ -115,8 +118,6 @@ class RendererVulkan : public Renderer { size_t push_constants_size = 0; std::vector sampler_uniform_names; int desc_set_count = 0; - std::vector spirv_vertex; - std::vector spirv_fragment; VkPipelineLayout pipeline_layout = VK_NULL_HANDLE; VkPipeline pipeline = VK_NULL_HANDLE; }; @@ -248,7 +249,9 @@ class RendererVulkan : public Renderer { VkImageLayout old_layout, VkImageLayout new_layout); - bool CreatePipelineLayout(ShaderVulkan* shader); + bool CreatePipelineLayout(ShaderVulkan* shader, + const std::vector& spirv_vertex, + const std::vector& spirv_fragment); void DrawListBegin(); void DrawListEnd();