From b066d51dfa03b960028fc6f88c8de133eb6db1da Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 22 Oct 2016 20:50:36 +1000 Subject: [PATCH] Vulkan: Remove parameters/members of single-instance classes There's not a lot of point in passing these around or storing them (texture cache/state tracker mainly) as there will only ever be a single instance of the class. Also adds downcast helpers such as Vulkan::Renderer::GetInstance(). --- .../Core/VideoBackends/Vulkan/BoundingBox.cpp | 19 +- .../Core/VideoBackends/Vulkan/BoundingBox.h | 11 +- .../Vulkan/FramebufferManager.cpp | 76 ++++---- .../VideoBackends/Vulkan/FramebufferManager.h | 24 +-- .../Vulkan/PaletteTextureConverter.cpp | 5 +- .../Vulkan/PaletteTextureConverter.h | 8 +- .../Core/VideoBackends/Vulkan/PerfQuery.cpp | 19 +- Source/Core/VideoBackends/Vulkan/PerfQuery.h | 7 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 174 +++++++++--------- Source/Core/VideoBackends/Vulkan/Renderer.h | 8 +- .../VideoBackends/Vulkan/StateTracker.cpp | 37 +++- .../Core/VideoBackends/Vulkan/StateTracker.h | 10 +- .../VideoBackends/Vulkan/TextureCache.cpp | 103 ++++++----- .../Core/VideoBackends/Vulkan/TextureCache.h | 11 +- .../VideoBackends/Vulkan/TextureEncoder.cpp | 16 +- .../VideoBackends/Vulkan/TextureEncoder.h | 9 +- Source/Core/VideoBackends/Vulkan/Util.cpp | 9 +- Source/Core/VideoBackends/Vulkan/Util.h | 2 +- .../VideoBackends/Vulkan/VertexManager.cpp | 58 +++--- .../Core/VideoBackends/Vulkan/VertexManager.h | 7 +- Source/Core/VideoBackends/Vulkan/main.cpp | 26 ++- 21 files changed, 336 insertions(+), 303 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/BoundingBox.cpp b/Source/Core/VideoBackends/Vulkan/BoundingBox.cpp index e9dad9f9d6..5cfc174bf8 100644 --- a/Source/Core/VideoBackends/Vulkan/BoundingBox.cpp +++ b/Source/Core/VideoBackends/Vulkan/BoundingBox.cpp @@ -10,6 +10,7 @@ #include "VideoBackends/Vulkan/BoundingBox.h" #include "VideoBackends/Vulkan/CommandBufferManager.h" #include "VideoBackends/Vulkan/ObjectCache.h" +#include "VideoBackends/Vulkan/Renderer.h" #include "VideoBackends/Vulkan/StagingBuffer.h" #include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/Util.h" @@ -47,7 +48,7 @@ bool BoundingBox::Initialize() return true; } -void BoundingBox::Flush(StateTracker* state_tracker) +void BoundingBox::Flush() { if (m_gpu_buffer == VK_NULL_HANDLE) return; @@ -75,7 +76,7 @@ void BoundingBox::Flush(StateTracker* state_tracker) // However, the writes must be serialized, so we can't put it in the init buffer. if (!updated_buffer) { - state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); // Ensure GPU buffer is in a state where it can be transferred to. Util::BufferMemoryBarrier( @@ -104,7 +105,7 @@ void BoundingBox::Flush(StateTracker* state_tracker) m_valid = true; } -void BoundingBox::Invalidate(StateTracker* state_tracker) +void BoundingBox::Invalidate() { if (m_gpu_buffer == VK_NULL_HANDLE) return; @@ -112,19 +113,19 @@ void BoundingBox::Invalidate(StateTracker* state_tracker) m_valid = false; } -s32 BoundingBox::Get(StateTracker* state_tracker, size_t index) +s32 BoundingBox::Get(size_t index) { _assert_(index < NUM_VALUES); if (!m_valid) - Readback(state_tracker); + Readback(); s32 value; m_readback_buffer->Read(index * sizeof(s32), &value, sizeof(value), false); return value; } -void BoundingBox::Set(StateTracker* state_tracker, size_t index, s32 value) +void BoundingBox::Set(size_t index, s32 value) { _assert_(index < NUM_VALUES); @@ -212,10 +213,10 @@ bool BoundingBox::CreateReadbackBuffer() return true; } -void BoundingBox::Readback(StateTracker* state_tracker) +void BoundingBox::Readback() { // Can't be done within a render pass. - state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); // Ensure all writes are completed to the GPU buffer prior to the transfer. Util::BufferMemoryBarrier( @@ -240,7 +241,7 @@ void BoundingBox::Readback(StateTracker* state_tracker) VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT); // Wait until these commands complete. - Util::ExecuteCurrentCommandsAndRestoreState(state_tracker, false, true); + Util::ExecuteCurrentCommandsAndRestoreState(false, true); // Cache is now valid. m_readback_buffer->InvalidateCPUCache(); diff --git a/Source/Core/VideoBackends/Vulkan/BoundingBox.h b/Source/Core/VideoBackends/Vulkan/BoundingBox.h index 0647c08607..872f49aa31 100644 --- a/Source/Core/VideoBackends/Vulkan/BoundingBox.h +++ b/Source/Core/VideoBackends/Vulkan/BoundingBox.h @@ -15,7 +15,6 @@ namespace Vulkan { class StagingBuffer; -class StateTracker; class BoundingBox { @@ -28,16 +27,16 @@ public: VkBuffer GetGPUBuffer() const { return m_gpu_buffer; } VkDeviceSize GetGPUBufferOffset() const { return 0; } VkDeviceSize GetGPUBufferSize() const { return BUFFER_SIZE; } - s32 Get(StateTracker* state_tracker, size_t index); - void Set(StateTracker* state_tracker, size_t index, s32 value); + s32 Get(size_t index); + void Set(size_t index, s32 value); - void Invalidate(StateTracker* state_tracker); - void Flush(StateTracker* state_tracker); + void Invalidate(); + void Flush(); private: bool CreateGPUBuffer(); bool CreateReadbackBuffer(); - void Readback(StateTracker* state_tracker); + void Readback(); VkBuffer m_gpu_buffer = VK_NULL_HANDLE; VkDeviceMemory m_gpu_memory = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index f78cf9953f..9e3245b27e 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -49,6 +49,11 @@ FramebufferManager::~FramebufferManager() DestroyPokeShaders(); } +FramebufferManager* FramebufferManager::GetInstance() +{ + return static_cast(g_framebuffer_manager.get()); +} + bool FramebufferManager::Initialize() { if (!CreateEFBRenderPass()) @@ -450,15 +455,14 @@ void FramebufferManager::ReinterpretPixelData(int convtype) std::swap(m_efb_framebuffer, m_efb_convert_framebuffer); } -Texture2D* FramebufferManager::ResolveEFBColorTexture(StateTracker* state_tracker, - const VkRect2D& region) +Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region) { // Return the normal EFB texture if multisampling is off. if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT) return m_efb_color_texture.get(); // Can't resolve within a render pass. - state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); // Resolving is considered to be a transfer operation. m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), @@ -485,15 +489,14 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(StateTracker* state_tracke return m_efb_resolve_color_texture.get(); } -Texture2D* FramebufferManager::ResolveEFBDepthTexture(StateTracker* state_tracker, - const VkRect2D& region) +Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region) { // Return the normal EFB texture if multisampling is off. if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT) return m_efb_depth_texture.get(); // Can't resolve within a render pass. - state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -659,9 +662,9 @@ void FramebufferManager::DestroyConversionShaders() DestroyShader(m_ps_depth_resolve); } -u32 FramebufferManager::PeekEFBColor(StateTracker* state_tracker, u32 x, u32 y) +u32 FramebufferManager::PeekEFBColor(u32 x, u32 y) { - if (!m_color_readback_texture_valid && !PopulateColorReadbackTexture(state_tracker)) + if (!m_color_readback_texture_valid && !PopulateColorReadbackTexture()) return 0; u32 value; @@ -669,18 +672,18 @@ u32 FramebufferManager::PeekEFBColor(StateTracker* state_tracker, u32 x, u32 y) return value; } -bool FramebufferManager::PopulateColorReadbackTexture(StateTracker* state_tracker) +bool FramebufferManager::PopulateColorReadbackTexture() { // Can't be in our normal render pass. - state_tracker->EndRenderPass(); - state_tracker->OnReadback(); + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->OnReadback(); // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}}; Texture2D* src_texture = m_efb_color_texture.get(); VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_COLOR_BIT; if (m_efb_samples > 1) - src_texture = ResolveEFBColorTexture(state_tracker, src_region); + src_texture = ResolveEFBColorTexture(src_region); if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT) { @@ -728,8 +731,8 @@ bool FramebufferManager::PopulateColorReadbackTexture(StateTracker* state_tracke // Wait until the copy is complete. g_command_buffer_mgr->ExecuteCommandBuffer(false, true); - state_tracker->InvalidateDescriptorSets(); - state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateDescriptorSets(); + StateTracker::GetInstance()->SetPendingRebind(); // Map to host memory. if (!m_color_readback_texture->IsMapped() && !m_color_readback_texture->Map()) @@ -739,9 +742,9 @@ bool FramebufferManager::PopulateColorReadbackTexture(StateTracker* state_tracke return true; } -float FramebufferManager::PeekEFBDepth(StateTracker* state_tracker, u32 x, u32 y) +float FramebufferManager::PeekEFBDepth(u32 x, u32 y) { - if (!m_depth_readback_texture_valid && !PopulateDepthReadbackTexture(state_tracker)) + if (!m_depth_readback_texture_valid && !PopulateDepthReadbackTexture()) return 0.0f; float value; @@ -749,11 +752,11 @@ float FramebufferManager::PeekEFBDepth(StateTracker* state_tracker, u32 x, u32 y return value; } -bool FramebufferManager::PopulateDepthReadbackTexture(StateTracker* state_tracker) +bool FramebufferManager::PopulateDepthReadbackTexture() { // Can't be in our normal render pass. - state_tracker->EndRenderPass(); - state_tracker->OnReadback(); + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->OnReadback(); // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}}; @@ -762,7 +765,7 @@ bool FramebufferManager::PopulateDepthReadbackTexture(StateTracker* state_tracke if (m_efb_samples > 1) { // EFB depth resolves are written out as color textures - src_texture = ResolveEFBDepthTexture(state_tracker, src_region); + src_texture = ResolveEFBDepthTexture(src_region); src_aspect = VK_IMAGE_ASPECT_COLOR_BIT; } if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT) @@ -812,8 +815,8 @@ bool FramebufferManager::PopulateDepthReadbackTexture(StateTracker* state_tracke // Wait until the copy is complete. g_command_buffer_mgr->ExecuteCommandBuffer(false, true); - state_tracker->InvalidateDescriptorSets(); - state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateDescriptorSets(); + StateTracker::GetInstance()->SetPendingRebind(); // Map to host memory. if (!m_depth_readback_texture->IsMapped() && !m_depth_readback_texture->Map()) @@ -1086,11 +1089,11 @@ void FramebufferManager::DestroyReadbackFramebuffer() } } -void FramebufferManager::PokeEFBColor(StateTracker* state_tracker, u32 x, u32 y, u32 color) +void FramebufferManager::PokeEFBColor(u32 x, u32 y, u32 color) { // Flush if we exceeded the number of vertices per batch. if ((m_color_poke_vertices.size() + 6) > MAX_POKE_VERTICES) - FlushEFBPokes(state_tracker); + FlushEFBPokes(); CreatePokeVertices(&m_color_poke_vertices, x, y, 0.0f, color); @@ -1099,11 +1102,11 @@ void FramebufferManager::PokeEFBColor(StateTracker* state_tracker, u32 x, u32 y, m_color_readback_texture->WriteTexel(x, y, &color, sizeof(color)); } -void FramebufferManager::PokeEFBDepth(StateTracker* state_tracker, u32 x, u32 y, float depth) +void FramebufferManager::PokeEFBDepth(u32 x, u32 y, float depth) { // Flush if we exceeded the number of vertices per batch. if ((m_color_poke_vertices.size() + 6) > MAX_POKE_VERTICES) - FlushEFBPokes(state_tracker); + FlushEFBPokes(); CreatePokeVertices(&m_depth_poke_vertices, x, y, depth, 0); @@ -1140,27 +1143,22 @@ void FramebufferManager::CreatePokeVertices(std::vector* destinat } } -void FramebufferManager::FlushEFBPokes(StateTracker* state_tracker) +void FramebufferManager::FlushEFBPokes() { if (!m_color_poke_vertices.empty()) { - DrawPokeVertices(state_tracker, m_color_poke_vertices.data(), m_color_poke_vertices.size(), - true, false); - + DrawPokeVertices(m_color_poke_vertices.data(), m_color_poke_vertices.size(), true, false); m_color_poke_vertices.clear(); } if (!m_depth_poke_vertices.empty()) { - DrawPokeVertices(state_tracker, m_depth_poke_vertices.data(), m_depth_poke_vertices.size(), - false, true); - + DrawPokeVertices(m_depth_poke_vertices.data(), m_depth_poke_vertices.size(), false, true); m_depth_poke_vertices.clear(); } } -void FramebufferManager::DrawPokeVertices(StateTracker* state_tracker, - const EFBPokeVertex* vertices, size_t vertex_count, +void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t vertex_count, bool write_color, bool write_depth) { // Relatively simple since we don't have any bindings. @@ -1205,7 +1203,7 @@ void FramebufferManager::DrawPokeVertices(StateTracker* state_tracker, { // Kick a command buffer first. WARN_LOG(VIDEO, "Kicking command buffer due to no EFB poke space."); - Util::ExecuteCurrentCommandsAndRestoreState(state_tracker, true); + Util::ExecuteCurrentCommandsAndRestoreState(true); command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); if (!m_poke_vertex_stream_buffer->ReserveMemory(vertices_size, sizeof(EfbPokeData), true, true, @@ -1221,9 +1219,9 @@ void FramebufferManager::DrawPokeVertices(StateTracker* state_tracker, m_poke_vertex_stream_buffer->CommitMemory(vertices_size); // Set up state. - state_tracker->EndClearRenderPass(); - state_tracker->BeginRenderPass(); - state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->EndClearRenderPass(); + StateTracker::GetInstance()->BeginRenderPass(); + StateTracker::GetInstance()->SetPendingRebind(); Util::SetViewportAndScissor(command_buffer, 0, 0, m_efb_width, m_efb_height); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindVertexBuffers(command_buffer, 0, 1, &vb_buffer, &vb_offset); diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h index a8c5f0fc64..00fd335f49 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h @@ -30,6 +30,8 @@ public: FramebufferManager(); ~FramebufferManager(); + static FramebufferManager* GetInstance(); + bool Initialize(); VkRenderPass GetEFBLoadRenderPass() const { return m_efb_load_render_pass; } @@ -69,18 +71,18 @@ public: // This render pass can be used for other readback operations. VkRenderPass GetColorCopyForReadbackRenderPass() const { return m_copy_color_render_pass; } // Resolve color/depth textures to a non-msaa texture, and return it. - Texture2D* ResolveEFBColorTexture(StateTracker* state_tracker, const VkRect2D& region); - Texture2D* ResolveEFBDepthTexture(StateTracker* state_tracker, const VkRect2D& region); + Texture2D* ResolveEFBColorTexture(const VkRect2D& region); + Texture2D* ResolveEFBDepthTexture(const VkRect2D& region); // Reads a framebuffer value back from the GPU. This may block if the cache is not current. - u32 PeekEFBColor(StateTracker* state_tracker, u32 x, u32 y); - float PeekEFBDepth(StateTracker* state_tracker, u32 x, u32 y); + u32 PeekEFBColor(u32 x, u32 y); + float PeekEFBDepth(u32 x, u32 y); void InvalidatePeekCache(); // Writes a value to the framebuffer. This will never block, and writes will be batched. - void PokeEFBColor(StateTracker* state_tracker, u32 x, u32 y, u32 color); - void PokeEFBDepth(StateTracker* state_tracker, u32 x, u32 y, float depth); - void FlushEFBPokes(StateTracker* state_tracker); + void PokeEFBColor(u32 x, u32 y, u32 color); + void PokeEFBDepth(u32 x, u32 y, float depth); + void FlushEFBPokes(); private: struct EFBPokeVertex @@ -112,14 +114,14 @@ private: bool CompilePokeShaders(); void DestroyPokeShaders(); - bool PopulateColorReadbackTexture(StateTracker* state_tracker); - bool PopulateDepthReadbackTexture(StateTracker* state_tracker); + bool PopulateColorReadbackTexture(); + bool PopulateDepthReadbackTexture(); void CreatePokeVertices(std::vector* destination_list, u32 x, u32 y, float z, u32 color); - void DrawPokeVertices(StateTracker* state_tracker, const EFBPokeVertex* vertices, - size_t vertex_count, bool write_color, bool write_depth); + void DrawPokeVertices(const EFBPokeVertex* vertices, size_t vertex_count, bool write_color, + bool write_depth); VkRenderPass m_efb_load_render_pass = VK_NULL_HANDLE; VkRenderPass m_efb_clear_render_pass = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.cpp index 07100eb7bb..3e992d4944 100644 --- a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.cpp @@ -62,8 +62,7 @@ bool PaletteTextureConverter::Initialize() return true; } -void PaletteTextureConverter::ConvertTexture(StateTracker* state_tracker, - VkCommandBuffer command_buffer, +void PaletteTextureConverter::ConvertTexture(VkCommandBuffer command_buffer, VkRenderPass render_pass, VkFramebuffer dst_framebuffer, Texture2D* src_texture, u32 width, u32 height, void* palette, @@ -89,7 +88,7 @@ void PaletteTextureConverter::ConvertTexture(StateTracker* state_tracker, g_command_buffer_mgr->AllocateDescriptorSet(m_palette_set_layout)) == VK_NULL_HANDLE) { WARN_LOG(VIDEO, "Executing command list while waiting for space in palette buffer"); - Util::ExecuteCurrentCommandsAndRestoreState(state_tracker, false); + Util::ExecuteCurrentCommandsAndRestoreState(false); if (!m_palette_stream_buffer->ReserveMemory(palette_size, g_vulkan_context->GetTexelBufferAlignment()) || diff --git a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.h b/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.h index 39b8cccd8c..2540b5affa 100644 --- a/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.h +++ b/Source/Core/VideoBackends/Vulkan/PaletteTextureConverter.h @@ -13,7 +13,6 @@ namespace Vulkan { -class StateTracker; class Texture2D; // Since this converter uses a uniform texel buffer, we can't use the general pipeline generators. @@ -26,10 +25,9 @@ public: bool Initialize(); - void ConvertTexture(StateTracker* state_tracker, VkCommandBuffer command_buffer, - VkRenderPass render_pass, VkFramebuffer dst_framebuffer, - Texture2D* src_texture, u32 width, u32 height, void* palette, - TlutFormat format, u32 src_format); + void ConvertTexture(VkCommandBuffer command_buffer, VkRenderPass render_pass, + VkFramebuffer dst_framebuffer, Texture2D* src_texture, u32 width, u32 height, + void* palette, TlutFormat format, u32 src_format); private: static const size_t NUM_PALETTE_CONVERSION_SHADERS = 3; diff --git a/Source/Core/VideoBackends/Vulkan/PerfQuery.cpp b/Source/Core/VideoBackends/Vulkan/PerfQuery.cpp index 2a64babb32..11ba898bf6 100644 --- a/Source/Core/VideoBackends/Vulkan/PerfQuery.cpp +++ b/Source/Core/VideoBackends/Vulkan/PerfQuery.cpp @@ -32,10 +32,13 @@ PerfQuery::~PerfQuery() vkDestroyQueryPool(g_vulkan_context->GetDevice(), m_query_pool, nullptr); } -bool PerfQuery::Initialize(StateTracker* state_tracker) +Vulkan::PerfQuery* PerfQuery::GetInstance() { - m_state_tracker = state_tracker; + return static_cast(g_perf_query.get()); +} +bool PerfQuery::Initialize() +{ if (!CreateQueryPool()) { PanicAlert("Failed to create query pool"); @@ -86,11 +89,11 @@ void PerfQuery::EnableQuery(PerfQueryGroup type) // Ensure the query starts within a render pass. // TODO: Is this needed? - m_state_tracker->BeginRenderPass(); + StateTracker::GetInstance()->BeginRenderPass(); vkCmdBeginQuery(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_query_pool, index, flags); // Prevent background command buffer submission while the query is active. - m_state_tracker->SetBackgroundCommandBufferExecution(false); + StateTracker::GetInstance()->SetBackgroundCommandBufferExecution(false); } } @@ -101,7 +104,7 @@ void PerfQuery::DisableQuery(PerfQueryGroup type) // DisableQuery should be called for each EnableQuery, so subtract one to get the previous one. u32 index = (m_query_read_pos + m_query_count - 1) % PERF_QUERY_BUFFER_SIZE; vkCmdEndQuery(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_query_pool, index); - m_state_tracker->SetBackgroundCommandBufferExecution(true); + StateTracker::GetInstance()->SetBackgroundCommandBufferExecution(true); DEBUG_LOG(VIDEO, "end query %u", index); } } @@ -113,7 +116,7 @@ void PerfQuery::ResetQuery() std::fill_n(m_results, ArraySize(m_results), 0); // Reset entire query pool, ensuring all queries are ready to write to. - m_state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); vkCmdResetQueryPool(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_query_pool, 0, PERF_QUERY_BUFFER_SIZE); @@ -346,7 +349,7 @@ void PerfQuery::NonBlockingPartialFlush() // Submit a command buffer in the background if the front query is not bound to one. // Ideally this will complete before the buffer fills. if (m_query_buffer[m_query_read_pos].pending_fence == VK_NULL_HANDLE) - Util::ExecuteCurrentCommandsAndRestoreState(m_state_tracker, true, false); + Util::ExecuteCurrentCommandsAndRestoreState(true, false); } void PerfQuery::BlockingPartialFlush() @@ -360,7 +363,7 @@ void PerfQuery::BlockingPartialFlush() { // This will callback OnCommandBufferQueued which will set the fence on the entry. // We wait for completion, which will also call OnCommandBufferExecuted, and clear the fence. - Util::ExecuteCurrentCommandsAndRestoreState(m_state_tracker, false, true); + Util::ExecuteCurrentCommandsAndRestoreState(false, true); } else { diff --git a/Source/Core/VideoBackends/Vulkan/PerfQuery.h b/Source/Core/VideoBackends/Vulkan/PerfQuery.h index 3d385299f1..c5f5d13e90 100644 --- a/Source/Core/VideoBackends/Vulkan/PerfQuery.h +++ b/Source/Core/VideoBackends/Vulkan/PerfQuery.h @@ -14,7 +14,6 @@ namespace Vulkan { class StagingBuffer; -class StateTracker; class PerfQuery : public PerfQueryBase { @@ -22,7 +21,9 @@ public: PerfQuery(); ~PerfQuery(); - bool Initialize(StateTracker* state_tracker); + static PerfQuery* GetInstance(); + + bool Initialize(); void EnableQuery(PerfQueryGroup type) override; void DisableQuery(PerfQueryGroup type) override; @@ -52,8 +53,6 @@ private: void NonBlockingPartialFlush(); void BlockingPartialFlush(); - StateTracker* m_state_tracker = nullptr; - // when testing in SMS: 64 was too small, 128 was ok // TODO: This should be size_t, but the base class uses u32s using PerfQueryDataType = u32; diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 3fac85e340..714a021699 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -68,10 +68,13 @@ Renderer::~Renderer() DestroySemaphores(); } -bool Renderer::Initialize(FramebufferManager* framebuffer_mgr) +Renderer* Renderer::GetInstance() +{ + return static_cast(g_renderer.get()); +} + +bool Renderer::Initialize() { - m_framebuffer_mgr = framebuffer_mgr; - m_state_tracker = std::make_unique(); BindEFBToStateTracker(); if (!CreateSemaphores()) @@ -103,9 +106,9 @@ bool Renderer::Initialize(FramebufferManager* framebuffer_mgr) if (g_vulkan_context->SupportsBoundingBox()) { // Bind bounding box to state tracker - m_state_tracker->SetBBoxBuffer(m_bounding_box->GetGPUBuffer(), - m_bounding_box->GetGPUBufferOffset(), - m_bounding_box->GetGPUBufferSize()); + StateTracker::GetInstance()->SetBBoxBuffer(m_bounding_box->GetGPUBuffer(), + m_bounding_box->GetGPUBufferOffset(), + m_bounding_box->GetGPUBufferSize()); } // Various initialization routines will have executed commands on the command buffer. @@ -170,7 +173,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { if (type == PEEK_COLOR) { - u32 color = m_framebuffer_mgr->PeekEFBColor(m_state_tracker.get(), x, y); + u32 color = FramebufferManager::GetInstance()->PeekEFBColor(x, y); // a little-endian value is expected to be returned color = ((color & 0xFF00FF00) | ((color >> 16) & 0xFF) | ((color << 16) & 0xFF0000)); @@ -207,7 +210,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) else // if (type == PEEK_Z) { // Depth buffer is inverted for improved precision near far plane - float depth = 1.0f - m_framebuffer_mgr->PeekEFBDepth(m_state_tracker.get(), x, y); + float depth = 1.0f - FramebufferManager::GetInstance()->PeekEFBDepth(x, y); u32 ret = 0; if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) @@ -235,7 +238,7 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num const EfbPokeData& point = points[i]; u32 color = ((point.data & 0xFF00FF00) | ((point.data >> 16) & 0xFF) | ((point.data << 16) & 0xFF0000)); - m_framebuffer_mgr->PokeEFBColor(m_state_tracker.get(), point.x, point.y, color); + FramebufferManager::GetInstance()->PokeEFBColor(point.x, point.y, color); } } else // if (type == POKE_Z) @@ -245,14 +248,14 @@ void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num // Convert to floating-point depth. const EfbPokeData& point = points[i]; float depth = (1.0f - float(point.data & 0xFFFFFF) / 16777216.0f); - m_framebuffer_mgr->PokeEFBDepth(m_state_tracker.get(), point.x, point.y, depth); + FramebufferManager::GetInstance()->PokeEFBDepth(point.x, point.y, depth); } } } u16 Renderer::BBoxRead(int index) { - s32 value = m_bounding_box->Get(m_state_tracker.get(), static_cast(index)); + s32 value = m_bounding_box->Get(static_cast(index)); // Here we get the min/max value of the truncated position of the upscaled framebuffer. // So we have to correct them to the unscaled EFB sizes. @@ -294,7 +297,7 @@ void Renderer::BBoxWrite(int index, u16 value) scaled_value = scaled_value * s_target_height / EFB_HEIGHT; } - m_bounding_box->Set(m_state_tracker.get(), static_cast(index), scaled_value); + m_bounding_box->Set(static_cast(index), scaled_value); } TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) @@ -314,8 +317,8 @@ void Renderer::BeginFrame() // Ensure that the state tracker rebinds everything, and allocates a new set // of descriptors out of the next pool. - m_state_tracker->InvalidateDescriptorSets(); - m_state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateDescriptorSets(); + StateTracker::GetInstance()->SetPendingRebind(); } void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, @@ -350,7 +353,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha // If we're not in a render pass (start of the frame), we can use a clear render pass // to discard the data, rather than loading and then clearing. bool use_clear_render_pass = (color_enable && alpha_enable && z_enable); - if (m_state_tracker->InRenderPass()) + if (StateTracker::GetInstance()->InRenderPass()) { // Prefer not to end a render pass just to do a clear. use_clear_render_pass = false; @@ -360,7 +363,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha if (use_clear_render_pass) { VkClearValue clear_values[2] = {clear_color_value, clear_depth_value}; - m_state_tracker->BeginClearRenderPass(target_vk_rc, clear_values); + StateTracker::GetInstance()->BeginClearRenderPass(target_vk_rc, clear_values); return; } @@ -388,17 +391,17 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha } if (num_clear_attachments > 0) { - VkClearRect clear_rect = {target_vk_rc, 0, m_framebuffer_mgr->GetEFBLayers()}; - if (!m_state_tracker->IsWithinRenderArea(target_vk_rc.offset.x, target_vk_rc.offset.y, - target_vk_rc.extent.width, - target_vk_rc.extent.height)) + VkClearRect vk_rect = {target_vk_rc, 0, FramebufferManager::GetInstance()->GetEFBLayers()}; + if (!StateTracker::GetInstance()->IsWithinRenderArea( + target_vk_rc.offset.x, target_vk_rc.offset.y, target_vk_rc.extent.width, + target_vk_rc.extent.height)) { - m_state_tracker->EndClearRenderPass(); + StateTracker::GetInstance()->EndClearRenderPass(); } - m_state_tracker->BeginRenderPass(); + StateTracker::GetInstance()->BeginRenderPass(); vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_clear_attachments, - clear_attachments, 1, &clear_rect); + clear_attachments, 1, &vk_rect); } } @@ -407,13 +410,14 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha return; // Clearing must occur within a render pass. - if (!m_state_tracker->IsWithinRenderArea(target_vk_rc.offset.x, target_vk_rc.offset.y, - target_vk_rc.extent.width, target_vk_rc.extent.height)) + if (!StateTracker::GetInstance()->IsWithinRenderArea(target_vk_rc.offset.x, target_vk_rc.offset.y, + target_vk_rc.extent.width, + target_vk_rc.extent.height)) { - m_state_tracker->EndClearRenderPass(); + StateTracker::GetInstance()->EndClearRenderPass(); } - m_state_tracker->BeginRenderPass(); - m_state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->BeginRenderPass(); + StateTracker::GetInstance()->SetPendingRebind(); // Mask away the appropriate colors and use a shader BlendState blend_state = Util::GetNoBlendingBlendState(); @@ -431,13 +435,14 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha RasterizationState rs_state = Util::GetNoCullRasterizationState(); rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE; - rs_state.samples = m_framebuffer_mgr->GetEFBSamples(); + rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples(); // No need to start a new render pass, but we do need to restore viewport state - UtilityShaderDraw draw( - g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetStandardPipelineLayout(), - m_framebuffer_mgr->GetEFBLoadRenderPass(), g_object_cache->GetPassthroughVertexShader(), - g_object_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader); + UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), + g_object_cache->GetStandardPipelineLayout(), + FramebufferManager::GetInstance()->GetEFBLoadRenderPass(), + g_object_cache->GetPassthroughVertexShader(), + g_object_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader); draw.SetRasterizationState(rs_state); draw.SetDepthStencilState(depth_state); @@ -451,9 +456,9 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha void Renderer::ReinterpretPixelData(unsigned int convtype) { - m_state_tracker->EndRenderPass(); - m_state_tracker->SetPendingRebind(); - m_framebuffer_mgr->ReinterpretPixelData(convtype); + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->SetPendingRebind(); + FramebufferManager::GetInstance()->ReinterpretPixelData(convtype); // EFB framebuffer has now changed, so update accordingly. BindEFBToStateTracker(); @@ -463,20 +468,21 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height const EFBRectangle& rc, u64 ticks, float gamma) { // Flush any pending EFB pokes. - m_framebuffer_mgr->FlushEFBPokes(m_state_tracker.get()); + FramebufferManager::GetInstance()->FlushEFBPokes(); // End the current render pass. - m_state_tracker->EndRenderPass(); - m_state_tracker->OnEndFrame(); + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->OnEndFrame(); // Scale the source rectangle to the selected internal resolution. TargetRectangle source_rc = Renderer::ConvertEFBRectangle(rc); // Transition the EFB render target to a shader resource. VkRect2D src_region = {{0, 0}, - {m_framebuffer_mgr->GetEFBWidth(), m_framebuffer_mgr->GetEFBHeight()}}; + {FramebufferManager::GetInstance()->GetEFBWidth(), + FramebufferManager::GetInstance()->GetEFBHeight()}}; Texture2D* efb_color_texture = - m_framebuffer_mgr->ResolveEFBColorTexture(m_state_tracker.get(), src_region); + FramebufferManager::GetInstance()->ResolveEFBColorTexture(src_region); efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -491,7 +497,7 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height } // Restore the EFB color texture to color attachment ready for rendering the next frame. - m_framebuffer_mgr->GetEFBColorTexture()->TransitionToLayout( + FramebufferManager::GetInstance()->GetEFBColorTexture()->TransitionToLayout( g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); // Ensure the worker thread is not still submitting a previous command buffer. @@ -613,19 +619,20 @@ bool Renderer::DrawScreenshot(const TargetRectangle& src_rect, const Texture2D* VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; VkClearRect clear_rect = {{{0, 0}, {width, height}}, 0, 1}; VkClearAttachment clear_attachment = {VK_IMAGE_ASPECT_COLOR_BIT, 0, clear_value}; - VkRenderPassBeginInfo info = {VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - nullptr, - m_framebuffer_mgr->GetColorCopyForReadbackRenderPass(), - m_screenshot_framebuffer, - {{0, 0}, {width, height}}, - 1, - &clear_value}; + VkRenderPassBeginInfo info = { + VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, + nullptr, + FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(), + m_screenshot_framebuffer, + {{0, 0}, {width, height}}, + 1, + &clear_value}; vkCmdBeginRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer(), &info, VK_SUBPASS_CONTENTS_INLINE); vkCmdClearAttachments(g_command_buffer_mgr->GetCurrentCommandBuffer(), 1, &clear_attachment, 1, &clear_rect); - BlitScreen(m_framebuffer_mgr->GetColorCopyForReadbackRenderPass(), target_rect, src_rect, src_tex, - true); + BlitScreen(FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(), target_rect, + src_rect, src_tex, true); vkCmdEndRenderPass(g_command_buffer_mgr->GetCurrentCommandBuffer()); // Copy to the readback texture. @@ -712,7 +719,7 @@ bool Renderer::ResizeScreenshotBuffer(u32 new_width, u32 new_height) VkImageView attachment = m_screenshot_render_texture->GetView(); VkFramebufferCreateInfo info = {}; info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - info.renderPass = m_framebuffer_mgr->GetColorCopyForReadbackRenderPass(); + info.renderPass = FramebufferManager::GetInstance()->GetColorCopyForReadbackRenderPass(); info.attachmentCount = 1; info.pAttachments = &attachment; info.width = new_width; @@ -889,8 +896,8 @@ void Renderer::CheckForConfigChanges() if (msaa_changed || stereo_changed) { g_command_buffer_mgr->WaitForGPUIdle(); - m_framebuffer_mgr->RecreateRenderPass(); - m_framebuffer_mgr->ResizeEFBTextures(); + FramebufferManager::GetInstance()->RecreateRenderPass(); + FramebufferManager::GetInstance()->ResizeEFBTextures(); BindEFBToStateTracker(); } @@ -900,7 +907,7 @@ void Renderer::CheckForConfigChanges() { g_command_buffer_mgr->WaitForGPUIdle(); RecompileShaders(); - m_framebuffer_mgr->RecompileShaders(); + FramebufferManager::GetInstance()->RecompileShaders(); g_object_cache->ClearPipelineCache(); } @@ -931,25 +938,28 @@ void Renderer::OnSwapChainResized() void Renderer::BindEFBToStateTracker() { // Update framebuffer in state tracker - VkRect2D framebuffer_size = { - {0, 0}, {m_framebuffer_mgr->GetEFBWidth(), m_framebuffer_mgr->GetEFBHeight()}}; - m_state_tracker->SetRenderPass(m_framebuffer_mgr->GetEFBLoadRenderPass(), - m_framebuffer_mgr->GetEFBClearRenderPass()); - m_state_tracker->SetFramebuffer(m_framebuffer_mgr->GetEFBFramebuffer(), framebuffer_size); + VkRect2D framebuffer_size = {{0, 0}, + {FramebufferManager::GetInstance()->GetEFBWidth(), + FramebufferManager::GetInstance()->GetEFBHeight()}}; + StateTracker::GetInstance()->SetRenderPass( + FramebufferManager::GetInstance()->GetEFBLoadRenderPass(), + FramebufferManager::GetInstance()->GetEFBClearRenderPass()); + StateTracker::GetInstance()->SetFramebuffer( + FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size); // Update rasterization state with MSAA info RasterizationState rs_state = {}; - rs_state.bits = m_state_tracker->GetRasterizationState().bits; - rs_state.samples = m_framebuffer_mgr->GetEFBSamples(); + rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits; + rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples(); rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE; - m_state_tracker->SetRasterizationState(rs_state); + StateTracker::GetInstance()->SetRasterizationState(rs_state); } void Renderer::ResizeEFBTextures() { // Ensure the GPU is finished with the current EFB textures. g_command_buffer_mgr->WaitForGPUIdle(); - m_framebuffer_mgr->ResizeEFBTextures(); + FramebufferManager::GetInstance()->ResizeEFBTextures(); BindEFBToStateTracker(); // Viewport and scissor rect have to be reset since they will be scaled differently. @@ -976,19 +986,19 @@ void Renderer::ApplyState(bool bUseDstAlpha) void Renderer::ResetAPIState() { // End the EFB render pass if active - m_state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); } void Renderer::RestoreAPIState() { // Instruct the state tracker to re-bind everything before the next draw - m_state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->SetPendingRebind(); } void Renderer::SetGenerationMode() { RasterizationState new_rs_state = {}; - new_rs_state.bits = m_state_tracker->GetRasterizationState().bits; + new_rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits; switch (bpmem.genMode.cullmode) { @@ -1009,7 +1019,7 @@ void Renderer::SetGenerationMode() break; } - m_state_tracker->SetRasterizationState(new_rs_state); + StateTracker::GetInstance()->SetRasterizationState(new_rs_state); } void Renderer::SetDepthMode() @@ -1050,7 +1060,7 @@ void Renderer::SetDepthMode() break; } - m_state_tracker->SetDepthStencilState(new_ds_state); + StateTracker::GetInstance()->SetDepthStencilState(new_ds_state); } void Renderer::SetColorMask() @@ -1066,16 +1076,16 @@ void Renderer::SetColorMask() } BlendState new_blend_state = {}; - new_blend_state.bits = m_state_tracker->GetBlendState().bits; + new_blend_state.bits = StateTracker::GetInstance()->GetBlendState().bits; new_blend_state.write_mask = color_mask; - m_state_tracker->SetBlendState(new_blend_state); + StateTracker::GetInstance()->SetBlendState(new_blend_state); } void Renderer::SetBlendMode(bool force_update) { BlendState new_blend_state = {}; - new_blend_state.bits = m_state_tracker->GetBlendState().bits; + new_blend_state.bits = StateTracker::GetInstance()->GetBlendState().bits; // Fast path for blending disabled if (!bpmem.blendmode.blendenable) @@ -1087,7 +1097,7 @@ void Renderer::SetBlendMode(bool force_update) new_blend_state.alpha_blend_op = VK_BLEND_OP_ADD; new_blend_state.src_alpha_blend = VK_BLEND_FACTOR_ONE; new_blend_state.dst_alpha_blend = VK_BLEND_FACTOR_ZERO; - m_state_tracker->SetBlendState(new_blend_state); + StateTracker::GetInstance()->SetBlendState(new_blend_state); return; } // Fast path for subtract blending @@ -1100,7 +1110,7 @@ void Renderer::SetBlendMode(bool force_update) new_blend_state.alpha_blend_op = VK_BLEND_OP_REVERSE_SUBTRACT; new_blend_state.src_alpha_blend = VK_BLEND_FACTOR_ONE; new_blend_state.dst_alpha_blend = VK_BLEND_FACTOR_ONE; - m_state_tracker->SetBlendState(new_blend_state); + StateTracker::GetInstance()->SetBlendState(new_blend_state); return; } @@ -1195,13 +1205,13 @@ void Renderer::SetBlendMode(bool force_update) new_blend_state.dst_alpha_blend = Util::GetAlphaBlendFactor(new_blend_state.dst_blend); } - m_state_tracker->SetBlendState(new_blend_state); + StateTracker::GetInstance()->SetBlendState(new_blend_state); } void Renderer::SetLogicOpMode() { BlendState new_blend_state = {}; - new_blend_state.bits = m_state_tracker->GetBlendState().bits; + new_blend_state.bits = StateTracker::GetInstance()->GetBlendState().bits; // Does our device support logic ops? bool logic_op_enable = bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable; @@ -1224,7 +1234,7 @@ void Renderer::SetLogicOpMode() new_blend_state.logic_op = VK_LOGIC_OP_CLEAR; } - m_state_tracker->SetBlendState(new_blend_state); + StateTracker::GetInstance()->SetBlendState(new_blend_state); } else { @@ -1269,7 +1279,7 @@ void Renderer::SetLogicOpMode() new_blend_state.src_alpha_blend = Util::GetAlphaBlendFactor(new_blend_state.src_blend); new_blend_state.dst_alpha_blend = Util::GetAlphaBlendFactor(new_blend_state.dst_blend); - m_state_tracker->SetBlendState(new_blend_state); + StateTracker::GetInstance()->SetBlendState(new_blend_state); } else { @@ -1338,7 +1348,7 @@ void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) sampler = g_object_cache->GetPointSampler(); } - m_state_tracker->SetSampler(bind_index, sampler); + StateTracker::GetInstance()->SetSampler(bind_index, sampler); m_sampler_states[bind_index].bits = new_state.bits; } @@ -1352,7 +1362,7 @@ void Renderer::ResetSamplerStates() for (size_t i = 0; i < m_sampler_states.size(); i++) { m_sampler_states[i].bits = std::numeric_limits::max(); - m_state_tracker->SetSampler(i, g_object_cache->GetPointSampler()); + StateTracker::GetInstance()->SetSampler(i, g_object_cache->GetPointSampler()); } // Invalidate all sampler objects (some will be unused now). @@ -1375,7 +1385,7 @@ void Renderer::SetScissorRect(const EFBRectangle& rc) {target_rc.left, target_rc.top}, {static_cast(target_rc.GetWidth()), static_cast(target_rc.GetHeight())}}; - m_state_tracker->SetScissor(scissor); + StateTracker::GetInstance()->SetScissor(scissor); } void Renderer::SetViewport() @@ -1420,7 +1430,7 @@ void Renderer::SetViewport() } VkViewport viewport = {x, y, width, height, min_depth, max_depth}; - m_state_tracker->SetViewport(viewport); + StateTracker::GetInstance()->SetViewport(viewport); } void Renderer::ChangeSurface(void* new_surface_handle) diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index d3a5d42926..a84449dbed 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -18,7 +18,6 @@ class BoundingBox; class FramebufferManager; class SwapChain; class StagingTexture2D; -class StateTracker; class Texture2D; class RasterFont; @@ -28,10 +27,11 @@ public: Renderer(std::unique_ptr swap_chain); ~Renderer(); + static Renderer* GetInstance(); + SwapChain* GetSwapChain() const { return m_swap_chain.get(); } - StateTracker* GetStateTracker() const { return m_state_tracker.get(); } BoundingBox* GetBoundingBox() const { return m_bounding_box.get(); } - bool Initialize(FramebufferManager* framebuffer_mgr); + bool Initialize(); void RenderText(const std::string& pstr, int left, int top, u32 color) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; @@ -94,13 +94,11 @@ private: const TargetRectangle& src_rect, const Texture2D* src_tex, bool linear_filter); bool ResizeScreenshotBuffer(u32 new_width, u32 new_height); void DestroyScreenshotResources(); - FramebufferManager* m_framebuffer_mgr = nullptr; VkSemaphore m_image_available_semaphore = VK_NULL_HANDLE; VkSemaphore m_rendering_finished_semaphore = VK_NULL_HANDLE; std::unique_ptr m_swap_chain; - std::unique_ptr m_state_tracker; std::unique_ptr m_bounding_box; std::unique_ptr m_raster_font; diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 84b1099862..bfd198886b 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -24,10 +24,33 @@ namespace Vulkan { -StateTracker::StateTracker() +static std::unique_ptr s_state_tracker; + +StateTracker* StateTracker::GetInstance() +{ + return s_state_tracker.get(); +} + +bool StateTracker::CreateInstance() +{ + _assert_(!s_state_tracker); + s_state_tracker = std::make_unique(); + if (!s_state_tracker->Initialize()) + { + s_state_tracker.reset(); + return false; + } + return true; +} + +void StateTracker::DestroyInstance() +{ + s_state_tracker.reset(); +} + +bool StateTracker::Initialize() { // Set some sensible defaults - m_pipeline_state.pipeline_layout = g_object_cache->GetStandardPipelineLayout(); m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE; m_pipeline_state.rasterization_state.per_sample_shading = VK_FALSE; m_pipeline_state.rasterization_state.depth_clamp = VK_FALSE; @@ -68,7 +91,10 @@ StateTracker::StateTracker() StreamBuffer::Create(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, INITIAL_UNIFORM_STREAM_BUFFER_SIZE, MAXIMUM_UNIFORM_STREAM_BUFFER_SIZE); if (!m_uniform_stream_buffer) + { PanicAlert("Failed to create uniform stream buffer"); + return false; + } // The validation layer complains if max(offsets) + max(ubo_ranges) >= ubo_size. // To work around this we reserve the maximum buffer size at all times, but only commit @@ -87,10 +113,7 @@ StateTracker::StateTracker() // Set default constants UploadAllConstants(); -} - -StateTracker::~StateTracker() -{ + return true; } void StateTracker::SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset) @@ -372,7 +395,7 @@ void StateTracker::UploadAllConstants() // If this fails, wait until the GPU has caught up. // The only places that call constant updates are safe to have state restored. WARN_LOG(VIDEO, "Executing command list while waiting for space in uniform buffer"); - Util::ExecuteCurrentCommandsAndRestoreState(this, false); + Util::ExecuteCurrentCommandsAndRestoreState(false); if (!m_uniform_stream_buffer->ReserveMemory(total_allocation_size, g_vulkan_context->GetUniformBufferAlignment(), true, true, false)) diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index a763c72b7f..b31adec6b5 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -24,8 +24,12 @@ class VertexFormat; class StateTracker { public: - StateTracker(); - ~StateTracker(); + StateTracker() = default; + ~StateTracker() = default; + + static StateTracker* GetInstance(); + static bool CreateInstance(); + static void DestroyInstance(); const RasterizationState& GetRasterizationState() const { @@ -108,6 +112,8 @@ public: bool IsWithinRenderArea(s32 x, s32 y, u32 width, u32 height) const; private: + bool Initialize(); + // 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; diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp index 60790c687f..9795492d5a 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.cpp @@ -44,9 +44,13 @@ TextureCache::~TextureCache() TextureCache::DeleteShaders(); } -bool TextureCache::Initialize(StateTracker* state_tracker) +TextureCache* TextureCache::GetInstance() +{ + return static_cast(g_texture_cache.get()); +} + +bool TextureCache::Initialize() { - m_state_tracker = state_tracker; m_texture_upload_buffer = StreamBuffer::Create(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, INITIAL_TEXTURE_UPLOAD_BUFFER_SIZE, MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE); @@ -99,8 +103,8 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase* if (unconverted->IsEfbCopy()) { command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - m_state_tracker->EndRenderPass(); - m_state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->SetPendingRebind(); } else { @@ -109,9 +113,9 @@ void TextureCache::ConvertTexture(TCacheEntryBase* base_entry, TCacheEntryBase* } m_palette_texture_converter->ConvertTexture( - m_state_tracker, command_buffer, GetRenderPassForTextureUpdate(entry->GetTexture()), - entry->GetFramebuffer(), unconverted->GetTexture(), entry->config.width, entry->config.height, - palette, format, unconverted->format); + command_buffer, GetRenderPassForTextureUpdate(entry->GetTexture()), entry->GetFramebuffer(), + unconverted->GetTexture(), entry->config.width, entry->config.height, palette, format, + unconverted->format); // Render pass transitions to SHADER_READ_ONLY. entry->GetTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -121,12 +125,8 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_ u32 num_blocks_y, u32 memory_stride, PEControl::PixelFormat src_format, const EFBRectangle& src_rect, bool is_intensity, bool scale_by_half) { - // A better way of doing this would be nice. - FramebufferManager* framebuffer_mgr = - static_cast(g_framebuffer_manager.get()); - // Flush EFB pokes first, as they're expected to be included. - framebuffer_mgr->FlushEFBPokes(m_state_tracker); + FramebufferManager::GetInstance()->FlushEFBPokes(); // MSAA case where we need to resolve first. // TODO: Do in one pass. @@ -134,24 +134,26 @@ void TextureCache::CopyEFB(u8* dst, u32 format, u32 native_width, u32 bytes_per_ VkRect2D region = {{scaled_src_rect.left, scaled_src_rect.top}, {static_cast(scaled_src_rect.GetWidth()), static_cast(scaled_src_rect.GetHeight())}}; - Texture2D* src_texture = (src_format == PEControl::Z24) ? - framebuffer_mgr->ResolveEFBDepthTexture(m_state_tracker, region) : - framebuffer_mgr->ResolveEFBColorTexture(m_state_tracker, region); + Texture2D* src_texture; + if (src_format == PEControl::Z24) + src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region); + else + src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(region); // End render pass before barrier (since we have no self-dependencies) - m_state_tracker->EndRenderPass(); - m_state_tracker->SetPendingRebind(); - m_state_tracker->InvalidateDescriptorSets(); - m_state_tracker->OnReadback(); + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateDescriptorSets(); + StateTracker::GetInstance()->OnReadback(); // Transition to shader resource before reading. VkImageLayout original_layout = src_texture->GetLayout(); src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - m_texture_encoder->EncodeTextureToRam(m_state_tracker, src_texture->GetView(), dst, format, - native_width, bytes_per_row, num_blocks_y, memory_stride, - src_format, is_intensity, scale_by_half, src_rect); + m_texture_encoder->EncodeTextureToRam(src_texture->GetView(), dst, format, native_width, + bytes_per_row, num_blocks_y, memory_stride, src_format, + is_intensity, scale_by_half, src_rect); // Transition back to original state src_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), original_layout); @@ -207,7 +209,7 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry texture->GetLayout(), &clear_value, 1, &clear_range); } - return new TCacheEntry(config, this, std::move(texture), framebuffer); + return new TCacheEntry(config, std::move(texture), framebuffer); } bool TextureCache::CreateRenderPasses() @@ -319,20 +321,17 @@ VkRenderPass TextureCache::GetRenderPassForTextureUpdate(const Texture2D* textur return m_update_render_pass; } -TextureCache::TCacheEntry::TCacheEntry(const TCacheEntryConfig& config_, TextureCache* parent, +TextureCache::TCacheEntry::TCacheEntry(const TCacheEntryConfig& config_, std::unique_ptr texture, VkFramebuffer framebuffer) - : TCacheEntryBase(config_), m_parent(parent), m_texture(std::move(texture)), - m_framebuffer(framebuffer) + : TCacheEntryBase(config_), m_texture(std::move(texture)), m_framebuffer(framebuffer) { } TextureCache::TCacheEntry::~TCacheEntry() { - // Texture is automatically cleaned up, however, we don't want to leave it bound to the state - // tracker. - m_parent->m_state_tracker->UnbindTexture(m_texture->GetView()); - + // Texture is automatically cleaned up, however, we don't want to leave it bound. + StateTracker::GetInstance()->UnbindTexture(m_texture->GetView()); if (m_framebuffer != VK_NULL_HANDLE) g_command_buffer_mgr->DeferFramebufferDestruction(m_framebuffer); } @@ -376,14 +375,14 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, (upload_size + upload_alignment) <= MAXIMUM_TEXTURE_UPLOAD_BUFFER_SIZE) { // Assume tightly packed rows, with no padding as the buffer source. - StreamBuffer* upload_buffer = m_parent->m_texture_upload_buffer.get(); + StreamBuffer* upload_buffer = TextureCache::GetInstance()->m_texture_upload_buffer.get(); // Allocate memory from the streaming buffer for the texture data. if (!upload_buffer->ReserveMemory(upload_size, g_vulkan_context->GetBufferImageGranularity())) { // Execute the command buffer first. WARN_LOG(VIDEO, "Executing command list while waiting for space in texture upload buffer"); - Util::ExecuteCurrentCommandsAndRestoreState(m_parent->m_state_tracker, false); + Util::ExecuteCurrentCommandsAndRestoreState(false); // Try allocating again. This may cause a fence wait. if (!upload_buffer->ReserveMemory(upload_size, g_vulkan_context->GetBufferImageGranularity())) @@ -470,23 +469,25 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat bool is_depth_copy = (src_format == PEControl::Z24); // Flush EFB pokes first, as they're expected to be included. - framebuffer_mgr->FlushEFBPokes(m_parent->m_state_tracker); + framebuffer_mgr->FlushEFBPokes(); // Has to be flagged as a render target. _assert_(m_framebuffer != VK_NULL_HANDLE); // Can't be done in a render pass, since we're doing our own render pass! - StateTracker* state_tracker = m_parent->m_state_tracker; VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer(); - state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); // Transition EFB to shader resource before binding VkRect2D region = {{scaled_src_rect.left, scaled_src_rect.top}, {static_cast(scaled_src_rect.GetWidth()), static_cast(scaled_src_rect.GetHeight())}}; - Texture2D* src_texture = is_depth_copy ? - framebuffer_mgr->ResolveEFBDepthTexture(state_tracker, region) : - framebuffer_mgr->ResolveEFBColorTexture(state_tracker, region); + Texture2D* src_texture; + if (is_depth_copy) + src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region); + else + src_texture = FramebufferManager::GetInstance()->ResolveEFBColorTexture(region); + VkSampler src_sampler = scale_by_half ? g_object_cache->GetLinearSampler() : g_object_cache->GetPointSampler(); VkImageLayout original_layout = src_texture->GetLayout(); @@ -494,9 +495,10 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat UtilityShaderDraw draw( command_buffer, g_object_cache->GetPushConstantPipelineLayout(), - m_parent->GetRenderPassForTextureUpdate(m_texture.get()), + TextureCache::GetInstance()->GetRenderPassForTextureUpdate(m_texture.get()), g_object_cache->GetPassthroughVertexShader(), g_object_cache->GetPassthroughGeometryShader(), - is_depth_copy ? m_parent->m_efb_depth_to_tex_shader : m_parent->m_efb_color_to_tex_shader); + is_depth_copy ? TextureCache::GetInstance()->m_efb_depth_to_tex_shader : + TextureCache::GetInstance()->m_efb_color_to_tex_shader); draw.SetPushConstants(colmat, (is_depth_copy ? sizeof(float) * 20 : sizeof(float) * 28)); draw.SetPSSampler(0, src_texture->GetView(), src_sampler); @@ -512,7 +514,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u8* dst, PEControl::PixelFormat draw.EndRenderPass(); // We touched everything, so put it back. - state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->SetPendingRebind(); // Transition the EFB back to its original layout. src_texture->TransitionToLayout(command_buffer, original_layout); @@ -553,7 +555,7 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* }; // Must be called outside of a render pass. - m_parent->m_state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); source_vk->m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); m_texture->TransitionToLayout(command_buffer, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); @@ -569,8 +571,8 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* } // Can't do this within a game render pass. - m_parent->m_state_tracker->EndRenderPass(); - m_parent->m_state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->SetPendingRebind(); // Can't render to a non-rendertarget (no framebuffer). _assert_msg_(VIDEO, config.rendertarget, @@ -578,8 +580,9 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* UtilityShaderDraw draw( g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetStandardPipelineLayout(), - m_parent->GetRenderPassForTextureUpdate(m_texture.get()), - g_object_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE, m_parent->m_copy_shader); + TextureCache::GetInstance()->GetRenderPassForTextureUpdate(m_texture.get()), + g_object_cache->GetPassthroughVertexShader(), VK_NULL_HANDLE, + TextureCache::GetInstance()->m_copy_shader); VkRect2D region = { {dst_rect.left, dst_rect.top}, @@ -597,7 +600,7 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* void TextureCache::TCacheEntry::Bind(unsigned int stage) { - m_parent->m_state_tracker->SetTexture(stage, m_texture->GetView()); + StateTracker::GetInstance()->SetTexture(stage, m_texture->GetView()); } bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level) @@ -617,7 +620,7 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l // since we'll be executing the command buffer. m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - m_parent->m_state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); // Copy to download buffer. staging_texture->CopyFromImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), @@ -630,8 +633,8 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l // Block until the GPU has finished copying to the staging texture. g_command_buffer_mgr->ExecuteCommandBuffer(false, true); - m_parent->m_state_tracker->InvalidateDescriptorSets(); - m_parent->m_state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateDescriptorSets(); + StateTracker::GetInstance()->SetPendingRebind(); // Map the staging texture so we can copy the contents out. if (staging_texture->Map()) diff --git a/Source/Core/VideoBackends/Vulkan/TextureCache.h b/Source/Core/VideoBackends/Vulkan/TextureCache.h index 18c8bd6020..1de1bbfc10 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureCache.h +++ b/Source/Core/VideoBackends/Vulkan/TextureCache.h @@ -23,7 +23,9 @@ public: TextureCache(); ~TextureCache(); - bool Initialize(StateTracker* state_tracker); + static TextureCache* GetInstance(); + + bool Initialize(); bool CompileShaders() override; void DeleteShaders() override; @@ -37,8 +39,8 @@ public: private: struct TCacheEntry : TCacheEntryBase { - TCacheEntry(const TCacheEntryConfig& config_, TextureCache* parent, - std::unique_ptr texture, VkFramebuffer framebuffer); + TCacheEntry(const TCacheEntryConfig& config_, std::unique_ptr texture, + VkFramebuffer framebuffer); ~TCacheEntry(); Texture2D* GetTexture() const { return m_texture.get(); } @@ -55,7 +57,6 @@ private: bool Save(const std::string& filename, unsigned int level) override; private: - TextureCache* m_parent; std::unique_ptr m_texture; // If we're an EFB copy, framebuffer for drawing into. @@ -68,8 +69,6 @@ private: VkRenderPass GetRenderPassForTextureUpdate(const Texture2D* texture) const; - StateTracker* m_state_tracker = nullptr; - VkRenderPass m_initialize_render_pass = VK_NULL_HANDLE; VkRenderPass m_update_render_pass = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/TextureEncoder.cpp b/Source/Core/VideoBackends/Vulkan/TextureEncoder.cpp index 0771d37193..0d58ae6a85 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureEncoder.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureEncoder.cpp @@ -73,11 +73,11 @@ bool TextureEncoder::Initialize() return true; } -void TextureEncoder::EncodeTextureToRam(StateTracker* state_tracker, VkImageView src_texture, - u8* dest_ptr, u32 format, u32 native_width, - u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, - PEControl::PixelFormat src_format, bool is_intensity, - int scale_by_half, const EFBRectangle& src_rect) +void TextureEncoder::EncodeTextureToRam(VkImageView src_texture, u8* dest_ptr, u32 format, + u32 native_width, u32 bytes_per_row, u32 num_blocks_y, + u32 memory_stride, PEControl::PixelFormat src_format, + bool is_intensity, int scale_by_half, + const EFBRectangle& src_rect) { if (m_texture_encoding_shaders[format] == VK_NULL_HANDLE) { @@ -86,7 +86,7 @@ void TextureEncoder::EncodeTextureToRam(StateTracker* state_tracker, VkImageView } // Can't do our own draw within a render pass. - state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetPushConstantPipelineLayout(), m_encoding_render_pass, @@ -122,8 +122,8 @@ void TextureEncoder::EncodeTextureToRam(StateTracker* state_tracker, VkImageView // Block until the GPU has finished copying to the staging texture. g_command_buffer_mgr->ExecuteCommandBuffer(false, true); - state_tracker->InvalidateDescriptorSets(); - state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateDescriptorSets(); + StateTracker::GetInstance()->SetPendingRebind(); // Copy from staging texture to the final destination, adjusting pitch if necessary. m_download_texture->ReadTexels(0, 0, render_width, render_height, dest_ptr, memory_stride); diff --git a/Source/Core/VideoBackends/Vulkan/TextureEncoder.h b/Source/Core/VideoBackends/Vulkan/TextureEncoder.h index daea8b59ff..c1863a04b2 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureEncoder.h +++ b/Source/Core/VideoBackends/Vulkan/TextureEncoder.h @@ -15,7 +15,6 @@ namespace Vulkan { class StagingTexture2D; -class StateTracker; class Texture2D; class TextureEncoder @@ -29,10 +28,10 @@ public: // Uses an encoding shader to copy src_texture to dest_ptr. // Assumes that no render pass is currently in progress. // WARNING: Executes the current command buffer. - void EncodeTextureToRam(StateTracker* state_tracker, VkImageView src_texture, u8* dest_ptr, - u32 format, u32 native_width, u32 bytes_per_row, u32 num_blocks_y, - u32 memory_stride, PEControl::PixelFormat src_format, bool is_intensity, - int scale_by_half, const EFBRectangle& source); + void EncodeTextureToRam(VkImageView src_texture, u8* dest_ptr, u32 format, u32 native_width, + u32 bytes_per_row, u32 num_blocks_y, u32 memory_stride, + PEControl::PixelFormat src_format, bool is_intensity, int scale_by_half, + const EFBRectangle& source); private: // From OGL. diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 9ef432d779..2e8025dbc1 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -195,13 +195,12 @@ void BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer, &buffer_info, 0, nullptr); } -void ExecuteCurrentCommandsAndRestoreState(StateTracker* state_tracker, bool execute_off_thread, - bool wait_for_completion) +void ExecuteCurrentCommandsAndRestoreState(bool execute_off_thread, bool wait_for_completion) { - state_tracker->EndRenderPass(); + StateTracker::GetInstance()->EndRenderPass(); g_command_buffer_mgr->ExecuteCommandBuffer(execute_off_thread, wait_for_completion); - state_tracker->InvalidateDescriptorSets(); - state_tracker->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateDescriptorSets(); + StateTracker::GetInstance()->SetPendingRebind(); } VkShaderModule CreateShaderModule(const u32* spv, size_t spv_word_count) diff --git a/Source/Core/VideoBackends/Vulkan/Util.h b/Source/Core/VideoBackends/Vulkan/Util.h index e9dec51700..6900cce08b 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.h +++ b/Source/Core/VideoBackends/Vulkan/Util.h @@ -47,7 +47,7 @@ void BufferMemoryBarrier(VkCommandBuffer command_buffer, VkBuffer buffer, // Completes the current render pass, executes the command buffer, and restores state ready for next // render. Use when you want to kick the current buffer to make room for new data. -void ExecuteCurrentCommandsAndRestoreState(StateTracker* state_tracker, bool execute_off_thread, +void ExecuteCurrentCommandsAndRestoreState(bool execute_off_thread, bool wait_for_completion = false); // Create a shader module from the specified SPIR-V. diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp index 02be335aea..8300fb5fdd 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp @@ -36,10 +36,13 @@ VertexManager::~VertexManager() { } -bool VertexManager::Initialize(StateTracker* state_tracker) +VertexManager* VertexManager::GetInstance() { - m_state_tracker = state_tracker; + return static_cast(g_vertex_manager.get()); +} +bool VertexManager::Initialize() +{ m_vertex_stream_buffer = StreamBuffer::Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, INITIAL_VERTEX_BUFFER_SIZE, MAX_VERTEX_BUFFER_SIZE); @@ -72,8 +75,9 @@ void VertexManager::PrepareDrawBuffers(u32 stride) ADDSTAT(stats.thisFrame.bytesVertexStreamed, static_cast(vertex_data_size)); ADDSTAT(stats.thisFrame.bytesIndexStreamed, static_cast(index_data_size)); - m_state_tracker->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0); - m_state_tracker->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0, VK_INDEX_TYPE_UINT16); + StateTracker::GetInstance()->SetVertexBuffer(m_vertex_stream_buffer->GetBuffer(), 0); + StateTracker::GetInstance()->SetIndexBuffer(m_index_stream_buffer->GetBuffer(), 0, + VK_INDEX_TYPE_UINT16); } void VertexManager::ResetBuffer(u32 stride) @@ -94,7 +98,7 @@ void VertexManager::ResetBuffer(u32 stride) { // Flush any pending commands first, so that we can wait on the fences WARN_LOG(VIDEO, "Executing command list while waiting for space in vertex/index buffer"); - Util::ExecuteCurrentCommandsAndRestoreState(m_state_tracker, false); + Util::ExecuteCurrentCommandsAndRestoreState(false); // Attempt to allocate again, this may cause a fence wait if (!has_vbuffer_allocation) @@ -133,21 +137,21 @@ void VertexManager::vFlush(bool use_dst_alpha) u32 index_count = IndexGenerator::GetIndexLen(); // Update assembly state - m_state_tracker->SetVertexFormat(vertex_format); + StateTracker::GetInstance()->SetVertexFormat(vertex_format); switch (m_current_primitive_type) { case PRIMITIVE_POINTS: - m_state_tracker->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_POINT_LIST); - m_state_tracker->DisableBackFaceCulling(); + StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_POINT_LIST); + StateTracker::GetInstance()->DisableBackFaceCulling(); break; case PRIMITIVE_LINES: - m_state_tracker->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST); - m_state_tracker->DisableBackFaceCulling(); + StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST); + StateTracker::GetInstance()->DisableBackFaceCulling(); break; case PRIMITIVE_TRIANGLES: - m_state_tracker->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); + StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP); g_renderer->SetGenerationMode(); break; } @@ -158,37 +162,34 @@ void VertexManager::vFlush(bool use_dst_alpha) dstalpha_mode = DSTALPHA_DUAL_SOURCE_BLEND; // Check for any shader stage changes - m_state_tracker->CheckForShaderChanges(m_current_primitive_type, dstalpha_mode); + StateTracker::GetInstance()->CheckForShaderChanges(m_current_primitive_type, dstalpha_mode); // Update any changed constants - m_state_tracker->UpdateVertexShaderConstants(); - m_state_tracker->UpdateGeometryShaderConstants(); - m_state_tracker->UpdatePixelShaderConstants(); + StateTracker::GetInstance()->UpdateVertexShaderConstants(); + StateTracker::GetInstance()->UpdateGeometryShaderConstants(); + StateTracker::GetInstance()->UpdatePixelShaderConstants(); // Flush all EFB pokes and invalidate the peek cache. - // TODO: Cleaner way without the cast. - FramebufferManager* framebuffer_mgr = - static_cast(g_framebuffer_manager.get()); - framebuffer_mgr->InvalidatePeekCache(); - framebuffer_mgr->FlushEFBPokes(m_state_tracker); + FramebufferManager::GetInstance()->InvalidatePeekCache(); + FramebufferManager::GetInstance()->FlushEFBPokes(); // If bounding box is enabled, we need to flush any changes first, then invalidate what we have. if (g_vulkan_context->SupportsBoundingBox()) { - BoundingBox* bounding_box = static_cast(g_renderer.get())->GetBoundingBox(); + BoundingBox* bounding_box = Renderer::GetInstance()->GetBoundingBox(); bool bounding_box_enabled = (::BoundingBox::active && g_ActiveConfig.bBBoxEnable); if (bounding_box_enabled) { - bounding_box->Flush(m_state_tracker); - bounding_box->Invalidate(m_state_tracker); + bounding_box->Flush(); + bounding_box->Invalidate(); } // Update which descriptor set/pipeline layout to use. - m_state_tracker->SetBBoxEnable(bounding_box_enabled); + StateTracker::GetInstance()->SetBBoxEnable(bounding_box_enabled); } // Bind all pending state to the command buffer - if (!m_state_tracker->Bind()) + if (!StateTracker::GetInstance()->Bind()) { WARN_LOG(VIDEO, "Skipped draw of %u indices", index_count); return; @@ -207,8 +208,9 @@ void VertexManager::vFlush(bool use_dst_alpha) bool logic_op_enabled = bpmem.blendmode.logicopenable && !bpmem.blendmode.blendenable; if (use_dst_alpha && (!g_vulkan_context->SupportsDualSourceBlend() || logic_op_enabled)) { - m_state_tracker->CheckForShaderChanges(m_current_primitive_type, DSTALPHA_ALPHA_PASS); - if (!m_state_tracker->Bind()) + StateTracker::GetInstance()->CheckForShaderChanges(m_current_primitive_type, + DSTALPHA_ALPHA_PASS); + if (!StateTracker::GetInstance()->Bind()) { WARN_LOG(VIDEO, "Skipped draw of %u indices (alpha pass)", index_count); return; @@ -218,7 +220,7 @@ void VertexManager::vFlush(bool use_dst_alpha) m_current_draw_base_index, m_current_draw_base_vertex, 0); } - m_state_tracker->OnDraw(); + StateTracker::GetInstance()->OnDraw(); } } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.h b/Source/Core/VideoBackends/Vulkan/VertexManager.h index 0de4faae85..b79e671c6c 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.h +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.h @@ -12,7 +12,6 @@ namespace Vulkan { -class StateTracker; class StreamBuffer; class VertexManager : public VertexManagerBase @@ -21,7 +20,9 @@ public: VertexManager(); ~VertexManager(); - bool Initialize(StateTracker* state_tracker); + static VertexManager* GetInstance(); + + bool Initialize(); NativeVertexFormat* CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) override; @@ -32,8 +33,6 @@ protected: private: void vFlush(bool use_dst_alpha) override; - StateTracker* m_state_tracker = nullptr; - std::vector m_cpu_vertex_buffer; std::vector m_cpu_index_buffer; diff --git a/Source/Core/VideoBackends/Vulkan/main.cpp b/Source/Core/VideoBackends/Vulkan/main.cpp index 1fb8f6c6ab..4a70a6e509 100644 --- a/Source/Core/VideoBackends/Vulkan/main.cpp +++ b/Source/Core/VideoBackends/Vulkan/main.cpp @@ -194,19 +194,16 @@ bool VideoBackend::Initialize(void* window_handle) g_framebuffer_manager = std::make_unique(); g_renderer = std::make_unique(std::move(swap_chain)); - // Cast to our wrapper classes, so we can call the init methods. - Renderer* renderer = static_cast(g_renderer.get()); - FramebufferManager* framebuffer_mgr = - static_cast(g_framebuffer_manager.get()); - // Invoke init methods on main wrapper classes. // These have to be done before the others because the destructors // for the remaining classes may call methods on these. - if (!g_object_cache->Initialize() || !framebuffer_mgr->Initialize() || - !renderer->Initialize(framebuffer_mgr)) + if (!g_object_cache->Initialize() || !FramebufferManager::GetInstance()->Initialize() || + !StateTracker::CreateInstance() || !Renderer::GetInstance()->Initialize()) { PanicAlert("Failed to initialize Vulkan classes."); g_renderer.reset(); + StateTracker::DestroyInstance(); + g_framebuffer_manager.reset(); g_object_cache.reset(); g_command_buffer_mgr.reset(); g_vulkan_context.reset(); @@ -219,18 +216,16 @@ bool VideoBackend::Initialize(void* window_handle) g_vertex_manager = std::make_unique(); g_texture_cache = std::make_unique(); g_perf_query = std::make_unique(); - VertexManager* vertex_manager = static_cast(g_vertex_manager.get()); - TextureCache* texture_cache = static_cast(g_texture_cache.get()); - PerfQuery* perf_query = static_cast(g_perf_query.get()); - if (!vertex_manager->Initialize(renderer->GetStateTracker()) || - !texture_cache->Initialize(renderer->GetStateTracker()) || - !perf_query->Initialize(renderer->GetStateTracker())) + if (!VertexManager::GetInstance()->Initialize() || !TextureCache::GetInstance()->Initialize() || + !PerfQuery::GetInstance()->Initialize()) { PanicAlert("Failed to initialize Vulkan classes."); g_perf_query.reset(); g_texture_cache.reset(); g_vertex_manager.reset(); g_renderer.reset(); + StateTracker::DestroyInstance(); + g_framebuffer_manager.reset(); g_object_cache.reset(); g_command_buffer_mgr.reset(); g_vulkan_context.reset(); @@ -273,11 +268,12 @@ void VideoBackend::Video_Cleanup() // Save all cached pipelines out to disk for next time. g_object_cache->SavePipelineCache(); - g_texture_cache.reset(); g_perf_query.reset(); + g_texture_cache.reset(); g_vertex_manager.reset(); - g_renderer.reset(); g_framebuffer_manager.reset(); + StateTracker::DestroyInstance(); + g_renderer.reset(); CleanupShared(); }