summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/Renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.cpp527
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