diff options
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/Vulkan/Renderer.cpp | 527 |
1 files changed, 142 insertions, 385 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index a3085aa486..0254f128a8 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -18,27 +18,22 @@ #include "VideoBackends/Vulkan/BoundingBox.h" #include "VideoBackends/Vulkan/CommandBufferManager.h" -#include "VideoBackends/Vulkan/FramebufferManager.h" #include "VideoBackends/Vulkan/ObjectCache.h" -#include "VideoBackends/Vulkan/PostProcessing.h" +#include "VideoBackends/Vulkan/PerfQuery.h" #include "VideoBackends/Vulkan/Renderer.h" #include "VideoBackends/Vulkan/StateTracker.h" #include "VideoBackends/Vulkan/StreamBuffer.h" #include "VideoBackends/Vulkan/SwapChain.h" -#include "VideoBackends/Vulkan/TextureCache.h" -#include "VideoBackends/Vulkan/Util.h" #include "VideoBackends/Vulkan/VKPipeline.h" #include "VideoBackends/Vulkan/VKShader.h" #include "VideoBackends/Vulkan/VKTexture.h" +#include "VideoBackends/Vulkan/VertexFormat.h" #include "VideoBackends/Vulkan/VulkanContext.h" -#include "VideoCommon/BPFunctions.h" -#include "VideoCommon/BPMemory.h" #include "VideoCommon/DriverDetails.h" -#include "VideoCommon/OnScreenDisplay.h" -#include "VideoCommon/PixelEngine.h" +#include "VideoCommon/FramebufferManager.h" #include "VideoCommon/RenderState.h" -#include "VideoCommon/TextureCacheBase.h" +#include "VideoCommon/VertexManagerBase.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoCommon.h" #include "VideoCommon/VideoConfig.h" @@ -59,11 +54,6 @@ Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain, float backbuffer_scale Renderer::~Renderer() = default; -Renderer* Renderer::GetInstance() -{ - return static_cast<Renderer*>(g_renderer.get()); -} - bool Renderer::IsHeadless() const { return m_swap_chain == nullptr; @@ -74,8 +64,6 @@ bool Renderer::Initialize() if (!::Renderer::Initialize()) return false; - BindEFBToStateTracker(); - m_bounding_box = std::make_unique<BoundingBox>(); if (!m_bounding_box->Initialize()) { @@ -83,34 +71,16 @@ bool Renderer::Initialize() return false; } - if (g_vulkan_context->SupportsBoundingBox()) - { - // Bind bounding box to state tracker - StateTracker::GetInstance()->SetBBoxBuffer(m_bounding_box->GetGPUBuffer(), - m_bounding_box->GetGPUBufferOffset(), - m_bounding_box->GetGPUBufferSize()); - } - - // Initialize post processing. - m_post_processor = std::make_unique<VulkanPostProcessing>(); - if (!static_cast<VulkanPostProcessing*>(m_post_processor.get())->Initialize()) - { - PanicAlert("failed to initialize post processor."); - return false; - } - // Various initialization routines will have executed commands on the command buffer. // Execute what we have done before beginning the first frame. - g_command_buffer_mgr->PrepareToSubmitCommandBuffer(); - g_command_buffer_mgr->SubmitCommandBuffer(false); - BeginFrame(); - + ExecuteCommandBuffer(true, false); return true; } void Renderer::Shutdown() { ::Renderer::Shutdown(); + m_swap_chain.reset(); } std::unique_ptr<AbstractTexture> Renderer::CreateTexture(const TextureConfig& config) @@ -136,17 +106,22 @@ std::unique_ptr<AbstractShader> Renderer::CreateShaderFromBinary(ShaderStage sta return VKShader::CreateFromBinary(stage, data, length); } +std::unique_ptr<NativeVertexFormat> +Renderer::CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) +{ + return std::make_unique<VertexFormat>(vtx_decl); +} + std::unique_ptr<AbstractPipeline> Renderer::CreatePipeline(const AbstractPipelineConfig& config) { return VKPipeline::Create(config); } -std::unique_ptr<AbstractFramebuffer> -Renderer::CreateFramebuffer(const AbstractTexture* color_attachment, - const AbstractTexture* depth_attachment) +std::unique_ptr<AbstractFramebuffer> Renderer::CreateFramebuffer(AbstractTexture* color_attachment, + AbstractTexture* depth_attachment) { - return VKFramebuffer::Create(static_cast<const VKTexture*>(color_attachment), - static_cast<const VKTexture*>(depth_attachment)); + return VKFramebuffer::Create(static_cast<VKTexture*>(color_attachment), + static_cast<VKTexture*>(depth_attachment)); } void Renderer::SetPipeline(const AbstractPipeline* pipeline) @@ -154,90 +129,6 @@ void Renderer::SetPipeline(const AbstractPipeline* pipeline) StateTracker::GetInstance()->SetPipeline(static_cast<const VKPipeline*>(pipeline)); } -u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) -{ - if (type == EFBAccessType::PeekColor) - { - 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)); - - // check what to do with the alpha channel (GX_PokeAlphaRead) - PixelEngine::UPEAlphaReadReg alpha_read_mode = PixelEngine::GetAlphaReadMode(); - - if (bpmem.zcontrol.pixel_format == PEControl::RGBA6_Z24) - { - color = RGBA8ToRGBA6ToRGBA8(color); - } - else if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - color = RGBA8ToRGB565ToRGBA8(color); - } - if (bpmem.zcontrol.pixel_format != PEControl::RGBA6_Z24) - { - color |= 0xFF000000; - } - - if (alpha_read_mode.ReadMode == 2) - { - return color; // GX_READ_NONE - } - else if (alpha_read_mode.ReadMode == 1) - { - return color | 0xFF000000; // GX_READ_FF - } - else /*if(alpha_read_mode.ReadMode == 0)*/ - { - return color & 0x00FFFFFF; // GX_READ_00 - } - } - else // if (type == EFBAccessType::PeekZ) - { - // Depth buffer is inverted for improved precision near far plane - float depth = 1.0f - FramebufferManager::GetInstance()->PeekEFBDepth(x, y); - u32 ret = 0; - - if (bpmem.zcontrol.pixel_format == PEControl::RGB565_Z16) - { - // if Z is in 16 bit format you must return a 16 bit integer - ret = MathUtil::Clamp<u32>(static_cast<u32>(depth * 65536.0f), 0, 0xFFFF); - } - else - { - ret = MathUtil::Clamp<u32>(static_cast<u32>(depth * 16777216.0f), 0, 0xFFFFFF); - } - - return ret; - } -} - -void Renderer::PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) -{ - if (type == EFBAccessType::PokeColor) - { - for (size_t i = 0; i < num_points; i++) - { - // Convert to expected format (BGRA->RGBA) - // TODO: Check alpha, depending on mode? - const EfbPokeData& point = points[i]; - u32 color = ((point.data & 0xFF00FF00) | ((point.data >> 16) & 0xFF) | - ((point.data << 16) & 0xFF0000)); - FramebufferManager::GetInstance()->PokeEFBColor(point.x, point.y, color); - } - } - else // if (type == EFBAccessType::PokeZ) - { - for (size_t i = 0; i < num_points; i++) - { - // Convert to floating-point depth. - const EfbPokeData& point = points[i]; - float depth = (1.0f - float(point.data & 0xFFFFFF) / 16777216.0f); - FramebufferManager::GetInstance()->PokeEFBDepth(point.x, point.y, depth); - } - } -} - u16 Renderer::BBoxRead(int index) { s32 value = m_bounding_box->Get(static_cast<size_t>(index)); @@ -285,31 +176,18 @@ void Renderer::BBoxWrite(int index, u16 value) m_bounding_box->Set(static_cast<size_t>(index), scaled_value); } -TargetRectangle Renderer::ConvertEFBRectangle(const EFBRectangle& rc) +void Renderer::BBoxFlush() { - TargetRectangle result; - result.left = EFBToScaledX(rc.left); - result.top = EFBToScaledY(rc.top); - result.right = EFBToScaledX(rc.right); - result.bottom = EFBToScaledY(rc.bottom); - return result; -} - -void Renderer::BeginFrame() -{ - // Activate a new command list, and restore state ready for the next draw - g_command_buffer_mgr->ActivateCommandBuffer(); - - // Ensure that the state tracker rebinds everything, and allocates a new set - // of descriptors out of the next pool. - StateTracker::GetInstance()->InvalidateDescriptorSets(); - StateTracker::GetInstance()->InvalidateConstants(); - StateTracker::GetInstance()->SetPendingRebind(); + m_bounding_box->Flush(); + m_bounding_box->Invalidate(); } void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha_enable, bool z_enable, u32 color, u32 z) { + g_framebuffer_manager->FlushEFBPokes(); + g_framebuffer_manager->InvalidatePeekCache(); + // Native -> EFB coordinates TargetRectangle target_rc = Renderer::ConvertEFBRectangle(rc); @@ -340,7 +218,9 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha clear_color_value.color.float32[1] = static_cast<float>((color >> 8) & 0xFF) / 255.0f; clear_color_value.color.float32[2] = static_cast<float>((color >> 0) & 0xFF) / 255.0f; clear_color_value.color.float32[3] = static_cast<float>((color >> 24) & 0xFF) / 255.0f; - clear_depth_value.depthStencil.depth = (1.0f - (static_cast<float>(z & 0xFFFFFF) / 16777216.0f)); + clear_depth_value.depthStencil.depth = static_cast<float>(z & 0xFFFFFF) / 16777216.0f; + if (!g_ActiveConfig.backend_info.bSupportsReversedDepthRange) + clear_depth_value.depthStencil.depth = 1.0f - clear_depth_value.depthStencil.depth; // 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. @@ -396,7 +276,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha } if (num_clear_attachments > 0) { - VkClearRect vk_rect = {target_vk_rc, 0, FramebufferManager::GetInstance()->GetEFBLayers()}; + VkClearRect vk_rect = {target_vk_rc, 0, g_framebuffer_manager->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)) @@ -414,57 +294,17 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha if (!color_enable && !alpha_enable && !z_enable) return; - // Clearing must occur within a render pass. - if (!StateTracker::GetInstance()->IsWithinRenderArea(target_vk_rc.offset.x, target_vk_rc.offset.y, - target_vk_rc.extent.width, - target_vk_rc.extent.height)) - { - StateTracker::GetInstance()->EndClearRenderPass(); - } - StateTracker::GetInstance()->BeginRenderPass(); - StateTracker::GetInstance()->SetPendingRebind(); - - // Mask away the appropriate colors and use a shader - BlendingState blend_state = RenderState::GetNoBlendingBlendState(); - blend_state.colorupdate = color_enable; - blend_state.alphaupdate = alpha_enable; - - DepthState depth_state = RenderState::GetNoDepthTestingDepthStencilState(); - depth_state.testenable = z_enable; - depth_state.updateenable = z_enable; - depth_state.func = ZMode::ALWAYS; - - // 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->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), - FramebufferManager::GetInstance()->GetEFBLoadRenderPass(), - g_shader_cache->GetPassthroughVertexShader(), - g_shader_cache->GetPassthroughGeometryShader(), - g_shader_cache->GetClearFragmentShader()); - - draw.SetMultisamplingState(FramebufferManager::GetInstance()->GetEFBMultisamplingState()); - draw.SetDepthState(depth_state); - draw.SetBlendState(blend_state); - - draw.DrawColoredQuad(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight(), - clear_color_value.color.float32[0], clear_color_value.color.float32[1], - clear_color_value.color.float32[2], clear_color_value.color.float32[3], - clear_depth_value.depthStencil.depth); + g_framebuffer_manager->ClearEFB(rc, color_enable, alpha_enable, z_enable, color, z); } -void Renderer::ReinterpretPixelData(unsigned int convtype) +void Renderer::Flush() { - StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->SetPendingRebind(); - FramebufferManager::GetInstance()->ReinterpretPixelData(convtype); - - // EFB framebuffer has now changed, so update accordingly. - BindEFBToStateTracker(); + ExecuteCommandBuffer(true, false); } -void Renderer::Flush() +void Renderer::WaitForGPUIdle() { - Util::ExecuteCurrentCommandsAndRestoreState(true, false); + ExecuteCommandBuffer(false, true); } void Renderer::BindBackbuffer(const ClearColor& clear_color) @@ -475,35 +315,13 @@ void Renderer::BindBackbuffer(const ClearColor& clear_color) CheckForSurfaceChange(); CheckForSurfaceResize(); - // Ensure the worker thread is not still submitting a previous command buffer. - // In other words, the last frame has been submitted (otherwise the next call would - // be a race, as the image may not have been consumed yet). - g_command_buffer_mgr->PrepareToSubmitCommandBuffer(); - - VkResult res; - if (!g_command_buffer_mgr->CheckLastPresentFail()) - { - // Grab the next image from the swap chain in preparation for drawing the window. - res = m_swap_chain->AcquireNextImage(); - } - else - { - // If the last present failed, we need to recreate the swap chain. - res = VK_ERROR_OUT_OF_DATE_KHR; - } - + VkResult res = g_command_buffer_mgr->CheckLastPresentFail() ? VK_ERROR_OUT_OF_DATE_KHR : + m_swap_chain->AcquireNextImage(); if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) { - // There's an issue here. We can't resize the swap chain while the GPU is still busy with it, - // but calling WaitForGPUIdle would create a deadlock as PrepareToSubmitCommandBuffer has been - // called by SwapImpl. WaitForGPUIdle waits on the semaphore, which PrepareToSubmitCommandBuffer - // has already done, so it blocks indefinitely. To work around this, we submit the current - // command buffer, resize the swap chain (which calls WaitForGPUIdle), and then finally call - // PrepareToSubmitCommandBuffer to return to the state that the caller expects. - g_command_buffer_mgr->SubmitCommandBuffer(false); + // Execute cmdbuffer before resizing, as the last frame could still be presenting. + ExecuteCommandBuffer(false, true); m_swap_chain->ResizeSwapChain(); - BeginFrame(); - g_command_buffer_mgr->PrepareToSubmitCommandBuffer(); res = m_swap_chain->AcquireNextImage(); } if (res != VK_SUCCESS) @@ -512,30 +330,18 @@ void Renderer::BindBackbuffer(const ClearColor& clear_color) // Transition from undefined (or present src, but it can be substituted) to // color attachment ready for writing. These transitions must occur outside // a render pass, unless the render pass declares a self-dependency. - Texture2D* backbuffer = m_swap_chain->GetCurrentTexture(); - backbuffer->OverrideImageLayout(VK_IMAGE_LAYOUT_UNDEFINED); - backbuffer->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - m_current_framebuffer = nullptr; - m_current_framebuffer_width = backbuffer->GetWidth(); - m_current_framebuffer_height = backbuffer->GetHeight(); - - // Draw to the backbuffer. - VkRect2D region = {{0, 0}, {backbuffer->GetWidth(), backbuffer->GetHeight()}}; - StateTracker::GetInstance()->SetRenderPass(m_swap_chain->GetLoadRenderPass(), - m_swap_chain->GetClearRenderPass()); - StateTracker::GetInstance()->SetFramebuffer(m_swap_chain->GetCurrentFramebuffer(), region); - - // Begin render pass for rendering to the swap chain. - VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; - StateTracker::GetInstance()->BeginClearRenderPass(region, &clear_value, 1); + m_swap_chain->GetCurrentTexture()->OverrideImageLayout(VK_IMAGE_LAYOUT_UNDEFINED); + m_swap_chain->GetCurrentTexture()->TransitionToLayout( + g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + SetAndClearFramebuffer(m_swap_chain->GetCurrentFramebuffer(), + ClearColor{{0.0f, 0.0f, 0.0f, 1.0f}}); } void Renderer::PresentBackbuffer() { // End drawing to backbuffer StateTracker::GetInstance()->EndRenderPass(); - StateTracker::GetInstance()->OnEndFrame(); + PerfQuery::GetInstance()->FlushQueries(); // Transition the backbuffer to PRESENT_SRC to ensure all commands drawing // to it have finished before present. @@ -546,47 +352,25 @@ void Renderer::PresentBackbuffer() // Because this final command buffer is rendering to the swap chain, we need to wait for // the available semaphore to be signaled before executing the buffer. This final submission // can happen off-thread in the background while we're preparing the next frame. - g_command_buffer_mgr->SubmitCommandBuffer(true, m_swap_chain->GetImageAvailableSemaphore(), - m_swap_chain->GetRenderingFinishedSemaphore(), - m_swap_chain->GetSwapChain(), + g_command_buffer_mgr->SubmitCommandBuffer(true, m_swap_chain->GetSwapChain(), m_swap_chain->GetCurrentImageIndex()); - BeginFrame(); + + // New cmdbuffer, so invalidate state. + StateTracker::GetInstance()->InvalidateCachedState(); } -void Renderer::RenderXFBToScreen(const AbstractTexture* texture, const EFBRectangle& rc) +void Renderer::ExecuteCommandBuffer(bool submit_off_thread, bool wait_for_completion) { - const TargetRectangle target_rc = GetTargetRectangle(); + StateTracker::GetInstance()->EndRenderPass(); + PerfQuery::GetInstance()->FlushQueries(); - VulkanPostProcessing* post_processor = static_cast<VulkanPostProcessing*>(m_post_processor.get()); - if (g_ActiveConfig.stereo_mode == StereoMode::SBS || - g_ActiveConfig.stereo_mode == StereoMode::TAB) - { - TargetRectangle left_rect; - TargetRectangle right_rect; - std::tie(left_rect, right_rect) = ConvertStereoRectangle(target_rc); - - post_processor->BlitFromTexture(left_rect, rc, - static_cast<const VKTexture*>(texture)->GetRawTexIdentifier(), - 0, m_swap_chain->GetLoadRenderPass()); - post_processor->BlitFromTexture(right_rect, rc, - static_cast<const VKTexture*>(texture)->GetRawTexIdentifier(), - 1, m_swap_chain->GetLoadRenderPass()); - } - else if (g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer) - { - post_processor->BlitFromTexture(target_rc, rc, - static_cast<const VKTexture*>(texture)->GetRawTexIdentifier(), - -1, m_swap_chain->GetLoadRenderPass()); - } - else - { - post_processor->BlitFromTexture(target_rc, rc, - static_cast<const VKTexture*>(texture)->GetRawTexIdentifier(), - 0, m_swap_chain->GetLoadRenderPass()); - } + // If we're waiting for completion, don't bother waking the worker thread. + const VkFence pending_fence = g_command_buffer_mgr->GetCurrentCommandBufferFence(); + g_command_buffer_mgr->SubmitCommandBuffer(submit_off_thread && wait_for_completion); + if (wait_for_completion) + g_command_buffer_mgr->WaitForFence(pending_fence); - // The post-processor uses the old-style Vulkan draws, which mess with the tracked state. - StateTracker::GetInstance()->SetPendingRebind(); + StateTracker::GetInstance()->InvalidateCachedState(); } void Renderer::CheckForSurfaceChange() @@ -595,8 +379,7 @@ void Renderer::CheckForSurfaceChange() return; // Submit the current draws up until rendering the XFB. - g_command_buffer_mgr->ExecuteCommandBuffer(false, false); - g_command_buffer_mgr->WaitForGPUIdle(); + ExecuteCommandBuffer(false, true); // Clear the present failed flag, since we don't want to resize after recreating. g_command_buffer_mgr->CheckLastPresentFail(); @@ -624,8 +407,7 @@ void Renderer::CheckForSurfaceResize() } // Wait for the GPU to catch up since we're going to destroy the swap chain. - g_command_buffer_mgr->ExecuteCommandBuffer(false, false); - g_command_buffer_mgr->WaitForGPUIdle(); + ExecuteCommandBuffer(false, true); // Clear the present failed flag, since we don't want to resize after recreating. g_command_buffer_mgr->CheckLastPresentFail(); @@ -637,45 +419,29 @@ void Renderer::CheckForSurfaceResize() void Renderer::OnConfigChanged(u32 bits) { - // Update texture cache settings with any changed options. - TextureCache::GetInstance()->OnConfigChanged(g_ActiveConfig); - - // Handle settings that can cause the EFB framebuffer to change. - if (bits & CONFIG_CHANGE_BIT_TARGET_SIZE) - RecreateEFBFramebuffer(); - - // MSAA samples changed, we need to recreate the EFB render pass. - // If the stereoscopy mode changed, we need to recreate the buffers as well. - // SSAA changed on/off, we have to recompile shaders. - // Changing stereoscopy from off<->on also requires shaders to be recompiled. - if (bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES)) - { - RecreateEFBFramebuffer(); - FramebufferManager::GetInstance()->RecompileShaders(); - g_shader_cache->ReloadPipelineCache(); - g_shader_cache->RecompileSharedShaders(); - } + if (bits & CONFIG_CHANGE_BIT_HOST_CONFIG) + g_object_cache->ReloadPipelineCache(); // For vsync, we need to change the present mode, which means recreating the swap chain. if (m_swap_chain && bits & CONFIG_CHANGE_BIT_VSYNC) { - g_command_buffer_mgr->WaitForGPUIdle(); + ExecuteCommandBuffer(false, true); m_swap_chain->SetVSync(g_ActiveConfig.bVSyncActive); } // For quad-buffered stereo we need to change the layer count, so recreate the swap chain. if (m_swap_chain && bits & CONFIG_CHANGE_BIT_STEREO_MODE) { - g_command_buffer_mgr->WaitForGPUIdle(); + ExecuteCommandBuffer(false, true); m_swap_chain->RecreateSwapChain(); } // Wipe sampler cache if force texture filtering or anisotropy changes. if (bits & (CONFIG_CHANGE_BIT_ANISOTROPY | CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING)) + { + ExecuteCommandBuffer(false, true); ResetSamplerStates(); - - // Check for a changed post-processing shader and recompile if needed. - static_cast<VulkanPostProcessing*>(m_post_processor.get())->UpdateConfig(); + } } void Renderer::OnSwapChainResized() @@ -684,103 +450,55 @@ void Renderer::OnSwapChainResized() m_backbuffer_height = m_swap_chain->GetHeight(); } -void Renderer::BindEFBToStateTracker() -{ - // Update framebuffer in state tracker - 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); - m_current_framebuffer = nullptr; - m_current_framebuffer_width = FramebufferManager::GetInstance()->GetEFBWidth(); - m_current_framebuffer_height = FramebufferManager::GetInstance()->GetEFBHeight(); -} - -void Renderer::RecreateEFBFramebuffer() -{ - // Ensure the GPU is finished with the current EFB textures. - g_command_buffer_mgr->WaitForGPUIdle(); - FramebufferManager::GetInstance()->RecreateEFBFramebuffer(); - BindEFBToStateTracker(); - - // Viewport and scissor rect have to be reset since they will be scaled differently. - BPFunctions::SetViewport(); - BPFunctions::SetScissor(); -} - -void Renderer::ApplyState() +void Renderer::BindFramebuffer(VKFramebuffer* fb) { -} - -void Renderer::ResetAPIState() -{ - // End the EFB render pass if active StateTracker::GetInstance()->EndRenderPass(); -} - -void Renderer::RestoreAPIState() -{ - StateTracker::GetInstance()->EndRenderPass(); - if (m_current_framebuffer) - static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample(); - - BindEFBToStateTracker(); - BPFunctions::SetViewport(); - BPFunctions::SetScissor(); - - // Instruct the state tracker to re-bind everything before the next draw - StateTracker::GetInstance()->SetPendingRebind(); -} -void Renderer::BindFramebuffer(const VKFramebuffer* fb) -{ - const VkRect2D render_area = {static_cast<int>(fb->GetWidth()), - static_cast<int>(fb->GetHeight())}; - - StateTracker::GetInstance()->EndRenderPass(); - if (m_current_framebuffer) - static_cast<const VKFramebuffer*>(m_current_framebuffer)->TransitionForSample(); + // Shouldn't be bound as a texture. + if (fb->GetColorAttachment()) + { + StateTracker::GetInstance()->UnbindTexture( + static_cast<VKTexture*>(fb->GetColorAttachment())->GetView()); + } + if (fb->GetDepthAttachment()) + { + StateTracker::GetInstance()->UnbindTexture( + static_cast<VKTexture*>(fb->GetDepthAttachment())->GetView()); + } fb->TransitionForRender(); - StateTracker::GetInstance()->SetFramebuffer(fb->GetFB(), render_area); - StateTracker::GetInstance()->SetRenderPass(fb->GetLoadRenderPass(), fb->GetClearRenderPass()); + StateTracker::GetInstance()->SetFramebuffer(fb); m_current_framebuffer = fb; - m_current_framebuffer_width = fb->GetWidth(); - m_current_framebuffer_height = fb->GetHeight(); } -void Renderer::SetFramebuffer(const AbstractFramebuffer* framebuffer) +void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer) { - const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer); + if (m_current_framebuffer == framebuffer) + return; + + VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer); BindFramebuffer(vkfb); - StateTracker::GetInstance()->BeginRenderPass(); } -void Renderer::SetAndDiscardFramebuffer(const AbstractFramebuffer* framebuffer) +void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer) { - const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer); + if (m_current_framebuffer == framebuffer) + return; + + VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer); BindFramebuffer(vkfb); // If we're discarding, begin the discard pass, then switch to a load pass. // This way if the command buffer is flushed, we don't start another discard pass. - StateTracker::GetInstance()->SetRenderPass(vkfb->GetDiscardRenderPass(), - vkfb->GetClearRenderPass()); - StateTracker::GetInstance()->BeginRenderPass(); - StateTracker::GetInstance()->SetRenderPass(vkfb->GetLoadRenderPass(), vkfb->GetClearRenderPass()); + StateTracker::GetInstance()->BeginDiscardRenderPass(); } -void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer, +void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer, const ClearColor& color_value, float depth_value) { - const VKFramebuffer* vkfb = static_cast<const VKFramebuffer*>(framebuffer); + VKFramebuffer* vkfb = static_cast<VKFramebuffer*>(framebuffer); BindFramebuffer(vkfb); - const VkRect2D render_area = {static_cast<int>(vkfb->GetWidth()), - static_cast<int>(vkfb->GetHeight())}; std::array<VkClearValue, 2> clear_values; u32 num_clear_values = 0; if (vkfb->GetColorFormat() != AbstractTextureFormat::Undefined) @@ -795,7 +513,7 @@ void Renderer::SetAndClearFramebuffer(const AbstractFramebuffer* framebuffer, clear_values[num_clear_values].depthStencil.stencil = 0; num_clear_values++; } - StateTracker::GetInstance()->BeginClearRenderPass(render_area, clear_values.data(), + StateTracker::GetInstance()->BeginClearRenderPass(vkfb->GetRect(), clear_values.data(), num_clear_values); } @@ -803,9 +521,27 @@ void Renderer::SetTexture(u32 index, const AbstractTexture* texture) { // Texture should always be in SHADER_READ_ONLY layout prior to use. // This is so we don't need to transition during render passes. - auto* tex = texture ? static_cast<const VKTexture*>(texture)->GetRawTexIdentifier() : nullptr; - DEBUG_ASSERT(!tex || tex->GetLayout() == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - StateTracker::GetInstance()->SetTexture(index, tex ? tex->GetView() : VK_NULL_HANDLE); + const VKTexture* tex = static_cast<const VKTexture*>(texture); + if (tex) + { + if (tex->GetLayout() != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + { + if (StateTracker::GetInstance()->InRenderPass()) + { + WARN_LOG(VIDEO, "Transitioning image in render pass in Renderer::SetTexture()"); + StateTracker::GetInstance()->EndRenderPass(); + } + + tex->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + } + + StateTracker::GetInstance()->SetTexture(index, tex->GetView()); + } + else + { + StateTracker::GetInstance()->SetTexture(0, VK_NULL_HANDLE); + } } void Renderer::SetSamplerState(u32 index, const SamplerState& state) @@ -826,10 +562,27 @@ void Renderer::SetSamplerState(u32 index, const SamplerState& state) m_sampler_states[index].hex = state.hex; } +void Renderer::SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) +{ + VKTexture* vk_texture = static_cast<VKTexture*>(texture); + if (vk_texture) + { + StateTracker::GetInstance()->EndRenderPass(); + StateTracker::GetInstance()->SetImageTexture(vk_texture->GetView()); + vk_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + read ? (write ? VKTexture::ComputeImageLayout::ReadWrite : + VKTexture::ComputeImageLayout::ReadOnly) : + VKTexture::ComputeImageLayout::WriteOnly); + } + else + { + StateTracker::GetInstance()->SetImageTexture(VK_NULL_HANDLE); + } +} + void Renderer::UnbindTexture(const AbstractTexture* texture) { - StateTracker::GetInstance()->UnbindTexture( - static_cast<const VKTexture*>(texture)->GetRawTexIdentifier()->GetView()); + StateTracker::GetInstance()->UnbindTexture(static_cast<const VKTexture*>(texture)->GetView()); } void Renderer::ResetSamplerStates() @@ -839,7 +592,7 @@ void Renderer::ResetSamplerStates() g_command_buffer_mgr->WaitForGPUIdle(); // Invalidate all sampler states, next draw will re-initialize them. - for (size_t i = 0; i < m_sampler_states.size(); i++) + for (u32 i = 0; i < m_sampler_states.size(); i++) { m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex; StateTracker::GetInstance()->SetSampler(i, g_object_cache->GetPointSampler()); @@ -849,10 +602,6 @@ void Renderer::ResetSamplerStates() g_object_cache->ClearSamplerCache(); } -void Renderer::SetInterlacingMode() -{ -} - void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc) { VkRect2D scissor = {{rc.left, rc.top}, @@ -863,14 +612,13 @@ void Renderer::SetScissorRect(const MathUtil::Rectangle<int>& rc) void Renderer::SetViewport(float x, float y, float width, float height, float near_depth, float far_depth) { - VkViewport viewport = {x, y, std::max(width, 1.0f), std::max(height, 1.0f), - near_depth, far_depth}; + VkViewport viewport = {x, y, width, height, near_depth, far_depth}; StateTracker::GetInstance()->SetViewport(viewport); } void Renderer::Draw(u32 base_vertex, u32 num_vertices) { - if (StateTracker::GetInstance()->Bind()) + if (!StateTracker::GetInstance()->Bind()) return; vkCmdDraw(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_vertices, 1, base_vertex, 0); @@ -884,4 +632,13 @@ void Renderer::DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) vkCmdDrawIndexed(g_command_buffer_mgr->GetCurrentCommandBuffer(), num_indices, 1, base_index, base_vertex, 0); } + +void Renderer::DispatchComputeShader(const AbstractShader* shader, u32 groups_x, u32 groups_y, + u32 groups_z) +{ + StateTracker::GetInstance()->SetComputeShader(static_cast<const VKShader*>(shader)); + if (StateTracker::GetInstance()->BindCompute()) + vkCmdDispatch(g_command_buffer_mgr->GetCurrentCommandBuffer(), groups_x, groups_y, groups_z); +} + } // namespace Vulkan |
