Vulkan/StagingTexture: Keep mapped throughout transfers

The underlying bug here was not invalidating the buffer after mapping (is
this supposed to be necessary?). But by keeping it mapped, we invalidate
it anyway.

Fixes screen corruption in Final Fantasy IX on Mali GPUs.
This commit is contained in:
Connor McLaughlin 2020-09-01 12:02:29 +10:00
parent e21fc9e253
commit dd0ae0fc9d
2 changed files with 9 additions and 19 deletions

View File

@ -209,10 +209,8 @@ void StagingTexture::Flush()
void StagingTexture::ReadTexels(u32 src_x, u32 src_y, u32 width, u32 height, void* out_ptr, u32 out_stride) void StagingTexture::ReadTexels(u32 src_x, u32 src_y, u32 width, u32 height, void* out_ptr, u32 out_stride)
{ {
Assert(m_staging_buffer.GetType() != StagingBuffer::Type::Upload); Assert(m_staging_buffer.GetType() != StagingBuffer::Type::Upload);
if (!PrepareForAccess())
return;
Assert((src_x + width) <= m_width && (src_y + height) <= m_height); Assert((src_x + width) <= m_width && (src_y + height) <= m_height);
PrepareForAccess();
// Offset pointer to point to start of region being copied out. // Offset pointer to point to start of region being copied out.
const char* current_ptr = m_staging_buffer.GetMapPointer(); const char* current_ptr = m_staging_buffer.GetMapPointer();
@ -239,10 +237,9 @@ void StagingTexture::ReadTexels(u32 src_x, u32 src_y, u32 width, u32 height, voi
void StagingTexture::ReadTexel(u32 x, u32 y, void* out_ptr) void StagingTexture::ReadTexel(u32 x, u32 y, void* out_ptr)
{ {
Assert(m_staging_buffer.GetType() != StagingBuffer::Type::Upload); Assert(m_staging_buffer.GetType() != StagingBuffer::Type::Upload);
if (!PrepareForAccess())
return;
Assert(x < m_width && y < m_height); Assert(x < m_width && y < m_height);
PrepareForAccess();
const char* src_ptr = GetMappedPointer() + y * GetMappedStride() + x * m_texel_size; const char* src_ptr = GetMappedPointer() + y * GetMappedStride() + x * m_texel_size;
std::memcpy(out_ptr, src_ptr, m_texel_size); std::memcpy(out_ptr, src_ptr, m_texel_size);
} }
@ -250,10 +247,8 @@ void StagingTexture::ReadTexel(u32 x, u32 y, void* out_ptr)
void StagingTexture::WriteTexels(u32 dst_x, u32 dst_y, u32 width, u32 height, const void* in_ptr, u32 in_stride) void StagingTexture::WriteTexels(u32 dst_x, u32 dst_y, u32 width, u32 height, const void* in_ptr, u32 in_stride)
{ {
Assert(m_staging_buffer.GetType() != StagingBuffer::Type::Readback); Assert(m_staging_buffer.GetType() != StagingBuffer::Type::Readback);
if (!PrepareForAccess())
return;
Assert((dst_x + width) <= m_width && (dst_y + height) <= m_height); Assert((dst_x + width) <= m_width && (dst_y + height) <= m_height);
PrepareForAccess();
// Offset pointer to point to start of region being copied to. // Offset pointer to point to start of region being copied to.
char* current_ptr = GetMappedPointer(); char* current_ptr = GetMappedPointer();
@ -279,23 +274,18 @@ void StagingTexture::WriteTexels(u32 dst_x, u32 dst_y, u32 width, u32 height, co
void StagingTexture::WriteTexel(u32 x, u32 y, const void* in_ptr) void StagingTexture::WriteTexel(u32 x, u32 y, const void* in_ptr)
{ {
if (!PrepareForAccess())
return;
Assert(x < m_width && y < m_height); Assert(x < m_width && y < m_height);
PrepareForAccess();
char* dest_ptr = GetMappedPointer() + y * m_map_stride + x * m_texel_size; char* dest_ptr = GetMappedPointer() + y * m_map_stride + x * m_texel_size;
std::memcpy(dest_ptr, in_ptr, m_texel_size); std::memcpy(dest_ptr, in_ptr, m_texel_size);
} }
bool StagingTexture::PrepareForAccess() void StagingTexture::PrepareForAccess()
{ {
Assert(IsMapped());
if (m_needs_flush) if (m_needs_flush)
{
if (IsMapped())
Unmap();
Flush(); Flush();
}
return IsMapped() || Map();
} }
} // namespace Vulkan } // namespace Vulkan

View File

@ -73,7 +73,7 @@ public:
void WriteTexel(u32 x, u32 y, const void* in_ptr); void WriteTexel(u32 x, u32 y, const void* in_ptr);
private: private:
bool PrepareForAccess(); void PrepareForAccess();
StagingBuffer m_staging_buffer; StagingBuffer m_staging_buffer;
u64 m_flush_fence_counter = 0; u64 m_flush_fence_counter = 0;