shader: type pixel outputs of UINT and SINT render targets as integer vectors

Co-authored-by: Ali Almohaya <AliAlmohaya@gmail.com>
Co-authored-by: Mac <me@itsmemac.com>
Co-authored-by: Senaxx <michelbeld@gmail.com>
This commit is contained in:
nmzik
2026-10-26 04:06:00 +01:00
parent 4ebae87a1b
commit 26ca609236
9 changed files with 103 additions and 23 deletions
+34
View File
@@ -19808,6 +19808,40 @@ public:
}
Require(name, "packed rounding program distinction", half_up_program != truncate_program,
"half-up and truncate exports shared one shader specialization");
// UINT and SINT targets give their exports integer outputs.
registers.Reset();
registers.SetViewportTransformControl(0x300);
registers.SetRenderTargetMask(0xffu);
registers.SetShaderMask(0xffu);
shaders.SetPsShaderBase(pixel_address);
for (const auto [slot, type] : {std::pair{0u, Prospero::ChannelType::kUInt},
std::pair{1u, Prospero::ChannelType::kSInt}}) {
registers.SetTargetOutputMode(slot, 9);
registers.SetColorBase(slot, {.addr = depth_address + 0x10000 * (slot + 1)});
registers.SetColorInfo(slot, {.format = Prospero::ChannelLayout::k32, .channel_type = type,
.channel_order = Prospero::ChannelOrder::kStandard});
registers.SetColorAttrib2(slot, {.height = extent - 1, .width = extent - 1});
registers.SetColorAttrib3(slot, {.tile_mode = Prospero::TileMode::kLinear, .dimension = 1});
}
native_programs();
Require(name, "integer target outputs",
pixel.target_uint_mask == 1u && pixel.target_sint_mask == 2u,
"UINT and SINT targets did not select integer export outputs");
// MRT1 is the second blend source of a dual-source float target 0, not integer target 1.
HW::BlendControl dual_blend{};
dual_blend.enable = true;
dual_blend.color_srcblend = static_cast<uint8_t>(Prospero::BlendFactor::kSrc1Color);
registers.SetBlendControl(0, dual_blend);
for (const auto [slot, type] : {std::pair{0u, Prospero::ChannelType::kFloat},
std::pair{1u, Prospero::ChannelType::kUInt}}) {
registers.SetColorInfo(slot, {.format = Prospero::ChannelLayout::k32, .channel_type = type,
.channel_order = Prospero::ChannelOrder::kStandard});
native_programs();
Require(name, "dual-source float outputs",
pixel.dual_source_blending && pixel.target_uint_mask == 0u &&
pixel.target_sint_mask == 0u,
"the second blend source kept the integer type of render target 1");
}
DestroyBuffer(&packed_output);
m_device.destroySampler(packed_sampler);
DestroyBuffer(&stencil_readback);
+23
View File
@@ -13748,6 +13748,7 @@ void TestNewShaderRecompilerExpPixelOutputs() {
ShaderPixelInputInfo uint16_info;
uint16_info.target_output_mode[0] = 7;
uint16_info.target_uint_mask = 1;
options.input_info.pixel = &uint16_info;
auto uint16_result = RecompileForTest(shader, options);
const auto uint16_source = DisassembleSpirvBinary(uint16_result.spirv);
@@ -13762,6 +13763,18 @@ void TestNewShaderRecompilerExpPixelOutputs() {
"compressed UINT16 MRT export was incorrectly decoded as FP16");
CheckSpirvBinaryValidates(uint16_result.spirv);
ShaderPixelInputInfo sint16_info;
sint16_info.target_output_mode[0] = 8;
sint16_info.target_sint_mask = 1;
options.input_info.pixel = &sint16_info;
auto sint16_result = RecompileForTest(shader, options);
const auto sint16_source = DisassembleSpirvBinary(sint16_result.spirv);
Check(sint16_source.find("OpVariable %_ptr_Output_v4int Output") != std::string::npos &&
CountSourceOccurrences(sint16_source, "OpBitFieldSExtract") == 4u &&
!SpirvContainsExtInst(sint16_result.spirv, 62),
"compressed SINT16 MRT export did not sign-extend into a signed output");
CheckSpirvBinaryValidates(sint16_result.spirv);
ShaderPixelInputInfo unorm16_info;
unorm16_info.target_output_mode[0] = 5;
options.input_info.pixel = &unorm16_info;
@@ -13789,6 +13802,7 @@ void TestNewShaderRecompilerExpPixelOutputs() {
ShaderPixelInputInfo uint_info;
uint_info.target_output_mode[0] = 7;
uint_info.target_uint_mask = 1;
options.input_info.pixel = &uint_info;
auto partial_uint_result =
RecompileForTest(partial_shader, options);
@@ -13815,6 +13829,15 @@ void TestNewShaderRecompilerExpPixelOutputs() {
"compressed UINT16 BA-only export did not read and unpack VSRC1");
CheckSpirvBinaryValidates(compressed_ba_result.spirv);
// 32-bit exports keep their raw bits in a UINT target's integer output.
uint_info.target_output_mode[0] = 9;
auto raw_uint_result = RecompileForTest(partial_shader, options);
const auto raw_uint_source = DisassembleSpirvBinary(raw_uint_result.spirv);
Check(raw_uint_source.find("OpVariable %_ptr_Output_v4uint Output") != std::string::npos &&
raw_uint_source.find("OpBitcast %v4float") == std::string::npos,
"32-bit MRT export to a UINT target did not use an unsigned integer output");
CheckSpirvBinaryValidates(raw_uint_result.spirv);
unorm16_info.target_output_mode[0] = 5;
options.input_info.pixel = &unorm16_info;
auto unorm16_ba_result =