diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eb8dd533..8704dfdbd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -68,6 +68,14 @@ if(BUILD_TESTING) ${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler) add_test(NAME shader_cache_file_read COMMAND shader_cache_file_read_tests) set_tests_properties(shader_cache_file_read PROPERTIES TIMEOUT 20) + add_test_executable(request_serializer_tests + ${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/tests/RequestSerializerTests.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp) + target_include_directories(request_serializer_tests PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler + ${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/ControlFlow/include) + add_test(NAME request_serializer COMMAND request_serializer_tests) + set_tests_properties(request_serializer PROPERTIES TIMEOUT 20) find_package(Python3 QUIET COMPONENTS Interpreter) if(Python3_Interpreter_FOUND) add_test(NAME pr_overlap_encoding COMMAND ${Python3_EXECUTABLE} diff --git a/core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp b/core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp index 217d54eee..eb3c70970 100644 --- a/core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp +++ b/core/shader/recompiler/ControlFlow/src/RequestSerializer.cpp @@ -153,6 +153,8 @@ public: bool ReadBool() { return ReadU8() != 0u; } + std::uint64_t Remaining() const { return m_data.size() - m_offset; } + std::uint32_t ReadU32() { std::uint32_t value = 0u; for (std::uint32_t i = 0; i < 4u; i++) { @@ -808,7 +810,15 @@ DeserializedRequest RequestSerializer::Deserialize(std::string_view text) const if (version >= 17u) result.request.target.registrationModules = reader.ReadBool(); if (version >= 17u) result.request.target.registrationWordLimit = reader.ReadU32(); if (version >= 18u) result.request.target.vertexSubgroups = reader.ReadBool(); - if (version >= 21u) result.request.target.float16DenormPreserve = reader.ReadBool(); + if (version >= 21u) { + if (reader.Remaining() == 1u) { + const auto float16DenormPreserve = reader.ReadU8(); + if (float16DenormPreserve > 1u) throw std::runtime_error("RequestSerializer: invalid float16DenormPreserve value"); + result.request.target.float16DenormPreserve = float16DenormPreserve != 0u; + } else if (reader.Remaining() != 0u) { + throw std::runtime_error("RequestSerializer: unexpected trailing data"); + } + } return result; } diff --git a/core/shader/recompiler/tests/RequestSerializerTests.cpp b/core/shader/recompiler/tests/RequestSerializerTests.cpp new file mode 100644 index 000000000..9066ce55c --- /dev/null +++ b/core/shader/recompiler/tests/RequestSerializerTests.cpp @@ -0,0 +1,33 @@ +#include "ControlFlow/RequestSerializer.hpp" + +#include +#include + +namespace { + +constexpr char kHistoricalVersion21[] = + "NVNQQRUAAAAFAAADAAAAAAABAAAAAAAAAAAAgb8AAAAAAAAAAAAAAAAAAAAAQAAAAAgAAAADAAAAAAAAAN+bVxPgrGgk776t3gABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAAAAAAOQAAAAAAAAAAAAAAAAAAAAAAQEAAAEAAAAAAAAAAAAFAAAAAAAEAAAAAAAAABI0VngAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAALAAAAEAAAAEAAAAAAAAF4VjQSAQEBOTAAAAA="; + +void Require(bool condition) { + if (!condition) std::abort(); +} + +} + +int main() { + const ShaderRecompiler::RequestSerializer serializer; + + const auto historical = serializer.Deserialize(kHistoricalVersion21); + Require(!historical.request.target.float16DenormPreserve); + + ShaderRecompiler::RecompileRequest request{}; + request.target.float16DenormPreserve = false; + const auto withoutPreserve = serializer.Deserialize(serializer.Serialize(request)); + Require(!withoutPreserve.request.target.float16DenormPreserve); + + request.target.float16DenormPreserve = true; + const auto withPreserve = serializer.Deserialize(serializer.Serialize(request)); + Require(withPreserve.request.target.float16DenormPreserve); + + return 0; +}