mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-10-11 22:49:55 +00:00
vk: Fix edge cases in DEPTH format transfer logic
- Lots of edge cases and wrong sizes used for barriers - Incorrect e4m12 conversion logic caused readback errors
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
R"(
|
||||
// Some RSX data such as the D16_FLOAT format data uses E4M12 instead of the standard FP16.
|
||||
// This gives it more precision for depth data which is almost always in the range [0,1] while still allowing reverse depth techniques which require Z > 1.
|
||||
#if defined(_CONVERT_F32_TO_E4M12) && _CONVERT_F32_TO_E4M12
|
||||
// Clamp to [0, 511.9375] (0xFFFF), rebias by 2^-120, then round the 11 dropped mantissa bits to nearest.
|
||||
uint pack_e4m12_pack16(const in uvec2 value)
|
||||
{
|
||||
const vec2 f = clamp(uintBitsToFloat(value), 0., uintBitsToFloat(0x43FFF800u)) * uintBitsToFloat(0x03800000u);
|
||||
const uvec2 result = (floatBitsToUint(f) + 0x400u) >> 11;
|
||||
return bitfieldInsert(result.x, result.y, 16, 16);
|
||||
}
|
||||
#else
|
||||
// Move each half's E4M12 bits onto the low end of the f32 exponent/mantissa, then rebias by 2^120.
|
||||
// Rebiasing with a float multiply keeps 0 as 0 and decodes E=0 as a denormal (m * 2^-18).
|
||||
uvec2 unpack_e4m12_pack16(const in uint value)
|
||||
{
|
||||
const uvec2 bits = uvec2(value << 11u, value >> 5u) & 0x07FFF800u; // 5 = 16 - 11. We'd have shifted down by 16 then up by 11 normally to extract the high word...
|
||||
return floatBitsToUint(uintBitsToFloat(bits) * uintBitsToFloat(0x7B800000u)); // Exponent addition using mul to preserve 0. Otherwise special numbers like 0 would get corrupted if you add (120 << 23) like the old impl.
|
||||
}
|
||||
#endif
|
||||
)"
|
||||
@@ -250,28 +250,6 @@ namespace vk
|
||||
{
|
||||
u32 m_ssbo_length = 0;
|
||||
|
||||
void declare_f16_expansion()
|
||||
{
|
||||
method_declarations +=
|
||||
"uvec2 unpack_e4m12_pack16(const in uint value)\n"
|
||||
"{\n"
|
||||
" uvec2 result = uvec2(bitfieldExtract(value, 0, 16), bitfieldExtract(value, 16, 16));\n"
|
||||
" result <<= 11;\n"
|
||||
" result += (120 << 23);\n"
|
||||
" return result;\n"
|
||||
"}\n\n";
|
||||
}
|
||||
|
||||
void declare_f16_contraction()
|
||||
{
|
||||
method_declarations +=
|
||||
"uint pack_e4m12_pack16(const in uvec2 value)\n"
|
||||
"{\n"
|
||||
" uvec2 result = (value - (120 << 23)) >> 11;\n"
|
||||
" return (result.x & 0xFFFF) | (result.y << 16);\n"
|
||||
"}\n\n";
|
||||
}
|
||||
|
||||
cs_fconvert_task()
|
||||
{
|
||||
use_push_constants = true;
|
||||
@@ -290,9 +268,9 @@ namespace vk
|
||||
" if ((index * 2) >= block_length)\n"
|
||||
" return;\n";
|
||||
|
||||
static_assert(sizeof(To) == 2);
|
||||
declare_f16_contraction();
|
||||
method_declarations += "#define _CONVERT_F32_TO_E4M12 1\n";
|
||||
|
||||
static_assert(sizeof(To) == 2);
|
||||
work_kernel +=
|
||||
" const uint src_offset = (index * 2) + in_offset;\n"
|
||||
" const uint dst_offset = index + out_offset;\n"
|
||||
@@ -322,8 +300,6 @@ namespace vk
|
||||
" return;\n";
|
||||
|
||||
static_assert(sizeof(To) == 4);
|
||||
declare_f16_expansion();
|
||||
|
||||
work_kernel +=
|
||||
" const uint src_offset = index + in_offset;\n"
|
||||
" const uint dst_offset = (index * 2) + out_offset;\n"
|
||||
@@ -348,6 +324,10 @@ namespace vk
|
||||
" data[dst_offset + 1] = tmp.z;\n";
|
||||
}
|
||||
|
||||
method_declarations +=
|
||||
#include "Emu/RSX/Program/GLSLSnippets/E4M12Conversion.glsl"
|
||||
;
|
||||
|
||||
cs_shuffle_base::build("");
|
||||
}
|
||||
|
||||
|
||||
@@ -160,12 +160,12 @@ namespace vk
|
||||
const u32 packed32_length = out_w * out_h * 4;
|
||||
const u32 packed16_length = out_w * out_h * 2;
|
||||
|
||||
const auto allocation_end = region.bufferOffset + packed32_length + packed16_length;
|
||||
ensure(dst->size() >= allocation_end);
|
||||
|
||||
const auto data_offset = u32(region.bufferOffset);
|
||||
const auto z32_offset = utils::align<u32>(data_offset + packed16_length, 256);
|
||||
|
||||
const auto allocation_end = z32_offset + packed32_length;
|
||||
ensure(dst->size() >= allocation_end);
|
||||
|
||||
// 1. Copy the depth to buffer
|
||||
VkBufferImageCopy region2;
|
||||
region2 = region;
|
||||
@@ -214,13 +214,13 @@ namespace vk
|
||||
const u32 in_depth_size = packed_length;
|
||||
const u32 in_stencil_size = out_w * out_h;
|
||||
|
||||
const auto allocation_end = region.bufferOffset + packed_length + in_depth_size + in_stencil_size;
|
||||
ensure(dst->size() >= allocation_end);
|
||||
|
||||
const auto data_offset = u32(region.bufferOffset);
|
||||
const auto z_offset = utils::align<u32>(data_offset + packed_length, 256);
|
||||
const auto s_offset = utils::align<u32>(z_offset + in_depth_size, 256);
|
||||
|
||||
const auto allocation_end = s_offset + in_stencil_size;
|
||||
ensure(dst->size() >= allocation_end);
|
||||
|
||||
// 1. Copy the depth and stencil blocks to separate banks
|
||||
VkBufferImageCopy sub_regions[2];
|
||||
sub_regions[0] = sub_regions[1] = region;
|
||||
@@ -263,9 +263,14 @@ namespace vk
|
||||
}
|
||||
}
|
||||
|
||||
vk::insert_buffer_memory_barrier(cmd, dst->value, z_offset, in_depth_size + in_stencil_size,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
|
||||
vk::insert_buffer_memory_barrier(cmd,
|
||||
dst->value,
|
||||
z_offset,
|
||||
(s_offset + in_stencil_size) - z_offset,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT);
|
||||
|
||||
job->run(cmd, dst, data_offset, packed_length, z_offset, s_offset);
|
||||
|
||||
@@ -282,7 +287,7 @@ namespace vk
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // switch
|
||||
}
|
||||
|
||||
void copy_buffer_to_image(const vk::command_buffer& cmd, const vk::buffer* src, const vk::image* dst, const VkBufferImageCopy& region)
|
||||
@@ -312,16 +317,22 @@ namespace vk
|
||||
const u32 packed32_length = out_w * out_h * 4;
|
||||
const u32 packed16_length = out_w * out_h * 2;
|
||||
|
||||
const auto allocation_end = region.bufferOffset + packed32_length + packed16_length;
|
||||
ensure(src->size() >= allocation_end);
|
||||
|
||||
const auto data_offset = u32(region.bufferOffset);
|
||||
const auto z32_offset = utils::align<u32>(data_offset + packed16_length, 256);
|
||||
|
||||
const auto allocation_end = z32_offset + packed32_length;
|
||||
ensure(src->size() >= allocation_end);
|
||||
|
||||
// 1. Pre-compute barrier
|
||||
vk::insert_buffer_memory_barrier(cmd, src->value, z32_offset, packed32_length,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
|
||||
vk::insert_buffer_memory_barrier(
|
||||
cmd,
|
||||
src->value,
|
||||
data_offset,
|
||||
packed16_length,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT);
|
||||
|
||||
// 2. Do conversion with byteswap [D16F->D32F]
|
||||
auto job = vk::get_compute_task<vk::cs_fconvert_task<f16, f32>>();
|
||||
@@ -347,19 +358,25 @@ namespace vk
|
||||
const u32 in_depth_size = packed_length;
|
||||
const u32 in_stencil_size = out_w * out_h;
|
||||
|
||||
const auto allocation_end = region.bufferOffset + packed_length + in_depth_size + in_stencil_size;
|
||||
ensure(src->size() >= allocation_end); // "Out of memory (compute heap). Lower your resolution scale setting."
|
||||
|
||||
const auto data_offset = u32(region.bufferOffset);
|
||||
const auto z_offset = utils::align<u32>(data_offset + packed_length, 256);
|
||||
const auto s_offset = utils::align<u32>(z_offset + in_depth_size, 256);
|
||||
|
||||
const auto allocation_end = s_offset + in_stencil_size;
|
||||
ensure(src->size() >= allocation_end); // "Out of memory (compute heap). Lower your resolution scale setting."
|
||||
|
||||
// Zero out the stencil block
|
||||
vkCmdFillBuffer(cmd, src->value, s_offset, utils::align(in_stencil_size, 4), 0);
|
||||
|
||||
vk::insert_buffer_memory_barrier(cmd, src->value, s_offset, in_stencil_size,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
|
||||
vk::insert_buffer_memory_barrier(
|
||||
cmd,
|
||||
src->value,
|
||||
data_offset,
|
||||
(s_offset + in_stencil_size) - data_offset,
|
||||
VK_PIPELINE_STAGE_TRANSFER_BIT | VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||
VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT);
|
||||
|
||||
// 1. Scatter the interleaved data into separate depth and stencil blocks
|
||||
vk::cs_interleave_task *job;
|
||||
@@ -378,7 +395,11 @@ namespace vk
|
||||
|
||||
job->run(cmd, src, data_offset, packed_length, z_offset, s_offset);
|
||||
|
||||
vk::insert_buffer_memory_barrier(cmd, src->value, z_offset, in_depth_size + in_stencil_size,
|
||||
vk::insert_buffer_memory_barrier(
|
||||
cmd,
|
||||
src->value,
|
||||
z_offset,
|
||||
(s_offset + in_stencil_size) - z_offset,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT,
|
||||
VK_ACCESS_SHADER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
|
||||
|
||||
|
||||
@@ -1124,6 +1124,7 @@
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\CopyBufferToGenericImage.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\CopyD24x8ToBuffer.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\CopyRGBA8ToBuffer.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\E4M12Conversion.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\GenericVSPassthrough.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl" />
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\OverlayRenderFS.glsl" />
|
||||
|
||||
@@ -3027,6 +3027,9 @@
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\E4M12Conversion.glsl">
|
||||
<Filter>Emu\GPU\RSX\Program\Snippets</Filter>
|
||||
</None>
|
||||
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">
|
||||
<Filter>Emu\GPU\RSX\Program\Snippets</Filter>
|
||||
</None>
|
||||
|
||||
Reference in New Issue
Block a user