From b4853a0e083cb78c89d7c0bfd098101f51fcc0a9 Mon Sep 17 00:00:00 2001 From: nmzik Date: Fri, 9 Oct 2026 02:42:43 +0200 Subject: [PATCH] shader: preserve export vectors instead of rebuilding scalar components --- .../backend/spirv/spirvEmitterFlow.cpp | 68 +++++++++---------- tests/shaderCfgTests.cpp | 5 +- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp index f53790ea4..33a20fcbd 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterFlow.cpp @@ -304,50 +304,46 @@ uint32_t ExportVector(ValueEmitContext& ctx, uint32_t data, const IR::ExportInfo f32[0], f32[1], f32[2], f32[3]); return vector; } - uint32_t raw[4] = { - ConstantU32(state, 0), - ConstantU32(state, 0), - ConstantU32(state, 0), - ConstantU32(state, uint_output ? 1u : 0x3f800000u), - }; - if (exp.compr) { - for (uint32_t pair = 0; pair < 2u; pair++) { - if ((exp.en & (3u << (pair * 2u))) == 0u) { - continue; - } - const auto packed = ExportRawComponent(ctx, data, pair); - for (uint32_t lane = 0; lane < 2u; lane++) { - const auto component = pair * 2u + lane; - if (((exp.en >> component) & 1u) == 0u) { + if (exp.compr || exp.en != 0xfu) { + uint32_t raw[4] = { + ConstantU32(state, 0), + ConstantU32(state, 0), + ConstantU32(state, 0), + ConstantU32(state, uint_output ? 1u : 0x3f800000u), + }; + if (exp.compr) { + for (uint32_t pair = 0; pair < 2u; pair++) { + if ((exp.en & (3u << (pair * 2u))) == 0u) { continue; } - raw[component] = state.builder.AllocateId(); - state.builder.AddFunction(spv::OpBitFieldUExtract, TypeU32(state), raw[component], - packed, ConstantU32(state, lane * 16u), - ConstantU32(state, 16)); - } - } - } else { - for (uint32_t component = 0; component < 4u; component++) { - if (((exp.en >> component) & 1u) != 0u) { - raw[component] = ExportRawComponent(ctx, data, component); + const auto packed = ExportRawComponent(ctx, data, pair); + for (uint32_t lane = 0; lane < 2u; lane++) { + const auto component = pair * 2u + lane; + if (((exp.en >> component) & 1u) == 0u) { + continue; + } + raw[component] = state.builder.AllocateId(); + state.builder.AddFunction(spv::OpBitFieldUExtract, TypeU32(state), raw[component], + packed, ConstantU32(state, lane * 16u), + ConstantU32(state, 16)); + } + } + } else { + for (uint32_t component = 0; component < 4u; component++) { + if (((exp.en >> component) & 1u) != 0u) { + raw[component] = ExportRawComponent(ctx, data, component); + } } } + data = state.builder.AllocateId(); + state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(state, 4), data, + raw[0], raw[1], raw[2], raw[3]); } if (uint_output) { - const auto vector = state.builder.AllocateId(); - state.builder.AddFunction(spv::OpCompositeConstruct, TypeU32Vector(state, 4), vector, - raw[0], raw[1], raw[2], raw[3]); - return vector; - } - uint32_t f32[4] {}; - for (uint32_t component = 0; component < 4u; component++) { - f32[component] = state.builder.AllocateId(); - state.builder.AddFunction(spv::OpBitcast, TypeF32(state), f32[component], raw[component]); + return data; } const auto vector = state.builder.AllocateId(); - state.builder.AddFunction(spv::OpCompositeConstruct, TypeF32Vector(state, 4), vector, f32[0], - f32[1], f32[2], f32[3]); + state.builder.AddFunction(spv::OpBitcast, TypeF32Vector(state, 4), vector, data); return vector; } diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index e29c76c89..f603117c1 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -12826,7 +12826,7 @@ void TestNewShaderRecompilerExpPixelOutputs() { options.input_info.pixel = &default_info; auto partial_result = RecompileForTest(partial_shader, options); const auto partial_source = DisassembleSpirvBinary(partial_result.spirv); - Check(SpirvSourceHasInstructionOperand(partial_source, "OpBitcast", + Check(SpirvSourceHasInstructionOperand(partial_source, "OpCompositeConstruct", "%uint_1065353216"), "disabled float alpha export did not default to 1.0f bits"); CheckSpirvBinaryValidates(partial_result.spirv); @@ -13228,8 +13228,9 @@ void TestLogicalAlphaBlendExport() { const auto source = DisassembleSpirvBinary(guest.spirv); Check(source.find("OpDecorate %out_mrt_1 Location 0") != std::string::npos && source.find("OpDecorate %out_mrt_1 Index 1") != std::string::npos && + CountSourceOccurrences(source, "OpStore %out_mrt_0 ") == 1 && CountSourceOccurrences(source, "OpStore %out_mrt_1 ") == 1 && - SpirvInstructionOpcodeCount(guest.spirv, 81u) == 8u, + !SpirvContainsVectorShuffle(guest.spirv, {3u, 3u, 3u, 3u}), "guest dual-source export was replaced by synthetic alpha"); }