summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/Renderer.cpp
diff options
context:
space:
mode:
authorshuffle2 <godisgovernment@gmail.com>2016-10-04 01:47:59 -0700
committerGitHub <noreply@github.com>2016-10-04 01:47:59 -0700
commitea33405febf183058bb30a22f4f627fed4bb8e17 (patch)
tree6222aceb31b2d6d922a8b3e45331b42fa1abba2d /Source/Core/VideoBackends/Vulkan/Renderer.cpp
parent037f0a1803c274ce7e9f97ff9b7baed2955b9004 (diff)
parent28e5fa8d261cd486e9339a66d91b4713e83d9a14 (diff)
Merge pull request #4270 from stenzek/vulkan-defer-fix
Vulkan: Miscellaneous minor fixes
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/Renderer.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/Renderer.cpp147
1 files changed, 71 insertions, 76 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
index e1c6394b30..7bb15aacdf 100644
--- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp
+++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp
@@ -22,6 +22,7 @@
#include "VideoBackends/Vulkan/StagingTexture2D.h"
#include "VideoBackends/Vulkan/StateTracker.h"
#include "VideoBackends/Vulkan/SwapChain.h"
+#include "VideoBackends/Vulkan/TextureCache.h"
#include "VideoBackends/Vulkan/Util.h"
#include "VideoBackends/Vulkan/VulkanContext.h"
@@ -41,37 +42,39 @@
namespace Vulkan
{
-Renderer::Renderer()
+Renderer::Renderer(std::unique_ptr<SwapChain> swap_chain) : m_swap_chain(std::move(swap_chain))
{
+ g_Config.bRunning = true;
+ UpdateActiveConfig();
+
// Set to something invalid, forcing all states to be re-initialized.
for (size_t i = 0; i < m_sampler_states.size(); i++)
m_sampler_states[i].bits = std::numeric_limits<decltype(m_sampler_states[i].bits)>::max();
- // Set default size so a decent EFB is created initially.
- s_backbuffer_width = MAX_XFB_WIDTH;
- s_backbuffer_height = MAX_XFB_HEIGHT;
+ // These have to be initialized before FramebufferManager is created.
+ // If running surfaceless, assume a window size of MAX_XFB_{WIDTH,HEIGHT}.
FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
- PixelShaderManager::SetEfbScaleChanged();
+ s_backbuffer_width = m_swap_chain ? m_swap_chain->GetWidth() : MAX_XFB_WIDTH;
+ s_backbuffer_height = m_swap_chain ? m_swap_chain->GetHeight() : MAX_XFB_HEIGHT;
+ s_last_efb_scale = g_ActiveConfig.iEFBScale;
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
CalculateTargetSize(s_backbuffer_width, s_backbuffer_height);
+ PixelShaderManager::SetEfbScaleChanged();
}
Renderer::~Renderer()
{
g_Config.bRunning = false;
UpdateActiveConfig();
+ DestroyScreenshotResources();
+ DestroyShaders();
DestroySemaphores();
}
-bool Renderer::Initialize(FramebufferManager* framebuffer_mgr, void* window_handle,
- VkSurfaceKHR surface)
+bool Renderer::Initialize(FramebufferManager* framebuffer_mgr)
{
m_framebuffer_mgr = framebuffer_mgr;
- g_Config.bRunning = true;
- UpdateActiveConfig();
-
- // Create state tracker, doesn't require any resources
m_state_tracker = std::make_unique<StateTracker>();
BindEFBToStateTracker();
@@ -109,24 +112,6 @@ bool Renderer::Initialize(FramebufferManager* framebuffer_mgr, void* window_hand
m_bounding_box->GetGPUBufferSize());
}
- // Initialize annoying statics
- s_last_efb_scale = g_ActiveConfig.iEFBScale;
-
- // Create swap chain
- if (surface)
- {
- // Update backbuffer dimensions
- m_swap_chain = SwapChain::Create(window_handle, surface);
- if (!m_swap_chain)
- {
- PanicAlert("Failed to create swap chain.");
- return false;
- }
-
- // Update render rectangle etc.
- OnSwapChainResized();
- }
-
// 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();
@@ -164,13 +149,13 @@ void Renderer::DestroySemaphores()
if (m_image_available_semaphore)
{
vkDestroySemaphore(g_vulkan_context->GetDevice(), m_image_available_semaphore, nullptr);
- m_image_available_semaphore = nullptr;
+ m_image_available_semaphore = VK_NULL_HANDLE;
}
if (m_rendering_finished_semaphore)
{
vkDestroySemaphore(g_vulkan_context->GetDevice(), m_rendering_finished_semaphore, nullptr);
- m_rendering_finished_semaphore = nullptr;
+ m_rendering_finished_semaphore = VK_NULL_HANDLE;
}
}
@@ -491,9 +476,6 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
// Scale the source rectangle to the selected internal resolution.
TargetRectangle source_rc = Renderer::ConvertEFBRectangle(rc);
- // Target rectangle can change if the VI aspect ratio changes.
- UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
-
// Transition the EFB render target to a shader resource.
VkRect2D src_region = {{0, 0},
{m_framebuffer_mgr->GetEFBWidth(), m_framebuffer_mgr->GetEFBHeight()}};
@@ -519,6 +501,10 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
StopFrameDump();
}
+ // Restore the EFB color texture to color attachment ready for rendering the next frame.
+ m_framebuffer_mgr->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.
// 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).
@@ -543,22 +529,28 @@ void Renderer::SwapImpl(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height
g_command_buffer_mgr->SubmitCommandBuffer(true);
}
+ // NOTE: It is important that no rendering calls are made to the EFB between submitting the
+ // (now-previous) frame and after the below config checks are completed. If the target size
+ // changes, as the resize methods to not defer the destruction of the framebuffer, the current
+ // command buffer will contain references to a now non-existent framebuffer.
+
// Prep for the next frame (get command buffer ready) before doing anything else.
BeginFrame();
- // Restore the EFB color texture to color attachment ready for rendering.
- m_framebuffer_mgr->GetEFBColorTexture()->TransitionToLayout(
- g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
+ // Determine what (if anything) has changed in the config.
+ CheckForConfigChanges();
- // Clean up stale textures
- TextureCacheBase::Cleanup(frameCount);
+ // Handle host window resizes.
+ CheckForSurfaceChange();
- // Handle window resizes.
+ // Handle output size changes from the guest.
+ // There is a downside to doing this here is that if the game changes its XFB source area,
+ // the changes will be delayed by one frame. For the moment it has to be done here because
+ // this can cause a target size change, which would result in a black frame if done earlier.
CheckForTargetResize(fb_width, fb_stride, fb_height);
- CheckForSurfaceChange();
- // Determine what has changed in the config.
- CheckForConfigChanges();
+ // Clean up stale textures.
+ TextureCacheBase::Cleanup(frameCount);
}
void Renderer::DrawScreen(const TargetRectangle& src_rect, const Texture2D* src_tex)
@@ -829,13 +821,23 @@ void Renderer::StopFrameDump()
void Renderer::CheckForTargetResize(u32 fb_width, u32 fb_stride, u32 fb_height)
{
- if (FramebufferManagerBase::LastXfbWidth() != fb_stride ||
- FramebufferManagerBase::LastXfbHeight() != fb_height)
+ if (FramebufferManagerBase::LastXfbWidth() == fb_stride &&
+ FramebufferManagerBase::LastXfbHeight() == fb_height)
{
- u32 last_w = (fb_stride < 1 || fb_stride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fb_stride;
- u32 last_h = (fb_height < 1 || fb_height > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fb_height;
- FramebufferManagerBase::SetLastXfbWidth(last_w);
- FramebufferManagerBase::SetLastXfbHeight(last_h);
+ return;
+ }
+
+ u32 new_width = (fb_stride < 1 || fb_stride > MAX_XFB_WIDTH) ? MAX_XFB_WIDTH : fb_stride;
+ u32 new_height = (fb_height < 1 || fb_height > MAX_XFB_HEIGHT) ? MAX_XFB_HEIGHT : fb_height;
+ FramebufferManagerBase::SetLastXfbWidth(new_width);
+ FramebufferManagerBase::SetLastXfbHeight(new_height);
+
+ // Changing the XFB source area will likely change the final drawing rectangle.
+ UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
+ if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height))
+ {
+ PixelShaderManager::SetEfbScaleChanged();
+ ResizeEFBTextures();
}
// This call is needed for auto-resizing to work.
@@ -850,9 +852,6 @@ void Renderer::CheckForSurfaceChange()
u32 old_width = m_swap_chain ? m_swap_chain->GetWidth() : 0;
u32 old_height = m_swap_chain ? m_swap_chain->GetHeight() : 0;
- // Wait for the GPU to catch up since we're going to destroy the swap chain.
- g_command_buffer_mgr->WaitForGPUIdle();
-
// Fast path, if the surface handle is the same, the window has just been resized.
if (m_swap_chain && s_new_surface_handle == m_swap_chain->GetNativeHandle())
{
@@ -866,6 +865,9 @@ void Renderer::CheckForSurfaceChange()
}
else
{
+ // Wait for the GPU to catch up since we're going to destroy the swap chain.
+ g_command_buffer_mgr->WaitForGPUIdle();
+
// Did we previously have a swap chain?
if (m_swap_chain)
{
@@ -888,7 +890,7 @@ void Renderer::CheckForSurfaceChange()
s_new_surface_handle);
if (surface != VK_NULL_HANDLE)
{
- m_swap_chain = SwapChain::Create(s_new_surface_handle, surface);
+ m_swap_chain = SwapChain::Create(s_new_surface_handle, surface, g_ActiveConfig.IsVSync());
if (!m_swap_chain)
PanicAlert("Failed to create swap chain.");
}
@@ -915,7 +917,6 @@ void Renderer::CheckForSurfaceChange()
void Renderer::CheckForConfigChanges()
{
// Compare g_Config to g_ActiveConfig to determine what has changed before copying.
- bool vsync_changed = (g_Config.bVSync != g_ActiveConfig.bVSync);
bool msaa_changed = (g_Config.iMultisamples != g_ActiveConfig.iMultisamples);
bool ssaa_changed = (g_Config.bSSAA != g_ActiveConfig.bSSAA);
bool anisotropy_changed = (g_Config.iMaxAnisotropy != g_ActiveConfig.iMaxAnisotropy);
@@ -926,6 +927,9 @@ void Renderer::CheckForConfigChanges()
// Copy g_Config to g_ActiveConfig.
UpdateActiveConfig();
+ // Update texture cache settings with any changed options.
+ TextureCache::OnConfigChanged(g_ActiveConfig);
+
// MSAA samples changed, we need to recreate the EFB render pass, and all shaders.
if (msaa_changed)
{
@@ -958,8 +962,11 @@ void Renderer::CheckForConfigChanges()
}
// For vsync, we need to change the present mode, which means recreating the swap chain.
- if (vsync_changed)
- ResizeSwapChain();
+ if (m_swap_chain && g_ActiveConfig.IsVSync() != m_swap_chain->IsVSyncEnabled())
+ {
+ g_command_buffer_mgr->WaitForGPUIdle();
+ m_swap_chain->SetVSync(g_ActiveConfig.IsVSync());
+ }
// Wipe sampler cache if force texture filtering or anisotropy changes.
if (anisotropy_changed || force_texture_filtering_changed)
@@ -970,13 +977,12 @@ void Renderer::OnSwapChainResized()
{
s_backbuffer_width = m_swap_chain->GetWidth();
s_backbuffer_height = m_swap_chain->GetHeight();
- FramebufferManagerBase::SetLastXfbWidth(MAX_XFB_WIDTH);
- FramebufferManagerBase::SetLastXfbHeight(MAX_XFB_HEIGHT);
UpdateDrawRectangle(s_backbuffer_width, s_backbuffer_height);
if (CalculateTargetSize(s_backbuffer_width, s_backbuffer_height))
+ {
+ PixelShaderManager::SetEfbScaleChanged();
ResizeEFBTextures();
-
- PixelShaderManager::SetEfbScaleChanged();
+ }
}
void Renderer::BindEFBToStateTracker()
@@ -1361,13 +1367,9 @@ void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
}
// If mipmaps are disabled, clamp min/max lod
- new_state.max_lod = (SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) ?
- static_cast<u32>(MathUtil::Clamp(tm1.max_lod / 16.0f, 0.0f, 255.0f)) :
- 0;
- new_state.min_lod =
- std::min(new_state.max_lod.Value(),
- static_cast<u32>(MathUtil::Clamp(tm1.min_lod / 16.0f, 0.0f, 255.0f)));
- new_state.lod_bias = static_cast<s32>(tm0.lod_bias / 32.0f);
+ new_state.max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0;
+ new_state.min_lod = std::min(new_state.max_lod.Value(), tm1.min_lod);
+ new_state.lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias : 0;
// Custom textures may have a greater number of mips
if (custom_tex)
@@ -1381,15 +1383,7 @@ void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
new_state.wrap_v = address_modes[tm0.wrap_t];
// Only use anisotropic filtering for textures that would be linearly filtered.
- if (g_vulkan_context->SupportsAnisotropicFiltering() && g_ActiveConfig.iMaxAnisotropy > 0 &&
- !SamplerCommon::IsBpTexMode0PointFiltering(tm0))
- {
- new_state.anisotropy = g_ActiveConfig.iMaxAnisotropy;
- }
- else
- {
- new_state.anisotropy = 0;
- }
+ new_state.enable_anisotropic_filtering = SamplerCommon::IsBpTexMode0PointFiltering(tm0) ? 0 : 1;
// Skip lookup if the state hasn't changed.
size_t bind_index = (texindex * 4) + stage;
@@ -1411,6 +1405,7 @@ void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex)
void Renderer::ResetSamplerStates()
{
// Ensure none of the sampler objects are in use.
+ // This assumes that none of the samplers are in use on the command list currently being recorded.
g_command_buffer_mgr->WaitForGPUIdle();
// Invalidate all sampler states, next draw will re-initialize them.