From cf0cbee02dc86032f9de5bee5a5d69d8ad747413 Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 6 Sep 2026 05:47:20 +0400 Subject: [PATCH] shader: fix vertex attribute identity swizzles --- src/graphics/shader/shader.cpp | 124 +++------------------------------ tests/shaderCfgTests.cpp | 41 +++++++++-- 2 files changed, 48 insertions(+), 117 deletions(-) diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index 6e97b787f..24c9a0b65 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -375,113 +375,6 @@ static void ShaderDetectBuffers(ShaderVertexInputInfo& info) { } } -static Prospero::BufferFormat -VertexAttribFormatToBufferFormat(Prospero::VertexAttribFormat format) { - struct FormatMap { - Prospero::VertexAttribFormat vertex; - Prospero::BufferFormat buffer; - }; - - static constexpr FormatMap format_map[] = { - {Prospero::VertexAttribFormat::kInvalid, Prospero::BufferFormat::kInvalid}, - {Prospero::VertexAttribFormat::k8UNorm, Prospero::BufferFormat::k8UNorm}, - {Prospero::VertexAttribFormat::k8SNorm, Prospero::BufferFormat::k8SNorm}, - {Prospero::VertexAttribFormat::k8UScaled, Prospero::BufferFormat::k8UScaled}, - {Prospero::VertexAttribFormat::k8SScaled, Prospero::BufferFormat::k8SScaled}, - {Prospero::VertexAttribFormat::k8UInt, Prospero::BufferFormat::k8UInt}, - {Prospero::VertexAttribFormat::k8SInt, Prospero::BufferFormat::k8SInt}, - {Prospero::VertexAttribFormat::k16UNorm, Prospero::BufferFormat::k16UNorm}, - {Prospero::VertexAttribFormat::k16SNorm, Prospero::BufferFormat::k16SNorm}, - {Prospero::VertexAttribFormat::k16UScaled, Prospero::BufferFormat::k16UScaled}, - {Prospero::VertexAttribFormat::k16SScaled, Prospero::BufferFormat::k16SScaled}, - {Prospero::VertexAttribFormat::k16UInt, Prospero::BufferFormat::k16UInt}, - {Prospero::VertexAttribFormat::k16SInt, Prospero::BufferFormat::k16SInt}, - {Prospero::VertexAttribFormat::k16Float, Prospero::BufferFormat::k16Float}, - {Prospero::VertexAttribFormat::k8_8UNorm, Prospero::BufferFormat::k8_8UNorm}, - {Prospero::VertexAttribFormat::k8_8SNorm, Prospero::BufferFormat::k8_8SNorm}, - {Prospero::VertexAttribFormat::k8_8UScaled, Prospero::BufferFormat::k8_8UScaled}, - {Prospero::VertexAttribFormat::k8_8SScaled, Prospero::BufferFormat::k8_8SScaled}, - {Prospero::VertexAttribFormat::k8_8UInt, Prospero::BufferFormat::k8_8UInt}, - {Prospero::VertexAttribFormat::k8_8SInt, Prospero::BufferFormat::k8_8SInt}, - {Prospero::VertexAttribFormat::k32UInt, Prospero::BufferFormat::k32UInt}, - {Prospero::VertexAttribFormat::k32SInt, Prospero::BufferFormat::k32SInt}, - {Prospero::VertexAttribFormat::k32Float, Prospero::BufferFormat::k32Float}, - {Prospero::VertexAttribFormat::k16_16UNorm, Prospero::BufferFormat::k16_16UNorm}, - {Prospero::VertexAttribFormat::k16_16SNorm, Prospero::BufferFormat::k16_16SNorm}, - {Prospero::VertexAttribFormat::k16_16UScaled, Prospero::BufferFormat::k16_16UScaled}, - {Prospero::VertexAttribFormat::k16_16SScaled, Prospero::BufferFormat::k16_16SScaled}, - {Prospero::VertexAttribFormat::k16_16UInt, Prospero::BufferFormat::k16_16UInt}, - {Prospero::VertexAttribFormat::k16_16SInt, Prospero::BufferFormat::k16_16SInt}, - {Prospero::VertexAttribFormat::k16_16Float, Prospero::BufferFormat::k16_16Float}, - {Prospero::VertexAttribFormat::k11_11_10UNorm, Prospero::BufferFormat::k11_11_10UNorm}, - {Prospero::VertexAttribFormat::k11_11_10SNorm, Prospero::BufferFormat::k11_11_10SNorm}, - {Prospero::VertexAttribFormat::k11_11_10UScaled, Prospero::BufferFormat::k11_11_10UScaled}, - {Prospero::VertexAttribFormat::k11_11_10SScaled, Prospero::BufferFormat::k11_11_10SScaled}, - {Prospero::VertexAttribFormat::k11_11_10UInt, Prospero::BufferFormat::k11_11_10UInt}, - {Prospero::VertexAttribFormat::k11_11_10SInt, Prospero::BufferFormat::k11_11_10SInt}, - {Prospero::VertexAttribFormat::k11_11_10Float, Prospero::BufferFormat::k11_11_10Float}, - {Prospero::VertexAttribFormat::k10_11_11UNorm, Prospero::BufferFormat::k10_11_11UNorm}, - {Prospero::VertexAttribFormat::k10_11_11SNorm, Prospero::BufferFormat::k10_11_11SNorm}, - {Prospero::VertexAttribFormat::k10_11_11UScaled, Prospero::BufferFormat::k10_11_11UScaled}, - {Prospero::VertexAttribFormat::k10_11_11SScaled, Prospero::BufferFormat::k10_11_11SScaled}, - {Prospero::VertexAttribFormat::k10_11_11UInt, Prospero::BufferFormat::k10_11_11UInt}, - {Prospero::VertexAttribFormat::k10_11_11SInt, Prospero::BufferFormat::k10_11_11SInt}, - {Prospero::VertexAttribFormat::k10_11_11Float, Prospero::BufferFormat::k10_11_11Float}, - {Prospero::VertexAttribFormat::k2_10_10_10UNorm, Prospero::BufferFormat::k2_10_10_10UNorm}, - {Prospero::VertexAttribFormat::k2_10_10_10SNorm, Prospero::BufferFormat::k2_10_10_10SNorm}, - {Prospero::VertexAttribFormat::k2_10_10_10UScaled, - Prospero::BufferFormat::k2_10_10_10UScaled}, - {Prospero::VertexAttribFormat::k2_10_10_10SScaled, - Prospero::BufferFormat::k2_10_10_10SScaled}, - {Prospero::VertexAttribFormat::k2_10_10_10UInt, Prospero::BufferFormat::k2_10_10_10UInt}, - {Prospero::VertexAttribFormat::k2_10_10_10SInt, Prospero::BufferFormat::k2_10_10_10SInt}, - {Prospero::VertexAttribFormat::k10_10_10_2UNorm, Prospero::BufferFormat::k10_10_10_2UNorm}, - {Prospero::VertexAttribFormat::k10_10_10_2SNorm, Prospero::BufferFormat::k10_10_10_2SNorm}, - {Prospero::VertexAttribFormat::k10_10_10_2UScaled, - Prospero::BufferFormat::k10_10_10_2UScaled}, - {Prospero::VertexAttribFormat::k10_10_10_2SScaled, - Prospero::BufferFormat::k10_10_10_2SScaled}, - {Prospero::VertexAttribFormat::k10_10_10_2UInt, Prospero::BufferFormat::k10_10_10_2UInt}, - {Prospero::VertexAttribFormat::k10_10_10_2SInt, Prospero::BufferFormat::k10_10_10_2SInt}, - {Prospero::VertexAttribFormat::k8_8_8_8UNorm, Prospero::BufferFormat::k8_8_8_8UNorm}, - {Prospero::VertexAttribFormat::k8_8_8_8SNorm, Prospero::BufferFormat::k8_8_8_8SNorm}, - {Prospero::VertexAttribFormat::k8_8_8_8UScaled, Prospero::BufferFormat::k8_8_8_8UScaled}, - {Prospero::VertexAttribFormat::k8_8_8_8SScaled, Prospero::BufferFormat::k8_8_8_8SScaled}, - {Prospero::VertexAttribFormat::k8_8_8_8UInt, Prospero::BufferFormat::k8_8_8_8UInt}, - {Prospero::VertexAttribFormat::k8_8_8_8SInt, Prospero::BufferFormat::k8_8_8_8SInt}, - {Prospero::VertexAttribFormat::k32_32UInt, Prospero::BufferFormat::k32_32UInt}, - {Prospero::VertexAttribFormat::k32_32SInt, Prospero::BufferFormat::k32_32SInt}, - {Prospero::VertexAttribFormat::k32_32Float, Prospero::BufferFormat::k32_32Float}, - {Prospero::VertexAttribFormat::k16_16_16_16UNorm, - Prospero::BufferFormat::k16_16_16_16UNorm}, - {Prospero::VertexAttribFormat::k16_16_16_16SNorm, - Prospero::BufferFormat::k16_16_16_16SNorm}, - {Prospero::VertexAttribFormat::k16_16_16_16UScaled, - Prospero::BufferFormat::k16_16_16_16UScaled}, - {Prospero::VertexAttribFormat::k16_16_16_16SScaled, - Prospero::BufferFormat::k16_16_16_16SScaled}, - {Prospero::VertexAttribFormat::k16_16_16_16UInt, Prospero::BufferFormat::k16_16_16_16UInt}, - {Prospero::VertexAttribFormat::k16_16_16_16SInt, Prospero::BufferFormat::k16_16_16_16SInt}, - {Prospero::VertexAttribFormat::k16_16_16_16Float, - Prospero::BufferFormat::k16_16_16_16Float}, - {Prospero::VertexAttribFormat::k32_32_32UInt, Prospero::BufferFormat::k32_32_32UInt}, - {Prospero::VertexAttribFormat::k32_32_32SInt, Prospero::BufferFormat::k32_32_32SInt}, - {Prospero::VertexAttribFormat::k32_32_32Float, Prospero::BufferFormat::k32_32_32Float}, - {Prospero::VertexAttribFormat::k32_32_32_32UInt, Prospero::BufferFormat::k32_32_32_32UInt}, - {Prospero::VertexAttribFormat::k32_32_32_32SInt, Prospero::BufferFormat::k32_32_32_32SInt}, - {Prospero::VertexAttribFormat::k32_32_32_32Float, - Prospero::BufferFormat::k32_32_32_32Float}, - }; - - for (const auto& entry: format_map) { - if (format == entry.vertex) { - return entry.buffer; - } - } - - return static_cast(static_cast(format)); -} - static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info, const ShaderSemantic* input_semantics, uint32_t num_input_semantics, const uint32_t* attrib, @@ -536,18 +429,23 @@ static void ShaderApplyAttribSemantics(ShaderVertexInputInfo& info, r.fields[2] = sharp[2]; r.fields[3] = sharp[3]; if (format != Prospero::VertexAttribFormat::kInvalid) { - auto buffer_format = VertexAttribFormatToBufferFormat(format); - static std::atomic log_count = 0; - auto log_id = log_count.fetch_add(1); + const auto format_raw = static_cast(format); + const auto buffer_format = format_raw >> 2u; + const auto channels = (format_raw & 3u) + 1u; + static std::atomic log_count = 0; + auto log_id = log_count.fetch_add(1); if (log_id < 64) { - LOGF("\t temporary: PS5 vertex attrib semantic %u uses attrib format %u -> buffer " + LOGF("\t PS5 vertex attrib semantic %u uses attrib format %u -> buffer " "format %u, offset %u, buffer index %zu\n", static_cast(in.semantic), static_cast(format), static_cast(buffer_format), offset, index); } - const auto buffer_format_raw = static_cast(buffer_format); + // AGC vertex formats encode the buffer format above the two channel-count bits. + // The fetch prolog selects X001, XY01, XYZ1, or XYZW from that count. r.fields[3] = (r.fields[3] & ~((0x7fu << 12u) | 0xfffu)) | - ((buffer_format_raw & 0x7fu) << 12u) | DstSel(4, 5, 6, 7); + (buffer_format << 12u) | + DstSel(4, channels > 1u ? 5u : 0u, channels > 2u ? 6u : 0u, + channels > 3u ? 7u : 1u); } if (offset != 0) { r.UpdateAddress48(r.Base48() + offset); diff --git a/tests/shaderCfgTests.cpp b/tests/shaderCfgTests.cpp index 1d5491588..aed8ce5d7 100644 --- a/tests/shaderCfgTests.cpp +++ b/tests/shaderCfgTests.cpp @@ -9221,6 +9221,7 @@ void TestEmbeddedVertexFormatSwizzle() { Prospero::BufferFormat format; uint32_t swizzle, opcode, components, source_width; std::array expected; + Prospero::VertexAttribFormat attribute_format = Prospero::VertexAttribFormat::kInvalid; }; const Case cases[] = { {Prospero::BufferFormat::k32_32_32Float, DstSel(4, 5, 6, 7), 3, 4, 3, @@ -9237,18 +9238,50 @@ void TestEmbeddedVertexFormatSwizzle() { {0x3f800000, 0, 0x3f800000, 0}}, {Prospero::BufferFormat::k32_32_32_32Float, DstSel(7, 6, 5, 4), 0x0e, 4, 4, {0x3e800000, 0x3f000000, 0x3f400000, 0x40000000}}, + {Prospero::BufferFormat::k32UInt, DstSel(7, 6, 5, 4), 3, 4, 1, + {0x3e800000, 0, 0, 1}, Prospero::VertexAttribFormat::k32UInt}, + {Prospero::BufferFormat::k32_32Float, DstSel(7, 6, 5, 4), 3, 4, 2, + {0x3e800000, 0x3f000000, 0, 0x3f800000}, Prospero::VertexAttribFormat::k32_32Float}, + {Prospero::BufferFormat::k32_32_32Float, DstSel(7, 6, 5, 4), 3, 4, 3, + {0x3e800000, 0x3f000000, 0x3f400000, 0x3f800000}, + Prospero::VertexAttribFormat::k32_32_32Float}, + {Prospero::BufferFormat::k32_32_32_32Float, DstSel(7, 6, 5, 4), 3, 4, 4, + {0x3e800000, 0x3f000000, 0x3f400000, 0x40000000}, + Prospero::VertexAttribFormat::k32_32_32_32Float}, }; + std::array(AgcDirectResourceType::Last) + 1> offsets; + offsets.fill(AGC_ILLEGAL_DIRECT_OFFSET); + offsets[static_cast(AgcDirectResourceType::PtrVertexBufferTable)] = 0; + offsets[static_cast(AgcDirectResourceType::PtrVertexAttribDescTable)] = 2; + ShaderUserData user_data{}; + user_data.direct_resource_offset = offsets.data(); + user_data.direct_resource_count = static_cast(offsets.size()); for (const auto &test : cases) { const uint32_t code[] = {EncodeMubuf0(test.opcode), EncodeMubuf1(9, 0, 0), EncodeExp0(0x20, (1u << test.components) - 1u), EncodeExp1(9, 10, 11, 12), EncodeSopp(0x01)}; Decoder::Program decoded; Decoder::DecodeProgram(code, decoded); + const uint32_t attribute = static_cast(test.attribute_format) << 5u; + const uint32_t buffer[] = {0x10000000u, 16u << 16u, 1u, + (static_cast(test.format) << 12u) | test.swizzle}; + HW::VertexShaderInfo regs{}; + regs.es_regs.data_addr = reinterpret_cast(code); + regs.gs_regs.rsrc2.user_sgpr = 4; + const uint64_t tables[] = {reinterpret_cast(buffer), + reinterpret_cast(&attribute)}; + std::memcpy(regs.gs_user_sgpr.value, tables, sizeof(tables)); + ShaderSemantic semantic{}; + semantic.hardware_mapping = 9; + semantic.size_in_elements = test.components; + ShaderMappedData mapped{}; + mapped.user_data = &user_data; + mapped.input_semantics = &semantic; + mapped.num_input_semantics = 1; + mapped.code_size_bytes = sizeof(code); + ShaderMapUserData(regs.es_regs.data_addr, mapped); ShaderVertexInputInfo input{}; - input.resources_num = 1; - input.resources[0].fields[3] = (static_cast(test.format) << 12u) | test.swizzle; - input.resources_dst[0].attr_id = 0; - input.resources_dst[0].registers_num = static_cast(test.components); + PrepareProgram(regs, HW::Context{}, HW::UserConfig{}, input); Frontend::EmbeddedFetchPlan fetch; fetch.loads.push_back({.pc = 0, .attrib_id = 0, .components = test.components}); Frontend::TranslateOptions options{};