diff options
| author | Stenzek <stenzek@gmail.com> | 2018-02-25 01:15:35 +1000 |
|---|---|---|
| committer | Stenzek <stenzek@gmail.com> | 2018-03-10 15:56:30 +1000 |
| commit | dec0c3bce85ceda89ea05f00b94aad00e675598d (patch) | |
| tree | 8c967a47d8a531ae3f0245e419d7ec652535ee3a /Source/Core/VideoBackends/Vulkan | |
| parent | 24df896eb8d1520706b086039743ef2dca7ce6df (diff) | |
Move shader caches to VideoCommon
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Constants.h | 4 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/ObjectCache.cpp | 24 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.cpp | 28 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.h | 4 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/ShaderCache.cpp | 527 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/ShaderCache.h | 98 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/StateTracker.cpp | 457 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/StateTracker.h | 86 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Util.cpp | 23 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/VertexManager.cpp | 6 | ||||
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/main.cpp | 22 |
11 files changed, 81 insertions, 1198 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Constants.h b/Source/Core/VideoBackends/Vulkan/Constants.h index c6758c6fdc..f2af115b2a 100644 --- a/Source/Core/VideoBackends/Vulkan/Constants.h +++ b/Source/Core/VideoBackends/Vulkan/Constants.h @@ -48,8 +48,7 @@ enum DESCRIPTOR_SET_BIND_POINT // - Standard // - Per-stage UBO (VS/GS/PS, VS constants accessible from PS) // - 8 combined image samplers (accessible from PS) -// - BBox Enabled -// - Same as standard, plus a single SSBO accessible from PS +// - 1 SSBO accessible from PS if supported // - Push Constant // - Same as standard, plus 128 bytes of push constants, accessible from all stages. // - Texture Decoding @@ -67,7 +66,6 @@ enum DESCRIPTOR_SET_BIND_POINT enum PIPELINE_LAYOUT { PIPELINE_LAYOUT_STANDARD, - PIPELINE_LAYOUT_BBOX, PIPELINE_LAYOUT_PUSH_CONSTANT, PIPELINE_LAYOUT_TEXTURE_CONVERSION, PIPELINE_LAYOUT_UTILITY, diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index cbd28b3630..8f5721b4d3 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -109,6 +109,9 @@ bool ObjectCache::CreateDescriptorSetLayouts() static const VkDescriptorSetLayoutBinding single_ubo_set_bindings[] = { 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_GEOMETRY_BIT | VK_SHADER_STAGE_FRAGMENT_BIT}; + + // The geometry shader buffer must be last in this binding set, as we don't include it + // if geometry shaders are not supported by the device. See the decrement below. static const VkDescriptorSetLayoutBinding per_stage_ubo_set_bindings[] = { {UBO_DESCRIPTOR_SET_BINDING_PS, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_FRAGMENT_BIT}, @@ -139,7 +142,7 @@ bool ObjectCache::CreateDescriptorSetLayouts() {7, VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1, VK_SHADER_STAGE_COMPUTE_BIT}, }; - static const VkDescriptorSetLayoutCreateInfo create_infos[NUM_DESCRIPTOR_SET_LAYOUTS] = { + VkDescriptorSetLayoutCreateInfo create_infos[NUM_DESCRIPTOR_SET_LAYOUTS] = { {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, static_cast<u32>(ArraySize(single_ubo_set_bindings)), single_ubo_set_bindings}, {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, @@ -153,6 +156,10 @@ bool ObjectCache::CreateDescriptorSetLayouts() {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, nullptr, 0, static_cast<u32>(ArraySize(compute_set_bindings)), compute_set_bindings}}; + // Don't set the GS bit if geometry shaders aren't available. + if (!g_vulkan_context->SupportsGeometryShaders()) + create_infos[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS].bindingCount--; + for (size_t i = 0; i < NUM_DESCRIPTOR_SET_LAYOUTS; i++) { VkResult res = vkCreateDescriptorSetLayout(g_vulkan_context->GetDevice(), &create_infos[i], @@ -180,12 +187,11 @@ bool ObjectCache::CreatePipelineLayouts() { VkResult res; - // Descriptor sets for each pipeline layout + // Descriptor sets for each pipeline layout. + // In the standard set, the SSBO must be the last descriptor, as we do not include it + // when fragment stores and atomics are not supported by the device. VkDescriptorSetLayout standard_sets[] = { m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS], - m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS]}; - VkDescriptorSetLayout bbox_sets[] = { - m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PER_STAGE_UNIFORM_BUFFERS], m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_PIXEL_SHADER_SAMPLERS], m_descriptor_set_layouts[DESCRIPTOR_SET_LAYOUT_SHADER_STORAGE_BUFFERS]}; VkDescriptorSetLayout texture_conversion_sets[] = { @@ -207,10 +213,6 @@ bool ObjectCache::CreatePipelineLayouts() {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, static_cast<u32>(ArraySize(standard_sets)), standard_sets, 0, nullptr}, - // BBox - {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, - static_cast<u32>(ArraySize(bbox_sets)), bbox_sets, 0, nullptr}, - // Push Constant {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, static_cast<u32>(ArraySize(standard_sets)), standard_sets, 1, &push_constant_range}, @@ -228,6 +230,10 @@ bool ObjectCache::CreatePipelineLayouts() {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0, static_cast<u32>(ArraySize(compute_sets)), compute_sets, 1, &compute_push_constant_range}}; + // If bounding box is unsupported, don't bother with the SSBO descriptor set. + if (!g_vulkan_context->SupportsBoundingBox()) + pipeline_layout_info[PIPELINE_LAYOUT_STANDARD].setLayoutCount--; + for (size_t i = 0; i < NUM_PIPELINE_LAYOUTS; i++) { if ((res = vkCreatePipelineLayout(g_vulkan_context->GetDevice(), &pipeline_layout_info[i], diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 588e4b0919..1beb4f3461 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -224,7 +224,7 @@ std::tuple<VkBuffer, u32> Renderer::UpdateUtilityUniformBuffer(const void* unifo void Renderer::SetPipeline(const AbstractPipeline* pipeline) { - m_graphics_pipeline = static_cast<const VKPipeline*>(pipeline); + StateTracker::GetInstance()->SetPipeline(static_cast<const VKPipeline*>(pipeline)); } void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, const void* vertices, @@ -305,7 +305,7 @@ void Renderer::DrawUtilityPipeline(const void* uniforms, u32 uniforms_size, cons // Build commands. VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_graphics_pipeline->GetPipeline()); + StateTracker::GetInstance()->GetPipeline()->GetVkPipeline()); if (vertex_buffer != VK_NULL_HANDLE) vkCmdBindVertexBuffers(command_buffer, 0, 1, &vertex_buffer, &vertex_buffer_offset); @@ -759,9 +759,6 @@ void Renderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& xfb_region // Clean up stale textures. TextureCache::GetInstance()->Cleanup(frameCount); - - // Pull in now-ready async shaders. - g_shader_cache->RetrieveAsyncShaders(); } void Renderer::DrawScreen(VKTexture* xfb_texture, const EFBRectangle& xfb_region) @@ -975,10 +972,8 @@ void Renderer::CheckForConfigChanges() RecreateEFBFramebuffer(); RecompileShaders(); FramebufferManager::GetInstance()->RecompileShaders(); - g_shader_cache->ReloadShaderAndPipelineCaches(); + g_shader_cache->ReloadPipelineCache(); g_shader_cache->RecompileSharedShaders(); - StateTracker::GetInstance()->InvalidateShaderPointers(); - StateTracker::GetInstance()->ReloadPipelineUIDCache(); } // For vsync, we need to change the present mode, which means recreating the swap chain. @@ -1021,8 +1016,6 @@ void Renderer::BindEFBToStateTracker() FramebufferManager::GetInstance()->GetEFBClearRenderPass()); StateTracker::GetInstance()->SetFramebuffer( FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size); - StateTracker::GetInstance()->SetMultisamplingstate( - FramebufferManager::GetInstance()->GetEFBMultisamplingState()); m_current_framebuffer = nullptr; m_current_framebuffer_width = FramebufferManager::GetInstance()->GetEFBWidth(); m_current_framebuffer_height = FramebufferManager::GetInstance()->GetEFBHeight(); @@ -1125,21 +1118,6 @@ void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer, num_clear_values); } -void Renderer::SetRasterizationState(const RasterizationState& state) -{ - StateTracker::GetInstance()->SetRasterizationState(state); -} - -void Renderer::SetDepthState(const DepthState& state) -{ - StateTracker::GetInstance()->SetDepthState(state); -} - -void Renderer::SetBlendingState(const BlendingState& state) -{ - StateTracker::GetInstance()->SetBlendState(state); -} - void Renderer::SetTexture(u32 index, const AbstractTexture* texture) { // Texture should always be in SHADER_READ_ONLY layout prior to use. diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index e62849ac19..b2662a3d4b 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -77,10 +77,7 @@ public: void SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer, const ClearColor& color_value = {}, float depth_value = 0.0f) override; - void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const MathUtil::Rectangle<int>& rc) override; - void SetRasterizationState(const RasterizationState& state) override; - void SetDepthState(const DepthState& state) override; void SetTexture(u32 index, const AbstractTexture* texture) override; void SetSamplerState(u32 index, const SamplerState& state) override; void UnbindTexture(const AbstractTexture* texture) override; @@ -135,6 +132,5 @@ private: // Shaders used for clear/blit. VkShaderModule m_clear_fragment_shader = VK_NULL_HANDLE; - const VKPipeline* m_graphics_pipeline = nullptr; }; } diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp index 9f77958b0f..2fa75f4913 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp @@ -23,12 +23,7 @@ #include "VideoBackends/Vulkan/Util.h" #include "VideoBackends/Vulkan/VertexFormat.h" #include "VideoBackends/Vulkan/VulkanContext.h" -#include "VideoCommon/AsyncShaderCompiler.h" -#include "VideoCommon/GeometryShaderGen.h" #include "VideoCommon/Statistics.h" -#include "VideoCommon/UberShaderPixel.h" -#include "VideoCommon/UberShaderVertex.h" -#include "VideoCommon/VertexLoaderManager.h" namespace Vulkan { @@ -41,7 +36,6 @@ ShaderCache::ShaderCache() ShaderCache::~ShaderCache() { DestroyPipelineCache(); - DestroyShaderCaches(); DestroySharedShaders(); } @@ -49,7 +43,6 @@ bool ShaderCache::Initialize() { if (g_ActiveConfig.bShaderCache) { - LoadShaderCaches(); if (!LoadPipelineCache()) return false; } @@ -62,21 +55,11 @@ bool ShaderCache::Initialize() if (!CompileSharedShaders()) return false; - m_async_shader_compiler = std::make_unique<VideoCommon::AsyncShaderCompiler>(); - m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.CanPrecompileUberShaders() ? - g_ActiveConfig.GetShaderPrecompilerThreads() : - g_ActiveConfig.GetShaderCompilerThreads()); return true; } void ShaderCache::Shutdown() { - if (m_async_shader_compiler) - { - m_async_shader_compiler->StopWorkerThreads(); - m_async_shader_compiler->RetrieveWorkItems(); - } - if (g_ActiveConfig.bShaderCache && m_pipeline_cache != VK_NULL_HANDLE) SavePipelineCache(); } @@ -393,39 +376,13 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info) VkPipeline ShaderCache::GetPipeline(const PipelineInfo& info) { - return GetPipelineWithCacheResult(info).first; -} - -std::pair<VkPipeline, bool> ShaderCache::GetPipelineWithCacheResult(const PipelineInfo& info) -{ auto iter = m_pipeline_objects.find(info); if (iter != m_pipeline_objects.end()) - { - // If it's background compiling, ignore it, and recompile it synchronously. - if (!iter->second.second) - return std::make_pair(iter->second.first, true); - else - m_pipeline_objects.erase(iter); - } + return iter->second; VkPipeline pipeline = CreatePipeline(info); - m_pipeline_objects.emplace(info, std::make_pair(pipeline, false)); - _assert_(pipeline != VK_NULL_HANDLE); - return {pipeline, false}; -} - -std::pair<std::pair<VkPipeline, bool>, bool> -ShaderCache::GetPipelineWithCacheResultAsync(const PipelineInfo& info) -{ - auto iter = m_pipeline_objects.find(info); - if (iter != m_pipeline_objects.end()) - return std::make_pair(iter->second, true); - - // Kick a job off. - m_async_shader_compiler->QueueWorkItem( - m_async_shader_compiler->CreateWorkItem<PipelineCompilerWorkItem>(info)); - m_pipeline_objects.emplace(info, std::make_pair(static_cast<VkPipeline>(VK_NULL_HANDLE), true)); - return std::make_pair(std::make_pair(static_cast<VkPipeline>(VK_NULL_HANDLE), true), false); + m_pipeline_objects.emplace(info, pipeline); + return pipeline; } VkPipeline ShaderCache::CreateComputePipeline(const ComputePipelineInfo& info) @@ -465,11 +422,10 @@ VkPipeline ShaderCache::GetComputePipeline(const ComputePipelineInfo& info) void ShaderCache::ClearPipelineCache() { - // TODO: Stop any async compiling happening. for (const auto& it : m_pipeline_objects) { - if (it.second.first != VK_NULL_HANDLE) - vkDestroyPipeline(g_vulkan_context->GetDevice(), it.second.first, nullptr); + if (it.second != VK_NULL_HANDLE) + vkDestroyPipeline(g_vulkan_context->GetDevice(), it.second, nullptr); } m_pipeline_objects.clear(); @@ -673,266 +629,6 @@ void ShaderCache::SavePipelineCache() disk_cache.Close(); } -// Cache inserter that is called back when reading from the file -template <typename Uid> -struct ShaderCacheReader : public LinearDiskCacheReader<Uid, u32> -{ - ShaderCacheReader(std::map<Uid, std::pair<VkShaderModule, bool>>& shader_map) - : m_shader_map(shader_map) - { - } - void Read(const Uid& key, const u32* value, u32 value_size) override - { - // We don't insert null modules into the shader map since creation could succeed later on. - // e.g. we're generating bad code, but fix this in a later version, and for some reason - // the cache is not invalidated. - VkShaderModule module = Util::CreateShaderModule(value, value_size); - if (module == VK_NULL_HANDLE) - return; - - m_shader_map.emplace(key, std::make_pair(module, false)); - } - - std::map<Uid, std::pair<VkShaderModule, bool>>& m_shader_map; -}; - -void ShaderCache::LoadShaderCaches() -{ - ShaderCacheReader<VertexShaderUid> vs_reader(m_vs_cache.shader_map); - m_vs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "VS", true, true), - vs_reader); - - ShaderCacheReader<PixelShaderUid> ps_reader(m_ps_cache.shader_map); - m_ps_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "PS", true, true), - ps_reader); - - if (g_vulkan_context->SupportsGeometryShaders()) - { - ShaderCacheReader<GeometryShaderUid> gs_reader(m_gs_cache.shader_map); - m_gs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "GS", true, true), - gs_reader); - } - - ShaderCacheReader<UberShader::VertexShaderUid> uber_vs_reader(m_uber_vs_cache.shader_map); - m_uber_vs_cache.disk_cache.OpenAndRead( - GetDiskShaderCacheFileName(APIType::Vulkan, "UberVS", false, true), uber_vs_reader); - ShaderCacheReader<UberShader::PixelShaderUid> uber_ps_reader(m_uber_ps_cache.shader_map); - m_uber_ps_cache.disk_cache.OpenAndRead( - GetDiskShaderCacheFileName(APIType::Vulkan, "UberPS", false, true), uber_ps_reader); - - SETSTAT(stats.numPixelShadersCreated, static_cast<int>(m_ps_cache.shader_map.size())); - SETSTAT(stats.numPixelShadersAlive, static_cast<int>(m_ps_cache.shader_map.size())); - SETSTAT(stats.numVertexShadersCreated, static_cast<int>(m_vs_cache.shader_map.size())); - SETSTAT(stats.numVertexShadersAlive, static_cast<int>(m_vs_cache.shader_map.size())); -} - -template <typename T> -static void DestroyShaderCache(T& cache) -{ - cache.disk_cache.Sync(); - cache.disk_cache.Close(); - for (const auto& it : cache.shader_map) - { - if (it.second.first != VK_NULL_HANDLE) - vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second.first, nullptr); - } - cache.shader_map.clear(); -} - -void ShaderCache::DestroyShaderCaches() -{ - DestroyShaderCache(m_vs_cache); - DestroyShaderCache(m_ps_cache); - - if (g_vulkan_context->SupportsGeometryShaders()) - DestroyShaderCache(m_gs_cache); - - DestroyShaderCache(m_uber_vs_cache); - DestroyShaderCache(m_uber_ps_cache); - - SETSTAT(stats.numPixelShadersCreated, 0); - SETSTAT(stats.numPixelShadersAlive, 0); - SETSTAT(stats.numVertexShadersCreated, 0); - SETSTAT(stats.numVertexShadersAlive, 0); -} - -VkShaderModule ShaderCache::GetVertexShaderForUid(const VertexShaderUid& uid) -{ - auto it = m_vs_cache.shader_map.find(uid); - if (it != m_vs_cache.shader_map.end()) - { - // If it's pending, compile it synchronously. - if (!it->second.second) - return it->second.first; - else - m_vs_cache.shader_map.erase(it); - } - - // Not in the cache, so compile the shader. - ShaderCompiler::SPIRVCodeVector spv; - VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = - GenerateVertexShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); - if (ShaderCompiler::CompileVertexShader(&spv, source_code.GetBuffer().c_str(), - source_code.GetBuffer().length())) - { - module = Util::CreateShaderModule(spv.data(), spv.size()); - - // Append to shader cache if it created successfully. - if (module != VK_NULL_HANDLE) - { - m_vs_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size())); - INCSTAT(stats.numVertexShadersCreated); - INCSTAT(stats.numVertexShadersAlive); - } - } - - // We still insert null entries to prevent further compilation attempts. - m_vs_cache.shader_map.emplace(uid, std::make_pair(module, false)); - return module; -} - -VkShaderModule ShaderCache::GetGeometryShaderForUid(const GeometryShaderUid& uid) -{ - _assert_(g_vulkan_context->SupportsGeometryShaders()); - auto it = m_gs_cache.shader_map.find(uid); - if (it != m_gs_cache.shader_map.end()) - { - // If it's pending, compile it synchronously. - if (!it->second.second) - return it->second.first; - else - m_gs_cache.shader_map.erase(it); - } - - // Not in the cache, so compile the shader. - ShaderCompiler::SPIRVCodeVector spv; - VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = - GenerateGeometryShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); - if (ShaderCompiler::CompileGeometryShader(&spv, source_code.GetBuffer().c_str(), - source_code.GetBuffer().length())) - { - module = Util::CreateShaderModule(spv.data(), spv.size()); - - // Append to shader cache if it created successfully. - if (module != VK_NULL_HANDLE) - m_gs_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size())); - } - - // We still insert null entries to prevent further compilation attempts. - m_gs_cache.shader_map.emplace(uid, std::make_pair(module, false)); - return module; -} - -VkShaderModule ShaderCache::GetPixelShaderForUid(const PixelShaderUid& uid) -{ - auto it = m_ps_cache.shader_map.find(uid); - if (it != m_ps_cache.shader_map.end()) - { - // If it's pending, compile it synchronously. - if (!it->second.second) - return it->second.first; - else - m_ps_cache.shader_map.erase(it); - } - - // Not in the cache, so compile the shader. - ShaderCompiler::SPIRVCodeVector spv; - VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = - GeneratePixelShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); - if (ShaderCompiler::CompileFragmentShader(&spv, source_code.GetBuffer().c_str(), - source_code.GetBuffer().length())) - { - module = Util::CreateShaderModule(spv.data(), spv.size()); - - // Append to shader cache if it created successfully. - if (module != VK_NULL_HANDLE) - { - m_ps_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size())); - INCSTAT(stats.numPixelShadersCreated); - INCSTAT(stats.numPixelShadersAlive); - } - } - - // We still insert null entries to prevent further compilation attempts. - m_ps_cache.shader_map.emplace(uid, std::make_pair(module, false)); - return module; -} - -VkShaderModule ShaderCache::GetVertexUberShaderForUid(const UberShader::VertexShaderUid& uid) -{ - auto it = m_uber_vs_cache.shader_map.find(uid); - if (it != m_uber_vs_cache.shader_map.end()) - { - // If it's pending, compile it synchronously. - if (!it->second.second) - return it->second.first; - else - m_uber_vs_cache.shader_map.erase(it); - } - - // Not in the cache, so compile the shader. - ShaderCompiler::SPIRVCodeVector spv; - VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = UberShader::GenVertexShader( - APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); - if (ShaderCompiler::CompileVertexShader(&spv, source_code.GetBuffer().c_str(), - source_code.GetBuffer().length())) - { - module = Util::CreateShaderModule(spv.data(), spv.size()); - - // Append to shader cache if it created successfully. - if (module != VK_NULL_HANDLE) - { - m_uber_vs_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size())); - INCSTAT(stats.numVertexShadersCreated); - INCSTAT(stats.numVertexShadersAlive); - } - } - - // We still insert null entries to prevent further compilation attempts. - m_uber_vs_cache.shader_map.emplace(uid, std::make_pair(module, false)); - return module; -} - -VkShaderModule ShaderCache::GetPixelUberShaderForUid(const UberShader::PixelShaderUid& uid) -{ - auto it = m_uber_ps_cache.shader_map.find(uid); - if (it != m_uber_ps_cache.shader_map.end()) - { - // If it's pending, compile it synchronously. - if (!it->second.second) - return it->second.first; - else - m_uber_ps_cache.shader_map.erase(it); - } - - // Not in the cache, so compile the shader. - ShaderCompiler::SPIRVCodeVector spv; - VkShaderModule module = VK_NULL_HANDLE; - ShaderCode source_code = - UberShader::GenPixelShader(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData()); - if (ShaderCompiler::CompileFragmentShader(&spv, source_code.GetBuffer().c_str(), - source_code.GetBuffer().length())) - { - module = Util::CreateShaderModule(spv.data(), spv.size()); - - // Append to shader cache if it created successfully. - if (module != VK_NULL_HANDLE) - { - m_uber_ps_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size())); - INCSTAT(stats.numPixelShadersCreated); - INCSTAT(stats.numPixelShadersAlive); - } - } - - // We still insert null entries to prevent further compilation attempts. - m_uber_ps_cache.shader_map.emplace(uid, std::make_pair(module, false)); - return module; -} - void ShaderCache::RecompileSharedShaders() { DestroySharedShaders(); @@ -940,27 +636,15 @@ void ShaderCache::RecompileSharedShaders() PanicAlert("Failed to recompile shared shaders."); } -void ShaderCache::ReloadShaderAndPipelineCaches() +void ShaderCache::ReloadPipelineCache() { - m_async_shader_compiler->WaitUntilCompletion(); - m_async_shader_compiler->RetrieveWorkItems(); - SavePipelineCache(); - DestroyShaderCaches(); DestroyPipelineCache(); if (g_ActiveConfig.bShaderCache) - { - LoadShaderCaches(); LoadPipelineCache(); - } else - { CreatePipelineCache(); - } - - if (g_ActiveConfig.CanPrecompileUberShaders()) - PrecompileUberShaders(); } std::string ShaderCache::GetUtilityShaderHeader() const @@ -1160,203 +844,4 @@ void ShaderCache::DestroySharedShaders() DestroyShader(m_screen_quad_geometry_shader); DestroyShader(m_passthrough_geometry_shader); } - -void ShaderCache::CreateDummyPipeline(const UberShader::VertexShaderUid& vuid, - const GeometryShaderUid& guid, - const UberShader::PixelShaderUid& puid) -{ - PortableVertexDeclaration vertex_decl; - std::memset(&vertex_decl, 0, sizeof(vertex_decl)); - - PipelineInfo pinfo; - pinfo.vertex_format = - static_cast<const VertexFormat*>(VertexLoaderManager::GetUberVertexFormat(vertex_decl)); - pinfo.pipeline_layout = g_object_cache->GetPipelineLayout( - g_ActiveConfig.bBBoxEnable && g_ActiveConfig.BBoxUseFragmentShaderImplementation() ? - PIPELINE_LAYOUT_BBOX : - PIPELINE_LAYOUT_STANDARD); - pinfo.vs = GetVertexUberShaderForUid(vuid); - pinfo.gs = (!guid.GetUidData()->IsPassthrough() && g_vulkan_context->SupportsGeometryShaders()) ? - GetGeometryShaderForUid(guid) : - VK_NULL_HANDLE; - pinfo.ps = GetPixelUberShaderForUid(puid); - pinfo.render_pass = FramebufferManager::GetInstance()->GetEFBLoadRenderPass(); - pinfo.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex; - pinfo.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex; - pinfo.blend_state.hex = RenderState::GetNoBlendingBlendState().hex; - pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex; - pinfo.rasterization_state.primitive = - static_cast<PrimitiveType>(guid.GetUidData()->primitive_type); - GetPipelineWithCacheResultAsync(pinfo); -} - -void ShaderCache::PrecompileUberShaders() -{ - UberShader::EnumerateVertexShaderUids([&](const UberShader::VertexShaderUid& vuid) { - UberShader::EnumeratePixelShaderUids([&](const UberShader::PixelShaderUid& puid) { - // UIDs must have compatible texgens, a mismatching combination will never be queried. - if (vuid.GetUidData()->num_texgens != puid.GetUidData()->num_texgens) - return; - - EnumerateGeometryShaderUids([&](const GeometryShaderUid& guid) { - if (guid.GetUidData()->numTexGens != vuid.GetUidData()->num_texgens) - return; - - CreateDummyPipeline(vuid, guid, puid); - }); - }); - }); - - WaitForBackgroundCompilesToComplete(); - - // Switch to the runtime/background thread config. - m_async_shader_compiler->ResizeWorkerThreads(g_ActiveConfig.GetShaderCompilerThreads()); -} - -void ShaderCache::WaitForBackgroundCompilesToComplete() -{ - m_async_shader_compiler->WaitUntilCompletion([](size_t completed, size_t total) { - Host_UpdateProgressDialog(GetStringT("Compiling shaders...").c_str(), - static_cast<int>(completed), static_cast<int>(total)); - }); - m_async_shader_compiler->RetrieveWorkItems(); - Host_UpdateProgressDialog("", -1, -1); -} - -void ShaderCache::RetrieveAsyncShaders() -{ - m_async_shader_compiler->RetrieveWorkItems(); -} - -std::pair<VkShaderModule, bool> ShaderCache::GetVertexShaderForUidAsync(const VertexShaderUid& uid) -{ - auto it = m_vs_cache.shader_map.find(uid); - if (it != m_vs_cache.shader_map.end()) - return it->second; - - // Kick a compile job off. - m_async_shader_compiler->QueueWorkItem( - m_async_shader_compiler->CreateWorkItem<VertexShaderCompilerWorkItem>(uid)); - m_vs_cache.shader_map.emplace(uid, - std::make_pair(static_cast<VkShaderModule>(VK_NULL_HANDLE), true)); - return std::make_pair<VkShaderModule, bool>(VK_NULL_HANDLE, true); -} - -std::pair<VkShaderModule, bool> ShaderCache::GetPixelShaderForUidAsync(const PixelShaderUid& uid) -{ - auto it = m_ps_cache.shader_map.find(uid); - if (it != m_ps_cache.shader_map.end()) - return it->second; - - // Kick a compile job off. - m_async_shader_compiler->QueueWorkItem( - m_async_shader_compiler->CreateWorkItem<PixelShaderCompilerWorkItem>(uid)); - m_ps_cache.shader_map.emplace(uid, - std::make_pair(static_cast<VkShaderModule>(VK_NULL_HANDLE), true)); - return std::make_pair<VkShaderModule, bool>(VK_NULL_HANDLE, true); -} - -bool ShaderCache::VertexShaderCompilerWorkItem::Compile() -{ - ShaderCode code = - GenerateVertexShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), m_uid.GetUidData()); - if (!ShaderCompiler::CompileVertexShader(&m_spirv, code.GetBuffer().c_str(), - code.GetBuffer().length())) - return true; - - m_module = Util::CreateShaderModule(m_spirv.data(), m_spirv.size()); - return true; -} - -void ShaderCache::VertexShaderCompilerWorkItem::Retrieve() -{ - auto it = g_shader_cache->m_vs_cache.shader_map.find(m_uid); - if (it == g_shader_cache->m_vs_cache.shader_map.end()) - { - g_shader_cache->m_vs_cache.shader_map.emplace(m_uid, std::make_pair(m_module, false)); - g_shader_cache->m_vs_cache.disk_cache.Append(m_uid, m_spirv.data(), - static_cast<u32>(m_spirv.size())); - return; - } - - // The main thread may have also compiled this shader. - if (!it->second.second) - { - if (m_module != VK_NULL_HANDLE) - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_module, nullptr); - return; - } - - // No longer pending. - it->second.first = m_module; - it->second.second = false; - g_shader_cache->m_vs_cache.disk_cache.Append(m_uid, m_spirv.data(), - static_cast<u32>(m_spirv.size())); -} - -bool ShaderCache::PixelShaderCompilerWorkItem::Compile() -{ - ShaderCode code = - GeneratePixelShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), m_uid.GetUidData()); - if (!ShaderCompiler::CompileFragmentShader(&m_spirv, code.GetBuffer().c_str(), - code.GetBuffer().length())) - return true; - - m_module = Util::CreateShaderModule(m_spirv.data(), m_spirv.size()); - return true; -} - -void ShaderCache::PixelShaderCompilerWorkItem::Retrieve() -{ - auto it = g_shader_cache->m_ps_cache.shader_map.find(m_uid); - if (it == g_shader_cache->m_ps_cache.shader_map.end()) - { - g_shader_cache->m_ps_cache.shader_map.emplace(m_uid, std::make_pair(m_module, false)); - g_shader_cache->m_ps_cache.disk_cache.Append(m_uid, m_spirv.data(), - static_cast<u32>(m_spirv.size())); - return; - } - - // The main thread may have also compiled this shader. - if (!it->second.second) - { - if (m_module != VK_NULL_HANDLE) - vkDestroyShaderModule(g_vulkan_context->GetDevice(), m_module, nullptr); - return; - } - - // No longer pending. - it->second.first = m_module; - it->second.second = false; - g_shader_cache->m_ps_cache.disk_cache.Append(m_uid, m_spirv.data(), - static_cast<u32>(m_spirv.size())); -} - -bool ShaderCache::PipelineCompilerWorkItem::Compile() -{ - m_pipeline = g_shader_cache->CreatePipeline(m_info); - return true; -} - -void ShaderCache::PipelineCompilerWorkItem::Retrieve() -{ - auto it = g_shader_cache->m_pipeline_objects.find(m_info); - if (it == g_shader_cache->m_pipeline_objects.end()) - { - g_shader_cache->m_pipeline_objects.emplace(m_info, std::make_pair(m_pipeline, false)); - return; - } - - // The main thread may have also compiled this shader. - if (!it->second.second) - { - if (m_pipeline != VK_NULL_HANDLE) - vkDestroyPipeline(g_vulkan_context->GetDevice(), m_pipeline, nullptr); - return; - } - - // No longer pending. - it->second.first = m_pipeline; - it->second.second = false; -} } diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.h b/Source/Core/VideoBackends/Vulkan/ShaderCache.h index 0ad080a3fc..1082d0039e 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.h +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.h @@ -19,13 +19,7 @@ #include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ShaderCompiler.h" -#include "VideoCommon/AsyncShaderCompiler.h" -#include "VideoCommon/GeometryShaderGen.h" -#include "VideoCommon/PixelShaderGen.h" #include "VideoCommon/RenderState.h" -#include "VideoCommon/UberShaderPixel.h" -#include "VideoCommon/UberShaderVertex.h" -#include "VideoCommon/VertexShaderGen.h" namespace Vulkan { @@ -33,10 +27,6 @@ class CommandBufferManager; class VertexFormat; class StreamBuffer; -class CommandBufferManager; -class VertexFormat; -class StreamBuffer; - struct PipelineInfo { // These are packed in descending order of size, to avoid any padding so that the structure @@ -88,19 +78,6 @@ public: // Get utility shader header based on current config. std::string GetUtilityShaderHeader() const; - // Accesses ShaderGen shader caches - VkShaderModule GetVertexShaderForUid(const VertexShaderUid& uid); - VkShaderModule GetGeometryShaderForUid(const GeometryShaderUid& uid); - VkShaderModule GetPixelShaderForUid(const PixelShaderUid& uid); - - // Ubershader caches - VkShaderModule GetVertexUberShaderForUid(const UberShader::VertexShaderUid& uid); - VkShaderModule GetPixelUberShaderForUid(const UberShader::PixelShaderUid& uid); - - // Accesses ShaderGen shader caches asynchronously - std::pair<VkShaderModule, bool> GetVertexShaderForUidAsync(const VertexShaderUid& uid); - std::pair<VkShaderModule, bool> GetPixelShaderForUidAsync(const PixelShaderUid& uid); - // Perform at startup, create descriptor layouts, compiles all static shaders. bool Initialize(); void Shutdown(); @@ -112,13 +89,6 @@ public: // Find a pipeline by the specified description, if not found, attempts to create it. VkPipeline GetPipeline(const PipelineInfo& info); - // Find a pipeline by the specified description, if not found, attempts to create it. If this - // resulted in a pipeline being created, the second field of the return value will be false, - // otherwise for a cache hit it will be true. - std::pair<VkPipeline, bool> GetPipelineWithCacheResult(const PipelineInfo& info); - std::pair<std::pair<VkPipeline, bool>, bool> - GetPipelineWithCacheResultAsync(const PipelineInfo& info); - // Creates a compute pipeline, and does not track the handle. VkPipeline CreateComputePipeline(const ComputePipelineInfo& info); @@ -139,47 +109,22 @@ public: void RecompileSharedShaders(); // Reload pipeline cache. This will destroy all pipelines. - void ReloadShaderAndPipelineCaches(); + void ReloadPipelineCache(); // Shared shader accessors VkShaderModule GetScreenQuadVertexShader() const { return m_screen_quad_vertex_shader; } VkShaderModule GetPassthroughVertexShader() const { return m_passthrough_vertex_shader; } VkShaderModule GetScreenQuadGeometryShader() const { return m_screen_quad_geometry_shader; } VkShaderModule GetPassthroughGeometryShader() const { return m_passthrough_geometry_shader; } - void PrecompileUberShaders(); - void WaitForBackgroundCompilesToComplete(); - void RetrieveAsyncShaders(); - private: bool CreatePipelineCache(); bool LoadPipelineCache(); bool ValidatePipelineCache(const u8* data, size_t data_length); void DestroyPipelineCache(); - void LoadShaderCaches(); - void DestroyShaderCaches(); bool CompileSharedShaders(); void DestroySharedShaders(); - // We generate a dummy pipeline with some defaults in the blend/depth states, - // that way the driver is forced to compile something (looking at you, NVIDIA). - // It can then hopefully re-use part of this pipeline for others in the future. - void CreateDummyPipeline(const UberShader::VertexShaderUid& vuid, const GeometryShaderUid& guid, - const UberShader::PixelShaderUid& puid); - - template <typename Uid> - struct ShaderModuleCache - { - std::map<Uid, std::pair<VkShaderModule, bool>> shader_map; - LinearDiskCache<Uid, u32> disk_cache; - }; - ShaderModuleCache<VertexShaderUid> m_vs_cache; - ShaderModuleCache<GeometryShaderUid> m_gs_cache; - ShaderModuleCache<PixelShaderUid> m_ps_cache; - ShaderModuleCache<UberShader::VertexShaderUid> m_uber_vs_cache; - ShaderModuleCache<UberShader::PixelShaderUid> m_uber_ps_cache; - - std::unordered_map<PipelineInfo, std::pair<VkPipeline, bool>, PipelineInfoHash> - m_pipeline_objects; + std::unordered_map<PipelineInfo, VkPipeline, PipelineInfoHash> m_pipeline_objects; std::unordered_map<ComputePipelineInfo, VkPipeline, ComputePipelineInfoHash> m_compute_pipeline_objects; VkPipelineCache m_pipeline_cache = VK_NULL_HANDLE; @@ -190,45 +135,6 @@ private: VkShaderModule m_passthrough_vertex_shader = VK_NULL_HANDLE; VkShaderModule m_screen_quad_geometry_shader = VK_NULL_HANDLE; VkShaderModule m_passthrough_geometry_shader = VK_NULL_HANDLE; - - std::unique_ptr<VideoCommon::AsyncShaderCompiler> m_async_shader_compiler; - - // TODO: Use templates to reduce the number of these classes. - class VertexShaderCompilerWorkItem : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - explicit VertexShaderCompilerWorkItem(const VertexShaderUid& uid) : m_uid(uid) {} - bool Compile() override; - void Retrieve() override; - - private: - VertexShaderUid m_uid; - ShaderCompiler::SPIRVCodeVector m_spirv; - VkShaderModule m_module = VK_NULL_HANDLE; - }; - class PixelShaderCompilerWorkItem : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - explicit PixelShaderCompilerWorkItem(const PixelShaderUid& uid) : m_uid(uid) {} - bool Compile() override; - void Retrieve() override; - - private: - PixelShaderUid m_uid; - ShaderCompiler::SPIRVCodeVector m_spirv; - VkShaderModule m_module = VK_NULL_HANDLE; - }; - class PipelineCompilerWorkItem : public VideoCommon::AsyncShaderCompiler::WorkItem - { - public: - explicit PipelineCompilerWorkItem(const PipelineInfo& info) : m_info(info) {} - bool Compile() override; - void Retrieve() override; - - private: - PipelineInfo m_info; - VkPipeline m_pipeline; - }; }; extern std::unique_ptr<ShaderCache> g_shader_cache; diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index e5be3e2c1e..a3961daf48 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -15,6 +15,7 @@ #include "VideoBackends/Vulkan/ShaderCache.h" #include "VideoBackends/Vulkan/StreamBuffer.h" #include "VideoBackends/Vulkan/Util.h" +#include "VideoBackends/Vulkan/VKPipeline.h" #include "VideoBackends/Vulkan/VertexFormat.h" #include "VideoBackends/Vulkan/VulkanContext.h" @@ -53,12 +54,6 @@ void StateTracker::DestroyInstance() bool StateTracker::Initialize() { - // BBox is disabled by default. - m_pipeline_state.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD); - m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS; - m_bbox_enabled = false; - ClearShaders(); - // Initialize all samplers to point by default for (size_t i = 0; i < NUM_PIXEL_SHADER_SAMPLERS; i++) { @@ -97,122 +92,6 @@ bool StateTracker::Initialize() return true; } -void StateTracker::InvalidateShaderPointers() -{ - // Clear UIDs, forcing a false match next time. - m_vs_uid = {}; - m_gs_uid = {}; - m_ps_uid = {}; - - // Invalidate shader pointers. - m_pipeline_state.vs = VK_NULL_HANDLE; - m_pipeline_state.gs = VK_NULL_HANDLE; - m_pipeline_state.ps = VK_NULL_HANDLE; -} - -void StateTracker::ReloadPipelineUIDCache() -{ - class PipelineInserter final : public LinearDiskCacheReader<SerializedPipelineUID, u32> - { - public: - explicit PipelineInserter(StateTracker* this_ptr_) : this_ptr(this_ptr_) {} - void Read(const SerializedPipelineUID& key, const u32* value, u32 value_size) - { - this_ptr->PrecachePipelineUID(key); - } - - private: - StateTracker* this_ptr; - }; - - m_uid_cache.Sync(); - m_uid_cache.Close(); - - // UID caches don't contain any host state, so use a single uid cache per gameid. - std::string filename = GetDiskShaderCacheFileName(APIType::Vulkan, "PipelineUID", true, false); - if (g_ActiveConfig.bShaderCache) - { - PipelineInserter inserter(this); - m_uid_cache.OpenAndRead(filename, inserter); - } - - // If we were using background compilation, ensure everything is ready before continuing. - if (g_ActiveConfig.bBackgroundShaderCompiling) - g_shader_cache->WaitForBackgroundCompilesToComplete(); -} - -void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info) -{ - SerializedPipelineUID sinfo; - sinfo.blend_state_bits = info.blend_state.hex; - sinfo.rasterizer_state_bits = info.rasterization_state.hex; - sinfo.depth_state_bits = info.depth_state.hex; - sinfo.vertex_decl = m_pipeline_state.vertex_format->GetVertexDeclaration(); - sinfo.vs_uid = m_vs_uid; - sinfo.gs_uid = m_gs_uid; - sinfo.ps_uid = m_ps_uid; - - u32 dummy_value = 0; - m_uid_cache.Append(sinfo, &dummy_value, 1); -} - -bool StateTracker::PrecachePipelineUID(const SerializedPipelineUID& uid) -{ - PipelineInfo pinfo = {}; - - // Need to create the vertex declaration first, rather than deferring to when a game creates a - // vertex loader that uses this format, since we need it to create a pipeline. - pinfo.vertex_format = - static_cast<VertexFormat*>(VertexLoaderManager::GetOrCreateMatchingFormat(uid.vertex_decl)); - pinfo.pipeline_layout = uid.ps_uid.GetUidData()->bounding_box ? - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_BBOX) : - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD); - pinfo.vs = g_shader_cache->GetVertexShaderForUid(uid.vs_uid); - if (pinfo.vs == VK_NULL_HANDLE) - { - WARN_LOG(VIDEO, "Failed to get vertex shader from cached UID."); - return false; - } - if (g_vulkan_context->SupportsGeometryShaders() && !uid.gs_uid.GetUidData()->IsPassthrough()) - { - pinfo.gs = g_shader_cache->GetGeometryShaderForUid(uid.gs_uid); - if (pinfo.gs == VK_NULL_HANDLE) - { - WARN_LOG(VIDEO, "Failed to get geometry shader from cached UID."); - return false; - } - } - pinfo.ps = g_shader_cache->GetPixelShaderForUid(uid.ps_uid); - if (pinfo.ps == VK_NULL_HANDLE) - { - WARN_LOG(VIDEO, "Failed to get pixel shader from cached UID."); - return false; - } - pinfo.render_pass = m_load_render_pass; - pinfo.rasterization_state.hex = uid.rasterizer_state_bits; - pinfo.depth_state.hex = uid.depth_state_bits; - pinfo.blend_state.hex = uid.blend_state_bits; - pinfo.multisampling_state.hex = m_pipeline_state.multisampling_state.hex; - - if (g_ActiveConfig.bBackgroundShaderCompiling) - { - // Use async for multithreaded compilation. - g_shader_cache->GetPipelineWithCacheResultAsync(pinfo); - } - else - { - VkPipeline pipeline = g_shader_cache->GetPipeline(pinfo); - if (pipeline == VK_NULL_HANDLE) - { - WARN_LOG(VIDEO, "Failed to get pipeline from cached UID."); - return false; - } - } - - // We don't need to do anything with this pipeline, just make sure it exists. - return true; -} - void StateTracker::SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset) { if (m_vertex_buffer == buffer && m_vertex_buffer_offset == offset) @@ -238,14 +117,6 @@ void StateTracker::SetRenderPass(VkRenderPass load_render_pass, VkRenderPass cle { // Should not be changed within a render pass. _assert_(!InRenderPass()); - - // The clear and load render passes are compatible, so we don't need to change our pipeline. - if (m_pipeline_state.render_pass != load_render_pass) - { - m_pipeline_state.render_pass = load_render_pass; - m_dirty_flags |= DIRTY_FLAG_PIPELINE; - } - m_load_render_pass = load_render_pass; m_clear_render_pass = clear_render_pass; } @@ -258,169 +129,18 @@ void StateTracker::SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& ren m_framebuffer_size = render_area; } -void StateTracker::SetVertexFormat(const VertexFormat* vertex_format) -{ - if (m_vertex_format == vertex_format) - return; - - m_vertex_format = vertex_format; - UpdatePipelineVertexFormat(); -} - -void StateTracker::SetRasterizationState(const RasterizationState& state) -{ - if (m_pipeline_state.rasterization_state.hex == state.hex) - return; - - m_pipeline_state.rasterization_state.hex = state.hex; - m_dirty_flags |= DIRTY_FLAG_PIPELINE; -} - -void StateTracker::SetMultisamplingstate(const MultisamplingState& state) +void StateTracker::SetPipeline(const VKPipeline* pipeline) { - if (m_pipeline_state.multisampling_state.hex == state.hex) + if (m_pipeline == pipeline) return; - m_pipeline_state.multisampling_state.hex = state.hex; - m_dirty_flags |= DIRTY_FLAG_PIPELINE; -} - -void StateTracker::SetDepthState(const DepthState& state) -{ - if (m_pipeline_state.depth_state.hex == state.hex) - return; - - m_pipeline_state.depth_state.hex = state.hex; - m_dirty_flags |= DIRTY_FLAG_PIPELINE; -} - -void StateTracker::SetBlendState(const BlendingState& state) -{ - if (m_pipeline_state.blend_state.hex == state.hex) - return; - - m_pipeline_state.blend_state.hex = state.hex; - m_dirty_flags |= DIRTY_FLAG_PIPELINE; -} - -bool StateTracker::CheckForShaderChanges() -{ - VertexShaderUid vs_uid = GetVertexShaderUid(); - PixelShaderUid ps_uid = GetPixelShaderUid(); - ClearUnusedPixelShaderUidBits(APIType::Vulkan, &ps_uid); - - bool changed = false; - bool use_ubershaders = g_ActiveConfig.bDisableSpecializedShaders; - if (g_ActiveConfig.CanBackgroundCompileShaders() && !g_ActiveConfig.bDisableSpecializedShaders) - { - // Look up both VS and PS, and check if we can compile it asynchronously. - auto vs = g_shader_cache->GetVertexShaderForUidAsync(vs_uid); - auto ps = g_shader_cache->GetPixelShaderForUidAsync(ps_uid); - if (vs.second || ps.second) - { - // One of the shaders is still pending. Use the ubershader for both. - use_ubershaders = true; - } - else - { - // Use the standard shaders for both. - if (m_pipeline_state.vs != vs.first) - { - m_pipeline_state.vs = vs.first; - m_vs_uid = vs_uid; - changed = true; - } - if (m_pipeline_state.ps != ps.first) - { - m_pipeline_state.ps = ps.first; - m_ps_uid = ps_uid; - changed = true; - } - } - } - else - { - // Normal shader path. No ubershaders. - if (vs_uid != m_vs_uid) - { - m_vs_uid = vs_uid; - m_pipeline_state.vs = g_shader_cache->GetVertexShaderForUid(vs_uid); - changed = true; - } - if (ps_uid != m_ps_uid) - { - m_ps_uid = ps_uid; - m_pipeline_state.ps = g_shader_cache->GetPixelShaderForUid(ps_uid); - changed = true; - } - } - - // Switching to/from ubershaders? Have to adjust the vertex format and pipeline layout. - if (use_ubershaders != m_using_ubershaders) - { - m_using_ubershaders = use_ubershaders; - UpdatePipelineLayout(); - UpdatePipelineVertexFormat(); - } - - if (use_ubershaders) - { - UberShader::VertexShaderUid uber_vs_uid = UberShader::GetVertexShaderUid(); - VkShaderModule vs = g_shader_cache->GetVertexUberShaderForUid(uber_vs_uid); - if (vs != m_pipeline_state.vs) - { - m_uber_vs_uid = uber_vs_uid; - m_pipeline_state.vs = vs; - changed = true; - } - - UberShader::PixelShaderUid uber_ps_uid = UberShader::GetPixelShaderUid(); - UberShader::ClearUnusedPixelShaderUidBits(APIType::Vulkan, &uber_ps_uid); - VkShaderModule ps = g_shader_cache->GetPixelUberShaderForUid(uber_ps_uid); - if (ps != m_pipeline_state.ps) - { - m_uber_ps_uid = uber_ps_uid; - m_pipeline_state.ps = ps; - changed = true; - } - } - - if (g_vulkan_context->SupportsGeometryShaders()) - { - GeometryShaderUid gs_uid = GetGeometryShaderUid(m_pipeline_state.rasterization_state.primitive); - if (gs_uid != m_gs_uid) - { - m_gs_uid = gs_uid; - if (gs_uid.GetUidData()->IsPassthrough()) - m_pipeline_state.gs = VK_NULL_HANDLE; - else - m_pipeline_state.gs = g_shader_cache->GetGeometryShaderForUid(gs_uid); - - changed = true; - } - } - - if (changed) - m_dirty_flags |= DIRTY_FLAG_PIPELINE; - - return changed; -} - -void StateTracker::ClearShaders() -{ - // Set the UIDs to something that will never match, so on the first access they are checked. - std::memset(&m_vs_uid, 0xFF, sizeof(m_vs_uid)); - std::memset(&m_gs_uid, 0xFF, sizeof(m_gs_uid)); - std::memset(&m_ps_uid, 0xFF, sizeof(m_ps_uid)); - std::memset(&m_uber_vs_uid, 0xFF, sizeof(m_uber_vs_uid)); - std::memset(&m_uber_ps_uid, 0xFF, sizeof(m_uber_ps_uid)); - - m_pipeline_state.vs = VK_NULL_HANDLE; - m_pipeline_state.gs = VK_NULL_HANDLE; - m_pipeline_state.ps = VK_NULL_HANDLE; - m_pipeline_state.vertex_format = nullptr; + const bool new_usage = + pipeline && (!m_pipeline || m_pipeline->GetUsage() != pipeline->GetUsage()); + m_pipeline = pipeline; m_dirty_flags |= DIRTY_FLAG_PIPELINE; + if (new_usage) + m_dirty_flags |= DIRTY_FLAG_ALL_DESCRIPTOR_SETS; } void StateTracker::UpdateVertexShaderConstants() @@ -450,20 +170,6 @@ void StateTracker::UpdateVertexShaderConstants() void StateTracker::UpdateGeometryShaderConstants() { - // Skip updating geometry shader constants if it's not in use. - if (m_pipeline_state.gs == VK_NULL_HANDLE) - { - // However, if the buffer has changed, we can't skip the update, because then we'll - // try to include the now non-existant buffer in the descriptor set. - if (m_uniform_stream_buffer->GetBuffer() == - m_bindings.uniform_buffer_bindings[UBO_DESCRIPTOR_SET_BINDING_GS].buffer) - { - return; - } - - GeometryShaderManager::dirty = true; - } - if (!GeometryShaderManager::dirty || !ReserveConstantStorage()) return; @@ -614,15 +320,6 @@ void StateTracker::SetSampler(size_t index, VkSampler sampler) m_dirty_flags |= DIRTY_FLAG_PS_SAMPLERS; } -void StateTracker::SetBBoxEnable(bool enable) -{ - if (m_bbox_enabled == enable) - return; - - m_bbox_enabled = enable; - UpdatePipelineLayout(); -} - void StateTracker::SetBBoxBuffer(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range) { if (m_bindings.ps_ssbo.buffer == buffer && m_bindings.ps_ssbo.offset == offset && @@ -634,10 +331,7 @@ void StateTracker::SetBBoxBuffer(VkBuffer buffer, VkDeviceSize offset, VkDeviceS m_bindings.ps_ssbo.buffer = buffer; m_bindings.ps_ssbo.offset = offset; m_bindings.ps_ssbo.range = range; - - // Defer descriptor update until bbox is actually enabled. - if (IsSSBODescriptorRequired()) - m_dirty_flags |= DIRTY_FLAG_PS_SSBO; + m_dirty_flags |= DIRTY_FLAG_PS_SSBO; } void StateTracker::UnbindTexture(VkImageView view) @@ -653,10 +347,6 @@ void StateTracker::InvalidateDescriptorSets() { m_descriptor_sets.fill(VK_NULL_HANDLE); m_dirty_flags |= DIRTY_FLAG_ALL_DESCRIPTOR_SETS; - - // Defer SSBO descriptor update until bbox is actually enabled. - if (!IsSSBODescriptorRequired()) - m_dirty_flags &= ~DIRTY_FLAG_PS_SSBO; } void StateTracker::InvalidateConstants() @@ -669,9 +359,8 @@ void StateTracker::InvalidateConstants() void StateTracker::SetPendingRebind() { m_dirty_flags |= DIRTY_FLAG_DYNAMIC_OFFSETS | DIRTY_FLAG_DESCRIPTOR_SET_BINDING | - DIRTY_FLAG_PIPELINE_BINDING | DIRTY_FLAG_VERTEX_BUFFER | - DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_VIEWPORT | DIRTY_FLAG_SCISSOR | - DIRTY_FLAG_PIPELINE; + DIRTY_FLAG_VERTEX_BUFFER | DIRTY_FLAG_INDEX_BUFFER | DIRTY_FLAG_VIEWPORT | + DIRTY_FLAG_SCISSOR | DIRTY_FLAG_PIPELINE; } void StateTracker::BeginRenderPass() @@ -743,17 +432,14 @@ void StateTracker::SetScissor(const VkRect2D& scissor) bool StateTracker::Bind(bool rebind_all /*= false*/) { + // Must have a pipeline. + if (!m_pipeline) + return false; + // Check the render area if we were in a clear pass. if (m_current_render_pass == m_clear_render_pass && !IsViewportWithinRenderArea()) EndRenderPass(); - // Get new pipeline object if any parts have changed - if (m_dirty_flags & DIRTY_FLAG_PIPELINE && !UpdatePipeline()) - { - ERROR_LOG(VIDEO, "Failed to get pipeline object, skipping draw"); - return false; - } - // Get a new descriptor set if any parts have changed if (m_dirty_flags & DIRTY_FLAG_ALL_DESCRIPTOR_SETS && !UpdateDescriptorSet()) { @@ -780,20 +466,20 @@ bool StateTracker::Bind(bool rebind_all /*= false*/) if (m_dirty_flags & DIRTY_FLAG_INDEX_BUFFER || rebind_all) vkCmdBindIndexBuffer(command_buffer, m_index_buffer, m_index_buffer_offset, m_index_type); - if (m_dirty_flags & DIRTY_FLAG_PIPELINE_BINDING || rebind_all) - vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_object); + if (m_dirty_flags & DIRTY_FLAG_PIPELINE || rebind_all) + vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipeline()); if (m_dirty_flags & DIRTY_FLAG_DESCRIPTOR_SET_BINDING || rebind_all) { vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, - m_pipeline_state.pipeline_layout, 0, m_num_active_descriptor_sets, + m_pipeline->GetVkPipelineLayout(), 0, m_num_active_descriptor_sets, m_descriptor_sets.data(), NUM_UBO_DESCRIPTOR_SET_BINDINGS, m_bindings.uniform_buffer_offsets.data()); } else if (m_dirty_flags & DIRTY_FLAG_DYNAMIC_OFFSETS) { vkCmdBindDescriptorSets( - command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline_state.pipeline_layout, + command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline->GetVkPipelineLayout(), DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS, 1, &m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_UNIFORM_BUFFERS], NUM_UBO_DESCRIPTOR_SET_BINDINGS, m_bindings.uniform_buffer_offsets.data()); @@ -933,105 +619,6 @@ void StateTracker::EndClearRenderPass() EndRenderPass(); } -VkPipeline StateTracker::GetPipelineAndCacheUID() -{ - // We can't cache ubershader uids, only normal shader uids. - if (g_ActiveConfig.CanBackgroundCompileShaders() && !m_using_ubershaders) - { - // Append to UID cache if it is a new pipeline. - auto result = g_shader_cache->GetPipelineWithCacheResultAsync(m_pipeline_state); - if (!result.second && g_ActiveConfig.bShaderCache) - AppendToPipelineUIDCache(m_pipeline_state); - - // Still waiting for the pipeline to compile? - if (!result.first.second) - return result.first.first; - - // Use ubershader instead. - m_using_ubershaders = true; - UpdatePipelineLayout(); - UpdatePipelineVertexFormat(); - - PipelineInfo uber_info = m_pipeline_state; - UberShader::VertexShaderUid uber_vuid = UberShader::GetVertexShaderUid(); - UberShader::PixelShaderUid uber_puid = UberShader::GetPixelShaderUid(); - UberShader::ClearUnusedPixelShaderUidBits(APIType::Vulkan, &uber_puid); - uber_info.vs = g_shader_cache->GetVertexUberShaderForUid(uber_vuid); - uber_info.ps = g_shader_cache->GetPixelUberShaderForUid(uber_puid); - - auto uber_result = g_shader_cache->GetPipelineWithCacheResult(uber_info); - return uber_result.first; - } - else - { - // Add to the UID cache if it is a new pipeline. - auto result = g_shader_cache->GetPipelineWithCacheResult(m_pipeline_state); - if (!result.second && !m_using_ubershaders && g_ActiveConfig.bShaderCache) - AppendToPipelineUIDCache(m_pipeline_state); - - return result.first; - } -} - -bool StateTracker::IsSSBODescriptorRequired() const -{ - return m_bbox_enabled || (m_using_ubershaders && g_ActiveConfig.bBBoxEnable && - g_ActiveConfig.BBoxUseFragmentShaderImplementation()); -} - -bool StateTracker::UpdatePipeline() -{ - // We need at least a vertex and fragment shader - if (m_pipeline_state.vs == VK_NULL_HANDLE || m_pipeline_state.ps == VK_NULL_HANDLE) - return false; - - // Grab a new pipeline object, this can fail. - m_pipeline_object = GetPipelineAndCacheUID(); - - m_dirty_flags |= DIRTY_FLAG_PIPELINE_BINDING; - return m_pipeline_object != VK_NULL_HANDLE; -} - -void StateTracker::UpdatePipelineLayout() -{ - const bool use_bbox_pipeline_layout = IsSSBODescriptorRequired(); - VkPipelineLayout pipeline_layout = - use_bbox_pipeline_layout ? g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_BBOX) : - g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD); - if (m_pipeline_state.pipeline_layout == pipeline_layout) - return; - - // Change the number of active descriptor sets, as well as the pipeline layout - m_pipeline_state.pipeline_layout = pipeline_layout; - if (use_bbox_pipeline_layout) - { - m_num_active_descriptor_sets = NUM_GX_DRAW_WITH_BBOX_DESCRIPTOR_SETS; - - // The bbox buffer never changes, so we defer descriptor updates until it is enabled. - if (m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER] == VK_NULL_HANDLE) - m_dirty_flags |= DIRTY_FLAG_PS_SSBO; - } - else - { - m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS; - } - - m_dirty_flags |= DIRTY_FLAG_PIPELINE | DIRTY_FLAG_DESCRIPTOR_SET_BINDING; -} - -void StateTracker::UpdatePipelineVertexFormat() -{ - const NativeVertexFormat* vertex_format = - m_using_ubershaders ? - VertexLoaderManager::GetUberVertexFormat(m_vertex_format->GetVertexDeclaration()) : - m_vertex_format; - if (m_pipeline_state.vertex_format == vertex_format) - return; - - m_pipeline_state.vertex_format = static_cast<const VertexFormat*>(vertex_format); - m_dirty_flags |= DIRTY_FLAG_PIPELINE; -} - bool StateTracker::UpdateDescriptorSet() { const size_t MAX_DESCRIPTOR_WRITES = NUM_UBO_DESCRIPTOR_SET_BINDINGS + // UBO @@ -1051,6 +638,9 @@ bool StateTracker::UpdateDescriptorSet() for (size_t i = 0; i < NUM_UBO_DESCRIPTOR_SET_BINDINGS; i++) { + if (i == UBO_DESCRIPTOR_SET_BINDING_GS && !g_vulkan_context->SupportsGeometryShaders()) + continue; + writes[num_writes++] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, set, @@ -1091,7 +681,7 @@ bool StateTracker::UpdateDescriptorSet() m_dirty_flags |= DIRTY_FLAG_DESCRIPTOR_SET_BINDING; } - if (IsSSBODescriptorRequired() && + if (g_vulkan_context->SupportsBoundingBox() && (m_dirty_flags & DIRTY_FLAG_PS_SSBO || m_descriptor_sets[DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER] == VK_NULL_HANDLE)) { @@ -1119,6 +709,7 @@ bool StateTracker::UpdateDescriptorSet() if (num_writes > 0) vkUpdateDescriptorSets(g_vulkan_context->GetDevice(), num_writes, writes.data(), 0, nullptr); + m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS; return true; } diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index 92771504a9..547c62f655 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -9,19 +9,14 @@ #include <memory> #include "Common/CommonTypes.h" -#include "Common/LinearDiskCache.h" #include "VideoBackends/Vulkan/Constants.h" #include "VideoBackends/Vulkan/ShaderCache.h" -#include "VideoCommon/GeometryShaderGen.h" #include "VideoCommon/NativeVertexFormat.h" -#include "VideoCommon/PixelShaderGen.h" #include "VideoCommon/RenderBase.h" -#include "VideoCommon/UberShaderPixel.h" -#include "VideoCommon/UberShaderVertex.h" -#include "VideoCommon/VertexShaderGen.h" namespace Vulkan { +class VKPipeline; class StreamBuffer; class VertexFormat; @@ -35,31 +30,18 @@ public: static bool CreateInstance(); static void DestroyInstance(); - const RasterizationState& GetRasterizationState() const - { - return m_pipeline_state.rasterization_state; - } - const DepthState& GetDepthStencilState() const { return m_pipeline_state.depth_state; } - const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; } const std::array<VkDescriptorImageInfo, NUM_PIXEL_SHADER_SAMPLERS>& GetPSSamplerBindings() const { return m_bindings.ps_samplers; } VkFramebuffer GetFramebuffer() const { return m_framebuffer; } + const VKPipeline* GetPipeline() const { return m_pipeline; } void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset); void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type); void SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass); void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area); - void SetVertexFormat(const VertexFormat* vertex_format); - - void SetRasterizationState(const RasterizationState& state); - void SetMultisamplingstate(const MultisamplingState& state); - void SetDepthState(const DepthState& state); - void SetBlendState(const BlendingState& state); - - bool CheckForShaderChanges(); - void ClearShaders(); + void SetPipeline(const VKPipeline* pipeline); void UpdateVertexShaderConstants(); void UpdateGeometryShaderConstants(); @@ -68,7 +50,6 @@ public: void SetTexture(size_t index, VkImageView view); void SetSampler(size_t index, VkSampler sampler); - void SetBBoxEnable(bool enable); void SetBBoxBuffer(VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range); void UnbindTexture(VkImageView view); @@ -117,30 +98,11 @@ public: bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const; - // Reloads the UID cache, ensuring all pipelines used by the game so far have been created. - void ReloadPipelineUIDCache(); - - // Clears shader pointers, ensuring that now-deleted modules are not used. - void InvalidateShaderPointers(); - private: - // Serialized version of PipelineInfo, used when loading/saving the pipeline UID cache. - struct SerializedPipelineUID - { - u32 rasterizer_state_bits; - u32 depth_state_bits; - u32 blend_state_bits; - PortableVertexDeclaration vertex_decl; - VertexShaderUid vs_uid; - GeometryShaderUid gs_uid; - PixelShaderUid ps_uid; - }; - // Number of descriptor sets for game draws. enum { - NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_PIXEL_SHADER_SAMPLERS + 1, - NUM_GX_DRAW_WITH_BBOX_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1 + NUM_GX_DRAW_DESCRIPTOR_SETS = DESCRIPTOR_SET_BIND_POINT_STORAGE_OR_TEXEL_BUFFER + 1 }; enum DITRY_FLAG : u32 @@ -157,7 +119,6 @@ private: DIRTY_FLAG_SCISSOR = (1 << 9), DIRTY_FLAG_PIPELINE = (1 << 10), DIRTY_FLAG_DESCRIPTOR_SET_BINDING = (1 << 11), - DIRTY_FLAG_PIPELINE_BINDING = (1 << 12), DIRTY_FLAG_ALL_DESCRIPTOR_SETS = DIRTY_FLAG_VS_UBO | DIRTY_FLAG_GS_UBO | DIRTY_FLAG_PS_UBO | DIRTY_FLAG_PS_SAMPLERS | DIRTY_FLAG_PS_SSBO @@ -165,28 +126,10 @@ private: bool Initialize(); - // Appends the specified pipeline info, combined with the UIDs stored in the class. - // The info is here so that we can store variations of a UID, e.g. blend state. - void AppendToPipelineUIDCache(const PipelineInfo& info); - - // Precaches a pipeline based on the UID information. - bool PrecachePipelineUID(const SerializedPipelineUID& uid); - // Check that the specified viewport is within the render area. // If not, ends the render pass if it is a clear render pass. bool IsViewportWithinRenderArea() const; - // Obtains a Vulkan pipeline object for the specified pipeline configuration. - // Also adds this pipeline configuration to the UID cache if it is not present already. - VkPipeline GetPipelineAndCacheUID(); - - // Are bounding box ubershaders enabled? If so, we need to ensure the SSBO is set up, - // since the bbox writes are determined by a uniform. - bool IsSSBODescriptorRequired() const; - - bool UpdatePipeline(); - void UpdatePipelineLayout(); - void UpdatePipelineVertexFormat(); bool UpdateDescriptorSet(); // Allocates storage in the uniform buffer of the specified size. If this storage cannot be @@ -205,18 +148,8 @@ private: VkDeviceSize m_index_buffer_offset = 0; VkIndexType m_index_type = VK_INDEX_TYPE_UINT16; - // shader state - VertexShaderUid m_vs_uid = {}; - GeometryShaderUid m_gs_uid = {}; - PixelShaderUid m_ps_uid = {}; - UberShader::VertexShaderUid m_uber_vs_uid = {}; - UberShader::PixelShaderUid m_uber_ps_uid = {}; - bool m_using_ubershaders = false; - // pipeline state - PipelineInfo m_pipeline_state = {}; - VkPipeline m_pipeline_object = VK_NULL_HANDLE; - const VertexFormat* m_vertex_format = nullptr; + const VKPipeline* m_pipeline = nullptr; // shader bindings std::array<VkDescriptorSet, NUM_DESCRIPTOR_SET_BIND_POINTS> m_descriptor_sets = {}; @@ -230,8 +163,8 @@ private: VkDescriptorBufferInfo ps_ssbo = {}; } m_bindings; - u32 m_num_active_descriptor_sets = 0; size_t m_uniform_buffer_reserve_size = 0; + u32 m_num_active_descriptor_sets = 0; // rasterization VkViewport m_viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; @@ -246,18 +179,11 @@ private: VkRenderPass m_current_render_pass = VK_NULL_HANDLE; VkRect2D m_framebuffer_size = {}; VkRect2D m_framebuffer_render_area = {}; - bool m_bbox_enabled = false; // CPU access tracking u32 m_draw_counter = 0; std::vector<u32> m_cpu_accesses_this_frame; std::vector<u32> m_scheduled_command_buffer_kicks; bool m_allow_background_execution = true; - - // Draw state cache on disk - // We don't actually use the value field here, instead we generate the shaders from the uid - // on-demand. If all goes well, it should hit the shader and Vulkan pipeline cache, therefore - // loading should be reasonably efficient. - LinearDiskCache<SerializedPipelineUID, u32> m_uid_cache; }; } diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 4977a270a3..facae2ac14 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -592,16 +592,19 @@ void UtilityShaderDraw::BindDescriptors() &dummy_uniform_buffer, nullptr}; - set_writes[num_set_writes++] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, - nullptr, - set, - UBO_DESCRIPTOR_SET_BINDING_GS, - 0, - 1, - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, - nullptr, - &dummy_uniform_buffer, - nullptr}; + if (g_vulkan_context->SupportsGeometryShaders()) + { + set_writes[num_set_writes++] = {VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + nullptr, + set, + UBO_DESCRIPTOR_SET_BINDING_GS, + 0, + 1, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, + nullptr, + &dummy_uniform_buffer, + nullptr}; + } set_writes[num_set_writes++] = { VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, nullptr, set, UBO_DESCRIPTOR_SET_BINDING_PS, 0, 1, diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp index c9aad0254c..1e97cf6308 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp @@ -139,8 +139,6 @@ void VertexManager::vFlush() u32 index_count = IndexGenerator::GetIndexLen(); // Update tracked state - StateTracker::GetInstance()->SetVertexFormat(vertex_format); - StateTracker::GetInstance()->CheckForShaderChanges(); StateTracker::GetInstance()->UpdateVertexShaderConstants(); StateTracker::GetInstance()->UpdateGeometryShaderConstants(); StateTracker::GetInstance()->UpdatePixelShaderConstants(); @@ -165,12 +163,10 @@ void VertexManager::vFlush() bounding_box->Flush(); bounding_box->Invalidate(); } - - // Update which descriptor set/pipeline layout to use. - StateTracker::GetInstance()->SetBBoxEnable(bounding_box_enabled); } // Bind all pending state to the command buffer + g_renderer->SetPipeline(m_current_pipeline_object); if (!StateTracker::GetInstance()->Bind()) { WARN_LOG(VIDEO, "Skipped draw of %u indices", index_count); diff --git a/Source/Core/VideoBackends/Vulkan/main.cpp b/Source/Core/VideoBackends/Vulkan/main.cpp index d8a725845a..9bd4039138 100644 --- a/Source/Core/VideoBackends/Vulkan/main.cpp +++ b/Source/Core/VideoBackends/Vulkan/main.cpp @@ -223,6 +223,7 @@ bool VideoBackend::Initialize(void* window_handle) g_renderer = std::make_unique<Renderer>(std::move(swap_chain)); g_vertex_manager = std::make_unique<VertexManager>(); g_texture_cache = std::make_unique<TextureCache>(); + ::g_shader_cache = std::make_unique<VideoCommon::ShaderCache>(); g_perf_query = std::make_unique<PerfQuery>(); // Invoke init methods on main wrapper classes. @@ -230,21 +231,14 @@ bool VideoBackend::Initialize(void* window_handle) // for the remaining classes may call methods on these. if (!StateTracker::CreateInstance() || !FramebufferManager::GetInstance()->Initialize() || !Renderer::GetInstance()->Initialize() || !VertexManager::GetInstance()->Initialize() || - !TextureCache::GetInstance()->Initialize() || !PerfQuery::GetInstance()->Initialize()) + !TextureCache::GetInstance()->Initialize() || !PerfQuery::GetInstance()->Initialize() || + !::g_shader_cache->Initialize()) { PanicAlert("Failed to initialize Vulkan classes."); Shutdown(); return false; } - // Ensure all pipelines previously used by the game have been created. - StateTracker::GetInstance()->ReloadPipelineUIDCache(); - - // Lastly, precompile ubershaders, if requested. - // This has to be done after the texture cache and shader cache are initialized. - if (g_ActiveConfig.CanPrecompileUberShaders()) - g_shader_cache->PrecompileUberShaders(); - // Display the name so the user knows which device was actually created. INFO_LOG(VIDEO, "Vulkan Device: %s", g_vulkan_context->GetDeviceProperties().deviceName); return true; @@ -252,13 +246,17 @@ bool VideoBackend::Initialize(void* window_handle) void VideoBackend::Shutdown() { - if (g_renderer) - g_renderer->Shutdown(); - if (g_command_buffer_mgr) g_command_buffer_mgr->WaitForGPUIdle(); + if (::g_shader_cache) + ::g_shader_cache->Shutdown(); + + if (g_renderer) + g_renderer->Shutdown(); + g_perf_query.reset(); + ::g_shader_cache.reset(); g_texture_cache.reset(); g_vertex_manager.reset(); g_renderer.reset(); |
