From d9afb0af62ac7a0d90078da1557947dc631b87a6 Mon Sep 17 00:00:00 2001 From: Sanjaysrinivas Date: Thu, 8 Oct 2026 12:19:59 +0200 Subject: [PATCH] test(shader): cover half expansion bit patterns --- .../tests/execution/HalfExpansion.cpp | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 core/libs/prx/libSceAgcDriver/tests/execution/HalfExpansion.cpp diff --git a/core/libs/prx/libSceAgcDriver/tests/execution/HalfExpansion.cpp b/core/libs/prx/libSceAgcDriver/tests/execution/HalfExpansion.cpp new file mode 100644 index 000000000..94809ab80 --- /dev/null +++ b/core/libs/prx/libSceAgcDriver/tests/execution/HalfExpansion.cpp @@ -0,0 +1,116 @@ +#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp" +#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp" +#include "Recompiler.hpp" +#include "VulkanTestDevice.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace { + +using AgcDriver::Graphics::Require; +using ShaderRecompiler::ShaderStage; + +constexpr std::uint32_t Threads = 64; +constexpr std::uint32_t Results = 4; +alignas(256) std::array Input{}; +alignas(256) std::array Output{}; + +alignas(256) constexpr std::array Code{ + 0xe0302000, 0x80000400, 0xbf8c3f70, 0x7e141704, 0x2c0a0890, 0x7e161705, 0x7e0c0280, + 0x76180cf9, 0x06001604, 0x761a0cf9, 0x06011604, 0xe0782000, 0x80010a00, 0xbf810000, +}; + +struct Vector { + std::uint32_t input; + std::array expected; +}; + +constexpr Vector Vectors[] = { + {0x3c003c00u, {0x3f800000u, 0x3f800000u, 0x00000000u, 0x0000003cu}}, + {0xc000bc00u, {0xbf800000u, 0xc0000000u, 0x00000000u, 0x000000bcu}}, + {0x80000000u, {0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u}}, + {0x00008000u, {0x80000000u, 0x00000000u, 0x00000000u, 0x00000080u}}, + {0x03ff0001u, {0x33800000u, 0x387fc000u, 0x00000001u, 0x00000000u}}, + {0x040003ffu, {0x387fc000u, 0x38800000u, 0x000000ffu, 0x00000003u}}, + {0x7bff0400u, {0x38800000u, 0x477fe000u, 0x00000000u, 0x00000004u}}, + {0xfbff7bffu, {0x477fe000u, 0xc77fe000u, 0x000000ffu, 0x0000007bu}}, + {0xfc007c00u, {0x7f800000u, 0xff800000u, 0x00000000u, 0x0000007cu}}, + {0x7e01fe01u, {0xffc02000u, 0x7fc02000u, 0x00000001u, 0x000000feu}}, + {0xfe017e01u, {0x7fc02000u, 0xffc02000u, 0x00000001u, 0x0000007eu}}, + {0x7fff7e55u, {0x7fcaa000u, 0x7fffe000u, 0x00000055u, 0x0000007eu}}, + {0xfffffe55u, {0xffcaa000u, 0xffffe000u, 0x00000055u, 0x000000feu}}, + {0xfff0fff0u, {0xfffe0000u, 0xfffe0000u, 0x000000f0u, 0x000000ffu}}, + {0xa5a500f0u, {0x37700000u, 0xbcb4a000u, 0x000000f0u, 0x00000000u}}, + {0xdead00ffu, {0x377f0000u, 0xc3d5a000u, 0x000000ffu, 0x00000000u}}, + {0x7c003555u, {0x3eaaa000u, 0x7f800000u, 0x00000055u, 0x00000035u}}, + {0x3555fc00u, {0xff800000u, 0x3eaaa000u, 0x00000000u, 0x000000fcu}}, + {0x3c000200u, {0x38000000u, 0x3f800000u, 0x00000000u, 0x00000002u}}, + {0x80018001u, {0xb3800000u, 0xb3800000u, 0x00000001u, 0x00000080u}}, +}; + +std::array BufferDescriptor(const void* data, std::uint32_t stride) { + const auto address = reinterpret_cast(data); + return {static_cast(address), static_cast((address >> 32u) & 0xffffu) | (stride << 16u), Threads, 0x01016facu}; +} + +std::string Hex(std::uint32_t value) { + char text[16]; + std::snprintf(text, sizeof(text), "0x%08x", value); + return text; +} + +void Run(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const ShaderRecompiler::SpirvTarget& target) { + for (std::uint32_t tid = 0; tid < Threads; ++tid) Input[tid] = Vectors[tid % std::size(Vectors)].input; + Output.fill(0xdeadbeefu); + std::vector userData(8, 0u); + const auto input = BufferDescriptor(Input.data(), 4u); + const auto output = BufferDescriptor(Output.data(), Results * 4u); + std::copy(input.begin(), input.end(), userData.begin()); + std::copy(output.begin(), output.end(), userData.begin() + 4); + const std::span code(Code); + const std::array memory{{{reinterpret_cast(code.data()), std::as_bytes(code)}}}; + const ShaderRecompiler::ShaderComputeStageInfo compute{{waveSize, 1, 1}, 0u, {false, false, false}, false, 1}; + ShaderRecompiler::RecompileRequest request{ + {ShaderStage::Compute, reinterpret_cast(code.data()), code, 0, {}}, + {waveSize, 0, userData, compute, std::nullopt, std::nullopt, memory}, + target, + {0, 0, 0, 128} + }; + request.useCache = false; + const auto result = ShaderRecompiler::Recompile(request); + device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast(code.data())); + device.WaitIdle(); + constexpr std::array names{"low half", "high half", "BYTE_0 ldexp", "BYTE_1 ldexp"}; + for (std::uint32_t tid = 0; tid < waveSize; ++tid) { + const auto& vector = Vectors[tid % std::size(Vectors)]; + for (std::uint32_t i = 0; i < Results; ++i) { + const auto actual = Output[tid * Results + i]; + Require(actual == vector.expected[i], + "half expansion: wave " + std::to_string(waveSize) + ", lane " + std::to_string(tid) + + ", input " + Hex(vector.input) + ", " + names[i] + " is " + Hex(actual) + + ", expected " + Hex(vector.expected[i])); + } + } +} + +} + +int main() { + try { + const auto device = OpenVulkanTestDevice(); + if (!device) return VulkanTestSkipped; + Run(*device, 32u, device->ComputeTarget(32u)); + Run(*device, 64u, device->Target()); + Run(*device, 64u, device->ComputeTarget(32u)); + std::puts("half expansion tests passed"); + return 0; + } catch (const std::exception& error) { + std::cerr << error.what() << '\n'; + return 1; + } +}