From b0bd6470f3bc1f1145078152707490280538dbca Mon Sep 17 00:00:00 2001 From: nmzik Date: Sun, 16 Aug 2026 16:54:27 +0200 Subject: [PATCH] graphics: accept AGC vertex-buffer-only shaders --- src/graphics/shader/shader.cpp | 2 +- src/graphics/shader/shaderVertexMetadata.cpp | 17 +++++++++------ tests/ShaderVertexMetadataTests.cpp | 22 ++++++++++++++++++++ 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/graphics/shader/shader.cpp b/src/graphics/shader/shader.cpp index 6643341a4..52cbe4a4e 100644 --- a/src/graphics/shader/shader.cpp +++ b/src/graphics/shader/shader.cpp @@ -811,7 +811,7 @@ static bool ShaderGetStaticInputInfoVS(const HW::VertexShaderInfo& regs, return false; } - if (metadata.vertex_buffer_reg >= 0) { + if (metadata.vertex_attrib_reg >= 0) { info.fetch_external = false; info.fetch_embedded = true; info.fetch_attrib_reg = metadata.vertex_attrib_reg; diff --git a/src/graphics/shader/shaderVertexMetadata.cpp b/src/graphics/shader/shaderVertexMetadata.cpp index e5acd56a4..2b81a1c11 100644 --- a/src/graphics/shader/shaderVertexMetadata.cpp +++ b/src/graphics/shader/shaderVertexMetadata.cpp @@ -56,16 +56,21 @@ bool ShaderReadVertexMetadata(const ShaderMappedData& data, uint32_t max_user_sg } } - const bool embedded = next.vertex_buffer_reg >= 0 || next.vertex_attrib_reg >= 0; - if (!embedded) { + if (next.vertex_attrib_reg >= 0 && next.vertex_buffer_reg < 0) { + return Fail(error, "vertex attribute table requires a vertex buffer table"); + } + if (next.vertex_buffer_reg < 0) { metadata = next; return true; } - if (next.vertex_buffer_reg < 0 || next.vertex_attrib_reg < 0) { - return Fail(error, "vertex buffer and attribute tables must be supplied together"); + if (static_cast(next.vertex_buffer_reg) + 1u >= max_user_sgprs) { + return Fail(error, "vertex table pointer exceeds the user-SGPR domain"); } - if (static_cast(next.vertex_buffer_reg) + 1u >= max_user_sgprs || - static_cast(next.vertex_attrib_reg) + 1u >= max_user_sgprs) { + if (next.vertex_attrib_reg < 0) { + metadata = next; + return true; + } + if (static_cast(next.vertex_attrib_reg) + 1u >= max_user_sgprs) { return Fail(error, "vertex table pointer exceeds the user-SGPR domain"); } if (data.num_input_semantics == 0 || diff --git a/tests/ShaderVertexMetadataTests.cpp b/tests/ShaderVertexMetadataTests.cpp index abf016c9f..7d1078743 100644 --- a/tests/ShaderVertexMetadataTests.cpp +++ b/tests/ShaderVertexMetadataTests.cpp @@ -57,6 +57,22 @@ void TestValidAndInvalidMetadata() { output.input_semantics_count == 1, "valid AGC vertex metadata was decoded incorrectly"); + Fixture buffer_only; + buffer_only.offsets[static_cast(AgcDirectResourceType::PtrVertexAttribDescTable)] = + AGC_ILLEGAL_DIRECT_OFFSET; + buffer_only.mapped.input_semantics = nullptr; + buffer_only.mapped.num_input_semantics = 0; + Check(ShaderReadVertexMetadata(buffer_only.mapped, 64, output, &error), + "vertex-buffer-only AGC metadata was rejected"); + Check(output.vertex_buffer_reg == 2 && output.vertex_attrib_reg == -1 && + output.input_semantics_count == 0, + "vertex-buffer-only AGC metadata was decoded incorrectly"); + + Fixture attrib_only; + attrib_only.offsets[static_cast(AgcDirectResourceType::PtrVertexBufferTable)] = + AGC_ILLEGAL_DIRECT_OFFSET; + CheckRejected(attrib_only.mapped, "vertex-attribute-only AGC metadata was accepted"); + auto missing_header = fixture.mapped; missing_header.user_data = nullptr; CheckRejected(missing_header, "missing AGC user-data header was accepted"); @@ -79,6 +95,12 @@ void TestValidAndInvalidMetadata() { 63; CheckRejected(excessive_register.mapped, "out-of-domain vertex table SGPR was accepted"); + Fixture excessive_attrib_register; + excessive_attrib_register + .offsets[static_cast(AgcDirectResourceType::PtrVertexAttribDescTable)] = 63; + CheckRejected(excessive_attrib_register.mapped, + "out-of-domain vertex attribute table SGPR was accepted"); + Fixture missing_semantics; missing_semantics.mapped.input_semantics = nullptr; CheckRejected(missing_semantics.mapped, "missing vertex semantic array was accepted");