diff --git a/rpcs3/Emu/RSX/Program/GLSLSnippets/E4M12Conversion.glsl b/rpcs3/Emu/RSX/Program/GLSLSnippets/E4M12Conversion.glsl new file mode 100644 index 0000000000..788f3c008e --- /dev/null +++ b/rpcs3/Emu/RSX/Program/GLSLSnippets/E4M12Conversion.glsl @@ -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 +)" diff --git a/rpcs3/Emu/RSX/VK/VKCompute.h b/rpcs3/Emu/RSX/VK/VKCompute.h index 887cc03f8a..a45716d520 100644 --- a/rpcs3/Emu/RSX/VK/VKCompute.h +++ b/rpcs3/Emu/RSX/VK/VKCompute.h @@ -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(""); } diff --git a/rpcs3/Emu/RSX/VK/VKTexture.cpp b/rpcs3/Emu/RSX/VK/VKTexture.cpp index b969d6403f..4e293ef7b8 100644 --- a/rpcs3/Emu/RSX/VK/VKTexture.cpp +++ b/rpcs3/Emu/RSX/VK/VKTexture.cpp @@ -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(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(data_offset + packed_length, 256); const auto s_offset = utils::align(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(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>(); @@ -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(data_offset + packed_length, 256); const auto s_offset = utils::align(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); diff --git a/rpcs3/emucore.vcxproj b/rpcs3/emucore.vcxproj index fa4004f733..0ad8b3edd3 100644 --- a/rpcs3/emucore.vcxproj +++ b/rpcs3/emucore.vcxproj @@ -1124,6 +1124,7 @@ + diff --git a/rpcs3/emucore.vcxproj.filters b/rpcs3/emucore.vcxproj.filters index a87bc78913..b8d3022f78 100644 --- a/rpcs3/emucore.vcxproj.filters +++ b/rpcs3/emucore.vcxproj.filters @@ -3027,6 +3027,9 @@ + + Emu\GPU\RSX\Program\Snippets + Emu\GPU\RSX\Program\Snippets