GS/Vulkan: Handle uploads to render targets

This commit is contained in:
Connor McLaughlin 2022-01-10 00:08:24 +10:00 committed by lightningterror
parent 68f18245a7
commit 126ae4a0f0
2 changed files with 73 additions and 54 deletions

View File

@ -164,7 +164,7 @@ VkCommandBuffer GSTextureVK::GetCommandBufferForUpdate()
bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int layer) bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int layer)
{ {
if (m_type != Type::Texture || static_cast<u32>(layer) >= m_texture.GetLevels()) if (layer >= m_mipmap_levels)
return false; return false;
g_perfmon.Put(GSPerfMon::TextureUploads, 1); g_perfmon.Put(GSPerfMon::TextureUploads, 1);
@ -193,18 +193,30 @@ bool GSTextureVK::Update(const GSVector4i& r, const void* data, int pitch, int l
if (m_texture.GetLayout() == VK_IMAGE_LAYOUT_UNDEFINED) if (m_texture.GetLayout() == VK_IMAGE_LAYOUT_UNDEFINED)
m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
if (m_type == Type::RenderTarget)
{
if (!r.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
CommitClear(cmdbuf);
else
m_state = State::Dirty;
}
m_texture.UpdateFromBuffer( m_texture.UpdateFromBuffer(
cmdbuf, layer, 0, r.x, r.y, width, height, row_length, buffer.GetBuffer(), buffer_offset); cmdbuf, layer, 0, r.x, r.y, width, height, row_length, buffer.GetBuffer(), buffer_offset);
m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if (m_type == Type::Texture)
m_needs_mipmaps_generated |= (layer == 0); m_needs_mipmaps_generated |= (layer == 0);
return true; return true;
} }
bool GSTextureVK::Map(GSMap& m, const GSVector4i* r, int layer) bool GSTextureVK::Map(GSMap& m, const GSVector4i* r, int layer)
{ {
if (m_type == Type::Texture && static_cast<u32>(layer) < m_texture.GetLevels()) if (layer >= m_mipmap_levels)
{ return false;
// map for writing // map for writing
m_map_area = r ? *r : GSVector4i(0, 0, m_texture.GetWidth(), m_texture.GetHeight()); m_map_area = r ? *r : GSVector4i(0, 0, m_texture.GetWidth(), m_texture.GetHeight());
m_map_level = layer; m_map_level = layer;
@ -224,16 +236,8 @@ bool GSTextureVK::Map(GSMap& m, const GSVector4i* r, int layer)
m.bits = static_cast<u8*>(buffer.GetCurrentHostPointer()); m.bits = static_cast<u8*>(buffer.GetCurrentHostPointer());
return true; return true;
} }
else
{
// not available
return false;
}
}
void GSTextureVK::Unmap() void GSTextureVK::Unmap()
{
if (m_type == Type::Texture)
{ {
pxAssert(m_map_level < m_texture.GetLevels()); pxAssert(m_map_level < m_texture.GetLevels());
g_perfmon.Put(GSPerfMon::TextureUploads, 1); g_perfmon.Put(GSPerfMon::TextureUploads, 1);
@ -254,13 +258,22 @@ void GSTextureVK::Unmap()
if (m_texture.GetLayout() == VK_IMAGE_LAYOUT_UNDEFINED) if (m_texture.GetLayout() == VK_IMAGE_LAYOUT_UNDEFINED)
m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
// if we're an rt and have been cleared, and the full rect isn't being uploaded, do the clear
if (m_type == Type::RenderTarget)
{
if (!m_map_area.eq(GSVector4i(0, 0, m_size.x, m_size.y)))
CommitClear(cmdbuf);
else
m_state = State::Dirty;
}
m_texture.UpdateFromBuffer(cmdbuf, m_map_level, 0, m_map_area.x, m_map_area.y, width, height, width, m_texture.UpdateFromBuffer(cmdbuf, m_map_level, 0, m_map_area.x, m_map_area.y, width, height, width,
buffer.GetBuffer(), buffer_offset); buffer.GetBuffer(), buffer_offset);
m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if (m_type == Type::Texture)
m_needs_mipmaps_generated |= (m_map_level == 0); m_needs_mipmaps_generated |= (m_map_level == 0);
} }
}
void GSTextureVK::GenerateMipmap() void GSTextureVK::GenerateMipmap()
{ {
@ -308,20 +321,25 @@ void GSTextureVK::CommitClear()
GSDeviceVK::GetInstance()->EndRenderPass(); GSDeviceVK::GetInstance()->EndRenderPass();
TransitionToLayout(VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); CommitClear(g_vulkan_context->GetCurrentCommandBuffer());
}
void GSTextureVK::CommitClear(VkCommandBuffer cmdbuf)
{
m_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
if (IsDepthStencil()) if (IsDepthStencil())
{ {
const VkClearDepthStencilValue cv = { m_clear_value.depth }; const VkClearDepthStencilValue cv = { m_clear_value.depth };
const VkImageSubresourceRange srr = { VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u }; const VkImageSubresourceRange srr = { VK_IMAGE_ASPECT_DEPTH_BIT, 0u, 1u, 0u, 1u };
vkCmdClearDepthStencilImage(g_vulkan_context->GetCurrentCommandBuffer(), m_texture.GetImage(), m_texture.GetLayout(), &cv, 1, &srr); vkCmdClearDepthStencilImage(cmdbuf, m_texture.GetImage(), m_texture.GetLayout(), &cv, 1, &srr);
} }
else else
{ {
alignas(16) VkClearColorValue cv; alignas(16) VkClearColorValue cv;
GSVector4::store<true>(cv.float32, GetClearColor()); GSVector4::store<true>(cv.float32, GetClearColor());
const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u}; const VkImageSubresourceRange srr = {VK_IMAGE_ASPECT_COLOR_BIT, 0u, 1u, 0u, 1u};
vkCmdClearColorImage(g_vulkan_context->GetCurrentCommandBuffer(), m_texture.GetImage(), m_texture.GetLayout(), &cv, 1, &srr); vkCmdClearColorImage(cmdbuf, m_texture.GetImage(), m_texture.GetLayout(), &cv, 1, &srr);
} }
SetState(GSTexture::State::Dirty); SetState(GSTexture::State::Dirty);

View File

@ -52,6 +52,7 @@ public:
void TransitionToLayout(VkImageLayout layout); void TransitionToLayout(VkImageLayout layout);
void CommitClear(); void CommitClear();
void CommitClear(VkCommandBuffer cmdbuf);
/// Framebuffers are lazily allocated. /// Framebuffers are lazily allocated.
VkFramebuffer GetFramebuffer(bool feedback_loop); VkFramebuffer GetFramebuffer(bool feedback_loop);