shader: decode compressed UNORM16 MRT exports

This commit is contained in:
nmzik
2026-08-21 05:23:09 +02:00
parent 342fae06a6
commit 79443aa104
3 changed files with 36 additions and 7 deletions
@@ -203,10 +203,12 @@ uint32_t EmitAttribute(ValueEmitContext& ctx, uint32_t attr, uint32_t chan) {
return bits; return bits;
} }
bool MrtUsesUint(const EmitterState& state, const IR::ExportInfo& exp) { uint32_t MrtOutputMode(const EmitterState& state, const IR::ExportInfo& exp) {
return state.stage == ShaderType::Pixel && exp.kind == IR::ExportTargetKind::Mrt && if (state.stage != ShaderType::Pixel || exp.kind != IR::ExportTargetKind::Mrt ||
exp.index < std::size(state.input_info.pixel->target_output_mode) && exp.index >= std::size(state.input_info.pixel->target_output_mode)) {
state.input_info.pixel->target_output_mode[exp.index] == 7u; return 0;
}
return state.input_info.pixel->target_output_mode[exp.index];
} }
uint32_t ExportRawComponent(ValueEmitContext& ctx, uint32_t vector, uint32_t component) { uint32_t ExportRawComponent(ValueEmitContext& ctx, uint32_t vector, uint32_t component) {
@@ -220,6 +222,8 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
bool uint_output) { bool uint_output) {
auto& state = ctx.state; auto& state = ctx.state;
if (exp.compr && !uint_output) { if (exp.compr && !uint_output) {
const auto unpack = MrtOutputMode(state, exp) == 5u ? GlslUnpackUnorm2x16
: GlslUnpackHalf2x16;
uint32_t f32[4] = {ConstantF32(state, 0), ConstantF32(state, 0), ConstantF32(state, 0), uint32_t f32[4] = {ConstantF32(state, 0), ConstantF32(state, 0), ConstantF32(state, 0),
ConstantF32(state, 0x3f800000u)}; ConstantF32(state, 0x3f800000u)};
for (uint32_t pair = 0; pair < 2u; pair++) { for (uint32_t pair = 0; pair < 2u; pair++) {
@@ -229,8 +233,8 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo
const auto packed = state.builder.AllocateId(); const auto packed = state.builder.AllocateId();
const auto unpacked = state.builder.AllocateId(); const auto unpacked = state.builder.AllocateId();
state.builder.AddFunction({OpCompositeExtract, TypeU32(state), packed, data, pair}); state.builder.AddFunction({OpCompositeExtract, TypeU32(state), packed, data, pair});
state.builder.AddFunction({OpExtInst, TypeF32Vector(state, 2), unpacked, state.builder.AddFunction(
GlslStd450(state), GlslUnpackHalf2x16, packed}); {OpExtInst, TypeF32Vector(state, 2), unpacked, GlslStd450(state), unpack, packed});
for (uint32_t lane = 0; lane < 2u; lane++) { for (uint32_t lane = 0; lane < 2u; lane++) {
const auto component = pair * 2u + lane; const auto component = pair * 2u + lane;
if (((exp.en >> component) & 1u) != 0u) { if (((exp.en >> component) & 1u) != 0u) {
@@ -332,7 +336,7 @@ void EmitExport(ValueEmitContext& ctx, const IR::Inst& inst) {
if (variable == 0) { if (variable == 0) {
return; return;
} }
const bool uint_output = MrtUsesUint(state, exp); const bool uint_output = MrtOutputMode(state, exp) == 7u;
const auto vector_type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4); const auto vector_type = uint_output ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
auto value = ExportVector(ctx, data, exp, uint_output); auto value = ExportVector(ctx, data, exp, uint_output);
if (state.stage == ShaderType::Pixel && exp.kind == IR::ExportTargetKind::Mrt && if (state.stage == ShaderType::Pixel && exp.kind == IR::ExportTargetKind::Mrt &&
@@ -271,6 +271,7 @@ enum : uint32_t {
GlslPackSnorm2x16 = 56, GlslPackSnorm2x16 = 56,
GlslPackUnorm2x16 = 57, GlslPackUnorm2x16 = 57,
GlslPackHalf2x16 = 58, GlslPackHalf2x16 = 58,
GlslUnpackUnorm2x16 = 61,
GlslUnpackHalf2x16 = 62, GlslUnpackHalf2x16 = 62,
GlslFindILsb = 73, GlslFindILsb = 73,
GlslFindUMsb = 75, GlslFindUMsb = 75,
+24
View File
@@ -9851,6 +9851,19 @@ void TestNewShaderRecompilerExpPixelOutputs() {
"compressed UINT16 MRT export was incorrectly decoded as FP16"); "compressed UINT16 MRT export was incorrectly decoded as FP16");
CheckSpirvBinaryValidates(uint16_result.spirv); CheckSpirvBinaryValidates(uint16_result.spirv);
ShaderPixelInputInfo unorm16_info;
unorm16_info.target_output_mode[0] = 5;
options.input_info.pixel = &unorm16_info;
ShaderRecompiler::CompileResult unorm16_result;
Check(ShaderRecompiler::TryRecompile(shader, options, unorm16_result, &error),
error.c_str());
const auto unorm16_source = DisassembleSpirvBinary(unorm16_result.spirv);
Check(CountSourceOccurrences(unorm16_source, "UnpackUnorm2x16") == 2u,
"compressed UNORM16 MRT export did not unpack two normalized pairs");
Check(!SpirvContainsExtInst(unorm16_result.spirv, 62),
"compressed UNORM16 MRT export was incorrectly decoded as FP16");
CheckSpirvBinaryValidates(unorm16_result.spirv);
const uint32_t partial_shader[] = { const uint32_t partial_shader[] = {
EncodeExp0(0x00, 0x7), EncodeExp0(0x00, 0x7),
EncodeExp1(0, 1, 2, 3), EncodeExp1(0, 1, 2, 3),
@@ -9899,6 +9912,17 @@ void TestNewShaderRecompilerExpPixelOutputs() {
"OpBitFieldUExtract") == 2u, "OpBitFieldUExtract") == 2u,
"compressed UINT16 BA-only export did not read and unpack VSRC1"); "compressed UINT16 BA-only export did not read and unpack VSRC1");
CheckSpirvBinaryValidates(compressed_ba_result.spirv); CheckSpirvBinaryValidates(compressed_ba_result.spirv);
unorm16_info.target_output_mode[0] = 5;
options.input_info.pixel = &unorm16_info;
ShaderRecompiler::CompileResult unorm16_ba_result;
Check(ShaderRecompiler::TryRecompile(compressed_ba_shader, options,
unorm16_ba_result, &error),
error.c_str());
const auto unorm16_ba_source = DisassembleSpirvBinary(unorm16_ba_result.spirv);
Check(CountSourceOccurrences(unorm16_ba_source, "UnpackUnorm2x16") == 1u,
"compressed UNORM16 BA-only export did not unpack VSRC1");
CheckSpirvBinaryValidates(unorm16_ba_result.spirv);
} }
void TestRenderTargetReverseExportMapping() { void TestRenderTargetReverseExportMapping() {