Vulkan: Clamp framebuffer resolve rectangle to texture size
This is invalid and was causing the NVIDIA driver to throw an error.
This commit is contained in:
parent
eef7b6cf7a
commit
69b0a31938
|
@ -462,6 +462,12 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region)
|
|||
// Can't resolve within a render pass.
|
||||
StateTracker::GetInstance()->EndRenderPass();
|
||||
|
||||
// It's not valid to resolve out-of-bounds coordinates.
|
||||
// Ensuring the region is within the image is the caller's responsibility.
|
||||
_assert_(region.offset.x >= 0 && region.offset.y >= 0 &&
|
||||
(static_cast<u32>(region.offset.x) + region.extent.width) <= m_efb_width &&
|
||||
(static_cast<u32>(region.offset.y) + region.extent.height) <= m_efb_height);
|
||||
|
||||
// Resolving is considered to be a transfer operation.
|
||||
m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(),
|
||||
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
|
||||
|
|
|
@ -587,12 +587,11 @@ void Renderer::ResolveEFBForSwap(const TargetRectangle& scaled_rect)
|
|||
{
|
||||
// While the source rect can be out-of-range when drawing, the resolve rectangle must be within
|
||||
// the bounds of the texture.
|
||||
TargetRectangle resolve_rect{scaled_rect};
|
||||
resolve_rect.ClampUL(0, 0, m_target_width, m_target_height);
|
||||
|
||||
VkRect2D region = {
|
||||
{resolve_rect.left, resolve_rect.top},
|
||||
{static_cast<u32>(resolve_rect.GetWidth()), static_cast<u32>(resolve_rect.GetHeight())}};
|
||||
{scaled_rect.left, scaled_rect.top},
|
||||
{static_cast<u32>(scaled_rect.GetWidth()), static_cast<u32>(scaled_rect.GetHeight())}};
|
||||
region = Util::ClampRect2D(region, FramebufferManager::GetInstance()->GetEFBWidth(),
|
||||
FramebufferManager::GetInstance()->GetEFBHeight());
|
||||
FramebufferManager::GetInstance()->ResolveEFBColorTexture(region);
|
||||
}
|
||||
|
||||
|
|
|
@ -96,11 +96,14 @@ void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_widt
|
|||
FramebufferManager::GetInstance()->FlushEFBPokes();
|
||||
|
||||
// MSAA case where we need to resolve first.
|
||||
// TODO: Do in one pass.
|
||||
// An out-of-bounds source region is valid here, and fine for the draw (since it is converted
|
||||
// to texture coordinates), but it's not valid to resolve an out-of-range rectangle.
|
||||
TargetRectangle scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect);
|
||||
VkRect2D region = {{scaled_src_rect.left, scaled_src_rect.top},
|
||||
{static_cast<u32>(scaled_src_rect.GetWidth()),
|
||||
static_cast<u32>(scaled_src_rect.GetHeight())}};
|
||||
region = Util::ClampRect2D(region, FramebufferManager::GetInstance()->GetEFBWidth(),
|
||||
FramebufferManager::GetInstance()->GetEFBHeight());
|
||||
Texture2D* src_texture;
|
||||
if (is_depth_copy)
|
||||
src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region);
|
||||
|
@ -465,10 +468,14 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRe
|
|||
VkCommandBuffer command_buffer = g_command_buffer_mgr->GetCurrentCommandBuffer();
|
||||
StateTracker::GetInstance()->EndRenderPass();
|
||||
|
||||
// Transition EFB to shader resource before binding
|
||||
// Transition EFB to shader resource before binding.
|
||||
// An out-of-bounds source region is valid here, and fine for the draw (since it is converted
|
||||
// to texture coordinates), but it's not valid to resolve an out-of-range rectangle.
|
||||
VkRect2D region = {{scaled_src_rect.left, scaled_src_rect.top},
|
||||
{static_cast<u32>(scaled_src_rect.GetWidth()),
|
||||
static_cast<u32>(scaled_src_rect.GetHeight())}};
|
||||
region = Util::ClampRect2D(region, FramebufferManager::GetInstance()->GetEFBWidth(),
|
||||
FramebufferManager::GetInstance()->GetEFBHeight());
|
||||
Texture2D* src_texture;
|
||||
if (is_depth_copy)
|
||||
src_texture = FramebufferManager::GetInstance()->ResolveEFBDepthTexture(region);
|
||||
|
|
|
@ -97,6 +97,16 @@ u32 GetTexelSize(VkFormat format)
|
|||
}
|
||||
}
|
||||
|
||||
VkRect2D ClampRect2D(const VkRect2D& rect, u32 width, u32 height)
|
||||
{
|
||||
VkRect2D out;
|
||||
out.offset.x = MathUtil::Clamp(rect.offset.x, 0, static_cast<int32_t>(width - 1));
|
||||
out.offset.y = MathUtil::Clamp(rect.offset.y, 0, static_cast<int32_t>(height - 1));
|
||||
out.extent.width = std::min(rect.extent.width, width - static_cast<uint32_t>(rect.offset.x));
|
||||
out.extent.height = std::min(rect.extent.height, height - static_cast<uint32_t>(rect.offset.y));
|
||||
return out;
|
||||
}
|
||||
|
||||
VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor)
|
||||
{
|
||||
switch (factor)
|
||||
|
|
|
@ -27,6 +27,9 @@ bool IsDepthFormat(VkFormat format);
|
|||
VkFormat GetLinearFormat(VkFormat format);
|
||||
u32 GetTexelSize(VkFormat format);
|
||||
|
||||
// Clamps a VkRect2D to the specified dimensions.
|
||||
VkRect2D ClampRect2D(const VkRect2D& rect, u32 width, u32 height);
|
||||
|
||||
// Map {SRC,DST}_COLOR to {SRC,DST}_ALPHA
|
||||
VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor);
|
||||
|
||||
|
|
Loading…
Reference in New Issue