Merge pull request #4389 from ivica00/fix/rect-list-invariant-position

fix(shader): decorate rect-list gl_Position as Invariant
This commit is contained in:
Dean 2026-10-13 07:33:51 +13:00 committed by GitHub
commit 9f7c40e36f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 80 additions and 1 deletions

View File

@ -633,6 +633,19 @@ target_link_libraries(agc_formatted_buffer_once_tests PRIVATE shader_recompiler_
set_target_properties(agc_formatted_buffer_once_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_formatted_buffer_once_tests)
add_test_executable(agc_rect_list_position_invariant_tests EXCLUDE_FROM_ALL tests/RectListPositionInvariant.cpp)
target_link_libraries(agc_rect_list_position_invariant_tests PRIVATE shader_recompiler_agc_driver libc)
set_target_properties(agc_rect_list_position_invariant_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_rect_list_position_invariant_tests)
if(BUILD_TESTING)
set_target_properties(agc_rect_list_position_invariant_tests PROPERTIES EXCLUDE_FROM_ALL OFF)
add_test(NAME agc_rect_list_position_invariant COMMAND agc_rect_list_position_invariant_tests)
if(WIN32)
set_tests_properties(agc_rect_list_position_invariant PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()
add_test_executable(agc_shader_disk_cache_tests EXCLUDE_FROM_ALL tests/ShaderDiskCache.cpp)
target_include_directories(agc_shader_disk_cache_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(agc_shader_disk_cache_tests PRIVATE shader_recompiler_agc_driver libc)

View File

@ -0,0 +1,66 @@
#include "Recompiler.hpp"
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstdio>
#include <exception>
#include <span>
#include <spirv/unified1/spirv.hpp>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
namespace {
using namespace ShaderRecompiler;
void Check(bool condition, const std::string& message) {
if (!condition) throw std::runtime_error(message);
}
bool PositionIsInvariant(std::span<const std::uint32_t> words) {
Check(words.size() >= 5 && words[0] == spv::MagicNumber, "rect-list invariant: missing SPIR-V module");
std::vector<std::pair<std::uint32_t, std::uint32_t>> positionMembers;
std::vector<std::pair<std::uint32_t, std::uint32_t>> invariantMembers;
for (std::size_t offset = 5; offset < words.size();) {
const auto count = words[offset] >> spv::WordCountShift;
Check(count != 0 && count <= words.size() - offset, "rect-list invariant: malformed SPIR-V instruction");
const auto opcode = words[offset] & spv::OpCodeMask;
if (opcode == spv::OpMemberDecorate && count == 5 && words[offset + 3] == spv::DecorationBuiltIn && words[offset + 4] == spv::BuiltInPosition) {
positionMembers.emplace_back(words[offset + 1], words[offset + 2]);
}
if (opcode == spv::OpMemberDecorate && count == 4 && words[offset + 3] == spv::DecorationInvariant) {
invariantMembers.emplace_back(words[offset + 1], words[offset + 2]);
}
offset += count;
}
Check(!positionMembers.empty(), "rect-list invariant: shader has no gl_Position");
for (const auto& member : positionMembers) {
if (std::find(invariantMembers.begin(), invariantMembers.end(), member) == invariantMembers.end()) return false;
}
return true;
}
}
int main() {
try {
static constexpr std::array<std::uint32_t, 2> capabilities{spv::CapabilityShader, spv::CapabilityTessellation};
SpirvTarget target{};
target.vulkanVersion = 0x00401000u;
target.spirvVersion = 0x00010400u;
target.supportedCapabilities = capabilities;
target.tessellation = TessellationTargetLimits{32, 128, 128, 120, 4096, 128, 128};
RecompileResult vertex;
RecompileResult fragment;
const auto shaders = BuildRectListShaders(vertex, fragment, target);
Check(PositionIsInvariant(shaders.control.spirv.Words()), "rect-list control gl_Position is not Invariant");
Check(PositionIsInvariant(shaders.evaluation.spirv.Words()), "rect-list evaluation gl_Position is not Invariant");
std::printf("rect-list position invariant tests passed\n");
return 0;
} catch (const std::exception& error) {
std::fprintf(stderr, "%s\n", error.what());
return 1;
}
}

View File

@ -41,7 +41,7 @@ public:
vec4FloatType = type(spv::OpTypeVector, floatType, 4u);
functionType = type(spv::OpTypeFunction, voidType);
perVertexType = builder.DecoratedType(spv::OpTypeStruct, {{spv::OpMemberDecorate, {0u, spv::DecorationBuiltIn, spv::BuiltInPosition}}, {spv::OpDecorate, {spv::DecorationBlock}}}, vec4FloatType);
perVertexType = builder.DecoratedType(spv::OpTypeStruct, {{spv::OpMemberDecorate, {0u, spv::DecorationBuiltIn, spv::BuiltInPosition}}, {spv::OpMemberDecorate, {0u, spv::DecorationInvariant}}, {spv::OpDecorate, {spv::DecorationBlock}}}, vec4FloatType);
ptrInputVec4Float = pointer(spv::StorageClassInput, vec4FloatType);
ptrOutputVec4Float = pointer(spv::StorageClassOutput, vec4FloatType);