Merge pull request #500 from adriadam10/fix/f32-clamp-bits
fix(shader): clamp f32 results to +0 for NaN and -0
This commit is contained in:
commit
bbedad3b00
|
|
@ -0,0 +1,189 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 47> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0x7e1e0306, 0xd503800a, 0x02020b04,
|
||||
0xd504800b, 0x02020b04, 0xd508800c, 0x02020b04, 0xd508800d, 0x22020b04, 0xd54b800e, 0x041a0b04,
|
||||
0xd52b800f, 0x02020b04, 0xd50f8010, 0x02020b04, 0xd5108011, 0x22020b04, 0xd5578012, 0x041a0b04,
|
||||
0xd5a48013, 0x02010104, 0xd5a08014, 0x02010104, 0xd5858015, 0x02010104, 0xd5a18016, 0x22010104,
|
||||
0xd5a38017, 0x02010104, 0xd5548018, 0x041a0b04, 0xd5a28019, 0x22010104, 0xe0781000, 0x80010a03,
|
||||
0xe0781010, 0x80010e03, 0xe0781020, 0x80011203, 0xe0781030, 0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[32][4] = {
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x7f800000u, 0x80000000u, 0x80000000u, 0x00000000u},
|
||||
{0xbf000000u, 0x3f800000u, 0xff800000u, 0x00000000u},
|
||||
{0xff800000u, 0xff800000u, 0x80000000u, 0x00000000u},
|
||||
{0x3f800000u, 0x3f000000u, 0x3f800001u, 0x00000000u},
|
||||
{0xc0200000u, 0x00000000u, 0x3f000000u, 0x00000000u},
|
||||
{0x40000000u, 0xbf800000u, 0x3f000000u, 0x00000000u},
|
||||
{0x7fc00000u, 0x7fc00000u, 0x7fc00000u, 0x00000000u},
|
||||
{0x80000000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x40000000u, 0x3f800000u, 0xbf800000u, 0x00000000u},
|
||||
{0xbf800000u, 0x7f800000u, 0x7f800000u, 0x00000000u},
|
||||
{0x7fc00000u, 0xff800000u, 0x7fc00000u, 0x00000000u},
|
||||
{0x7f800000u, 0x3f800001u, 0x00000000u, 0x00000000u},
|
||||
{0xbf800000u, 0xbf800000u, 0x7fc00000u, 0x00000000u},
|
||||
{0x80000000u, 0x80000000u, 0x00000000u, 0x00000000u},
|
||||
{0x7fc00000u, 0x7f800000u, 0x00000000u, 0x00000000u},
|
||||
{0x3f800000u, 0xbf800000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x7fc00000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xffc00000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x7f800001u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x7fc12345u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x7f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xff800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x3f000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x3f800001u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xbf000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x3f7fffffu, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x40000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xbf800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0xc0200000u, 0x00000000u}
|
||||
};
|
||||
constexpr std::uint32_t Expected[32][16] = {
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x3f800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u},
|
||||
{0x3f000000u, 0x00000000u, 0x00000000u, 0x3f000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x3f800000u},
|
||||
{0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u},
|
||||
{0x3f800000u, 0x3f000000u, 0x3f000000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x3f000000u, 0x3f000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f000000u, 0x3f000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f000000u, 0x3f800000u},
|
||||
{0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x3f800000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u},
|
||||
{0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x3f800000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f000000u, 0x3f000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f7fffffu, 0x3f7fffffu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f7fffffu, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x3f800000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x3f800000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u}
|
||||
};
|
||||
constexpr std::uint32_t Checked[32] = {0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xfeffu, 0xffffu, 0xffffu, 0xffffu, 0xfeffu, 0xffffu, 0xfeffu, 0xffffu, 0xfeffu, 0xffffu, 0xffffu, 0xfeffu, 0xfeffu, 0xbeffu, 0xfeffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu, 0xffffu};
|
||||
constexpr const char* Names[16] = {
|
||||
"v_add_f32_e64 v10, v4, v5 clamp",
|
||||
"v_sub_f32_e64 v11, v4, v5 clamp",
|
||||
"v_mul_f32_e64 v12, v4, v5 clamp",
|
||||
"v_mul_f32_e64 v13, -v4, v5 clamp",
|
||||
"v_fma_f32 v14, v4, v5, v6 clamp",
|
||||
"v_fmac_f32_e64 v15, v4, v5 clamp",
|
||||
"v_min_f32_e64 v16, v4, v5 clamp",
|
||||
"v_max_f32_e64 v17, -v4, v5 clamp",
|
||||
"v_med3_f32 v18, v4, v5, v6 clamp",
|
||||
"v_floor_f32_e64 v19, v4 clamp",
|
||||
"v_fract_f32_e64 v20, v4 clamp",
|
||||
"v_cvt_f32_i32_e64 v21, v4 clamp",
|
||||
"v_trunc_f32_e64 v22, -v4 clamp",
|
||||
"v_rndne_f32_e64 v23, v4 clamp",
|
||||
"v_max3_f32 v24, v4, v5, v6 clamp",
|
||||
"v_ceil_f32_e64 v25, -v4 clamp",
|
||||
};
|
||||
|
||||
void Fill(std::uint32_t tid, std::uint32_t* words) {
|
||||
std::copy(std::begin(Rows[tid]), std::end(Rows[tid]), words);
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t bytes) {
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(data);
|
||||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x01016facu};
|
||||
}
|
||||
|
||||
std::string Hex(std::uint32_t value) {
|
||||
char text[16];
|
||||
std::snprintf(text, sizeof(text), "0x%08x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Expect(std::uint32_t tid, std::uint32_t actual, std::uint32_t expected, const char* name) {
|
||||
Require(actual == expected, std::string("f32 result clamp: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]);
|
||||
Output.fill(0xdeadbeefu);
|
||||
std::vector<std::uint32_t> userData(8, 0u);
|
||||
const auto input = BufferDescriptor(Input.data(), static_cast<std::uint32_t>(Input.size() * 4u));
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> memory{{{reinterpret_cast<std::uintptr_t>(code.data()), std::as_bytes(code)}}};
|
||||
const ShaderRecompiler::ShaderComputeStageInfo compute{{Threads, 1, 1}, 0u, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{32, 0, userData, compute, std::nullopt, std::nullopt, memory},
|
||||
device.Target(),
|
||||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void Check() {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const std::uint32_t* in = &Input[tid * Inputs];
|
||||
const std::uint32_t* out = &Output[tid * Results];
|
||||
for (std::uint32_t i = 0; i < 16; ++i) {
|
||||
if ((Checked[tid] >> i) & 1u) Expect(tid, out[i], Expected[tid][i], Names[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
Run(*device);
|
||||
Check();
|
||||
std::puts("f32 result clamp tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -256,7 +256,10 @@ std::uint32_t EmitPackFloat2x16Rtz(SpirvEmitterState& state, std::uint32_t arg0,
|
|||
}
|
||||
|
||||
std::uint32_t EmitFPSaturate32(SpirvEmitterState& state, std::uint32_t arg0) {
|
||||
return EmitExt(state, TypeF32(state), GLSLstd450FClamp, {arg0, ConstantF32(state, 0u), ConstantF32(state, 0x3f800000u)});
|
||||
const auto bits = Unary(state, spv::OpBitcast, TypeU32(state), arg0);
|
||||
const auto positive = Binary(state, spv::OpULessThan, TypeBool(state), Binary(state, spv::OpISub, TypeU32(state), bits, ConstantU32(state, 1u)), ConstantU32(state, 0x7f800000u));
|
||||
const auto upper = EmitExt(state, TypeU32(state), GLSLstd450UMin, {bits, ConstantU32(state, 0x3f800000u)});
|
||||
return Unary(state, spv::OpBitcast, TypeF32(state), Select(state, TypeU32(state), positive, upper, ConstantU32(state, 0u)));
|
||||
}
|
||||
|
||||
std::uint32_t EmitIAdd64(SpirvEmitterState& state, std::uint32_t arg0, std::uint32_t arg1) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue