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:
kd-11
2026-10-09 12:38:31 +03:00
committed by kd-11
parent 7c572eb4dd
commit cfd03fc026
5 changed files with 75 additions and 49 deletions
@@ -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
)"
+6 -26
View File
@@ -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("");
}
+44 -23
View File
@@ -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);
+1
View File
@@ -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" />
+3
View File
@@ -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>