Merge branch 'main' of https://github.com/boykopovar/AnyPS5 into feat/userservice-age-level
# Conflicts: # docs/dev/TechnicalDebt.md
This commit is contained in:
commit
aaefea9626
|
|
@ -30,6 +30,7 @@ add_library(libSceAgc SHARED EXCLUDE_FROM_ALL
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Registers.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/DcbState/src/Workload.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/PacketInfo.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Platform.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/RegisterDefaults.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/ShaderFusion.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Misc/src/Suspend.cpp
|
||||
|
|
@ -69,6 +70,19 @@ target_link_libraries(agc_command_tests PRIVATE libSceAgc libc)
|
|||
configure_windows_unwind(agc_command_tests)
|
||||
configure_windows_unwind(libSceAgc)
|
||||
|
||||
add_test_executable(agc_platform_tests EXCLUDE_FROM_ALL tests/Platform.cpp)
|
||||
target_include_directories(agc_platform_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_platform_tests PRIVATE libSceAgc libc)
|
||||
configure_windows_unwind(agc_platform_tests)
|
||||
if(BUILD_TESTING)
|
||||
set_target_properties(agc_platform_tests PROPERTIES EXCLUDE_FROM_ALL FALSE)
|
||||
add_test(NAME agc_platform_tests COMMAND agc_platform_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_platform_tests PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_register_command_tests EXCLUDE_FROM_ALL
|
||||
tests/RegisterCommands.cpp
|
||||
Command/src/Packet.cpp
|
||||
|
|
@ -121,6 +135,21 @@ if(BUILD_TESTING)
|
|||
endif()
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_interpolant_mapping_tests EXCLUDE_FROM_ALL tests/InterpolantMapping.cpp)
|
||||
target_include_directories(agc_interpolant_mapping_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_interpolant_mapping_tests PRIVATE libSceAgc libc)
|
||||
set_target_properties(agc_interpolant_mapping_tests PROPERTIES CXX_EXTENSIONS OFF)
|
||||
configure_windows_unwind(agc_interpolant_mapping_tests)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
set_target_properties(agc_interpolant_mapping_tests PROPERTIES EXCLUDE_FROM_ALL OFF)
|
||||
add_test(NAME agc_interpolant_mapping COMMAND agc_interpolant_mapping_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_interpolant_mapping PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_shader_link_tests ${LIBS_INCLUDE_DIR}/tests/GuestShaderLink.cpp)
|
||||
target_include_directories(guest_shader_link_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
#ifndef CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_PLATFORM_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCEAGC_MISC_INCLUDE_PLATFORM_HPP
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#include "prx/libSceAgc/Misc/include/Platform.hpp"
|
||||
#include "prx/libSceAgc/Command/include/Packet.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceAgcGetIsTrinityMode(bool* isTrinityMode) {
|
||||
Agc::Command::CheckAddress(reinterpret_cast<std::uintptr_t>(isTrinityMode), alignof(bool), __func__);
|
||||
*isTrinityMode = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -8,11 +8,48 @@
|
|||
#include "prx/libSceAgc/Shader/include/ShaderUtils.hpp"
|
||||
#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp"
|
||||
|
||||
extern "C" {
|
||||
namespace {
|
||||
|
||||
APS5_EXPORT("HV4j+E0MBHE", sceAgcCreateInterpolantMapping);
|
||||
int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
|
||||
constexpr auto fn = __func__;
|
||||
constexpr std::uint32_t InterpolantRegisterCount = 32;
|
||||
constexpr std::uint32_t InterpolantF16HiOnly = 2;
|
||||
|
||||
using CreateInterpolantValueFn = std::uint32_t (*)(std::uint32_t psWord, const ShaderSemantic* gsSemantic);
|
||||
|
||||
std::uint32_t CreateInterpolantValue(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
|
||||
const std::uint32_t value = ((psWord & 0x00300000u) != 0)
|
||||
? CreateInterpolantF16Value(psWord, gsSemantic)
|
||||
: CreateInterpolantNonF16Value(psWord, gsSemantic);
|
||||
|
||||
return (gsSemantic == nullptr)
|
||||
? CreateInterpolantDefaultValue(value, psWord)
|
||||
: CreateInterpolantMappingValue(value, psWord, ShaderSemanticWord(*gsSemantic));
|
||||
}
|
||||
|
||||
std::uint32_t CreateInterpolantF16HiValue(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
|
||||
std::uint32_t value = ((psWord << 4u) & 0x03000000u) | 0x00080000u;
|
||||
if (gsSemantic == nullptr || (psWord & ShaderSemanticWord(*gsSemantic) & 0x00200000u) == 0) {
|
||||
value |= 0x00000020u;
|
||||
}
|
||||
value = ApplyInterpolantDefaultValueHi(value, psWord);
|
||||
value |= ((psWord >> 30u) & 0x3u) << 8u;
|
||||
if (gsSemantic == nullptr) {
|
||||
return value;
|
||||
}
|
||||
|
||||
value |= (ShaderSemanticWord(*gsSemantic) >> 8u) & 0x1Fu;
|
||||
if ((psWord & 0x01400000u) != 0) {
|
||||
value |= 0x00000400u;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
std::uint32_t CreateInterpolantValueSplitF16(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
|
||||
return (((psWord >> 20u) & 0x3u) == InterpolantF16HiOnly)
|
||||
? CreateInterpolantF16HiValue(psWord, gsSemantic)
|
||||
: CreateInterpolantValue(psWord, gsSemantic);
|
||||
}
|
||||
|
||||
int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader* gs, const Shader* ps, CreateInterpolantValueFn createValue) {
|
||||
if (regs == nullptr) {
|
||||
throw std::runtime_error(std::string(fn) + ": regs is null");
|
||||
}
|
||||
|
|
@ -26,6 +63,10 @@ int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader*
|
|||
throw std::runtime_error(std::string(fn) + ": ps->input_semantics is null but num_input_semantics != 0");
|
||||
}
|
||||
|
||||
if (ps->num_input_semantics > InterpolantRegisterCount) {
|
||||
throw std::runtime_error(std::string(fn) + ": ps->num_input_semantics exceeds the interpolant register count");
|
||||
}
|
||||
|
||||
if (gs == nullptr) {
|
||||
throw std::runtime_error(std::string(fn) + ": gs is null");
|
||||
}
|
||||
|
|
@ -37,17 +78,7 @@ int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader*
|
|||
for (std::uint32_t i = 0; i < ps->num_input_semantics; ++i) {
|
||||
const ShaderSemantic& psSemantic = ps->input_semantics[i];
|
||||
const ShaderSemantic* gsSemantic = FindOutputSemantic(gs, psSemantic.semantic);
|
||||
const std::uint32_t psWord = ShaderSemanticWord(psSemantic);
|
||||
|
||||
std::uint32_t value = ((psWord & 0x00300000u) != 0)
|
||||
? CreateInterpolantF16Value(psWord, gsSemantic)
|
||||
: CreateInterpolantNonF16Value(psWord, gsSemantic);
|
||||
|
||||
value = (gsSemantic == nullptr)
|
||||
? CreateInterpolantDefaultValue(value, psWord)
|
||||
: CreateInterpolantMappingValue(value, psWord, ShaderSemanticWord(*gsSemantic));
|
||||
|
||||
SetInterpolantRegister(regs, i, value);
|
||||
SetInterpolantRegister(regs, i, createValue(ShaderSemanticWord(psSemantic), gsSemantic));
|
||||
}
|
||||
|
||||
FillIdentityInterpolants(regs, ps->num_input_semantics);
|
||||
|
|
@ -55,3 +86,17 @@ int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader*
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
APS5_EXPORT("HV4j+E0MBHE", sceAgcCreateInterpolantMapping);
|
||||
int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
|
||||
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValue);
|
||||
}
|
||||
|
||||
APS5_EXPORT("dbOlWdppb4o", sceAgcUnknownCreateInterpolantMapping);
|
||||
int APS5_VABI sceAgcUnknownCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
|
||||
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValueSplitF16);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,10 +70,6 @@ int APS5_VABI sceAgcGetGsOversubscription() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcGetIsTrinityMode() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcGetSemaphoreLabel() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
|
@ -84,8 +80,7 @@ int APS5_VABI sceAgcSetAmmSemaphoreMemory() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("6nths4DHNrs", sceAgcUnknown_6nths4DHNrs);
|
||||
int APS5_VABI sceAgcUnknown_6nths4DHNrs() {
|
||||
int APS5_VABI sceAgcCbMemsetExclusive() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -96,38 +91,32 @@ int APS5_VABI sceAgcUnknown_7Wa3aeJgeVU() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("EJBA4dbmvfg", sceAgcUnknown_EJBA4dbmvfg);
|
||||
int APS5_VABI sceAgcUnknown_EJBA4dbmvfg() {
|
||||
int APS5_VABI sceAgcAsyncWriteDataPatchSetDst() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("ICkECTBxrMw", sceAgcUnknown_ICkECTBxrMw);
|
||||
int APS5_VABI sceAgcUnknown_ICkECTBxrMw() {
|
||||
int APS5_VABI sceAgcGetGsPrimPayload() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("RTpj-tIlvZc", sceAgcUnknown_RTpj_MtIlvZc);
|
||||
int APS5_VABI sceAgcUnknown_RTpj_MtIlvZc() {
|
||||
int APS5_VABI sceAgcSetShaderInstrumentation() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("SwI6QxqwAC0", sceAgcUnknown_SwI6QxqwAC0);
|
||||
int APS5_VABI sceAgcUnknown_SwI6QxqwAC0() {
|
||||
int APS5_VABI sceAgcGetShaderInstrumentation() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("d4NZIlguzv0", sceAgcUnknown_d4NZIlguzv0);
|
||||
int APS5_VABI sceAgcUnknown_d4NZIlguzv0() {
|
||||
int APS5_VABI sceAgcAsyncWriteDataPatchSetAddressOrOffset() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("eAy8eGNsCuU", sceAgcUnknown_eAy8eGNsCuU);
|
||||
int APS5_VABI sceAgcUnknown_eAy8eGNsCuU() {
|
||||
int APS5_VABI sceAgcWriteDataPatchSetCachePolicy() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -138,14 +127,12 @@ int APS5_VABI sceAgcUnknown_rP5xLdOf26k() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("tmy-+rBpspY", sceAgcUnknown_tmy_M_PrBpspY);
|
||||
int APS5_VABI sceAgcUnknown_tmy_M_PrBpspY() {
|
||||
int APS5_VABI sceAgcWriteDataPatchSetDst() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("y5K5tPktiL8", sceAgcUnknown_y5K5tPktiL8);
|
||||
int APS5_VABI sceAgcUnknown_y5K5tPktiL8() {
|
||||
int APS5_VABI sceAgcAsyncWriteDataPatchSetCachePolicy() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
#include "SceShaders.hpp"
|
||||
#include "prx/libc/include/Shutdown.hpp"
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps);
|
||||
extern "C" int APS5_VABI sceAgcUnknownCreateInterpolantMapping(ShaderRegister* regs, const Shader* gs, const Shader* ps);
|
||||
|
||||
namespace {
|
||||
|
||||
using Registers = std::array<ShaderRegister, 32>;
|
||||
|
||||
void check(bool condition, const char* message) {
|
||||
if (!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
template <typename TAction>
|
||||
void expectFailure(TAction action) {
|
||||
try {
|
||||
action();
|
||||
} catch (const std::exception& error) {
|
||||
check(error.what()[0] != '\0', "empty exception message");
|
||||
return;
|
||||
}
|
||||
throw std::runtime_error("expected an exception");
|
||||
}
|
||||
|
||||
Registers filled() {
|
||||
Registers regs{};
|
||||
std::memset(regs.data(), 0xcc, sizeof(regs));
|
||||
return regs;
|
||||
}
|
||||
|
||||
ShaderSemantic semantic(std::uint32_t id, std::uint32_t hardwareMapping, std::uint32_t f16) {
|
||||
ShaderSemantic value{};
|
||||
value.semantic = id;
|
||||
value.hardware_mapping = hardwareMapping;
|
||||
value.is_f16 = f16;
|
||||
return value;
|
||||
}
|
||||
|
||||
void checkIdentity(const Registers& regs, std::uint32_t first, const char* message) {
|
||||
for (std::uint32_t i = first; i < regs.size(); ++i) {
|
||||
check(regs[i].offset == ShaderRegs::SPI_PS_INPUT_CNTL_0 + i && regs[i].value == i, message);
|
||||
}
|
||||
}
|
||||
|
||||
void testIdentity() {
|
||||
auto regs = filled();
|
||||
check(sceAgcUnknownCreateInterpolantMapping(regs.data(), nullptr, nullptr) == 0, "mapping without shaders failed");
|
||||
checkIdentity(regs, 0, "mapping without a pixel shader is not the identity");
|
||||
Shader ps{};
|
||||
regs = filled();
|
||||
check(sceAgcUnknownCreateInterpolantMapping(regs.data(), nullptr, &ps) == 0, "mapping without inputs failed");
|
||||
checkIdentity(regs, 0, "mapping without inputs is not the identity");
|
||||
}
|
||||
|
||||
void testMapping() {
|
||||
std::array<ShaderSemantic, 5> inputs{
|
||||
semantic(1, 0, 2), semantic(2, 0, 2), semantic(5, 0, 2), semantic(3, 0, 0), semantic(4, 0, 3)};
|
||||
inputs[0].is_flat_shaded = 1;
|
||||
inputs[0].default_value = 1;
|
||||
inputs[0].default_value_hi = 3;
|
||||
inputs[1].default_value_hi = 1;
|
||||
inputs[2].is_flat_shaded = 1;
|
||||
inputs[2].default_value_hi = 2;
|
||||
inputs[3].is_flat_shaded = 1;
|
||||
inputs[3].default_value = 2;
|
||||
std::array<ShaderSemantic, 4> outputs{semantic(1, 7, 3), semantic(2, 4, 1), semantic(3, 9, 0), semantic(4, 2, 1)};
|
||||
Shader gs{};
|
||||
gs.output_semantics = outputs.data();
|
||||
gs.num_output_semantics = static_cast<std::uint16_t>(outputs.size());
|
||||
Shader ps{};
|
||||
ps.input_semantics = inputs.data();
|
||||
ps.num_input_semantics = static_cast<std::uint32_t>(inputs.size());
|
||||
|
||||
auto split = filled();
|
||||
check(sceAgcUnknownCreateInterpolantMapping(split.data(), &gs, &ps) == 0, "split f16 mapping failed");
|
||||
for (std::uint32_t i = 0; i < inputs.size(); ++i) {
|
||||
check(split[i].offset == ShaderRegs::SPI_PS_INPUT_CNTL_0 + i, "interpolant register offset changed");
|
||||
}
|
||||
check(split[0].value == 0x02680707u, "high f16 half provided by the gs is not mapped");
|
||||
check(split[1].value == 0x02280124u, "high f16 half missing from the gs does not use its default");
|
||||
check(split[2].value == 0x02480220u, "unmatched high f16 half does not use its default");
|
||||
check(split[3].value == 0x00000609u, "32-bit interpolant mapping changed");
|
||||
check(split[4].value == 0x03180002u, "full f16 interpolant mapping changed");
|
||||
checkIdentity(split, static_cast<std::uint32_t>(inputs.size()), "unused interpolants are not the identity");
|
||||
|
||||
auto regular = filled();
|
||||
check(sceAgcCreateInterpolantMapping(regular.data(), &gs, &ps) == 0, "mapping failed");
|
||||
check(regular[3].value == split[3].value && regular[4].value == split[4].value, "mappings differ outside the high f16 half mode");
|
||||
checkIdentity(regular, static_cast<std::uint32_t>(inputs.size()), "unused interpolants are not the identity");
|
||||
}
|
||||
|
||||
void testRejections() {
|
||||
std::array<ShaderSemantic, 33> inputs{};
|
||||
Shader gs{};
|
||||
Shader ps{};
|
||||
ps.input_semantics = inputs.data();
|
||||
ps.num_input_semantics = static_cast<std::uint32_t>(inputs.size());
|
||||
std::array<ShaderRegister, 64> regs{};
|
||||
std::memset(regs.data(), 0xcc, sizeof(regs));
|
||||
const auto saved = regs;
|
||||
expectFailure([&] { sceAgcCreateInterpolantMapping(regs.data(), &gs, &ps); });
|
||||
expectFailure([&] { sceAgcUnknownCreateInterpolantMapping(regs.data(), &gs, &ps); });
|
||||
check(std::memcmp(regs.data(), saved.data(), sizeof(regs)) == 0, "rejected mapping wrote registers");
|
||||
ps.num_input_semantics = 1;
|
||||
expectFailure([&] { sceAgcUnknownCreateInterpolantMapping(regs.data(), nullptr, &ps); });
|
||||
expectFailure([&] { sceAgcUnknownCreateInterpolantMapping(nullptr, &gs, &ps); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
testIdentity();
|
||||
testMapping();
|
||||
testRejections();
|
||||
LibcRunShutdown_nid_postfix();
|
||||
std::puts("AGC interpolant mapping tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
try { LibcRunShutdown_nid_postfix(); }
|
||||
catch (const std::exception& shutdown) { std::fprintf(stderr, "shutdown: %s\n", shutdown.what()); }
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include "prx/libc/include/Shutdown.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" int APS5_VABI sceAgcGetIsTrinityMode(bool* isTrinityMode);
|
||||
|
||||
namespace {
|
||||
|
||||
void check(bool condition, const char* message) {
|
||||
if (!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
template <typename TAction>
|
||||
void expectFailure(TAction action) {
|
||||
try {
|
||||
action();
|
||||
} catch (const std::runtime_error& error) {
|
||||
check(error.what()[0] != '\0', "empty exception message");
|
||||
return;
|
||||
}
|
||||
throw std::runtime_error("expected an exception");
|
||||
}
|
||||
|
||||
void testTrinityMode() {
|
||||
std::array<bool, 3> flags{true, true, true};
|
||||
check(sceAgcGetIsTrinityMode(&flags[1]) == 0, "Trinity mode query did not return 0");
|
||||
check(!flags[1], "base PS5 GPU reported as Trinity");
|
||||
check(flags[0] && flags[2], "Trinity mode query wrote past its one-byte flag");
|
||||
}
|
||||
|
||||
void testRejections() {
|
||||
expectFailure([] { sceAgcGetIsTrinityMode(nullptr); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
testTrinityMode();
|
||||
testRejections();
|
||||
LibcRunShutdown_nid_postfix();
|
||||
std::puts("AGC platform tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
try { LibcRunShutdown_nid_postfix(); }
|
||||
catch (const std::exception& shutdown) { std::fprintf(stderr, "shutdown: %s\n", shutdown.what()); }
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -128,7 +128,7 @@ private:
|
|||
static std::array<WriteRecord, 16384>& writeHistory();
|
||||
static std::size_t& writeCursor();
|
||||
static void dumpPackets(std::span<const std::uint32_t> commands, const std::uint32_t* guest = nullptr);
|
||||
static void validate(std::span<const std::uint32_t> commands, std::uint32_t queue, const std::uint32_t* guest = nullptr);
|
||||
static void validate(const Submission& submission, const std::uint32_t* guest = nullptr);
|
||||
static void reportSkip(const char* kind, const std::string& what);
|
||||
static std::string dumpRequest(std::uint64_t address, const ShaderRecompiler::RecompileRequest& request);
|
||||
static bool matchesFillKernel(std::span<const std::uint32_t> code, const std::vector<std::uint32_t>& userData, const ShaderRecompiler::ShaderComputeStageInfo& compute);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ struct Submission {
|
|||
std::shared_ptr<const ShaderRegistry> shaders;
|
||||
std::map<std::size_t, std::shared_ptr<IFlipRequest>> flips;
|
||||
std::map<std::size_t, std::shared_ptr<IRenderingWait>> renderingWaits;
|
||||
std::map<std::size_t, std::size_t> conditionalEnds;
|
||||
bool suspend = false;
|
||||
bool waitFree = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ bool WaitSatisfiedUnchecked(std::span<const std::uint32_t> packet);
|
|||
// holds will store), without reading memory.
|
||||
bool WaitComparesValue(std::span<const std::uint32_t> packet, std::uint64_t value);
|
||||
std::size_t WaitAwaitedBytes(std::span<const std::uint32_t> packet);
|
||||
std::size_t ConditionalWords(std::span<const std::uint32_t> packet);
|
||||
std::uint32_t ReadCondition(std::span<const std::uint32_t> packet);
|
||||
// A label write (RELEASE_MEM with a data select, WRITE_DATA to memory): the destination and the
|
||||
// bytes it stores, so the write can be recorded on the GPU behind the work it signals. Packets
|
||||
// without a memory destination decode to nothing. No allocation per label (tens of thousands per
|
||||
|
|
|
|||
|
|
@ -47,8 +47,12 @@ void Driver::dumpPackets(std::span<const std::uint32_t> commands, const std::uin
|
|||
}
|
||||
}
|
||||
|
||||
void Driver::validate(std::span<const std::uint32_t> commands, std::uint32_t queue, const std::uint32_t* guest) {
|
||||
void Driver::validate(const Submission& submission, const std::uint32_t* guest) {
|
||||
const std::span<const std::uint32_t> commands = submission.commands;
|
||||
const auto queue = submission.queue;
|
||||
std::vector<std::size_t> guarded;
|
||||
for (std::size_t cursor = 0; cursor < commands.size();) {
|
||||
std::erase_if(guarded, [cursor](std::size_t end) { return end <= cursor; });
|
||||
const auto header = commands[cursor];
|
||||
if (Pm4::FillerPacket(header)) { ++cursor; continue; }
|
||||
if ((header & 0xc0000000u) != 0xc0000000u) {
|
||||
|
|
@ -65,6 +69,12 @@ void Driver::validate(std::span<const std::uint32_t> commands, std::uint32_t que
|
|||
require(count <= commands.size() - cursor, "truncated PM4 packet");
|
||||
try {
|
||||
Pm4::Validate(commands.subspan(cursor, count), queue);
|
||||
if (header == FlipPacketHeader && !guarded.empty()) throw std::runtime_error("a flip inside a conditional execution range (conditional flip reservation) is not implemented");
|
||||
if (((header >> 8u) & 0xffu) == 0x22u) {
|
||||
const auto end = submission.conditionalEnds.find(cursor);
|
||||
if (end == submission.conditionalEnds.end()) throw std::runtime_error("conditional execution range is not made of whole packets of its command buffer");
|
||||
guarded.push_back(end->second);
|
||||
}
|
||||
} catch (const std::exception& error) {
|
||||
dumpPackets(commands, guest);
|
||||
throw std::runtime_error("AGC driver: " + Pm4::Name(header) + " at DWORD " + std::to_string(cursor) + ": " + error.what());
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ void Driver::execute(const Submission& submission) {
|
|||
const auto count = Pm4::PacketWords(header);
|
||||
const auto packet = std::span(submission.commands).subspan(cursor, count);
|
||||
const auto opcode = (header >> 8u) & 0xffu;
|
||||
auto nextCursor = cursor + count;
|
||||
std::shared_lock deviceUse(deviceReplacement, std::defer_lock);
|
||||
if (opcode != 0x3c && opcode != 0x93 && header != RenderingWaitPacketHeader && header != FlipPacketHeader) deviceUse.lock();
|
||||
|
||||
|
|
@ -272,6 +273,11 @@ void Driver::execute(const Submission& submission) {
|
|||
}
|
||||
}); });
|
||||
finishDrawPacket(drawn);
|
||||
} else if (opcode == 0x22) {
|
||||
recordQueuedLabelsBeforeRead(submission.queue);
|
||||
const auto condition = Pm4::ReadCondition(packet);
|
||||
if (condition == 0) nextCursor = submission.conditionalEnds.at(cursor);
|
||||
if (traceGpu) std::fprintf(stderr, "[gpu] %.1f queue 0x%x COND_EXEC at DWORD %zu reads 0x%x at 0x%llx: %s %zu dwords\n", TraceMs(), submission.queue, cursor, condition, static_cast<unsigned long long>(packet[1] | (static_cast<std::uint64_t>(packet[2]) << 32u)), condition == 0 ? "skips" : "executes", submission.conditionalEnds.at(cursor) - cursor - count);
|
||||
} else if (sampleDump && !wroteOnGpu) {
|
||||
dumpSampleCounters(packet[2] | (static_cast<std::uint64_t>(packet[3]) << 32u));
|
||||
} else if (opcode != 0x42 && opcode != 0x46 && opcode != 0x58) {
|
||||
|
|
@ -284,7 +290,7 @@ void Driver::execute(const Submission& submission) {
|
|||
if (endOfPipeInterrupt && !interruptDeferred) AgcDriverDeliverEopInterrupt(submission.queue);
|
||||
}
|
||||
if (drawPacket || (sampleDump && wroteOnGpu)) Graphics::Recorder::CountRecordedWork();
|
||||
cursor += count;
|
||||
cursor = nextCursor;
|
||||
}
|
||||
|
||||
static const bool submitAtEnd = std::getenv("APS5_SUBMIT_AT_END") != nullptr;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ namespace AgcDriver::DriverDetail {
|
|||
|
||||
void Driver::copyCommands(Submission& submission, const std::uint32_t* guest, std::size_t words) {
|
||||
submission.commands.clear();
|
||||
submission.conditionalEnds.clear();
|
||||
std::size_t budget = std::size_t{1} << 26u;
|
||||
copySegment(submission, guest, words, budget);
|
||||
}
|
||||
|
|
@ -18,34 +19,57 @@ void Driver::copyCommands(Submission& submission, const std::uint32_t* guest, st
|
|||
bool Driver::copySegment(Submission& submission, const std::uint32_t* guest, std::size_t words, std::size_t& budget) {
|
||||
require(words <= budget, "command buffer jumps exceed the copy limit (a jump loop?)");
|
||||
budget -= words;
|
||||
std::vector<std::pair<std::size_t, std::size_t>> guarded;
|
||||
const auto reach = [&](std::size_t cursor, std::size_t next) {
|
||||
std::erase_if(guarded, [&](const auto& range) {
|
||||
if (range.first != cursor) return false;
|
||||
submission.conditionalEnds.emplace(range.second, submission.commands.size());
|
||||
return true;
|
||||
});
|
||||
for (const auto& range : guarded) require(range.first >= next, "conditional execution range ends inside a packet");
|
||||
};
|
||||
for (std::size_t cursor = 0; cursor < words;) {
|
||||
const auto header = guest[cursor];
|
||||
if (Pm4::FillerPacket(header)) { submission.commands.push_back(header); ++cursor; continue; }
|
||||
if (Pm4::FillerPacket(header)) {
|
||||
reach(cursor, cursor + 1);
|
||||
submission.commands.push_back(header);
|
||||
++cursor;
|
||||
continue;
|
||||
}
|
||||
const auto count = (header & 0xc0000000u) == 0xc0000000u ? Pm4::PacketWords(header) : words - cursor;
|
||||
if ((header & 0xc0000000u) != 0xc0000000u || count > words - cursor) {
|
||||
submission.commands.insert(submission.commands.end(), guest + cursor, guest + words);
|
||||
return false;
|
||||
}
|
||||
reach(cursor, cursor + count);
|
||||
const auto opcode = (header >> 8u) & 0xffu;
|
||||
if (opcode == 0x3fu) {
|
||||
require(count == 4, "invalid INDIRECT_BUFFER size");
|
||||
const auto* target = reinterpret_cast<const std::uint32_t*>(static_cast<std::uintptr_t>(guest[cursor + 1] & ~3u) | (static_cast<std::uintptr_t>(guest[cursor + 2] & 0xffffu) << 32u));
|
||||
const std::size_t targetWords = guest[cursor + 3] & 0xfffffu;
|
||||
const bool chain = (guest[cursor + 3] & (1u << 20u)) != 0;
|
||||
require(!chain || guarded.empty(), "a chained INDIRECT_BUFFER inside a conditional execution range is not implemented");
|
||||
GuestMemory::CheckRange(target, targetWords * sizeof(std::uint32_t), alignof(std::uint32_t));
|
||||
if (copySegment(submission, target, targetWords, budget)) return true;
|
||||
if (copySegment(submission, target, targetWords, budget)) {
|
||||
require(guarded.empty(), "a REWIND inside a conditional execution range is not implemented");
|
||||
return true;
|
||||
}
|
||||
if (chain) return false;
|
||||
cursor += count;
|
||||
continue;
|
||||
}
|
||||
if (opcode == 0x22u && count == 5) guarded.emplace_back(cursor + count + Pm4::ConditionalWords(std::span(guest + cursor, count)), submission.commands.size());
|
||||
submission.commands.insert(submission.commands.end(), guest + cursor, guest + cursor + count);
|
||||
cursor += count;
|
||||
if (opcode == 0x59u) {
|
||||
require(guarded.empty(), "a REWIND inside a conditional execution range is not implemented");
|
||||
submission.rewindTail = guest + cursor;
|
||||
submission.rewindWords = words - cursor;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
reach(words, words);
|
||||
require(guarded.empty(), "conditional execution range exceeds its command buffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +128,7 @@ void Driver::executeRewindTail(const Submission& stalled) {
|
|||
Submission tail{};
|
||||
tail.queue = stalled.queue;
|
||||
copyCommands(tail, stalled.rewindTail, stalled.rewindWords);
|
||||
validate(tail.commands, tail.queue, stalled.rewindTail);
|
||||
validate(tail, stalled.rewindTail);
|
||||
waitForFlipRoom(tail);
|
||||
{
|
||||
std::lock_guard lock(mutex);
|
||||
|
|
@ -135,7 +159,7 @@ void Driver::Submit(const Packet* packet, std::uint32_t queue) {
|
|||
copyCommands(submission, descriptor.addr, descriptor.dw_num);
|
||||
}
|
||||
const auto copied = profile ? std::chrono::steady_clock::now() : start;
|
||||
validate(submission.commands, queue, descriptor.addr);
|
||||
validate(submission, descriptor.addr);
|
||||
waitForFlipRoom(submission);
|
||||
static const bool trace = std::getenv("APS5_TRACE_GPU") != nullptr;
|
||||
if (trace) std::fprintf(stderr, "[gpu] %.1f submit queue=0x%x dwords=%zu at %p\n", TraceMs(), queue, submission.commands.size(), static_cast<const void*>(descriptor.addr));
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ std::string_view UnsupportedReason(std::uint32_t header) {
|
|||
}
|
||||
}
|
||||
switch (opcode) {
|
||||
case 0x11: case 0x12: case 0x13: case 0x15: case 0x16: case 0x26: case 0x27:
|
||||
case 0x11: case 0x12: case 0x13: case 0x15: case 0x16: case 0x22: case 0x26: case 0x27:
|
||||
case 0x2a: case 0x2d: case 0x2f: case 0x35: case 0x37: case 0x40: case 0x42: case 0x46: case 0x50:
|
||||
case 0x58: case 0x63: case 0x64: case 0x69: case 0x76: case 0x79: case 0x7a:
|
||||
case 0x81: case 0x83: case 0x9f: return {};
|
||||
|
|
@ -176,7 +176,6 @@ std::string_view UnsupportedReason(std::uint32_t header) {
|
|||
case 0x3a: case 0x8d:
|
||||
return "graphics draw, shader stages and guest render-target materialization are not implemented";
|
||||
case 0x20: return "GPU query predication is not implemented";
|
||||
case 0x22: return "conditional command execution and conditional flip reservation are not implemented";
|
||||
case 0x33: case 0x3f: return "nested command buffers, branching and nested flip reservation are not implemented";
|
||||
case 0x3c: case 0x93: return {};
|
||||
case 0x39:
|
||||
|
|
@ -194,8 +193,11 @@ std::string_view UnsupportedReason(std::uint32_t header) {
|
|||
}
|
||||
}
|
||||
|
||||
constexpr std::uint32_t ConditionCachePolicy = 3u << 25u;
|
||||
constexpr std::uint32_t ConditionalWordsMask = 0x3fffu;
|
||||
constexpr std::uint32_t DmaSourceCachePolicy = 3u << 13u;
|
||||
constexpr std::uint32_t DmaDestinationCachePolicy = 3u << 25u;
|
||||
constexpr std::uint32_t WriteDataCachePolicy = 3u << 25u;
|
||||
|
||||
void Validate(std::span<const std::uint32_t> packet, std::uint32_t queue) {
|
||||
require(!packet.empty(), "truncated PM4 header");
|
||||
|
|
@ -296,6 +298,13 @@ void Validate(std::span<const std::uint32_t> packet, std::uint32_t queue) {
|
|||
require(packet.size() == 3 || packet.size() == 4, "invalid indirect dispatch size");
|
||||
require((packet.back() & ~0xa020u) == 0x41u, "indirect dispatch modifiers are not implemented");
|
||||
break;
|
||||
case 0x22:
|
||||
size(5);
|
||||
require((packet[1] & 3u) == 0, "COND_EXEC reserved address bits are not implemented");
|
||||
require(packet[2] <= 0xffffu, "COND_EXEC address bits above 48 are not implemented");
|
||||
require((packet[3] & ~(queue == 0 ? 0u : ConditionCachePolicy)) == 0, "COND_EXEC reserved control fields are not implemented");
|
||||
require((packet[4] & ~ConditionalWordsMask) == 0, "COND_EXEC reserved count bits are not implemented");
|
||||
break;
|
||||
case 0x42: size(2); require(packet[1] == 0, "unsupported PFP_SYNC_ME payload"); break;
|
||||
case 0x46: {
|
||||
require((packet[1] & ~0x73fu) == 0, "unsupported EVENT_WRITE flags or reserved bits");
|
||||
|
|
@ -380,7 +389,7 @@ void Validate(std::span<const std::uint32_t> packet, std::uint32_t queue) {
|
|||
break;
|
||||
case 0x37: {
|
||||
require(packet.size() >= 5, "WRITE_DATA has no data");
|
||||
require((packet[1] & ~0x40110f00u) == 0, "WRITE_DATA engine, cache or reserved fields are not implemented");
|
||||
require((packet[1] & ~(0x40110f00u | WriteDataCachePolicy)) == 0, "WRITE_DATA engine or reserved fields are not implemented");
|
||||
const auto destination = (packet[1] >> 8u) & 0xfu;
|
||||
require(destination == 1 || destination == 2 || (queue != 0 && destination == 5), "WRITE_DATA register or GDS destination is not implemented");
|
||||
require((packet[2] & 3u) == 0, "misaligned WRITE_DATA destination");
|
||||
|
|
@ -462,6 +471,19 @@ std::size_t WaitAwaitedBytes(std::span<const std::uint32_t> packet) {
|
|||
return wide && (packet.size() < 8 || packet[7] != 0) ? 8 : 4;
|
||||
}
|
||||
|
||||
std::size_t ConditionalWords(std::span<const std::uint32_t> packet) {
|
||||
require(packet.size() == 5 && ((packet[0] >> 8u) & 0xffu) == 0x22u, "expected COND_EXEC packet");
|
||||
return packet[4] & ConditionalWordsMask;
|
||||
}
|
||||
|
||||
std::uint32_t ReadCondition(std::span<const std::uint32_t> packet) {
|
||||
require(packet.size() == 5 && ((packet[0] >> 8u) & 0xffu) == 0x22u, "expected COND_EXEC packet");
|
||||
std::uint32_t value = 0;
|
||||
const GuestMemory::ReadSiteScope site(GuestMemory::ReadSite::Wait);
|
||||
GuestMemory::Read(address(packet[1], packet[2]), std::as_writable_bytes(std::span(&value, 1)), 4);
|
||||
return value;
|
||||
}
|
||||
|
||||
std::optional<LabelWrite> DecodeLabelWrite(std::span<const std::uint32_t> packet) {
|
||||
const auto opcode = (packet[0] >> 8u) & 0xffu;
|
||||
if (opcode == 0x49 && packet.size() >= 7) {
|
||||
|
|
@ -537,7 +559,7 @@ bool UsesGpuCacheBarrier(std::span<const std::uint32_t> packet) {
|
|||
|
||||
bool AccessesMemory(std::uint32_t header) {
|
||||
switch ((header >> 8u) & 0xffu) {
|
||||
case 0x27: case 0x3c: case 0x93: case 0x49: case 0x16: case 0x2d: case 0x35: case 0x24: case 0x25: case 0x2c: case 0x38: case 0x37: case 0x40: case 0x50: case 0x63: case 0x64: case 0x83: case 0x9f: return true;
|
||||
case 0x22: case 0x27: case 0x3c: case 0x93: case 0x49: case 0x16: case 0x2d: case 0x35: case 0x24: case 0x25: case 0x2c: case 0x38: case 0x37: case 0x40: case 0x50: case 0x63: case 0x64: case 0x83: case 0x9f: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -803,7 +803,6 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window) : state(std::make_u
|
|||
state->capabilities.push_back(5283);
|
||||
state->spirvExtensions.push_back("SPV_EXT_mesh_shader");
|
||||
}
|
||||
APS5_LOG_OUT("Vulkan features tessellationAvailable=%u mesh=%u depthClip=%u depthRangeUnrestricted=%u", static_cast<unsigned>(state->tessellationShader), static_cast<unsigned>(state->meshShader), static_cast<unsigned>(state->depthClipControl), static_cast<unsigned>(state->depthRangeUnrestricted));
|
||||
const float priority = 1.0f;
|
||||
VkDeviceQueueCreateInfo queueInfo{VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO};
|
||||
queueInfo.queueFamilyIndex = family;
|
||||
|
|
@ -824,6 +823,7 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window) : state(std::make_u
|
|||
enabled.tessellationShader = available.tessellationShader;
|
||||
state->tessellationShader = enabled.tessellationShader == VK_TRUE;
|
||||
if (state->tessellationShader) state->capabilities.push_back(3);
|
||||
APS5_LOG_OUT("Vulkan features tessellationAvailable=%u mesh=%u depthClip=%u depthRangeUnrestricted=%u", static_cast<unsigned>(state->tessellationShader), static_cast<unsigned>(state->meshShader), static_cast<unsigned>(state->depthClipControl), static_cast<unsigned>(state->depthRangeUnrestricted));
|
||||
require(available.samplerAnisotropy && available.textureCompressionBC, "device lacks sampler anisotropy or BC texture compression support required for texture sampling");
|
||||
enabled.samplerAnisotropy = VK_TRUE;
|
||||
enabled.textureCompressionBC = VK_TRUE;
|
||||
|
|
|
|||
|
|
@ -411,6 +411,7 @@ private:
|
|||
std::vector<std::uint64_t> storageKeys;
|
||||
std::vector<bool> storageFirstLayer;
|
||||
std::vector<bool> storageWritten;
|
||||
std::vector<bool> storageAtomic;
|
||||
std::vector<std::shared_ptr<Sampler>> samplers;
|
||||
bool reusable = false;
|
||||
std::vector<DirectRegion> directRegions;
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ public:
|
|||
// so successive mip writes of a chain share one image and one write-back.
|
||||
VkImageView View(std::uint32_t mip);
|
||||
VkImageView FirstLayerView(std::uint32_t mip);
|
||||
VkImageView AtomicView(std::uint32_t mip, bool firstLayer);
|
||||
// Render targets live in the same images: draws attach mip 0 through a view of the color
|
||||
// buffer's format and mark the image dirty like a storage write.
|
||||
bool Attachable() const { return attachable; }
|
||||
|
|
@ -394,7 +395,7 @@ private:
|
|||
bool clearByKeysFill(DccKeys keys, std::uint8_t key);
|
||||
bool overlaps(std::uint64_t address, std::size_t bytes) const;
|
||||
bool pendingUnitInside(std::uint64_t address, std::size_t bytes) const;
|
||||
VkImageView createView(std::uint32_t mip, bool firstLayer = false) const;
|
||||
VkImageView createView(std::uint32_t mip, bool firstLayer, VkFormat format) const;
|
||||
void release() noexcept;
|
||||
|
||||
Context context;
|
||||
|
|
@ -442,6 +443,7 @@ private:
|
|||
std::uint32_t defaultMip = 0;
|
||||
std::map<std::uint32_t, VkImageView> extraViews;
|
||||
std::map<std::uint32_t, VkImageView> firstLayerViews;
|
||||
std::map<std::pair<std::uint32_t, bool>, VkImageView> atomicViews;
|
||||
bool attachable = false;
|
||||
std::map<std::tuple<VkFormat, std::uint32_t, std::uint32_t>, VkImageView> attachmentViews;
|
||||
VkFormat storageFormat = VK_FORMAT_UNDEFINED;
|
||||
|
|
|
|||
|
|
@ -1056,7 +1056,7 @@ void ShaderResources::buildComplete() {
|
|||
break;
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
write.pImageInfo = images.data() + images.size();
|
||||
for (const auto index : binding.imageAllocations) images.push_back({VK_NULL_HANDLE, storageFirstLayer[index] ? storageTextures[index]->FirstLayerView(storageMips[index]) : storageTextures[index]->View(storageMips[index]), VK_IMAGE_LAYOUT_GENERAL});
|
||||
for (const auto index : binding.imageAllocations) images.push_back({VK_NULL_HANDLE, storageAtomic[index] ? storageTextures[index]->AtomicView(storageMips[index], storageFirstLayer[index]) : storageFirstLayer[index] ? storageTextures[index]->FirstLayerView(storageMips[index]) : storageTextures[index]->View(storageMips[index]), VK_IMAGE_LAYOUT_GENERAL});
|
||||
break;
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
write.pImageInfo = images.data() + images.size();
|
||||
|
|
@ -1201,6 +1201,7 @@ std::vector<std::uint32_t> ShaderResources::ContentKey(const CompiledShader& sha
|
|||
packBits(binding.imageWritten);
|
||||
packBits(binding.samplerDepthCompare);
|
||||
packBits(binding.imageDepthCompare);
|
||||
packBits(binding.imageAtomic);
|
||||
// Read-only elements are bound without a write set: an object built for one written set
|
||||
// must not serve a build with another (the variant implies it, this makes it explicit).
|
||||
packBits(binding.bufferWritten);
|
||||
|
|
@ -2564,6 +2565,7 @@ void ShaderResources::resolveImageBinding(const ShaderRecompiler::DescriptorBind
|
|||
storageFirstLayer.push_back(firstLayer);
|
||||
// Images the shader only reads have nothing to store back.
|
||||
storageWritten.push_back(element >= binding.imageWritten.size() || binding.imageWritten[element]);
|
||||
storageAtomic.push_back(element < binding.imageAtomic.size() && binding.imageAtomic[element]);
|
||||
describedRanges.push_back({"storage", resource.baseAddress, guestBytes, resource.width, resource.height, resource.format, static_cast<int>(resource.tileMode), resource.dccAddress});
|
||||
item.imageAllocations.push_back(storageTextures.size() - 1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ constexpr std::uint32_t ScanModeMask = ~2u;
|
|||
constexpr std::uint32_t ScanControlMask = ~0x06003fffu;
|
||||
constexpr std::uint32_t ScreenOffsetMask = ~0x01ff01ffu;
|
||||
// Bits 26/27 (ZCLIP_NEAR/FAR_DISABLE) become depth clamping; bit 19 selects the [0, 1] clip space.
|
||||
constexpr std::uint32_t ClipControlMask = ~(0x80000u | 0x0c000000u);
|
||||
constexpr std::uint32_t ClipControlMask = ~(0x80000u | 0x01000000u | 0x0c000000u);
|
||||
|
||||
// Debug aid: APS5_IGNORE_DEPTH_TEST=1 renders depth- and stencil-tested draws without a depth
|
||||
// target as if their tests always passed (wrong occlusion, but the draws run), so stages that
|
||||
|
|
|
|||
|
|
@ -691,7 +691,7 @@ StorageTexture::StorageTexture(const Context& context, TextureDetiler& detiler,
|
|||
uploadReason = "first";
|
||||
upload();
|
||||
defaultMip = mipLevel;
|
||||
view = createView(mipLevel);
|
||||
view = createView(mipLevel, false, storageFormat);
|
||||
{
|
||||
auto& live = Live();
|
||||
std::lock_guard lock(live.mutex);
|
||||
|
|
@ -942,15 +942,18 @@ bool AdjacentGenerationEnabled() {
|
|||
|
||||
}
|
||||
|
||||
VkImageView StorageTexture::createView(std::uint32_t mip, bool firstLayer) const {
|
||||
VkImageView StorageTexture::createView(std::uint32_t mip, bool firstLayer, VkFormat format) const {
|
||||
Require(mip < descriptor.mipCount, "storage texture mip level is outside the texture");
|
||||
Require(!firstLayer || descriptor.dimension == TextureDimension::k2DArray, "a first-layer storage view needs a 2D array surface");
|
||||
const auto viewLayerCount = firstLayer ? 1u : geometry.imageLayers - descriptor.baseArray;
|
||||
VkImageViewUsageCreateInfo usage{VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO};
|
||||
usage.usage = VK_IMAGE_USAGE_STORAGE_BIT;
|
||||
VkImageViewCreateInfo viewInfo{VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO};
|
||||
viewInfo.pNext = format == storageFormat ? nullptr : &usage;
|
||||
viewInfo.image = image;
|
||||
// Storage views address one mip; cube faces are written as array layers.
|
||||
viewInfo.viewType = firstLayer ? VK_IMAGE_VIEW_TYPE_2D : descriptor.dimension == TextureDimension::k1D ? VK_IMAGE_VIEW_TYPE_1D : descriptor.dimension == TextureDimension::k2D ? VK_IMAGE_VIEW_TYPE_2D : descriptor.dimension == TextureDimension::k3D ? VK_IMAGE_VIEW_TYPE_3D : VK_IMAGE_VIEW_TYPE_2D_ARRAY;
|
||||
viewInfo.format = storageFormat;
|
||||
viewInfo.format = format;
|
||||
viewInfo.components = {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
|
||||
viewInfo.subresourceRange = {VK_IMAGE_ASPECT_COLOR_BIT, mip, 1u, descriptor.baseArray, viewLayerCount};
|
||||
VkImageView created = VK_NULL_HANDLE;
|
||||
|
|
@ -984,7 +987,7 @@ VkImageView StorageTexture::View(std::uint32_t mip) {
|
|||
if (mip == defaultMip) return view;
|
||||
const auto found = extraViews.find(mip);
|
||||
if (found != extraViews.end()) return found->second;
|
||||
const auto created = createView(mip);
|
||||
const auto created = createView(mip, false, storageFormat);
|
||||
extraViews.emplace(mip, created);
|
||||
return created;
|
||||
}
|
||||
|
|
@ -992,11 +995,21 @@ VkImageView StorageTexture::View(std::uint32_t mip) {
|
|||
VkImageView StorageTexture::FirstLayerView(std::uint32_t mip) {
|
||||
const auto found = firstLayerViews.find(mip);
|
||||
if (found != firstLayerViews.end()) return found->second;
|
||||
const auto created = createView(mip, true);
|
||||
const auto created = createView(mip, true, storageFormat);
|
||||
firstLayerViews.emplace(mip, created);
|
||||
return created;
|
||||
}
|
||||
|
||||
VkImageView StorageTexture::AtomicView(std::uint32_t mip, bool firstLayer) {
|
||||
if (storageFormat == VK_FORMAT_R32_UINT) return firstLayer ? FirstLayerView(mip) : View(mip);
|
||||
Require(storageFormat == VK_FORMAT_R32_SINT || storageFormat == VK_FORMAT_R32_SFLOAT, "storage image atomics need a surface of one 32-bit component");
|
||||
const auto found = atomicViews.find({mip, firstLayer});
|
||||
if (found != atomicViews.end()) return found->second;
|
||||
const auto created = createView(mip, firstLayer, VK_FORMAT_R32_UINT);
|
||||
atomicViews.emplace(std::pair{mip, firstLayer}, created);
|
||||
return created;
|
||||
}
|
||||
|
||||
const char* LookupOutcomes::Name(Kind kind) {
|
||||
static constexpr const char* names[Count] = {"sampled fast hit", "sampled fast miss", "sampled hit view", "sampled hit cleared view", "sampled hit snapshot", "sampled made view", "sampled made snapshot", "storage hit", "storage made", "refresh unchanged", "refresh compared", "upload direct", "upload cpu", "upload clear", "dcc scan", "pending flush"};
|
||||
return kind < Count ? names[kind] : "?";
|
||||
|
|
@ -3559,6 +3572,8 @@ void StorageTexture::release() noexcept {
|
|||
extraViews.clear();
|
||||
for (const auto& [mip, extra] : firstLayerViews) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, extra, nullptr);
|
||||
firstLayerViews.clear();
|
||||
for (const auto& [key, atomic] : atomicViews) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, atomic, nullptr);
|
||||
atomicViews.clear();
|
||||
for (const auto& [format, attachment] : attachmentViews) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, attachment, nullptr);
|
||||
attachmentViews.clear();
|
||||
if (view) context.Function<PFN_vkDestroyImageView>("vkDestroyImageView")(context.device, view, nullptr);
|
||||
|
|
|
|||
|
|
@ -85,26 +85,22 @@ int APS5_VABI sceAgcDriverUnregisterWorkloadStream() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("+iAOE3jCnkk", sceAgcDriverUnknown__PiAOE3jCnkk);
|
||||
int APS5_VABI sceAgcDriverUnknown__PiAOE3jCnkk() {
|
||||
int APS5_VABI sceAgcDriverSetSubmitValidationMode() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("ICaGtkEIXTk", sceAgcDriverUnknown_ICaGtkEIXTk);
|
||||
int APS5_VABI sceAgcDriverUnknown_ICaGtkEIXTk() {
|
||||
int APS5_VABI sceAgcDriverGetSubmitValidationConfig() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("WHIOMbb+iIU", sceAgcDriverUnknown_WHIOMbb_PiIU);
|
||||
int APS5_VABI sceAgcDriverUnknown_WHIOMbb_PiIU() {
|
||||
int APS5_VABI sceAgcDriverGetSubmitValidationMode() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("chJWZcNSzjk", sceAgcDriverUnknown_chJWZcNSzjk);
|
||||
int APS5_VABI sceAgcDriverUnknown_chJWZcNSzjk() {
|
||||
int APS5_VABI sceAgcDriverSetSubmitValidationConfig() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,6 +114,12 @@ void testFlipAndBoundary() {
|
|||
Packet rejected{rollback.data(), 12, 0, {}};
|
||||
expectFailure([&] { sceAgcDriverSubmitDcb(&rejected); });
|
||||
check(output->state->alive == 0 && output->state->ready == 0, "rejected submission retained or executed a reservation");
|
||||
alignas(4) static std::uint32_t condition = 1;
|
||||
const auto conditionAddress = reinterpret_cast<std::uintptr_t>(&condition);
|
||||
std::array<std::uint32_t, 11> guarded{0xc0032200, static_cast<std::uint32_t>(conditionAddress), static_cast<std::uint32_t>(conditionAddress >> 32u), 0, 6, 0xc004105c, 7, 0, 1, 0, 0};
|
||||
Packet conditionalFlip{guarded.data(), 11, 0, {}};
|
||||
check(expectFailure([&] { sceAgcDriverSubmitDcb(&conditionalFlip); }).find("a flip inside a conditional execution range") != std::string::npos, "a flip inside a COND_EXEC range was not rejected");
|
||||
check(output->state->alive == 0 && output->state->ready == 0, "a rejected conditional flip retained or executed a reservation");
|
||||
{
|
||||
std::lock_guard lock(output->state->mutex);
|
||||
output->state->block = true;
|
||||
|
|
|
|||
|
|
@ -728,9 +728,23 @@ void DepthClipTests() {
|
|||
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "inverted viewport depth clamp");
|
||||
queue.context[0xb4] = 0;
|
||||
for (std::uint32_t bit = 0; bit < 32; ++bit) {
|
||||
if (bit == 19 || bit == 26 || bit == 27) continue;
|
||||
queue.context[0x204] = 1u << bit;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "PA_CL_CLIP_CNTL");
|
||||
if (bit == 19 || bit == 24 || bit == 26 || bit == 27) continue;
|
||||
for (const auto linearBit : {0u, 0x01000000u}) {
|
||||
queue.context[0x204] = (1u << bit) | linearBit;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "PA_CL_CLIP_CNTL");
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, false).find("PA_CL_CLIP_CNTL") != std::string::npos, "the precheck accepted an unsupported PA_CL_CLIP_CNTL bit");
|
||||
}
|
||||
}
|
||||
queue = makeState();
|
||||
queue.context[0x1b3] = 2;
|
||||
queue.context[0x1b4] = 2;
|
||||
for (const auto clip : {0x00080000u, 0x00000000u, 0x0c080000u, 0x04000000u}) {
|
||||
queue.context[0x204] = clip;
|
||||
const auto plain = AgcDriver::Graphics::DecodeState(queue);
|
||||
queue.context[0x204] = clip | 0x01000000u;
|
||||
const auto linearClip = AgcDriver::Graphics::DecodeState(queue);
|
||||
Require(AgcDriver::Graphics::DrawRejection(queue, false).empty(), "the precheck rejected DX_LINEAR_ATTR_CLIP_ENA");
|
||||
Require(linearClip.negativeOneToOne == plain.negativeOneToOne && linearClip.depthClamp == plain.depthClamp && linearClip.viewport.minDepth == plain.viewport.minDepth && linearClip.viewport.maxDepth == plain.viewport.maxDepth, "DX_LINEAR_ATTR_CLIP_ENA changed the clip space, depth clamping or depth range");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,16 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/Driver.hpp"
|
||||
#include "prx/libSceAgcDriver/Submit/include/Dcb.hpp"
|
||||
#include "prx/libSceAgcDriver/Submit/include/Acb.hpp"
|
||||
#include "prx/libc/include/Shutdown.hpp"
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
|
|
@ -290,6 +294,9 @@ void testMemory() {
|
|||
check(data[0] == 22 && data[1] == 12, "WRITE_DATA fixed destination failed");
|
||||
execute(state, makePacket(0x37, {0x40000100, low(data.data()), high(data.data()), 41, 42}));
|
||||
check(data[0] == 41 && data[1] == 42, "WRITE_DATA from the PFP failed");
|
||||
execute(state, makePacket(0x37, {0x04100200, low(data.data()), high(data.data()), 61, 62}));
|
||||
check(data[0] == 61 && data[1] == 62, "WRITE_DATA with a cache policy failed");
|
||||
expectFailure([&] { AgcDriver::Pm4::Validate(makePacket(0x37, {0x08000100, low(data.data()), high(data.data()), 71}), 0); }, "reserved");
|
||||
expectFailure([&] { AgcDriver::Pm4::Validate(makePacket(0x37, {0x80000100, low(data.data()), high(data.data()), 51}), 0); }, "engine");
|
||||
execute(state, makePacket(0x81, {4, 31, 32}));
|
||||
execute(state, makePacket(0x83, {4, 2, low(data.data()), high(data.data())}));
|
||||
|
|
@ -405,6 +412,60 @@ void testMemorySynchronization() {
|
|||
check(memory.destination == 42, "failed synchronization changed the destination");
|
||||
}
|
||||
|
||||
void testConditionalValidation() {
|
||||
alignas(4) static std::uint32_t condition = 0;
|
||||
const auto valid = makePacket(0x22, {low(&condition), high(&condition), 0, 0x3fff});
|
||||
check(AgcDriver::Pm4::UnsupportedReason(valid[0]).empty() && AgcDriver::Pm4::AccessesMemory(valid[0]), "COND_EXEC is rejected or does not synchronize guest memory");
|
||||
AgcDriver::Pm4::Validate(valid, 0);
|
||||
AgcDriver::Pm4::Validate(valid, 0x20);
|
||||
check(AgcDriver::Pm4::ConditionalWords(valid) == 0x3fff, "COND_EXEC count decoded wrong");
|
||||
check(AgcDriver::Pm4::ConditionalWords(makePacket(0x22, {low(&condition), high(&condition), 0, 0})) == 0, "empty COND_EXEC range decoded wrong");
|
||||
AgcDriver::Pm4::Validate(makePacket(0x22, {low(&condition), high(&condition), 3u << 25u, 5}), 0x20);
|
||||
const auto invalidWord = [&](std::size_t word, std::uint32_t value, std::uint32_t queue, const char* text) {
|
||||
auto packet = valid;
|
||||
packet[word] = value;
|
||||
expectFailure([&] { AgcDriver::Pm4::Validate(packet, queue); }, text);
|
||||
};
|
||||
invalidWord(1, low(&condition) | 1u, 0, "reserved address bits");
|
||||
invalidWord(1, low(&condition) | 2u, 0x20, "reserved address bits");
|
||||
invalidWord(2, 0x10000u, 0, "above 48");
|
||||
invalidWord(3, 3u << 25u, 0, "reserved control fields");
|
||||
invalidWord(3, 1u, 0x20, "reserved control fields");
|
||||
invalidWord(3, 1u << 27u, 0x20, "reserved control fields");
|
||||
invalidWord(4, 0x4000u, 0, "reserved count bits");
|
||||
invalidWord(4, 0x80000005u, 0x20, "reserved count bits");
|
||||
expectFailure([] { AgcDriver::Pm4::Validate(makePacket(0x22, {0, 0, 0}), 0); }, "packet size");
|
||||
expectFailure([] { AgcDriver::Pm4::Validate(makePacket(0x22, {0, 0, 0, 0, 0}), 0); }, "packet size");
|
||||
expectFailure([] { AgcDriver::Pm4::Validate(makePacket(0x22, {0, 0, 0, 0}, 1), 0); }, "header flags");
|
||||
expectFailure([] { AgcDriver::Pm4::Validate(makePacket(0x22, {0, 0, 0, 0}, 2), 0x20); }, "header flags");
|
||||
expectFailure([] { AgcDriver::Pm4::ConditionalWords(makePacket(0x37, {0x100, 0, 0, 0})); }, "expected COND_EXEC");
|
||||
AgcDriver::QueueState state;
|
||||
expectFailure([&] { AgcDriver::Pm4::Execute(valid, state); }, "driver execution");
|
||||
}
|
||||
|
||||
void testConditionReadSynchronization() {
|
||||
alignas(4) static std::uint32_t condition = 0;
|
||||
static std::size_t flushed = 0;
|
||||
condition = 0;
|
||||
flushed = 0;
|
||||
struct FlushHookReset {
|
||||
~FlushHookReset() { AgcDriver::GuestMemory::SetFlushHook(nullptr); }
|
||||
} reset;
|
||||
AgcDriver::GuestMemory::SetFlushHook([](std::uint64_t address, std::size_t bytes) {
|
||||
check(address == reinterpret_cast<std::uintptr_t>(&condition) && bytes == sizeof(condition), "COND_EXEC synchronized an unrelated range");
|
||||
condition = 0x80;
|
||||
++flushed;
|
||||
});
|
||||
const auto packet = makePacket(0x22, {low(&condition), high(&condition), 0, 5});
|
||||
check(AgcDriver::Pm4::ReadCondition(packet) == 0x80 && flushed == 1, "COND_EXEC read its condition before the GPU work that writes it");
|
||||
AgcDriver::GuestMemory::SetFlushHook([](std::uint64_t, std::size_t) {
|
||||
throw std::runtime_error("condition synchronization failed");
|
||||
});
|
||||
expectFailure([&] { AgcDriver::Pm4::ReadCondition(packet); }, "condition synchronization failed");
|
||||
AgcDriver::GuestMemory::SetFlushHook(nullptr);
|
||||
expectFailure([] { AgcDriver::Pm4::ReadCondition(makePacket(0x22, {0x1000, 0, 0, 5})); }, "guest");
|
||||
}
|
||||
|
||||
void testWriteChangedKeepsUntouchedBytes() {
|
||||
alignas(256) static std::uint8_t guest[256];
|
||||
std::memset(guest, 0, sizeof(guest));
|
||||
|
|
@ -541,6 +602,97 @@ void testDriverSubmission() {
|
|||
check(destination[0] == 0, "rejected submission executed a prefix");
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> joinPackets(std::initializer_list<std::vector<std::uint32_t>> packets) {
|
||||
std::vector<std::uint32_t> words;
|
||||
for (const auto& packet : packets) words.insert(words.end(), packet.begin(), packet.end());
|
||||
return words;
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> writeWord(std::uint32_t& target, std::uint32_t value) {
|
||||
return makePacket(0x37, {0x00100200, low(&target), high(&target), value});
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> conditional(const std::uint32_t& condition, std::uint32_t words, std::uint32_t control = 0) {
|
||||
return makePacket(0x22, {low(&condition), high(&condition), control, words});
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> indirectBuffer(const std::vector<std::uint32_t>& target, bool chain = false) {
|
||||
return makePacket(0x3f, {low(target.data()), high(target.data()), static_cast<std::uint32_t>(target.size()) | (chain ? 1u << 20u : 0u)});
|
||||
}
|
||||
|
||||
void submitWords(std::vector<std::uint32_t>& words, std::uint32_t queue = 0) {
|
||||
Packet packet{words.data(), static_cast<std::uint32_t>(words.size()), 0, {}};
|
||||
check((queue == 0 ? sceAgcDriverSubmitDcb(&packet) : sceAgcDriverSubmitAcb(queue, &packet)) == 0, "conditional submission failed");
|
||||
}
|
||||
|
||||
void testConditionalSubmission() {
|
||||
alignas(8) static std::uint32_t zero = 0, one = 1, condition = 0;
|
||||
static std::array<std::uint32_t, 16> results{};
|
||||
results.fill(0);
|
||||
const auto run = [](std::vector<std::uint32_t> words, std::uint32_t queue = 0) {
|
||||
submitWords(words, queue);
|
||||
AgcDriverWaitIdle_nid_postfix();
|
||||
};
|
||||
run(joinPackets({conditional(one, 5), writeWord(results[0], 11), writeWord(results[1], 12)}));
|
||||
check(results[0] == 11 && results[1] == 12, "COND_EXEC skipped a range whose condition is set");
|
||||
run(joinPackets({conditional(zero, 6), {0x80000000u}, writeWord(results[0], 21), writeWord(results[1], 22)}));
|
||||
check(results[0] == 11 && results[1] == 22, "COND_EXEC did not skip exactly its range when the condition is zero");
|
||||
run(joinPackets({conditional(zero, 0), writeWord(results[2], 23)}));
|
||||
check(results[2] == 23, "an empty COND_EXEC range skipped the next packet");
|
||||
alignas(4) static std::uint32_t never = 0;
|
||||
never = 0;
|
||||
auto skippedWait = joinPackets({conditional(zero, 9), makePacket(0x3c, {0x13, low(&never), high(&never), 1, 0xffffffffu, 0x190}), makePacket(0x10, {0}, 0x30), writeWord(results[14], 24)});
|
||||
submitWords(skippedWait);
|
||||
const auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(10);
|
||||
while (std::atomic_ref<std::uint32_t>(results[14]).load() != 24 && std::chrono::steady_clock::now() < deadline) std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
const bool skipped = std::atomic_ref<std::uint32_t>(results[14]).load() == 24;
|
||||
std::atomic_ref<std::uint32_t>(never).store(1);
|
||||
AgcDriverWaitIdle_nid_postfix();
|
||||
check(skipped, "a WAIT_REG_MEM inside a skipped COND_EXEC range was executed");
|
||||
|
||||
condition = 1;
|
||||
run(joinPackets({writeWord(condition, 0), conditional(condition, 5), writeWord(results[0], 31), writeWord(results[1], 32)}));
|
||||
check(condition == 0 && results[0] == 11 && results[1] == 32, "COND_EXEC read its condition before an earlier packet of its queue stored it");
|
||||
run(joinPackets({writeWord(condition, 9), conditional(condition, 5), writeWord(results[0], 41)}));
|
||||
check(results[0] == 41, "COND_EXEC skipped a range whose condition an earlier packet of its queue set");
|
||||
condition = 0;
|
||||
run(joinPackets({conditional(condition, 5, 3u << 25u), writeWord(results[3], 42), writeWord(condition, 1), conditional(condition, 5, 1u << 25u), writeWord(results[4], 43)}), 0x20);
|
||||
check(results[3] == 0 && results[4] == 43, "compute queue COND_EXEC with a cache policy evaluated wrong");
|
||||
|
||||
run(joinPackets({conditional(one, 10), conditional(zero, 10), writeWord(results[5], 51), writeWord(results[6], 52), writeWord(results[7], 53)}));
|
||||
check(results[5] == 0 && results[6] == 0 && results[7] == 53, "a nested COND_EXEC range reaching past the outer range was not skipped exactly");
|
||||
run(joinPackets({conditional(zero, 10), conditional(one, 10), writeWord(results[5], 54), writeWord(results[6], 55), writeWord(results[7], 56)}));
|
||||
check(results[5] == 0 && results[6] == 55 && results[7] == 56, "a skipped COND_EXEC range did not skip the COND_EXEC inside it");
|
||||
|
||||
static std::vector<std::uint32_t> target;
|
||||
target = joinPackets({writeWord(results[8], 61), conditional(zero, 5), writeWord(results[9], 62), writeWord(results[10], 63)});
|
||||
run(joinPackets({conditional(zero, 4), indirectBuffer(target), writeWord(results[11], 64)}));
|
||||
check(results[8] == 0 && results[10] == 0 && results[11] == 64, "COND_EXEC over an INDIRECT_BUFFER did not skip the whole buffer");
|
||||
run(joinPackets({conditional(one, 4), indirectBuffer(target), writeWord(results[11], 65)}));
|
||||
check(results[8] == 61 && results[9] == 0 && results[10] == 63 && results[11] == 65, "COND_EXEC over an INDIRECT_BUFFER or inside one evaluated wrong");
|
||||
|
||||
const auto rejected = [](std::vector<std::uint32_t> words, const char* text) {
|
||||
results[12] = 0;
|
||||
expectFailure([&] { submitWords(words); }, text);
|
||||
AgcDriverWaitIdle_nid_postfix();
|
||||
check(results[12] == 0, "a rejected conditional submission executed a prefix");
|
||||
};
|
||||
const auto sentinel = writeWord(results[12], 1);
|
||||
rejected(joinPackets({sentinel, conditional(one, 3), writeWord(results[13], 1)}), "ends inside a packet");
|
||||
rejected(joinPackets({sentinel, conditional(one, 6), writeWord(results[13], 1)}), "exceeds its command buffer");
|
||||
rejected(joinPackets({sentinel, conditional(one, 6), {0xc004105cu, 7, 0, 1, 0, 0}}), "a flip inside a conditional execution range");
|
||||
rejected(joinPackets({sentinel, conditional(one, 2), makePacket(0x59, {0x80000000u})}), "REWIND inside a conditional execution range");
|
||||
rejected(joinPackets({sentinel, conditional(one, 4), indirectBuffer(target, true)}), "chained INDIRECT_BUFFER");
|
||||
rejected(joinPackets({sentinel, conditional(one, 2), {0x40000000u, 0}}), "whole packets");
|
||||
rejected(joinPackets({sentinel, makePacket(0x22, {low(&one), high(&one), 0, 0x4005}), writeWord(results[13], 1)}), "reserved count bits");
|
||||
static std::vector<std::uint32_t> unaligned, overlong;
|
||||
unaligned = joinPackets({conditional(one, 3), writeWord(results[13], 1)});
|
||||
overlong = joinPackets({conditional(one, 10), writeWord(results[13], 1)});
|
||||
rejected(joinPackets({sentinel, indirectBuffer(unaligned)}), "ends inside a packet");
|
||||
rejected(joinPackets({sentinel, indirectBuffer(overlong), writeWord(results[13], 1)}), "exceeds its command buffer");
|
||||
check(results[13] == 0, "a rejected conditional submission executed a guarded packet");
|
||||
}
|
||||
|
||||
void testAsyncMemoryFailure() {
|
||||
auto commands = makePacket(0x37, {0x100, 0x1000, 0, 1});
|
||||
Packet packet{commands.data(), static_cast<std::uint32_t>(commands.size()), 0, {}};
|
||||
|
|
@ -572,11 +724,14 @@ int main(int argc, char** argv) {
|
|||
testCopies();
|
||||
testMemoryCopyDecode();
|
||||
testMemorySynchronization();
|
||||
testConditionalValidation();
|
||||
testConditionReadSynchronization();
|
||||
testEventWrite();
|
||||
testAcquireMem();
|
||||
testDriverSubmission();
|
||||
testConditionalSubmission();
|
||||
LibcRunShutdown_nid_postfix();
|
||||
std::puts("PM4 catalog, registers, state, memory and submission tests passed");
|
||||
std::puts("PM4 catalog, registers, state, memory, conditional execution and submission tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
|
|
|
|||
|
|
@ -2573,6 +2573,44 @@ void firstLayerViewTests(const Device& device, Recorder& recorder) {
|
|||
expectRed(program.Red(flatTexture.View(), flatTexture.Layout(), 0.0f), 0x20 / 255.0f, "a 2D texture over the surface does not read its first layer");
|
||||
}
|
||||
|
||||
void atomicViewTests(const Device& device, Recorder& recorder) {
|
||||
const auto& context = device.GetContext();
|
||||
TextureDetiler detiler(context);
|
||||
auto withDetiler = context;
|
||||
withDetiler.detiler = &detiler;
|
||||
for (const std::uint32_t format : {20u, 21u, 22u, 56u}) {
|
||||
GuestTextureResource resource{};
|
||||
resource.width = 64;
|
||||
resource.height = 4;
|
||||
resource.mipCount = 1;
|
||||
resource.tileMode = TextureTileMode::kLinear;
|
||||
resource.dimension = TextureDimension::k2D;
|
||||
resource.format = format;
|
||||
resource.dstSelX = 4;
|
||||
resource.dstSelY = 5;
|
||||
resource.dstSelZ = 6;
|
||||
resource.dstSelW = 7;
|
||||
const auto geometry = DescribeSurface(resource);
|
||||
std::vector<std::uint8_t> memory(static_cast<std::size_t>(geometry.guestBytes) + 256);
|
||||
resource.baseAddress = (reinterpret_cast<std::uintptr_t>(memory.data()) + 255) & ~std::uintptr_t{255};
|
||||
auto image = std::make_shared<StorageTexture>(withDetiler, detiler, resource, 0);
|
||||
recorder.Keep(image);
|
||||
if (format == 56u) {
|
||||
bool refused = false;
|
||||
try {
|
||||
static_cast<void>(image->AtomicView(0, false));
|
||||
} catch (const std::exception&) {
|
||||
refused = true;
|
||||
}
|
||||
Require(refused, "an 8_8_8_8 storage image has an atomic view");
|
||||
continue;
|
||||
}
|
||||
const auto atomic = image->AtomicView(0, false);
|
||||
Require(atomic != VK_NULL_HANDLE && atomic == image->AtomicView(0, false), "atomic storage views are not reused");
|
||||
Require((atomic == image->View(0)) == (format == 20u), "only a 32_UINT storage image serves atomics through its own view");
|
||||
}
|
||||
}
|
||||
|
||||
void keysFillTests(const Device& device, Recorder& recorder) {
|
||||
const auto& base = device.GetContext();
|
||||
if (base.hostImportAlignment == 0) {
|
||||
|
|
@ -2724,6 +2762,7 @@ int main() {
|
|||
dataRefreshTests(device, recorder);
|
||||
minLodTests(device, recorder);
|
||||
firstLayerViewTests(device, recorder);
|
||||
atomicViewTests(device, recorder);
|
||||
metadataPassTests(device, recorder);
|
||||
pendingKeyStoreTests(device, recorder);
|
||||
sampleDumpTests(device, recorder);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ void setEnvironment(const char* name, const std::string& value) {
|
|||
}
|
||||
|
||||
bool sameBinding(const DescriptorBinding& left, const DescriptorBinding& right) {
|
||||
return left.kind == right.kind && left.role == right.role && left.descriptorSet == right.descriptorSet && left.binding == right.binding && left.count == right.count && left.guestDescriptor == right.guestDescriptor && left.readOnly == right.readOnly && left.imageShape == right.imageShape && left.samplerDepthCompare == right.samplerDepthCompare && left.imageWritten == right.imageWritten && left.imageDepthCompare == right.imageDepthCompare && left.bufferAtomic == right.bufferAtomic && left.bufferWritten == right.bufferWritten;
|
||||
return left.kind == right.kind && left.role == right.role && left.descriptorSet == right.descriptorSet && left.binding == right.binding && left.count == right.count && left.guestDescriptor == right.guestDescriptor && left.readOnly == right.readOnly && left.imageShape == right.imageShape && left.samplerDepthCompare == right.samplerDepthCompare && left.imageWritten == right.imageWritten && left.imageDepthCompare == right.imageDepthCompare && left.imageAtomic == right.imageAtomic && left.bufferAtomic == right.bufferAtomic && left.bufferWritten == right.bufferWritten;
|
||||
}
|
||||
|
||||
bool sameBindings(const std::vector<DescriptorBinding>& left, const std::vector<DescriptorBinding>& right) {
|
||||
|
|
@ -92,6 +92,7 @@ DescriptorBinding sampleBinding(std::uint32_t seed) {
|
|||
binding.samplerDepthCompare = {true, false, true};
|
||||
binding.imageDepthCompare = {false, true, false};
|
||||
binding.imageWritten = {false, true, true};
|
||||
binding.imageAtomic = {false, true, false};
|
||||
binding.bufferAtomic = {true};
|
||||
binding.bufferWritten = {false, false, true, true, false};
|
||||
return binding;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,289 @@
|
|||
#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 <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t MaxThreads = 64;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Checked = 16;
|
||||
alignas(256) std::array<std::uint32_t, MaxThreads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, MaxThreads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 81> Wave32Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0x7e1402ff, 0xdeaddead, 0x7e1602ff,
|
||||
0xdeaddead, 0x7e1802ff, 0xdeaddead, 0x7e1a02ff, 0xdeaddead, 0x7e1c02ff, 0xdeaddead, 0x7e1e02ff,
|
||||
0xdeaddead, 0x7e2002ff, 0xdeaddead, 0x7e2202ff, 0xdeaddead, 0x7e2402ff, 0xdeaddead, 0x7e2602ff,
|
||||
0xdeaddead, 0x7e2802ff, 0xdeaddead, 0x7e2a02ff, 0xdeaddead, 0x7e2c02ff, 0xdeaddead, 0x7e2e02ff,
|
||||
0xdeaddead, 0x7e3002ff, 0xdeaddead, 0x7e3202ff, 0xdeaddead, 0xbefe03ff, 0x33cc0ff3, 0x7e1402fa,
|
||||
0xff015004, 0x7e1602fa, 0xff055504, 0x7e1802fa, 0xff095c04, 0x7e1a02fa, 0xff0d5804, 0x7e1c02fa,
|
||||
0x5a095f04, 0x7e1e02fa, 0xff016104, 0x7e2002fa, 0xff056604, 0x7e2202fa, 0xff096f04, 0x7e2402fa,
|
||||
0xa5016a04, 0x4a260afa, 0xff015304, 0x4a280afa, 0xff095c04, 0x4a2a0afa, 0x69055404, 0x4a2c0afa,
|
||||
0xff016404, 0x4c2e0afa, 0xff0d6d04, 0x20300efa, 0xff095406, 0x20320efa, 0xff056906, 0xbefe03c1,
|
||||
0xe0781000, 0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020, 0x80011203, 0xe0781030, 0x80011603,
|
||||
0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 83> Wave64Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0x7e1402ff, 0xdeaddead, 0x7e1602ff,
|
||||
0xdeaddead, 0x7e1802ff, 0xdeaddead, 0x7e1a02ff, 0xdeaddead, 0x7e1c02ff, 0xdeaddead, 0x7e1e02ff,
|
||||
0xdeaddead, 0x7e2002ff, 0xdeaddead, 0x7e2202ff, 0xdeaddead, 0x7e2402ff, 0xdeaddead, 0x7e2602ff,
|
||||
0xdeaddead, 0x7e2802ff, 0xdeaddead, 0x7e2a02ff, 0xdeaddead, 0x7e2c02ff, 0xdeaddead, 0x7e2e02ff,
|
||||
0xdeaddead, 0x7e3002ff, 0xdeaddead, 0x7e3202ff, 0xdeaddead, 0xbefe03ff, 0x33cc0ff3, 0xbeff03ff,
|
||||
0xc3a5960f, 0x7e1402fa, 0xff015004, 0x7e1602fa, 0xff055504, 0x7e1802fa, 0xff095c04, 0x7e1a02fa,
|
||||
0xff0d5804, 0x7e1c02fa, 0x5a095f04, 0x7e1e02fa, 0xff016104, 0x7e2002fa, 0xff056604, 0x7e2202fa,
|
||||
0xff096f04, 0x7e2402fa, 0xa5016a04, 0x4a260afa, 0xff015304, 0x4a280afa, 0xff095c04, 0x4a2a0afa,
|
||||
0x69055404, 0x4a2c0afa, 0xff016404, 0x4c2e0afa, 0xff0d6d04, 0x20300efa, 0xff095406, 0x20320efa,
|
||||
0xff056906, 0xbefe04c1, 0xe0781000, 0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020, 0x80011203,
|
||||
0xe0781030, 0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[64][4] = {
|
||||
{0x6ecd1cd2u, 0x4bef5ab2u, 0xc1f00000u, 0xc0c00000u},
|
||||
{0x6a003be9u, 0xe12916b9u, 0x422a0000u, 0x41fc0000u},
|
||||
{0xe8ace817u, 0x43f615feu, 0x42600000u, 0xc21e0000u},
|
||||
{0x4e3aa244u, 0x2d47d909u, 0x42540000u, 0xc2220000u},
|
||||
{0x68060c75u, 0xd69d14d5u, 0x41940000u, 0xc1d40000u},
|
||||
{0x5af9fb5au, 0x54393673u, 0x42440000u, 0xc1080000u},
|
||||
{0xad52f58fu, 0x3c3ff249u, 0x3fc00000u, 0xc26c0000u},
|
||||
{0xcb826265u, 0xd06f4fc2u, 0x425c0000u, 0xc2420000u},
|
||||
{0xc99d74ceu, 0xcb3eacf5u, 0x41ac0000u, 0x42320000u},
|
||||
{0x9c7fb5dbu, 0xa5e8a4bau, 0xc2340000u, 0xc24a0000u},
|
||||
{0x1e7cc79eu, 0x3197b5a3u, 0x41c00000u, 0x42420000u},
|
||||
{0x099b18b9u, 0xc7d8a2a5u, 0xc26a0000u, 0xc1980000u},
|
||||
{0x1504efdfu, 0x7e04a9d5u, 0xc2520000u, 0x422a0000u},
|
||||
{0xf200add6u, 0xd20e47a3u, 0xc1680000u, 0xc1380000u},
|
||||
{0xe31908c0u, 0x60de8b85u, 0xc20c0000u, 0x421a0000u},
|
||||
{0xf1c81bb0u, 0xa39b139du, 0x40000000u, 0xc2300000u},
|
||||
{0xdd7dd010u, 0x93d28ae8u, 0xc1f80000u, 0xc2460000u},
|
||||
{0xea239e60u, 0x1136bab0u, 0xc0900000u, 0xc1840000u},
|
||||
{0x4a248cbdu, 0x2cde59ccu, 0xc1380000u, 0xc1c40000u},
|
||||
{0x06734af7u, 0xfc5d75e7u, 0x40b00000u, 0xc2200000u},
|
||||
{0x76646c94u, 0x33cb3f0cu, 0xc25e0000u, 0xc2080000u},
|
||||
{0xc3f02221u, 0xba35f124u, 0xc2600000u, 0x424e0000u},
|
||||
{0xb955e2e5u, 0xb0a01d78u, 0xc1a40000u, 0x41300000u},
|
||||
{0xad47bf7du, 0x7e37ee41u, 0xc2380000u, 0x41e80000u},
|
||||
{0x4467b3a9u, 0xc243faa9u, 0x42400000u, 0x42280000u},
|
||||
{0xee39a32fu, 0x5d27404bu, 0xc1e00000u, 0xc2020000u},
|
||||
{0x362b62e4u, 0x40e07905u, 0x425e0000u, 0xc2640000u},
|
||||
{0x3597987bu, 0x9f2dda53u, 0xc1280000u, 0xc0200000u},
|
||||
{0x8cdfd404u, 0xaa825860u, 0x42700000u, 0x41940000u},
|
||||
{0x2883e9fdu, 0x6fcb4509u, 0xc1bc0000u, 0xc2700000u},
|
||||
{0xa64c74f6u, 0x6c225e76u, 0x41c40000u, 0xc22a0000u},
|
||||
{0xc9c4946du, 0x27f8b552u, 0x41300000u, 0xbf000000u},
|
||||
{0xec1dd6b9u, 0x37eae67cu, 0x42300000u, 0xc1fc0000u},
|
||||
{0x080a718au, 0xdd3a87b9u, 0xc1480000u, 0x426c0000u},
|
||||
{0x4d7d2f79u, 0x242b5b96u, 0xc1b80000u, 0xc25e0000u},
|
||||
{0xda0d5bd5u, 0xbd1eab24u, 0x41f40000u, 0xc2060000u},
|
||||
{0x30aa4ea5u, 0x908d264eu, 0xc0800000u, 0xc0c00000u},
|
||||
{0x4d4b8ec9u, 0x59f9bbd9u, 0xc1c40000u, 0x40c00000u},
|
||||
{0x008d7334u, 0x81e7a48bu, 0x3f800000u, 0x423a0000u},
|
||||
{0xa985a1d6u, 0x6454c697u, 0xc2300000u, 0xc22a0000u},
|
||||
{0x6945a98eu, 0x56efdfffu, 0x425e0000u, 0x41200000u},
|
||||
{0x543a17e0u, 0x9680cbfau, 0xc2360000u, 0xc20e0000u},
|
||||
{0x0e1e5311u, 0x8dbd6564u, 0xc2480000u, 0xc24c0000u},
|
||||
{0xd6c814a2u, 0x7f2c1289u, 0xc0b00000u, 0x41e00000u},
|
||||
{0x248db44au, 0xc60fd986u, 0x42400000u, 0xc2160000u},
|
||||
{0xd6c5e906u, 0x10117cecu, 0xc1f80000u, 0x41a80000u},
|
||||
{0x324909c5u, 0xdcd7b8c2u, 0x42080000u, 0x42220000u},
|
||||
{0xf995627fu, 0xc6e555f6u, 0xc2260000u, 0xc1800000u},
|
||||
{0x735c003eu, 0xc54e7632u, 0x41900000u, 0xc25a0000u},
|
||||
{0xfc3effbbu, 0x46c20a66u, 0xc1ec0000u, 0xc20a0000u},
|
||||
{0x0986feb5u, 0x040b21dfu, 0xc2180000u, 0x3f800000u},
|
||||
{0xacca236du, 0x7cfef2f2u, 0x40f00000u, 0x41cc0000u},
|
||||
{0x00bd61d8u, 0x5654123eu, 0x41400000u, 0xc1100000u},
|
||||
{0xe319a18bu, 0x5d8bc32du, 0x41100000u, 0xc2480000u},
|
||||
{0x6583147du, 0x72ce7a51u, 0x41780000u, 0x426e0000u},
|
||||
{0x49981da9u, 0x9b4ba109u, 0xc1a40000u, 0xc1e00000u},
|
||||
{0xe341cf98u, 0x3ec5433cu, 0xc0000000u, 0xc23c0000u},
|
||||
{0xc861e665u, 0xda64e2ddu, 0xc1f00000u, 0x41900000u},
|
||||
{0x8c31f3d4u, 0x807eed38u, 0xc1300000u, 0xc24e0000u},
|
||||
{0xf5411da7u, 0x6886f7e2u, 0xc1580000u, 0x420e0000u},
|
||||
{0x56aecd4cu, 0x7cfe2052u, 0xc23a0000u, 0x423a0000u},
|
||||
{0x29fc3f6du, 0x843d8b71u, 0x41d40000u, 0xbfc00000u},
|
||||
{0xf14c9634u, 0x6de904e9u, 0xc1c40000u, 0xc1180000u},
|
||||
{0x0524b659u, 0xb07d24c5u, 0xc22e0000u, 0xc23a0000u}
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Expected32[32][16] = {
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x6a003be9u, 0xad52f58fu, 0x00000000u, 0xdeaddeadu, 0xdeaddeadu, 0x4bef5ab2u, 0xdeaddeadu, 0xb3f56727u, 0xa6115324u, 0x41940000u, 0xc0c00000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x6ecd1cd2u, 0xcb826265u, 0x00000000u, 0xdeaddeadu, 0xdeaddeadu, 0xe12916b9u, 0xdeaddeadu, 0x3c231213u, 0x33dbd926u, 0x41fc0000u, 0x41fc0000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0x5af9fb5au, 0xe8ace817u, 0x099b18b9u, 0xdeaddeadu, 0xdeaddeadu, 0xd69d14d5u, 0xdeaddeadu, 0x456a31a7u, 0xc5e2a106u, 0x41940000u, 0xc1680000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0x68060c75u, 0x4e3aa244u, 0x1e7cc79eu, 0xdeaddeadu, 0xdeaddeadu, 0x54393673u, 0xdeaddeadu, 0xbe39725cu, 0x75643e5bu, 0x41940000u, 0xc1080000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0xcb826265u, 0x6ecd1cd2u, 0x9c7fb5dbu, 0xdeaddeadu, 0xdeaddeadu, 0x3c3ff249u, 0xdeaddeadu, 0xdeaddeadu, 0xcd5b2670u, 0x41940000u, 0x40000000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0xad52f58fu, 0x6a003be9u, 0xc99d74ceu, 0xdeaddeadu, 0xdeaddeadu, 0xd06f4fc2u, 0xdeaddeadu, 0xdeaddeadu, 0x4e0d77dcu, 0x41940000u, 0xc20c0000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x9c7fb5dbu, 0xe31908c0u, 0xcb826265u, 0xdeaddeadu, 0xdeaddeadu, 0xcb3eacf5u, 0xdeaddeadu, 0xdeaddeadu, 0x8fbb4e65u, 0x42320000u, 0x42320000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0xc99d74ceu, 0xf1c81bb0u, 0xad52f58fu, 0xdeaddeadu, 0xdeaddeadu, 0xa5e8a4bau, 0xdeaddeadu, 0xdeaddeadu, 0xc21d67bbu, 0x41940000u, 0xc1f00000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x099b18b9u, 0x1504efdfu, 0x5af9fb5au, 0xdeaddeadu, 0xdeaddeadu, 0x3197b5a3u, 0xdeaddeadu, 0xdeaddeadu, 0x99eaacc2u, 0x42420000u, 0x42540000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x1e7cc79eu, 0xf200add6u, 0x68060c75u, 0xdeaddeadu, 0xdeaddeadu, 0xc7d8a2a5u, 0xdeaddeadu, 0xdeaddeadu, 0xe57a52eau, 0x41940000u, 0x42600000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x06734af7u, 0x76646c94u, 0x2883e9fdu, 0x4467b3a9u, 0x3351a4c3u, 0xb9be2dd0u, 0xa342c660u, 0xe6343cb1u, 0x9ce63aa1u, 0x00000000u, 0xc1280000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x4a248cbdu, 0xc3f02221u, 0x8cdfd404u, 0xee39a32fu, 0x02d0c0deu, 0x893d49ebu, 0x72c1e27bu, 0xa9a53564u, 0xa9eeff0fu, 0x00000000u, 0x425e0000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0xad47bf7du, 0xdd7dd010u, 0xee39a32fu, 0xdeaddeadu, 0xb713686fu, 0x3d7ff17cu, 0xdeaddeadu, 0xfac4aa35u, 0x84f77b03u, 0x41300000u, 0x41300000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0xb955e2e5u, 0xea239e60u, 0x4467b3a9u, 0xdeaddeadu, 0x84ab3938u, 0x0b17c245u, 0xdeaddeadu, 0x84ab3938u, 0xb7f374a3u, 0x41e80000u, 0x41e80000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0xee39a32fu, 0xa64c74f6u, 0xad47bf7du, 0x4a248cbdu, 0xc8b745a0u, 0x4f23ceadu, 0xdeaddeadu, 0x4f23ceadu, 0x01ac2778u, 0x42280000u, 0x42280000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x4467b3a9u, 0xc9c4946du, 0xb955e2e5u, 0x06734af7u, 0x639a8b42u, 0xea07144fu, 0xdeaddeadu, 0x85ab2a48u, 0x193d2c49u, 0x00000000u, 0xc1f80000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x2883e9fdu, 0x362b62e4u, 0x06734af7u, 0xdeaddeadu, 0xb0f5a357u, 0x37622c64u, 0x20e6c4f4u, 0xeeea0c09u, 0x3fa14600u, 0x41940000u, 0x41940000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x8cdfd404u, 0x3597987bu, 0x4a248cbdu, 0xdeaddeadu, 0x763e9000u, 0xfcab190du, 0xe62fb19du, 0x5e04e838u, 0x6db28b07u, 0x00000000u, 0xc25e0000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu}
|
||||
};
|
||||
constexpr std::uint32_t Expected64[64][16] = {
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x6a003be9u, 0xad52f58fu, 0x00000000u, 0xdeaddeadu, 0xdeaddeadu, 0x4bef5ab2u, 0xdeaddeadu, 0xb3f56727u, 0xa6115324u, 0x41940000u, 0xc0c00000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x6ecd1cd2u, 0xcb826265u, 0x00000000u, 0xdeaddeadu, 0xdeaddeadu, 0xe12916b9u, 0xdeaddeadu, 0x3c231213u, 0x33dbd926u, 0x41fc0000u, 0x41fc0000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0x5af9fb5au, 0xe8ace817u, 0x099b18b9u, 0xdeaddeadu, 0xdeaddeadu, 0xd69d14d5u, 0xdeaddeadu, 0x456a31a7u, 0xc5e2a106u, 0x41940000u, 0xc1680000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0x68060c75u, 0x4e3aa244u, 0x1e7cc79eu, 0xdeaddeadu, 0xdeaddeadu, 0x54393673u, 0xdeaddeadu, 0xbe39725cu, 0x75643e5bu, 0x41940000u, 0xc1080000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0xcb826265u, 0x6ecd1cd2u, 0x9c7fb5dbu, 0xdeaddeadu, 0xdeaddeadu, 0x3c3ff249u, 0xdeaddeadu, 0xdeaddeadu, 0xcd5b2670u, 0x41940000u, 0x40000000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0x00000000u, 0xad52f58fu, 0x6a003be9u, 0xc99d74ceu, 0xdeaddeadu, 0xdeaddeadu, 0xd06f4fc2u, 0xdeaddeadu, 0xdeaddeadu, 0x4e0d77dcu, 0x41940000u, 0xc20c0000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x9c7fb5dbu, 0xe31908c0u, 0xcb826265u, 0xdeaddeadu, 0xdeaddeadu, 0xcb3eacf5u, 0xdeaddeadu, 0xdeaddeadu, 0x8fbb4e65u, 0x42320000u, 0x42320000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0xc99d74ceu, 0xf1c81bb0u, 0xad52f58fu, 0xdeaddeadu, 0xdeaddeadu, 0xa5e8a4bau, 0xdeaddeadu, 0xdeaddeadu, 0xc21d67bbu, 0x41940000u, 0xc1f00000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x099b18b9u, 0x1504efdfu, 0x5af9fb5au, 0xdeaddeadu, 0xdeaddeadu, 0x3197b5a3u, 0xdeaddeadu, 0xdeaddeadu, 0x99eaacc2u, 0x42420000u, 0x42540000u},
|
||||
{0x6ecd1cd2u, 0x5af9fb5au, 0x00000000u, 0xc99d74ceu, 0xdeaddeadu, 0x1e7cc79eu, 0xf200add6u, 0x68060c75u, 0xdeaddeadu, 0xdeaddeadu, 0xc7d8a2a5u, 0xdeaddeadu, 0xdeaddeadu, 0xe57a52eau, 0x41940000u, 0x42600000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x06734af7u, 0x76646c94u, 0x2883e9fdu, 0x4467b3a9u, 0x3351a4c3u, 0xb9be2dd0u, 0xa342c660u, 0xe6343cb1u, 0x9ce63aa1u, 0x00000000u, 0xc1280000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x4a248cbdu, 0xc3f02221u, 0x8cdfd404u, 0xee39a32fu, 0x02d0c0deu, 0x893d49ebu, 0x72c1e27bu, 0xa9a53564u, 0xa9eeff0fu, 0x00000000u, 0x425e0000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0xad47bf7du, 0xdd7dd010u, 0xee39a32fu, 0xdeaddeadu, 0xb713686fu, 0x3d7ff17cu, 0xdeaddeadu, 0xfac4aa35u, 0x84f77b03u, 0x41300000u, 0x41300000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0xb955e2e5u, 0xea239e60u, 0x4467b3a9u, 0xdeaddeadu, 0x84ab3938u, 0x0b17c245u, 0xdeaddeadu, 0x84ab3938u, 0xb7f374a3u, 0x41e80000u, 0x41e80000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0xee39a32fu, 0xa64c74f6u, 0xad47bf7du, 0x4a248cbdu, 0xc8b745a0u, 0x4f23ceadu, 0xdeaddeadu, 0x4f23ceadu, 0x01ac2778u, 0x42280000u, 0x42280000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x4467b3a9u, 0xc9c4946du, 0xb955e2e5u, 0x06734af7u, 0x639a8b42u, 0xea07144fu, 0xdeaddeadu, 0x85ab2a48u, 0x193d2c49u, 0x00000000u, 0xc1f80000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x2883e9fdu, 0x362b62e4u, 0x06734af7u, 0xdeaddeadu, 0xb0f5a357u, 0x37622c64u, 0x20e6c4f4u, 0xeeea0c09u, 0x3fa14600u, 0x41940000u, 0x41940000u},
|
||||
{0xdeaddeadu, 0xc3f02221u, 0x8cdfd404u, 0x4467b3a9u, 0xdeaddeadu, 0x8cdfd404u, 0x3597987bu, 0x4a248cbdu, 0xdeaddeadu, 0x763e9000u, 0xfcab190du, 0xe62fb19du, 0x5e04e838u, 0x6db28b07u, 0x00000000u, 0xc25e0000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xdeaddeadu, 0x080a718au, 0x008d7334u, 0xf995627fu, 0xdeaddeadu, 0x11f84251u, 0x5c789ac6u, 0x68953521u, 0xdeaddeadu, 0x9edb028au, 0x00000000u, 0xc1fc0000u},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xdeaddeadu, 0xec1dd6b9u, 0xa985a1d6u, 0x00000000u, 0xdeaddeadu, 0xb747e38eu, 0x01c83c03u, 0x0de4d65eu, 0xdeaddeadu, 0x47532c91u, 0x426c0000u, 0x426c0000u},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xdeaddeadu, 0xda0d5bd5u, 0x30aa4ea5u, 0x00000000u, 0xdeaddeadu, 0xfe38b76bu, 0x48b90fe0u, 0x54d5aa3bu, 0xdeaddeadu, 0xd56a06e9u, 0x00000000u, 0xc0b00000u},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xdeaddeadu, 0x4d7d2f79u, 0x4d4b8ec9u, 0x248db44au, 0xdeaddeadu, 0x972c06f9u, 0xe1ac5f6eu, 0xedc8f9c9u, 0xdeaddeadu, 0x752a5ea1u, 0x00000000u, 0xc2060000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xdeaddeadu, 0xdeaddeadu, 0xf995627fu, 0x00000000u, 0xdeaddeadu, 0x708e27cfu, 0xbb0e8044u, 0xdeaddeadu, 0xdeaddeadu, 0x9a2982abu, 0x00000000u, 0x42300000u},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xdeaddeadu, 0xdeaddeadu, 0x248db44au, 0x00000000u, 0xdeaddeadu, 0x67cac139u, 0xb24b19aeu, 0xdeaddeadu, 0xdeaddeadu, 0x1bc83c72u, 0x00000000u, 0x41f40000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xf995627fu, 0xdeaddeadu, 0x0e1e5311u, 0xda0d5bd5u, 0xdeaddeadu, 0xa01d355bu, 0xea9d8dd0u, 0xf6ba282bu, 0xdeaddeadu, 0x41fa9804u, 0x00000000u, 0xc1c40000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xec1dd6b9u, 0x4d4b8ec9u, 0x248db44au, 0x6945a98eu, 0xf995627fu, 0xdeaddeadu, 0x543a17e0u, 0xec1dd6b9u, 0xdeaddeadu, 0xa0f2b1cbu, 0xeb730a40u, 0xf78fa49bu, 0xdeaddeadu, 0x8697d983u, 0x00000000u, 0x3f800000u},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0xdeaddeadu, 0x6583147du, 0x0524b659u, 0xdeaddeadu, 0xdeaddeadu, 0xc54e7632u, 0xdeaddeadu, 0xdeaddeadu, 0x64adc93bu, 0x00000000u, 0xc1f00000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0xdeaddeadu, 0x00bd61d8u, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0x040b21dfu, 0xdeaddeadu, 0xdeaddeadu, 0x0119947au, 0x3f800000u, 0x3f800000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0xdeaddeadu, 0xacca236du, 0x00000000u, 0xdeaddeadu, 0xdeaddeadu, 0x5d8bc32du, 0xdeaddeadu, 0xdeaddeadu, 0x85b60c6bu, 0x00000000u, 0xc23a0000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0xdeaddeadu, 0xfc3effbbu, 0xe341cf98u, 0xdeaddeadu, 0xdeaddeadu, 0x9b4ba109u, 0xdeaddeadu, 0xdeaddeadu, 0xf0e652cbu, 0x00000000u, 0xc1c40000u},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0xc861e665u, 0xf14c9634u, 0x49981da9u, 0x0986feb5u, 0xdeaddeadu, 0x3ec5433cu, 0xdeaddeadu, 0xdeaddeadu, 0xa4545e4fu, 0x00000000u, 0xc1ec0000u},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0xe341cf98u, 0x0524b659u, 0x00000000u, 0xdeaddeadu, 0xdeaddeadu, 0xda64e2ddu, 0xdeaddeadu, 0xdeaddeadu, 0x26587efbu, 0x41900000u, 0x41900000u},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu, 0xdeaddeadu},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0x0524b659u, 0xe341cf98u, 0x00000000u, 0xdeaddeadu, 0xdeaddeadu, 0x6de904e9u, 0xdeaddeadu, 0xdeaddeadu, 0x3ee11e84u, 0x00000000u, 0xc1180000u},
|
||||
{0x735c003eu, 0xe319a18bu, 0x00000000u, 0xe341cf98u, 0xdeaddeadu, 0xf14c9634u, 0xc861e665u, 0x735c003eu, 0xdeaddeadu, 0xdeaddeadu, 0xb07d24c5u, 0xdeaddeadu, 0xdeaddeadu, 0x5909d9f0u, 0x00000000u, 0x41780000u}
|
||||
};
|
||||
|
||||
constexpr const char* Names[Checked] = {"mov_row_share0", "mov_row_share5_fi", "mov_row_share12_bc", "mov_row_share8_bc_fi", "mov_row_share15_masks", "mov_row_xmask1", "mov_row_xmask6_fi", "mov_row_xmask15_bc", "mov_row_xmask10_masks", "add_row_share3", "add_row_share12_bc", "add_row_share4_fi_masks", "add_row_xmask4", "sub_row_xmask13_bc_fi", "max_f32_row_share4_bc", "max_f32_row_xmask9_fi"};
|
||||
|
||||
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 Run(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, std::uint32_t waveSize, const ShaderRecompiler::SpirvTarget& target) {
|
||||
for (std::uint32_t tid = 0; tid < MaxThreads; ++tid) std::copy(std::begin(Rows[tid]), std::end(Rows[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::array<ShaderRecompiler::MemoryRegion, 1> memory{{{reinterpret_cast<std::uintptr_t>(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<std::uintptr_t>(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<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
template<std::size_t Lanes>
|
||||
void Check(const std::uint32_t (&expected)[Lanes][Checked]) {
|
||||
for (std::uint32_t tid = 0; tid < Lanes; ++tid) {
|
||||
for (std::uint32_t index = 0; index < Checked; ++index) {
|
||||
const auto actual = Output[tid * Results + index];
|
||||
Require(actual == expected[tid][index], "dpp16 row share xmask wave" + std::to_string(Lanes) + ": lane " + std::to_string(tid) + " " + Names[index] + " is " + Hex(actual) + ", expected " + Hex(expected[tid][index]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
if (device->Target().subgroupSize < 32) {
|
||||
std::printf("skipped, subgroup size %u cannot hold a wave32\n", device->Target().subgroupSize);
|
||||
return VulkanTestSkipped;
|
||||
}
|
||||
Run(*device, Wave32Code, 32, device->ComputeTarget(32));
|
||||
Check(Expected32);
|
||||
Run(*device, Wave64Code, 64, device->Target());
|
||||
Check(Expected64);
|
||||
Run(*device, Wave64Code, 64, device->ComputeTarget(32));
|
||||
Check(Expected64);
|
||||
std::puts("dpp16 row share xmask tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -23,62 +23,58 @@ namespace {
|
|||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 64;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 4;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::uint8_t Fill = 0xcd;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 58> FlatCacheBitsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0xd70f6a1e, 0x02020208, 0x7e3e0209,
|
||||
0x503e3e80, 0xdc318000, 0x0a080001, 0xdc328004, 0x0b080001, 0xdc309008, 0x0c080001, 0xdc33900c,
|
||||
0x0d080001, 0xdc359004, 0x0e080001, 0xdc228001, 0x10080001, 0xdc259007, 0x11080001, 0xbf8c3f70,
|
||||
0xdc739000, 0x00080501, 0xdc628006, 0x00080601, 0xbf8c3f70, 0xdc359000, 0x12080001, 0xdccb9008,
|
||||
0x14080701, 0xdcce900c, 0x00080401, 0xbf8c3f70, 0xdc358008, 0x15080001, 0xdc311000, 0x177d001e,
|
||||
0xdc730000, 0x007d071e, 0xbf8c0070, 0xdcef1000, 0x187d061e, 0xbf8c0070, 0xdc320000, 0x197d001e,
|
||||
0xbf8c0070, 0xe0781000, 0x80010a02, 0xe0781010, 0x80010e02, 0xe0781020, 0x80011202, 0xe0781030,
|
||||
0x80011602, 0xbf810000
|
||||
alignas(256) constexpr std::array<std::uint32_t, 24> FlatCacheBitsCode{
|
||||
0x34020084, 0x34040084, 0xd70f6a1e, 0x02020208, 0x7e3e0209, 0x503e3e80, 0xd70f6a1e, 0x02023c8c,
|
||||
0x503e3e80, 0xdc379000, 0x0a080001, 0xdc331000, 0x0d7d001e, 0xbf8c0070, 0xdc739004, 0x00080d01,
|
||||
0xdccb9008, 0x0c080a01, 0xdc731000, 0x007d0b1e, 0xbf8c0070, 0xe0781000, 0x80010a02, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> memory;
|
||||
std::array<std::uint32_t, Results> results;
|
||||
std::array<std::uint32_t, 4> final;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, 32> Rows{{
|
||||
{{0x00000001, 0x0000007f, 0x00000080, 0x7fffffff}, {0x00000001, 0x0000007f, 0x00000080, 0x7fffffff, 0x0000007f, 0x00000080, 0x00000000, 0x00000000, 0x0000007f, 0x0080007f, 0x00000080, 0x8000007f, 0x7ffffffe, 0x0000007f, 0x7fffffff, 0x7fffff7f}},
|
||||
{{0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01}, {0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01, 0x000000ff, 0x80000000, 0x00000000, 0x00000000, 0x000000ff, 0x000000ff, 0x80000000, 0x00ff7f01, 0x80ff7e82, 0x000000ff, 0x80ff7f01, 0x00ff7f01}},
|
||||
{{0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff}, {0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff, 0x80000000, 0xdeadbeef, 0x00000000, 0xffffff80, 0x80000000, 0x80ef0000, 0xdeadbeef, 0xdeadbfee, 0x0000007f, 0x80000000, 0x000000ff, 0xdeadbe10}},
|
||||
{{0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef}, {0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef, 0x12345678, 0x00000001, 0x00000000, 0x00000012, 0x12345678, 0x12015678, 0x00000001, 0xdeadbef0, 0xdeadbdf0, 0x12345678, 0xdeadbeef, 0xdeadbeee}},
|
||||
{{0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080}, {0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080, 0x80ff7f01, 0x000000ff, 0x000000ff, 0xffffff80, 0x80ff7f01, 0x80ff7f01, 0x000000ff, 0x0000017f, 0x80000081, 0x80ff7f01, 0x00000080, 0x0000007f}},
|
||||
{{0x80000000, 0x00000001, 0xffffffff, 0x12345678}, {0x80000000, 0x00000001, 0xffffffff, 0x12345678, 0x00000001, 0xffffffff, 0x00000000, 0x00000000, 0x00000001, 0x00ff0001, 0xffffffff, 0x12345677, 0x92345678, 0x00000001, 0x12345678, 0xedcba987}},
|
||||
{{0xffffffff, 0x00000080, 0x80ff7f01, 0x0000007f}, {0xffffffff, 0x00000080, 0x80ff7f01, 0x0000007f, 0x00000080, 0x80ff7f01, 0x000000ff, 0x00000000, 0x00000080, 0x00010080, 0x80ff7f01, 0x80ff7f80, 0x00000080, 0x00000080, 0x0000007f, 0x80ff7f7e}},
|
||||
{{0x12345678, 0x7fffffff, 0x0000007f, 0xffffffff}, {0x12345678, 0x7fffffff, 0x0000007f, 0xffffffff, 0x7fffffff, 0x0000007f, 0x00000056, 0x0000007f, 0x7fffffff, 0x7f7fffff, 0x0000007f, 0x0000007e, 0xedcba987, 0x7fffffff, 0xffffffff, 0xffffff80}},
|
||||
{{0xdeadbeef, 0xffffffff, 0x7fffffff, 0x00000001}, {0xdeadbeef, 0xffffffff, 0x7fffffff, 0x00000001, 0xffffffff, 0x7fffffff, 0x000000be, 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff, 0x80000000, 0x21524112, 0xffffffff, 0x00000001, 0x7ffffffe}},
|
||||
{{0x80ff7f01, 0xdeadbeef, 0x12345678, 0x80000000}, {0x80ff7f01, 0xdeadbeef, 0x12345678, 0x80000000, 0xdeadbeef, 0x12345678, 0x0000007f, 0xffffffde, 0xdeadbeef, 0xde78beef, 0x12345678, 0x92345678, 0xff0080ff, 0xdeadbeef, 0x80000000, 0x92345678}},
|
||||
{{0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
{{0x00000001, 0x0000007f, 0x00000080, 0x7fffffff}, {0x00000001, 0x0000007f, 0x00000080, 0x7fffffff, 0x0000007f, 0x00000080, 0x00000000, 0x00000000, 0x0000007f, 0x0080007f, 0x00000080, 0x8000007f, 0x7ffffffe, 0x0000007f, 0x7fffffff, 0x7fffff7f}},
|
||||
{{0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01}, {0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01, 0x000000ff, 0x80000000, 0x00000000, 0x00000000, 0x000000ff, 0x000000ff, 0x80000000, 0x00ff7f01, 0x80ff7e82, 0x000000ff, 0x80ff7f01, 0x00ff7f01}},
|
||||
{{0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff}, {0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff, 0x80000000, 0xdeadbeef, 0x00000000, 0xffffff80, 0x80000000, 0x80ef0000, 0xdeadbeef, 0xdeadbfee, 0x0000007f, 0x80000000, 0x000000ff, 0xdeadbe10}},
|
||||
{{0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef}, {0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef, 0x12345678, 0x00000001, 0x00000000, 0x00000012, 0x12345678, 0x12015678, 0x00000001, 0xdeadbef0, 0xdeadbdf0, 0x12345678, 0xdeadbeef, 0xdeadbeee}},
|
||||
{{0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080}, {0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080, 0x80ff7f01, 0x000000ff, 0x000000ff, 0xffffff80, 0x80ff7f01, 0x80ff7f01, 0x000000ff, 0x0000017f, 0x80000081, 0x80ff7f01, 0x00000080, 0x0000007f}},
|
||||
{{0x2265b1f5, 0x91b7584a, 0xd8f16adf, 0xcd613e30}, {0x2265b1f5, 0x91b7584a, 0xd8f16adf, 0xcd613e30, 0x91b7584a, 0xd8f16adf, 0x000000b1, 0xffffff91, 0x91b7584a, 0x91df584a, 0xd8f16adf, 0xa652a90f, 0xaafb8c3b, 0x91b7584a, 0xcd613e30, 0x159054ef}},
|
||||
{{0xc386bbc4, 0x1027c4d1, 0x414c343c, 0x1e2feb89}, {0xc386bbc4, 0x1027c4d1, 0x414c343c, 0x1e2feb89, 0x1027c4d1, 0x414c343c, 0x000000bb, 0x00000010, 0x1027c4d1, 0x103cc4d1, 0x414c343c, 0x5f7c1fc5, 0x5aa92fc5, 0x1027c4d1, 0x1e2feb89, 0x5f63dfb5}},
|
||||
{{0x7ed4d57b, 0xc2ce6f44, 0x7311d8a3, 0x78e51061}, {0x7ed4d57b, 0xc2ce6f44, 0x7311d8a3, 0x78e51061, 0xc2ce6f44, 0x7311d8a3, 0x000000d5, 0xffffffc2, 0xc2ce6f44, 0xc2a36f44, 0x7311d8a3, 0xebf6e904, 0xfa103ae6, 0xc2ce6f44, 0x78e51061, 0x0bf4c8c2}},
|
||||
{{0xa6cecc1b, 0x612e7696, 0xc9e9c616, 0x35bf992d}, {0xa6cecc1b, 0x612e7696, 0xc9e9c616, 0x35bf992d, 0x612e7696, 0xc9e9c616, 0x000000cc, 0x00000061, 0x612e7696, 0x61167696, 0xc9e9c616, 0xffa95f43, 0x8ef0cd12, 0x612e7696, 0x35bf992d, 0xfc565f3b}},
|
||||
{{0x18072e8c, 0x7ce42c82, 0x0741c7a8, 0xe4b06ce6}, {0x18072e8c, 0x7ce42c82, 0x0741c7a8, 0xe4b06ce6, 0x7ce42c82, 0x0741c7a8, 0x0000002e, 0x0000007c, 0x7ce42c82, 0x7ca82c82, 0x0741c7a8, 0xebf2348e, 0xcca93e5a, 0x7ce42c82, 0xe4b06ce6, 0xe3f1ab4e}},
|
||||
{{0xd5f4b3b2, 0x63ca828d, 0x6ec9d286, 0x9b810e76}, {0xd5f4b3b2, 0x63ca828d, 0x6ec9d286, 0x9b810e76, 0x63ca828d, 0x6ec9d286, 0x000000b3, 0x00000063, 0x63ca828d, 0x6386828d, 0x6ec9d286, 0x0a4ae0fc, 0xc58c5ac4, 0x63ca828d, 0x9b810e76, 0xf548dcf0}},
|
||||
{{0xc324c985, 0xc4647159, 0x008a05a6, 0xb2221a58}, {0xc324c985, 0xc4647159, 0x008a05a6, 0xb2221a58, 0xc4647159, 0x008a05a6, 0x000000c9, 0xffffffc4, 0xc4647159, 0xc4a67159, 0x008a05a6, 0xb2ac1ffe, 0xeefd50d3, 0xc4647159, 0xb2221a58, 0xb2a81ffe}},
|
||||
{{0x7204e52d, 0x442e3d43, 0xb8b6d8fe, 0xcd447e35}, {0x7204e52d, 0x442e3d43, 0xb8b6d8fe, 0xcd447e35, 0x442e3d43, 0xb8b6d8fe, 0x000000e5, 0x00000044, 0x442e3d43, 0x44fe3d43, 0xb8b6d8fe, 0x85fb5733, 0x5b3f9908, 0x442e3d43, 0xcd447e35, 0x75f2a6cb}},
|
||||
{{0x3a902931, 0x9755d4c1, 0xf1fd42a2, 0x1a2b8f1f}, {0x3a902931, 0x9755d4c1, 0xf1fd42a2, 0x1a2b8f1f, 0x9755d4c1, 0xf1fd42a2, 0x00000029, 0xffffff97, 0x9755d4c1, 0x97a2d4c1, 0xf1fd42a2, 0x0c28d1c1, 0xdf9b65ee, 0x9755d4c1, 0x1a2b8f1f, 0xebd6cdbd}},
|
||||
{{0xe6c3f339, 0x51431193, 0x07d4bedc, 0x05b6e6e3}, {0xe6c3f339, 0x51431193, 0x07d4bedc, 0x05b6e6e3, 0x51431193, 0x07d4bedc, 0x000000f3, 0x00000051, 0x51431193, 0x51dc1193, 0x07d4bedc, 0x0d8ba5bf, 0x1ef2f3aa, 0x51431193, 0x05b6e6e3, 0x0262583f}},
|
||||
{{0x06839eb9, 0xa648a7dd, 0x8a9a021e, 0x025b413f}, {0x06839eb9, 0xa648a7dd, 0x8a9a021e, 0x025b413f, 0xa648a7dd, 0x8a9a021e, 0x0000009e, 0xffffffa6, 0xa648a7dd, 0xa61ea7dd, 0x8a9a021e, 0x8cf5435d, 0xfbd7a286, 0xa648a7dd, 0x025b413f, 0x88c14321}},
|
||||
{{0xf06c144a, 0xe1988ad9, 0x619699cf, 0xafbd67f9}, {0xf06c144a, 0xe1988ad9, 0x619699cf, 0xafbd67f9, 0xe1988ad9, 0x619699cf, 0x00000014, 0xffffffe1, 0xe1988ad9, 0xe1cf8ad9, 0x619699cf, 0x115401c8, 0xbf5153af, 0xe1988ad9, 0xafbd67f9, 0xce2bfe36}},
|
||||
{{0x37730edf, 0xf8130c42, 0x6c0fd4f5, 0xb9d179e0}, {0x37730edf, 0xf8130c42, 0x6c0fd4f5, 0xb9d179e0, 0xf8130c42, 0x6c0fd4f5, 0x0000000e, 0xfffffff8, 0xf8130c42, 0xf8f50c42, 0x6c0fd4f5, 0x25e14ed5, 0x825e6b01, 0xf8130c42, 0xb9d179e0, 0xd5dead15}},
|
||||
{{0x076f3787, 0x8712b8bc, 0x38c0c8fd, 0xc381e88f}, {0x076f3787, 0x8712b8bc, 0x38c0c8fd, 0xc381e88f, 0x8712b8bc, 0x38c0c8fd, 0x00000037, 0xffffff87, 0x8712b8bc, 0x87fdb8bc, 0x38c0c8fd, 0xfc42b18c, 0xbc12b108, 0x8712b8bc, 0xc381e88f, 0xfb412072}},
|
||||
{{0x701966a0, 0xf06d3fef, 0x7eed8d14, 0x8d88348a}, {0x701966a0, 0xf06d3fef, 0x7eed8d14, 0x8d88348a, 0xf06d3fef, 0x7eed8d14, 0x00000066, 0xfffffff0, 0xf06d3fef, 0xf0143fef, 0x7eed8d14, 0x0c75c19e, 0x1d6ecdea, 0xf06d3fef, 0x8d88348a, 0xf365b99e}},
|
||||
{{0x3bab6c39, 0x587fd280, 0x3b1a11df, 0xad45f23d}, {0x3bab6c39, 0x587fd280, 0x3b1a11df, 0xad45f23d, 0x587fd280, 0x3b1a11df, 0x0000006c, 0x00000058, 0x587fd280, 0x58dfd280, 0x3b1a11df, 0xe860041c, 0x719a8604, 0x587fd280, 0xad45f23d, 0x965fe3e2}}
|
||||
{{0x00000001, 0x0000007f, 0x00000080, 0x7fffffff}, {0x00000001, 0x0000007f, 0x00000080, 0x7fffffff}, {0x00000001, 0x7fffffff, 0x00000081, 0x0000007f}},
|
||||
{{0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01}, {0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01}, {0x0000007f, 0x80ff7f01, 0x8000007f, 0x000000ff}},
|
||||
{{0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff}, {0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff}, {0x00000080, 0x000000ff, 0xdeadbf6f, 0x80000000}},
|
||||
{{0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef}, {0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef}, {0x000000ff, 0xdeadbeef, 0x00000100, 0x12345678}},
|
||||
{{0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080}, {0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080}, {0x7fffffff, 0x00000080, 0x800000fe, 0x80ff7f01}},
|
||||
{{0x80000000, 0x00000001, 0xffffffff, 0x12345678}, {0x80000000, 0x00000001, 0xffffffff, 0x12345678}, {0x80000000, 0x12345678, 0x7fffffff, 0x00000001}},
|
||||
{{0xffffffff, 0x00000080, 0x80ff7f01, 0x0000007f}, {0xffffffff, 0x00000080, 0x80ff7f01, 0x0000007f}, {0xffffffff, 0x0000007f, 0x80ff7f00, 0x00000080}},
|
||||
{{0x12345678, 0x7fffffff, 0x0000007f, 0xffffffff}, {0x12345678, 0x7fffffff, 0x0000007f, 0xffffffff}, {0x12345678, 0xffffffff, 0x123456f7, 0x7fffffff}},
|
||||
{{0xdeadbeef, 0xffffffff, 0x7fffffff, 0x00000001}, {0xdeadbeef, 0xffffffff, 0x7fffffff, 0x00000001}, {0xdeadbeef, 0x00000001, 0x5eadbeee, 0xffffffff}},
|
||||
{{0x80ff7f01, 0xdeadbeef, 0x12345678, 0x80000000}, {0x80ff7f01, 0xdeadbeef, 0x12345678, 0x80000000}, {0x80ff7f01, 0x80000000, 0x9333d579, 0xdeadbeef}},
|
||||
{{0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||
{{0x00000001, 0x0000007f, 0x00000080, 0x7fffffff}, {0x00000001, 0x0000007f, 0x00000080, 0x7fffffff}, {0x00000001, 0x7fffffff, 0x00000081, 0x0000007f}},
|
||||
{{0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01}, {0x0000007f, 0x000000ff, 0x80000000, 0x80ff7f01}, {0x0000007f, 0x80ff7f01, 0x8000007f, 0x000000ff}},
|
||||
{{0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff}, {0x00000080, 0x80000000, 0xdeadbeef, 0x000000ff}, {0x00000080, 0x000000ff, 0xdeadbf6f, 0x80000000}},
|
||||
{{0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef}, {0x000000ff, 0x12345678, 0x00000001, 0xdeadbeef}, {0x000000ff, 0xdeadbeef, 0x00000100, 0x12345678}},
|
||||
{{0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080}, {0x7fffffff, 0x80ff7f01, 0x000000ff, 0x00000080}, {0x7fffffff, 0x00000080, 0x800000fe, 0x80ff7f01}},
|
||||
{{0x2265b1f5, 0x91b7584a, 0xd8f16adf, 0xcd613e30}, {0x2265b1f5, 0x91b7584a, 0xd8f16adf, 0xcd613e30}, {0x2265b1f5, 0xcd613e30, 0xfb571cd4, 0x91b7584a}},
|
||||
{{0xc386bbc4, 0x1027c4d1, 0x414c343c, 0x1e2feb89}, {0xc386bbc4, 0x1027c4d1, 0x414c343c, 0x1e2feb89}, {0xc386bbc4, 0x1e2feb89, 0x04d2f000, 0x1027c4d1}},
|
||||
{{0x7ed4d57b, 0xc2ce6f44, 0x7311d8a3, 0x78e51061}, {0x7ed4d57b, 0xc2ce6f44, 0x7311d8a3, 0x78e51061}, {0x7ed4d57b, 0x78e51061, 0xf1e6ae1e, 0xc2ce6f44}},
|
||||
{{0xa6cecc1b, 0x612e7696, 0xc9e9c616, 0x35bf992d}, {0xa6cecc1b, 0x612e7696, 0xc9e9c616, 0x35bf992d}, {0xa6cecc1b, 0x35bf992d, 0x70b89231, 0x612e7696}},
|
||||
{{0x18072e8c, 0x7ce42c82, 0x0741c7a8, 0xe4b06ce6}, {0x18072e8c, 0x7ce42c82, 0x0741c7a8, 0xe4b06ce6}, {0x18072e8c, 0xe4b06ce6, 0x1f48f634, 0x7ce42c82}},
|
||||
{{0xd5f4b3b2, 0x63ca828d, 0x6ec9d286, 0x9b810e76}, {0xd5f4b3b2, 0x63ca828d, 0x6ec9d286, 0x9b810e76}, {0xd5f4b3b2, 0x9b810e76, 0x44be8638, 0x63ca828d}},
|
||||
{{0xc324c985, 0xc4647159, 0x008a05a6, 0xb2221a58}, {0xc324c985, 0xc4647159, 0x008a05a6, 0xb2221a58}, {0xc324c985, 0xb2221a58, 0xc3aecf2b, 0xc4647159}},
|
||||
{{0x7204e52d, 0x442e3d43, 0xb8b6d8fe, 0xcd447e35}, {0x7204e52d, 0x442e3d43, 0xb8b6d8fe, 0xcd447e35}, {0x7204e52d, 0xcd447e35, 0x2abbbe2b, 0x442e3d43}},
|
||||
{{0x3a902931, 0x9755d4c1, 0xf1fd42a2, 0x1a2b8f1f}, {0x3a902931, 0x9755d4c1, 0xf1fd42a2, 0x1a2b8f1f}, {0x3a902931, 0x1a2b8f1f, 0x2c8d6bd3, 0x9755d4c1}},
|
||||
{{0xe6c3f339, 0x51431193, 0x07d4bedc, 0x05b6e6e3}, {0xe6c3f339, 0x51431193, 0x07d4bedc, 0x05b6e6e3}, {0xe6c3f339, 0x05b6e6e3, 0xee98b215, 0x51431193}},
|
||||
{{0x06839eb9, 0xa648a7dd, 0x8a9a021e, 0x025b413f}, {0x06839eb9, 0xa648a7dd, 0x8a9a021e, 0x025b413f}, {0x06839eb9, 0x025b413f, 0x911da0d7, 0xa648a7dd}},
|
||||
{{0xf06c144a, 0xe1988ad9, 0x619699cf, 0xafbd67f9}, {0xf06c144a, 0xe1988ad9, 0x619699cf, 0xafbd67f9}, {0xf06c144a, 0xafbd67f9, 0x5202ae19, 0xe1988ad9}},
|
||||
{{0x37730edf, 0xf8130c42, 0x6c0fd4f5, 0xb9d179e0}, {0x37730edf, 0xf8130c42, 0x6c0fd4f5, 0xb9d179e0}, {0x37730edf, 0xb9d179e0, 0xa382e3d4, 0xf8130c42}},
|
||||
{{0x076f3787, 0x8712b8bc, 0x38c0c8fd, 0xc381e88f}, {0x076f3787, 0x8712b8bc, 0x38c0c8fd, 0xc381e88f}, {0x076f3787, 0xc381e88f, 0x40300084, 0x8712b8bc}},
|
||||
{{0x701966a0, 0xf06d3fef, 0x7eed8d14, 0x8d88348a}, {0x701966a0, 0xf06d3fef, 0x7eed8d14, 0x8d88348a}, {0x701966a0, 0x8d88348a, 0xef06f3b4, 0xf06d3fef}},
|
||||
{{0x3bab6c39, 0x587fd280, 0x3b1a11df, 0xad45f23d}, {0x3bab6c39, 0x587fd280, 0x3b1a11df, 0xad45f23d}, {0x3bab6c39, 0xad45f23d, 0x76c57e18, 0x587fd280}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
|
|
@ -117,11 +113,6 @@ std::string Hex(std::uint32_t value) {
|
|||
return text;
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> FinalMemory(const Row& row) {
|
||||
const auto [a, b, c, d] = row.memory;
|
||||
return {d ^ c, (b & ~0xff0000u) | ((c & 0xffu) << 16u), c + d, d - a};
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
|
|
@ -160,9 +151,8 @@ void Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::uint32_t waveS
|
|||
}
|
||||
std::array<std::uint32_t, 4> memory{};
|
||||
std::memcpy(memory.data(), guest.Data() + tid * 16u, 16u);
|
||||
const auto expected = FinalMemory(row);
|
||||
for (std::uint32_t dword = 0; dword < 4u; ++dword) {
|
||||
Require(memory[dword] == expected[dword], wave + std::to_string(tid) + " memory dword " + std::to_string(dword) + " is " + Hex(memory[dword]) + ", expected " + Hex(expected[dword]));
|
||||
Require(memory[dword] == row.final[dword], wave + std::to_string(tid) + " memory dword " + std::to_string(dword) + " is " + Hex(memory[dword]) + ", expected " + Hex(row.final[dword]));
|
||||
}
|
||||
}
|
||||
for (std::size_t offset = Threads * 16u; offset < BlockBytes; ++offset) {
|
||||
|
|
@ -178,7 +168,6 @@ int main() {
|
|||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
Run(*device, guest, 32);
|
||||
Run(*device, guest, 64);
|
||||
std::puts("flat cache bits tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
|
|
@ -1,65 +1,10 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_TESTS_EXECUTION_FLATGLOBALLOADSREGION_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_TESTS_EXECUTION_FLATGLOBALLOADSREGION_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::size_t RegionOffset = Threads * 16u;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 84> GlobalLoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc208800, 0x0a080020, 0xdc2487ff,
|
||||
0x0b080020, 0xdc288ffd, 0x0c080020, 0xdc2c8001, 0x0d7d0022, 0xdc308fff, 0x0e080020, 0xdc348ffa,
|
||||
0x0f7d0022, 0xdc3c8003, 0x11080020, 0xdc3887f8, 0x147d0022, 0xdc308000, 0x18080021, 0xdc208800,
|
||||
0x197d0022, 0xbf8c0070, 0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010, 0x80010e02, 0xe0781020,
|
||||
0x80011202, 0xe0781030, 0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 84> FlatLoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc200000, 0x0a7d0024, 0xdc2407ff,
|
||||
0x0b7d0024, 0xdc280001, 0x0c7d0024, 0xdc2c0003, 0x0d7d0024, 0xdc300002, 0x0e7d0024, 0xdc340001,
|
||||
0x0f7d0024, 0xdc3c0007, 0x117d0024, 0xdc3807f1, 0x147d0024, 0xdc300400, 0x187d0024, 0xdc2807ff,
|
||||
0x197d0024, 0xbf8c0070, 0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010, 0x80010e02, 0xe0781020,
|
||||
0x80011202, 0xe0781030, 0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
constexpr std::array<std::uint8_t, 6144> Region{
|
||||
inline constexpr std::array<std::uint8_t, 6144> FlatGlobalLoadsRegion{
|
||||
0xd2, 0xf2, 0x26, 0x65, 0xa6, 0x0c, 0x12, 0xd2, 0x89, 0x18, 0x5d, 0x95, 0x0e, 0xe8, 0x81, 0x36,
|
||||
0x09, 0x16, 0x6f, 0x6b, 0x11, 0x3d, 0x17, 0x8d, 0x6c, 0x0f, 0xd3, 0x90, 0x1f, 0xf2, 0x39, 0xa1,
|
||||
0xa0, 0x95, 0xf2, 0x0f, 0x93, 0x95, 0x65, 0x0c, 0xf9, 0x38, 0x0b, 0x8e, 0xdb, 0x22, 0x4a, 0x6b,
|
||||
|
|
@ -446,140 +391,4 @@ constexpr std::array<std::uint8_t, 6144> Region{
|
|||
0xcd, 0x85, 0x85, 0x4d, 0x73, 0xa9, 0x16, 0x46, 0x65, 0x4a, 0xff, 0x72, 0xb1, 0x1c, 0x73, 0xa2
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> input;
|
||||
std::array<std::uint32_t, Results> global;
|
||||
std::array<std::uint32_t, Results> flat;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, Threads> Rows{{
|
||||
{{0x00000000, 0x00000000, 0x3ceb3ffd, 0x00000000}, {0x000000d2, 0x00000029, 0x0000ebf6, 0x00004397, 0x4397357a, 0xf6804124, 0x97357aeb, 0x513c819d, 0x2e32095f, 0xefa22967, 0x6595f862, 0x295aec03, 0x523df3dc, 0x457d538e, 0x6526f2d2, 0x000000d2}, {0x000000d2, 0x0000007a, 0x000026f2, 0xffffa665, 0x0ca66526, 0xa66526f2, 0x89d2120c, 0x5d1889d2, 0x81e80e95, 0x6f160936, 0xe5522840, 0xd0e7469d, 0x80412474, 0x357aebf6, 0xfe1ec477, 0x0000357a}},
|
||||
{{0x00000001, 0x00000001, 0x97b75093, 0x00000001}, {0x000000f2, 0xffffffdc, 0x00007aeb, 0xffff9d43, 0x9d439735, 0xebf68041, 0x4397357a, 0x5f513c81, 0x672e3209, 0x47efa229, 0x036595f8, 0xdc295aec, 0x8e523df3, 0x48457d53, 0xa66526f2, 0x000000f2}, {0x000000f2, 0x00000035, 0x00006526, 0x00000ca6, 0x120ca665, 0x0ca66526, 0x1889d212, 0x955d1889, 0x3681e80e, 0x6b6f1609, 0x9de55228, 0x74d0e746, 0xf6804124, 0x97357aeb, 0xe4fe1ec4, 0x00009735}},
|
||||
{{0x00000002, 0x00000fa0, 0x8b529b4b, 0x00000002}, {0x00000026, 0xfffffff3, 0x0000357a, 0xffff819d, 0x819d4397, 0x7aebf680, 0x9d439735, 0x095f513c, 0x29672e32, 0xad47efa2, 0xec036595, 0xf3dc295a, 0x538e523d, 0xe048457d, 0x0ca66526, 0x00000026}, {0x000000a4, 0x0000005a, 0x0000449e, 0xffffadea, 0x9fadea44, 0xadea449e, 0x8aa0459f, 0xecce8aa0, 0x40199f09, 0x6f03851f, 0x97578278, 0x3c61fe8b, 0xbecaa1d3, 0xb65a60de, 0x37307a70, 0x0000b65a}},
|
||||
{{0x00000003, 0x00000f9f, 0x21636369, 0x00000003}, {0x00000065, 0x0000003d, 0x00009735, 0x00003c81, 0x3c819d43, 0x357aebf6, 0x819d4397, 0x32095f51, 0xa229672e, 0x53ad47ef, 0x5aec0365, 0x3df3dc29, 0x7d538e52, 0xfce04845, 0x120ca665, 0x00000065}, {0x000000dd, 0x00000060, 0x00009ea4, 0xffffea44, 0xadea449e, 0xea449ea4, 0xa0459fad, 0xce8aa045, 0x199f09ec, 0x03851f40, 0x578278da, 0x61fe8b97, 0xcaa1d33c, 0x5a60debe, 0x307a70d9, 0x00005a60}},
|
||||
{{0x000003ff, 0x00000002, 0x5eb561a5, 0x000017fc}, {0x00000077, 0x00000072, 0x00007ea7, 0x00003154, 0x31541eca, 0xa734f958, 0x541eca7e, 0x204cb651, 0x16a2f996, 0x660affc8, 0x30d907a2, 0x72bdad38, 0xa92515b0, 0x948e5f94, 0xa2731cb1, 0x00000077}, {0x00000026, 0xffffff97, 0x0000a665, 0x0000120c, 0xd2120ca6, 0x120ca665, 0x5d1889d2, 0x0e955d18, 0x093681e8, 0x116b6f16, 0x469de552, 0x2474d0e7, 0xebf68041, 0x4397357a, 0x8ce4fe1e, 0x00004397}},
|
||||
{{0x000003fe, 0x00000003, 0xea7b5bf4, 0x000017fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fd, 0x000007ff, 0x9a9a80fd, 0x000017fa}, {0x00000049, 0xffffffad, 0x000034f9, 0x00001eca, 0x1eca7ea7, 0xf95881df, 0xca7ea734, 0xb6513154, 0xf996204c, 0xffc816a2, 0x07a2e287, 0xad3830d9, 0x15b072bd, 0x5f94a925, 0x1cb172ff, 0x00000049}, {0x0000007a, 0x0000005a, 0x00009735, 0xffff9d43, 0x819d4397, 0x9d439735, 0x5f513c81, 0x32095f51, 0xa229672e, 0x53ad47ef, 0x553e074f, 0x8b833038, 0x6595f862, 0x295aec03, 0x5131541e, 0x0000295a}},
|
||||
{{0x00000201, 0x00000801, 0x795b929f, 0x00000ffd}, {0x000000c6, 0xffffff91, 0x00002075, 0xffffb0c1, 0xb0c19888, 0x75f13ba1, 0xc1988820, 0x08a59ac0, 0x85539459, 0x73d7de27, 0x62c3c5bc, 0x91b7a807, 0x63034f25, 0x2db116b5, 0xdc295aec, 0x000000c6}, {0x00000097, 0xffffffdc, 0x00009d43, 0x00003c81, 0x513c819d, 0x3c819d43, 0x32095f51, 0x672e3209, 0x47efa229, 0x60e553ad, 0x3038553e, 0xf8628b83, 0xec036595, 0xf3dc295a, 0x4cb65131, 0x0000f3dc}},
|
||||
{{0x00000086, 0x000009b0, 0xe8a8529f, 0x0000006b}, {0x000000f1, 0x00000054, 0x00001873, 0xffffdf25, 0xdf25a310, 0x7326b53e, 0x25a31018, 0x6645c8aa, 0x02f743cf, 0x8fd2a50e, 0x3b946093, 0x54ebd216, 0x9bd7f852, 0x53f53ed6, 0x7dee2657, 0x000000f1}, {0x00000000, 0x00000058, 0x00003386, 0xffffc349, 0xc0c34933, 0xc3493386, 0x010dfac0, 0x7d59010d, 0xcbb17d18, 0x7ef72fd3, 0x1ff610a6, 0x59e9d36c, 0x30633e8d, 0x3c584877, 0xb4de5e8e, 0x00003c58}},
|
||||
{{0x000003c0, 0x00000426, 0x3bfd1d33, 0x000011a0}, {0x000000a8, 0x0000002d, 0x0000a25c, 0xffff9c05, 0x9c0507a5, 0x5ca32e13, 0x0507a5a2, 0xeebcae0b, 0xfbcf54ff, 0x7c7b8218, 0x02701056, 0x2dd3f4aa, 0x602ab9e7, 0xcd71014b, 0xf610a667, 0x000000a8}, {0x00000021, 0xffffff8b, 0x0000d19a, 0xffff82a1, 0xc782a1d1, 0x82a1d19a, 0xb41ce3c7, 0x3b5db41c, 0x7ce0e57f, 0x00280664, 0x300b011b, 0x9b79ebd2, 0xc90fa8c4, 0x9c8be880, 0x401ae5e1, 0x00009c8b}},
|
||||
{{0x00000188, 0x00000b79, 0x8a7d43b5, 0x00000f0c}, {0x000000d7, 0xffffffb6, 0x00004159, 0xffffb70c, 0xb70c48ee, 0x5905426c, 0x0c48ee41, 0x52e95ec2, 0x809af6c4, 0x9e49d979, 0x693895b7, 0xb6e0664f, 0xdeca057c, 0x2b2c163e, 0x3e052289, 0x000000d7}, {0x000000fa, 0x0000003d, 0x000017c8, 0xffffe6ab, 0xe4e6ab17, 0xe6ab17c8, 0xa2c98ce4, 0x4cd6a2c9, 0x36b17e32, 0xd6bd1487, 0x5bd3a52f, 0x225e3a51, 0xd65eeb8d, 0x0e3d40d4, 0x3f5aefae, 0x00000e3d}},
|
||||
{{0x000003cf, 0x0000065a, 0xdc6bf1e1, 0x00001473}, {0x0000003b, 0x00000015, 0x00007b82, 0x000024e5, 0x24e5c17c, 0x8218fbcf, 0xe5c17c7b, 0x6ab73608, 0x185620a0, 0x575da8dc, 0x59ac90cd, 0x15783291, 0x7584528a, 0xe888f86d, 0xdebaea1d, 0x0000003b}, {0x0000008d, 0x00000074, 0x0000538b, 0xfffffa29, 0x6dfa2953, 0xfa29538b, 0xfc1ae26d, 0x4312fc1a, 0x1835159f, 0xb5fd7f6b, 0x4506273f, 0x554bd692, 0x7d422acd, 0xe774511b, 0xda660308, 0x0000e774}},
|
||||
{{0x00000134, 0x000003b5, 0x26d0b944, 0x00001450}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000031e, 0x00000bdc, 0xabe19f59, 0x0000007c}, {0x00000021, 0x00000071, 0x00007769, 0xffff8cc2, 0x8cc24bff, 0x69d0cbd1, 0xc24bff77, 0xd5c720a6, 0xd9c85a78, 0x60b4443a, 0xf6724fb3, 0x7153291c, 0x4a5c9177, 0x0b128e2b, 0x7f9859b1, 0x00000021}, {0x0000005d, 0x00000066, 0x00007957, 0xffff86c7, 0x8d86c779, 0x86c77957, 0x35e9c58d, 0x6f4835e9, 0x8d406c57, 0x4a4ad30d, 0x528a1578, 0xf86d7584, 0xdda0e888, 0xf666f927, 0xb19c74d6, 0x0000f666}},
|
||||
{{0x00000083, 0x0000028c, 0x0af438d3, 0x000012ea}, {0x00000011, 0x00000016, 0x0000b53e, 0x00001018, 0x10187326, 0x3ecdef03, 0x187326b5, 0xaadf25a3, 0xcf6645c8, 0x0e02f743, 0x936f25cd, 0x163b9460, 0x5254ebd2, 0xd69bd7f8, 0x224cb259, 0x00000011}, {0x00000010, 0x0000006e, 0x0000fc1c, 0xffffc9eb, 0x3ac9ebfc, 0xc9ebfc1c, 0x1ae0f83a, 0x43151ae0, 0xc7e70a45, 0x21c1452e, 0xc6e0e1a7, 0xda95b3a4, 0xa42ead3a, 0x506e741f, 0x3c3e2f3f, 0x0000506e}},
|
||||
{{0x00000268, 0x00000c7b, 0xd2d58443, 0x000000fe}, {0x00000065, 0xffffff90, 0x0000764b, 0xffff9a41, 0x9a412405, 0x4ba1fb80, 0x41240576, 0xbd0167bc, 0x6edae83e, 0xbf9692b3, 0xa14f8d0a, 0x902df1a3, 0x7f913ad6, 0xec4185b7, 0x99571c29, 0x00000065}, {0x00000015, 0xffffffbe, 0x000078a4, 0xffffe536, 0x26e53678, 0xe53678a4, 0x6d03a026, 0x02016d03, 0xfc1fabaf, 0x3716dbf7, 0xfd9f16e3, 0x1d9033df, 0x5adebaea, 0xd7be5d2b, 0x936f25cd, 0x0000d7be}},
|
||||
{{0x00000227, 0x00000790, 0xb804d821, 0x00001308}, {0x00000053, 0x00000067, 0x00004431, 0xffffd3b4, 0xd3b4c14d, 0x31813cb2, 0xb4c14d44, 0xb9279ed7, 0xb93ff927, 0x59859a53, 0xb7d12049, 0x675b4866, 0xc676e8d8, 0xdca0e1a0, 0x034ab01d, 0x00000053}, {0x000000a0, 0x0000006b, 0x00004ec7, 0xffffeba6, 0x4eeba64e, 0xeba64ec7, 0x6c3f954e, 0xa8636c3f, 0x7080725e, 0x9e00052d, 0x871b5d02, 0x6e53112f, 0x05ab81b3, 0xf86b2339, 0x6b431e8e, 0x0000f86b}},
|
||||
{{0x00000319, 0x00000b6d, 0x651c5253, 0x00000da9}, {0x000000fd, 0x00000072, 0x0000d4a3, 0x000069d0, 0x69d0cbd1, 0xa3aa5a25, 0xd0cbd1d4, 0xc24bff77, 0xc720a68c, 0xc85a78d5, 0x324d47e5, 0x724fb31c, 0x53291cf6, 0x5c917771, 0x15602efe, 0x000000fd}, {0x000000c8, 0xffffffd3, 0x00003527, 0x000067e7, 0xca67e735, 0x67e73527, 0x9c2a88ca, 0xb0e49c2a, 0x17c8fa9b, 0x8ce4e6ab, 0x1a2baeed, 0x4fd4b8c8, 0x61539dbe, 0x5bd3a52f, 0xd052e9fc, 0x00005bd3}},
|
||||
{{0x0000038e, 0x00000f6c, 0xe0fd67dd, 0x0000044a}, {0x00000086, 0xfffffffe, 0x000070d6, 0xffff8e1d, 0x8e1de1ab, 0xd6bd1487, 0x1de1ab70, 0x3b6b431e, 0x7e7923d3, 0x777b0e8e, 0x6c7e37f1, 0xfe28bb7f, 0xa0949a4c, 0x3ab02414, 0x65d656c0, 0x00000086}, {0x000000cd, 0xfffffffd, 0x0000e9fc, 0xffffd052, 0x66d052e9, 0xd052e9fc, 0x0d8fd866, 0x84530d8f, 0xefaef525, 0x6cde3f5a, 0x68e162c2, 0xffe524cd, 0x9b3d01a2, 0x41fded80, 0x3a515bd3, 0x000041fd}},
|
||||
{{0x000002ec, 0x0000018f, 0x22cedafa, 0x00000125}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003f5, 0x00000378, 0xf729b4c9, 0x00000841}, {0x00000019, 0x00000057, 0x00005567, 0xffffdf45, 0xdf45fb80, 0x677ed35a, 0x45fb8055, 0x34f95881, 0x1eca7ea7, 0xb6513154, 0xa5a87b5e, 0x57dd4c23, 0x07a2e287, 0xad3830d9, 0xd14b0cf5, 0x00000019}, {0x000000fc, 0xffffffb0, 0x0000267e, 0xffffb948, 0x9eb94826, 0xb948267e, 0x0b25a49e, 0xd5d30b25, 0xa083e4b7, 0xcfb3bb6d, 0x5873c62f, 0xe73527c8, 0x2a88ca67, 0x9bb0e49c, 0xf83f261f, 0x00009bb0}},
|
||||
{{0x0000037d, 0x00000c76, 0xdaf0105b, 0x0000140d}, {0x0000009e, 0xffffff91, 0x000017c8, 0xffff8ce4, 0x8ce4e6ab, 0xc8fa9bb0, 0xe4e6ab17, 0x4cd6a2c9, 0x36b17e32, 0xd6bd1487, 0x3d40d4d6, 0x911b0a0e, 0xd1eba0cd, 0xe767b4ff, 0x1d426570, 0x0000009e}, {0x00000079, 0xffffffba, 0x000069c5, 0x00001a8c, 0x151a8c69, 0x1a8c69c5, 0x3678a415, 0x26e53678, 0x016d03a0, 0x1fabaf02, 0x6d22b51e, 0x9f16e3e8, 0x9033dffd, 0xdebaea1d, 0x892f4c71, 0x0000deba}},
|
||||
{{0x00000268, 0x000006bd, 0xd55ec1a5, 0x0000103b}, {0x00000065, 0xffffff90, 0x0000764b, 0xffff9a41, 0x9a412405, 0x4ba1fb80, 0x41240576, 0xbd0167bc, 0x6edae83e, 0xbf9692b3, 0xa14f8d0a, 0x902df1a3, 0x7f913ad6, 0xec4185b7, 0x79fec2ec, 0x00000065}, {0x00000013, 0x00000033, 0x0000835f, 0x00002ddd, 0x722ddd83, 0x2ddd835f, 0xc6429a72, 0xaac7c642, 0xa31b01f2, 0x599eb598, 0x2c46c27e, 0xab9c2334, 0x31cfa0b5, 0x02334e95, 0x19598433, 0x00000233}},
|
||||
{{0x00000316, 0x0000092f, 0x88bafad9, 0x00000b3a}, {0x000000a2, 0x0000001c, 0x00005a25, 0xffffd1d4, 0xd1d4a3aa, 0x25f6d039, 0xd4a3aa5a, 0x7769d0cb, 0x8cc24bff, 0xd5c720a6, 0xe50f0b34, 0x1c324d47, 0xf6724fb3, 0x7153291c, 0x524da73e, 0x000000a2}, {0x000000ca, 0x0000001b, 0x00006436, 0xffff959f, 0x13959f64, 0x959f6436, 0x2be99013, 0x08252be9, 0x9f1b1c06, 0xfa5829ed, 0x24ff8388, 0x9a693293, 0x8428251f, 0x071b82c2, 0x1588587f, 0x0000071b}},
|
||||
{{0x00000342, 0x00000959, 0xe779c471, 0x0000076f}, {0x0000008c, 0x00000017, 0x00006d7c, 0xffffa815, 0xa815a39f, 0x7c7a524d, 0x15a39f6d, 0xed275ce5, 0x0e62da4d, 0xe790d315, 0x528bc830, 0x17eb5b02, 0x9da049a4, 0xb3a7bbef, 0x660a3790, 0x0000008c}, {0x00000088, 0x0000000d, 0x0000aae4, 0xffffe110, 0xdee110aa, 0xe110aae4, 0xb6eac1de, 0x62f1b6ea, 0x34343f1b, 0xf308081c, 0xdb19a044, 0x1095f2e7, 0x9f733159, 0x380d0562, 0xe242e585, 0x0000380d}},
|
||||
{{0x000002b1, 0x00000ae9, 0xdb3d1151, 0x000000ea}, {0x00000047, 0x0000000d, 0x0000d463, 0x00001bf9, 0x1bf9e87d, 0x6302c753, 0xf9e87dd4, 0x378b4009, 0xf3c8b729, 0x598433f0, 0xa0d6d4b0, 0x0d8273a0, 0x6d34b2ad, 0xedd883ac, 0xaedff3c7, 0x00000047}, {0x00000013, 0xffffffef, 0x0000ea6b, 0xffffa06b, 0xb2a06bea, 0xa06bea6b, 0x945aacb2, 0x1b43945a, 0x66bd4d39, 0xf886f4f0, 0x7cb4af22, 0xb43c7bab, 0xb183013d, 0xa4ef2271, 0x72ee855b, 0x0000a4ef}},
|
||||
{{0x0000023c, 0x000009b1, 0xb2109306, 0x0000157b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000014e, 0x00000b2d, 0xf6f22f41, 0x00000a71}, {0x000000c7, 0xffffffdb, 0x0000b20a, 0x0000100b, 0x100bbc11, 0x0aa2a4b1, 0x0bbc11b2, 0x5dc397db, 0xd1f4d133, 0x10aae488, 0x082b465a, 0xdb19a044, 0x1095f2e7, 0x9f733159, 0x92b36eda, 0x000000c7}, {0x000000af, 0x00000015, 0x0000fb40, 0xffffad6d, 0x2fad6dfb, 0xad6dfb40, 0xce007b2f, 0xccb8ce00, 0xa73e5b47, 0x7c7a524d, 0x4a5c9177, 0x0b128e2b, 0xfafd7702, 0xbf157cc0, 0xde591a71, 0x0000bf15}},
|
||||
{{0x000000d5, 0x00000b6b, 0x360c4979, 0x000014f9}, {0x00000025, 0x0000002b, 0x00006fd8, 0x00001477, 0x1477e9be, 0xd8600189, 0x77e9be6f, 0x2c73a7bd, 0x421aff39, 0x1f09a43b, 0x87b15796, 0x2b17d0bf, 0xfa5d515c, 0x834fd313, 0x63779354, 0x00000025}, {0x00000073, 0x0000002f, 0x0000c858, 0x00003527, 0xe73527c8, 0x3527c858, 0x88ca67e7, 0x9c2a88ca, 0xfa9bb0e4, 0xe6ab17c8, 0xaeede5d8, 0xb8c81a2b, 0x9dbe4fd4, 0xa52f6153, 0xe9fccd90, 0x0000a52f}},
|
||||
{{0x00000222, 0x0000048f, 0x103ef3c3, 0x000003fb}, {0x000000c2, 0xffffffd1, 0x0000e2a4, 0x00003181, 0x31813cb2, 0xa4765520, 0x813cb2e2, 0xb4c14d44, 0x279ed7d3, 0x3ff927b9, 0x164fb710, 0xd1204939, 0x5b4866b7, 0x76e8d867, 0x764984b5, 0x000000c2}, {0x0000009d, 0xffffffde, 0x000023c0, 0xffffdea4, 0x49dea423, 0xdea423c0, 0xe90c7c49, 0x8cede90c, 0x6a782b20, 0x414c4857, 0x6d03a026, 0xabaf0201, 0xdbf7fc1f, 0x1fde3716, 0xa50e02f7, 0x00001fde}},
|
||||
{{0x000003db, 0x00000da9, 0xfd63ed5b, 0x00001470}, {0x00000049, 0xfffffff9, 0x00001856, 0x0000575d, 0x575da8dc, 0x5620a06a, 0x5da8dc18, 0x8d86c779, 0x4835e9c5, 0x406c576f, 0xe888f86d, 0xf927dda0, 0x9e9bf666, 0x0fcfcf14, 0x1d9033df, 0x00000049}, {0x000000fe, 0xffffff9a, 0x0000602e, 0x00000715, 0x0d071560, 0x0715602e, 0x5e8e080d, 0xb4de5e8e, 0xd8f27c75, 0xdc10e5e8, 0xa02ac205, 0x05b43c44, 0x72660c37, 0x489ae433, 0x30633e8d, 0x0000489a}},
|
||||
{{0x000003de, 0x0000016a, 0xccf3d0b2, 0x00000b02}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat global loads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
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%x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
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}, 0, {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 Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code, bool flat) {
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, code, guest.Data());
|
||||
const auto wave = std::string(flat ? "flat" : "global") + " loads: lane ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& expected = flat ? Rows[tid].flat : Rows[tid].global;
|
||||
for (std::uint32_t result = 0; result < Results; ++result) {
|
||||
const auto actual = Output[tid * Results + result];
|
||||
Require(actual == expected[result], wave + std::to_string(tid) + " v" + std::to_string(10u + result) + " is " + Hex(actual) + ", expected " + Hex(expected[result]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
std::memset(guest.Data(), 0, BlockBytes);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
std::memcpy(guest.Data() + tid * 16u, Rows[tid].input.data(), 16u);
|
||||
}
|
||||
std::memcpy(guest.Data() + RegionOffset, Region.data(), Region.size());
|
||||
Run(*device, guest, GlobalLoadsCode, false);
|
||||
Run(*device, guest, FlatLoadsCode, true);
|
||||
std::puts("flat global loads tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "FlatGlobalLoadsRegion.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::size_t RegionOffset = Threads * 16u;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 78> LoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc200000, 0x0a7d0024, 0xdc2407ff,
|
||||
0x0b7d0024, 0xdc280001, 0x0c7d0024, 0xdc2c0003, 0x0d7d0024, 0xdc300002, 0x0e7d0024, 0xdc300400,
|
||||
0x187d0024, 0xdc2807ff, 0x197d0024, 0xbf8c0070, 0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010,
|
||||
0x80010e02, 0xe0781020, 0x80011202, 0xe0781030, 0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> input;
|
||||
std::array<std::uint32_t, Results> results;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, Threads> Rows{{
|
||||
{{0x00000000, 0x00000000, 0x3ceb3ffd, 0x00000000}, {0x000000d2, 0x0000007a, 0x000026f2, 0xffffa665, 0x0ca66526, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xfe1ec477, 0x0000357a}},
|
||||
{{0x00000001, 0x00000001, 0x97b75093, 0x00000001}, {0x000000f2, 0x00000035, 0x00006526, 0x00000ca6, 0x120ca665, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xe4fe1ec4, 0x00009735}},
|
||||
{{0x00000002, 0x00000fa0, 0x8b529b4b, 0x00000002}, {0x000000a4, 0x0000005a, 0x0000449e, 0xffffadea, 0x9fadea44, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x37307a70, 0x0000b65a}},
|
||||
{{0x00000003, 0x00000f9f, 0x21636369, 0x00000003}, {0x000000dd, 0x00000060, 0x00009ea4, 0xffffea44, 0xadea449e, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x307a70d9, 0x00005a60}},
|
||||
{{0x000003ff, 0x00000002, 0x5eb561a5, 0x000017fc}, {0x00000026, 0xffffff97, 0x0000a665, 0x0000120c, 0xd2120ca6, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x8ce4fe1e, 0x00004397}},
|
||||
{{0x000003fe, 0x00000003, 0xea7b5bf4, 0x000017fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fd, 0x000007ff, 0x9a9a80fd, 0x000017fa}, {0x0000007a, 0x0000005a, 0x00009735, 0xffff9d43, 0x819d4397, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5131541e, 0x0000295a}},
|
||||
{{0x00000201, 0x00000801, 0x795b929f, 0x00000ffd}, {0x00000097, 0xffffffdc, 0x00009d43, 0x00003c81, 0x513c819d, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x4cb65131, 0x0000f3dc}},
|
||||
{{0x00000086, 0x000009b0, 0xe8a8529f, 0x0000006b}, {0x00000000, 0x00000058, 0x00003386, 0xffffc349, 0xc0c34933, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xb4de5e8e, 0x00003c58}},
|
||||
{{0x000003c0, 0x00000426, 0x3bfd1d33, 0x000011a0}, {0x00000021, 0xffffff8b, 0x0000d19a, 0xffff82a1, 0xc782a1d1, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x401ae5e1, 0x00009c8b}},
|
||||
{{0x00000188, 0x00000b79, 0x8a7d43b5, 0x00000f0c}, {0x000000fa, 0x0000003d, 0x000017c8, 0xffffe6ab, 0xe4e6ab17, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x3f5aefae, 0x00000e3d}},
|
||||
{{0x000003cf, 0x0000065a, 0xdc6bf1e1, 0x00001473}, {0x0000008d, 0x00000074, 0x0000538b, 0xfffffa29, 0x6dfa2953, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xda660308, 0x0000e774}},
|
||||
{{0x00000134, 0x000003b5, 0x26d0b944, 0x00001450}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000031e, 0x00000bdc, 0xabe19f59, 0x0000007c}, {0x0000005d, 0x00000066, 0x00007957, 0xffff86c7, 0x8d86c779, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xb19c74d6, 0x0000f666}},
|
||||
{{0x00000083, 0x0000028c, 0x0af438d3, 0x000012ea}, {0x00000010, 0x0000006e, 0x0000fc1c, 0xffffc9eb, 0x3ac9ebfc, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x3c3e2f3f, 0x0000506e}},
|
||||
{{0x00000268, 0x00000c7b, 0xd2d58443, 0x000000fe}, {0x00000015, 0xffffffbe, 0x000078a4, 0xffffe536, 0x26e53678, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x936f25cd, 0x0000d7be}},
|
||||
{{0x00000227, 0x00000790, 0xb804d821, 0x00001308}, {0x000000a0, 0x0000006b, 0x00004ec7, 0xffffeba6, 0x4eeba64e, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x6b431e8e, 0x0000f86b}},
|
||||
{{0x00000319, 0x00000b6d, 0x651c5253, 0x00000da9}, {0x000000c8, 0xffffffd3, 0x00003527, 0x000067e7, 0xca67e735, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xd052e9fc, 0x00005bd3}},
|
||||
{{0x0000038e, 0x00000f6c, 0xe0fd67dd, 0x0000044a}, {0x000000cd, 0xfffffffd, 0x0000e9fc, 0xffffd052, 0x66d052e9, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x3a515bd3, 0x000041fd}},
|
||||
{{0x000002ec, 0x0000018f, 0x22cedafa, 0x00000125}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003f5, 0x00000378, 0xf729b4c9, 0x00000841}, {0x000000fc, 0xffffffb0, 0x0000267e, 0xffffb948, 0x9eb94826, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xf83f261f, 0x00009bb0}},
|
||||
{{0x0000037d, 0x00000c76, 0xdaf0105b, 0x0000140d}, {0x00000079, 0xffffffba, 0x000069c5, 0x00001a8c, 0x151a8c69, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x892f4c71, 0x0000deba}},
|
||||
{{0x00000268, 0x000006bd, 0xd55ec1a5, 0x0000103b}, {0x00000013, 0x00000033, 0x0000835f, 0x00002ddd, 0x722ddd83, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x19598433, 0x00000233}},
|
||||
{{0x00000316, 0x0000092f, 0x88bafad9, 0x00000b3a}, {0x000000ca, 0x0000001b, 0x00006436, 0xffff959f, 0x13959f64, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x1588587f, 0x0000071b}},
|
||||
{{0x00000342, 0x00000959, 0xe779c471, 0x0000076f}, {0x00000088, 0x0000000d, 0x0000aae4, 0xffffe110, 0xdee110aa, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xe242e585, 0x0000380d}},
|
||||
{{0x000002b1, 0x00000ae9, 0xdb3d1151, 0x000000ea}, {0x00000013, 0xffffffef, 0x0000ea6b, 0xffffa06b, 0xb2a06bea, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x72ee855b, 0x0000a4ef}},
|
||||
{{0x0000023c, 0x000009b1, 0xb2109306, 0x0000157b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000014e, 0x00000b2d, 0xf6f22f41, 0x00000a71}, {0x000000af, 0x00000015, 0x0000fb40, 0xffffad6d, 0x2fad6dfb, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xde591a71, 0x0000bf15}},
|
||||
{{0x000000d5, 0x00000b6b, 0x360c4979, 0x000014f9}, {0x00000073, 0x0000002f, 0x0000c858, 0x00003527, 0xe73527c8, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xe9fccd90, 0x0000a52f}},
|
||||
{{0x00000222, 0x0000048f, 0x103ef3c3, 0x000003fb}, {0x0000009d, 0xffffffde, 0x000023c0, 0xffffdea4, 0x49dea423, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xa50e02f7, 0x00001fde}},
|
||||
{{0x000003db, 0x00000da9, 0xfd63ed5b, 0x00001470}, {0x000000fe, 0xffffff9a, 0x0000602e, 0x00000715, 0x0d071560, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x30633e8d, 0x0000489a}},
|
||||
{{0x000003de, 0x0000016a, 0xccf3d0b2, 0x00000b02}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat loads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
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%x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
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}, 0, {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 Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code) {
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, code, guest.Data());
|
||||
const std::string wave = "flat loads: lane ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& expected = Rows[tid].results;
|
||||
for (std::uint32_t result = 0; result < Results; ++result) {
|
||||
const auto actual = Output[tid * Results + result];
|
||||
Require(actual == expected[result], wave + std::to_string(tid) + " v" + std::to_string(10u + result) + " is " + Hex(actual) + ", expected " + Hex(expected[result]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
std::memset(guest.Data(), 0, BlockBytes);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
std::memcpy(guest.Data() + tid * 16u, Rows[tid].input.data(), 16u);
|
||||
}
|
||||
std::memcpy(guest.Data() + RegionOffset, FlatGlobalLoadsRegion.data(), FlatGlobalLoadsRegion.size());
|
||||
Run(*device, guest, LoadsCode);
|
||||
std::puts("flat loads tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "FlatGlobalLoadsRegion.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::size_t RegionOffset = Threads * 16u;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 68> LoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc340001, 0x0f7d0024, 0xdc3c0007,
|
||||
0x117d0024, 0xbf8c0070, 0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010, 0x80010e02, 0xe0781020,
|
||||
0x80011202, 0xe0781030, 0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> input;
|
||||
std::array<std::uint32_t, Results> results;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, Threads> Rows{{
|
||||
{{0x00000000, 0x00000000, 0x3ceb3ffd, 0x00000000}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xa66526f2, 0x89d2120c, 0x5d1889d2, 0x81e80e95, 0x6f160936, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000001, 0x00000001, 0x97b75093, 0x00000001}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x0ca66526, 0x1889d212, 0x955d1889, 0x3681e80e, 0x6b6f1609, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000002, 0x00000fa0, 0x8b529b4b, 0x00000002}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xadea449e, 0x8aa0459f, 0xecce8aa0, 0x40199f09, 0x6f03851f, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000003, 0x00000f9f, 0x21636369, 0x00000003}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xea449ea4, 0xa0459fad, 0xce8aa045, 0x199f09ec, 0x03851f40, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003ff, 0x00000002, 0x5eb561a5, 0x000017fc}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x120ca665, 0x5d1889d2, 0x0e955d18, 0x093681e8, 0x116b6f16, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fe, 0x00000003, 0xea7b5bf4, 0x000017fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fd, 0x000007ff, 0x9a9a80fd, 0x000017fa}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x9d439735, 0x5f513c81, 0x32095f51, 0xa229672e, 0x53ad47ef, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000201, 0x00000801, 0x795b929f, 0x00000ffd}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x3c819d43, 0x32095f51, 0x672e3209, 0x47efa229, 0x60e553ad, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000086, 0x000009b0, 0xe8a8529f, 0x0000006b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xc3493386, 0x010dfac0, 0x7d59010d, 0xcbb17d18, 0x7ef72fd3, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003c0, 0x00000426, 0x3bfd1d33, 0x000011a0}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x82a1d19a, 0xb41ce3c7, 0x3b5db41c, 0x7ce0e57f, 0x00280664, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000188, 0x00000b79, 0x8a7d43b5, 0x00000f0c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xe6ab17c8, 0xa2c98ce4, 0x4cd6a2c9, 0x36b17e32, 0xd6bd1487, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003cf, 0x0000065a, 0xdc6bf1e1, 0x00001473}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xfa29538b, 0xfc1ae26d, 0x4312fc1a, 0x1835159f, 0xb5fd7f6b, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000134, 0x000003b5, 0x26d0b944, 0x00001450}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000031e, 0x00000bdc, 0xabe19f59, 0x0000007c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x86c77957, 0x35e9c58d, 0x6f4835e9, 0x8d406c57, 0x4a4ad30d, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000083, 0x0000028c, 0x0af438d3, 0x000012ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xc9ebfc1c, 0x1ae0f83a, 0x43151ae0, 0xc7e70a45, 0x21c1452e, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x00000c7b, 0xd2d58443, 0x000000fe}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xe53678a4, 0x6d03a026, 0x02016d03, 0xfc1fabaf, 0x3716dbf7, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000227, 0x00000790, 0xb804d821, 0x00001308}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xeba64ec7, 0x6c3f954e, 0xa8636c3f, 0x7080725e, 0x9e00052d, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000319, 0x00000b6d, 0x651c5253, 0x00000da9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x67e73527, 0x9c2a88ca, 0xb0e49c2a, 0x17c8fa9b, 0x8ce4e6ab, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000038e, 0x00000f6c, 0xe0fd67dd, 0x0000044a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xd052e9fc, 0x0d8fd866, 0x84530d8f, 0xefaef525, 0x6cde3f5a, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002ec, 0x0000018f, 0x22cedafa, 0x00000125}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003f5, 0x00000378, 0xf729b4c9, 0x00000841}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xb948267e, 0x0b25a49e, 0xd5d30b25, 0xa083e4b7, 0xcfb3bb6d, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000037d, 0x00000c76, 0xdaf0105b, 0x0000140d}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x1a8c69c5, 0x3678a415, 0x26e53678, 0x016d03a0, 0x1fabaf02, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x000006bd, 0xd55ec1a5, 0x0000103b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x2ddd835f, 0xc6429a72, 0xaac7c642, 0xa31b01f2, 0x599eb598, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000316, 0x0000092f, 0x88bafad9, 0x00000b3a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x959f6436, 0x2be99013, 0x08252be9, 0x9f1b1c06, 0xfa5829ed, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000342, 0x00000959, 0xe779c471, 0x0000076f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xe110aae4, 0xb6eac1de, 0x62f1b6ea, 0x34343f1b, 0xf308081c, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002b1, 0x00000ae9, 0xdb3d1151, 0x000000ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xa06bea6b, 0x945aacb2, 0x1b43945a, 0x66bd4d39, 0xf886f4f0, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000023c, 0x000009b1, 0xb2109306, 0x0000157b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000014e, 0x00000b2d, 0xf6f22f41, 0x00000a71}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xad6dfb40, 0xce007b2f, 0xccb8ce00, 0xa73e5b47, 0x7c7a524d, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000000d5, 0x00000b6b, 0x360c4979, 0x000014f9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x3527c858, 0x88ca67e7, 0x9c2a88ca, 0xfa9bb0e4, 0xe6ab17c8, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000222, 0x0000048f, 0x103ef3c3, 0x000003fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xdea423c0, 0xe90c7c49, 0x8cede90c, 0x6a782b20, 0x414c4857, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003db, 0x00000da9, 0xfd63ed5b, 0x00001470}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x0715602e, 0x5e8e080d, 0xb4de5e8e, 0xd8f27c75, 0xdc10e5e8, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003de, 0x0000016a, 0xccf3d0b2, 0x00000b02}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat loads x2 x3: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
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%x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
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}, 0, {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 Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code) {
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, code, guest.Data());
|
||||
const std::string wave = "flat loads x2 x3: lane ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& expected = Rows[tid].results;
|
||||
for (std::uint32_t result = 0; result < Results; ++result) {
|
||||
const auto actual = Output[tid * Results + result];
|
||||
Require(actual == expected[result], wave + std::to_string(tid) + " v" + std::to_string(10u + result) + " is " + Hex(actual) + ", expected " + Hex(expected[result]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
std::memset(guest.Data(), 0, BlockBytes);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
std::memcpy(guest.Data() + tid * 16u, Rows[tid].input.data(), 16u);
|
||||
}
|
||||
std::memcpy(guest.Data() + RegionOffset, FlatGlobalLoadsRegion.data(), FlatGlobalLoadsRegion.size());
|
||||
Run(*device, guest, LoadsCode);
|
||||
std::puts("flat loads x2 x3 tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "FlatGlobalLoadsRegion.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::size_t RegionOffset = Threads * 16u;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 66> LoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc3807f1, 0x147d0024, 0xbf8c0070,
|
||||
0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010, 0x80010e02, 0xe0781020, 0x80011202, 0xe0781030,
|
||||
0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> input;
|
||||
std::array<std::uint32_t, Results> results;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, Threads> Rows{{
|
||||
{{0x00000000, 0x00000000, 0x3ceb3ffd, 0x00000000}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xe5522840, 0xd0e7469d, 0x80412474, 0x357aebf6, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000001, 0x00000001, 0x97b75093, 0x00000001}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x9de55228, 0x74d0e746, 0xf6804124, 0x97357aeb, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000002, 0x00000fa0, 0x8b529b4b, 0x00000002}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x97578278, 0x3c61fe8b, 0xbecaa1d3, 0xb65a60de, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000003, 0x00000f9f, 0x21636369, 0x00000003}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x578278da, 0x61fe8b97, 0xcaa1d33c, 0x5a60debe, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003ff, 0x00000002, 0x5eb561a5, 0x000017fc}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x469de552, 0x2474d0e7, 0xebf68041, 0x4397357a, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fe, 0x00000003, 0xea7b5bf4, 0x000017fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fd, 0x000007ff, 0x9a9a80fd, 0x000017fa}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x553e074f, 0x8b833038, 0x6595f862, 0x295aec03, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000201, 0x00000801, 0x795b929f, 0x00000ffd}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x3038553e, 0xf8628b83, 0xec036595, 0xf3dc295a, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000086, 0x000009b0, 0xe8a8529f, 0x0000006b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x1ff610a6, 0x59e9d36c, 0x30633e8d, 0x3c584877, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003c0, 0x00000426, 0x3bfd1d33, 0x000011a0}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x300b011b, 0x9b79ebd2, 0xc90fa8c4, 0x9c8be880, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000188, 0x00000b79, 0x8a7d43b5, 0x00000f0c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5bd3a52f, 0x225e3a51, 0xd65eeb8d, 0x0e3d40d4, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003cf, 0x0000065a, 0xdc6bf1e1, 0x00001473}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x4506273f, 0x554bd692, 0x7d422acd, 0xe774511b, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000134, 0x000003b5, 0x26d0b944, 0x00001450}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000031e, 0x00000bdc, 0xabe19f59, 0x0000007c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x528a1578, 0xf86d7584, 0xdda0e888, 0xf666f927, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000083, 0x0000028c, 0x0af438d3, 0x000012ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xc6e0e1a7, 0xda95b3a4, 0xa42ead3a, 0x506e741f, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x00000c7b, 0xd2d58443, 0x000000fe}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xfd9f16e3, 0x1d9033df, 0x5adebaea, 0xd7be5d2b, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000227, 0x00000790, 0xb804d821, 0x00001308}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x871b5d02, 0x6e53112f, 0x05ab81b3, 0xf86b2339, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000319, 0x00000b6d, 0x651c5253, 0x00000da9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x1a2baeed, 0x4fd4b8c8, 0x61539dbe, 0x5bd3a52f, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000038e, 0x00000f6c, 0xe0fd67dd, 0x0000044a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x68e162c2, 0xffe524cd, 0x9b3d01a2, 0x41fded80, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002ec, 0x0000018f, 0x22cedafa, 0x00000125}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003f5, 0x00000378, 0xf729b4c9, 0x00000841}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5873c62f, 0xe73527c8, 0x2a88ca67, 0x9bb0e49c, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000037d, 0x00000c76, 0xdaf0105b, 0x0000140d}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x6d22b51e, 0x9f16e3e8, 0x9033dffd, 0xdebaea1d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x000006bd, 0xd55ec1a5, 0x0000103b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x2c46c27e, 0xab9c2334, 0x31cfa0b5, 0x02334e95, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000316, 0x0000092f, 0x88bafad9, 0x00000b3a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x24ff8388, 0x9a693293, 0x8428251f, 0x071b82c2, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000342, 0x00000959, 0xe779c471, 0x0000076f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xdb19a044, 0x1095f2e7, 0x9f733159, 0x380d0562, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002b1, 0x00000ae9, 0xdb3d1151, 0x000000ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x7cb4af22, 0xb43c7bab, 0xb183013d, 0xa4ef2271, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000023c, 0x000009b1, 0xb2109306, 0x0000157b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000014e, 0x00000b2d, 0xf6f22f41, 0x00000a71}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x4a5c9177, 0x0b128e2b, 0xfafd7702, 0xbf157cc0, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000000d5, 0x00000b6b, 0x360c4979, 0x000014f9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xaeede5d8, 0xb8c81a2b, 0x9dbe4fd4, 0xa52f6153, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000222, 0x0000048f, 0x103ef3c3, 0x000003fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x6d03a026, 0xabaf0201, 0xdbf7fc1f, 0x1fde3716, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003db, 0x00000da9, 0xfd63ed5b, 0x00001470}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xa02ac205, 0x05b43c44, 0x72660c37, 0x489ae433, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003de, 0x0000016a, 0xccf3d0b2, 0x00000b02}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "flat loads x4: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
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%x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
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}, 0, {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 Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code) {
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, code, guest.Data());
|
||||
const std::string wave = "flat loads x4: lane ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& expected = Rows[tid].results;
|
||||
for (std::uint32_t result = 0; result < Results; ++result) {
|
||||
const auto actual = Output[tid * Results + result];
|
||||
Require(actual == expected[result], wave + std::to_string(tid) + " v" + std::to_string(10u + result) + " is " + Hex(actual) + ", expected " + Hex(expected[result]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
std::memset(guest.Data(), 0, BlockBytes);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
std::memcpy(guest.Data() + tid * 16u, Rows[tid].input.data(), 16u);
|
||||
}
|
||||
std::memcpy(guest.Data() + RegionOffset, FlatGlobalLoadsRegion.data(), FlatGlobalLoadsRegion.size());
|
||||
Run(*device, guest, LoadsCode);
|
||||
std::puts("flat loads x4 tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 64;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 4;
|
||||
constexpr std::uint32_t Written = 3;
|
||||
constexpr std::uint32_t SharedOffset = Threads * 4u;
|
||||
constexpr std::uint32_t Untouched = 0xdeadbeefu;
|
||||
constexpr std::uint32_t SharedPartial = 0x800186a0u;
|
||||
constexpr std::uint32_t SharedExhausted = 1000u;
|
||||
constexpr std::size_t BlockBytes = 4096;
|
||||
constexpr std::uint8_t Fill = 0xcd;
|
||||
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, 25> Code{
|
||||
0x34020084, 0x34060082, 0xe0301000, 0x80000a01, 0xe0301004, 0x80000b01, 0xe0301008, 0x80000c01,
|
||||
0x7e0e02ff, 0x00000100, 0xbf8c3f70, 0xdcd18000, 0x14080a03, 0xdcd18000, 0x15080b07, 0xdcd18004,
|
||||
0x16080c07, 0xbf8c3f70, 0xe0701000, 0x80011401, 0xe0701004, 0x80011501, 0xe0701008, 0x80011601,
|
||||
0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 3> NoReturnCode{
|
||||
0xdcd08000, 0x00080a03, 0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 3> FlatSegmentCode{
|
||||
0xdcd10000, 0x147f0a03, 0xbf810000,
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::uint32_t memory;
|
||||
std::uint32_t subtrahend;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, 16> Edges{{
|
||||
{0u, 0u}, {0u, 1u}, {1u, 0u}, {1u, 1u},
|
||||
{5u, 7u}, {7u, 5u}, {0xffffffffu, 1u}, {1u, 0xffffffffu},
|
||||
{0x80000000u, 0x7fffffffu}, {0x7fffffffu, 0x80000000u}, {0xffffffffu, 0xffffffffu}, {0x80000000u, 0x80000000u},
|
||||
{0x80000001u, 0x80000000u}, {0u, 0xffffffffu}, {0xffffffffu, 0u}, {0x12345678u, 0x12345679u},
|
||||
}};
|
||||
|
||||
Row RowOf(std::uint32_t tid) {
|
||||
if (tid < Edges.size()) return Edges[tid];
|
||||
const std::uint32_t memory = (tid + 1u) * 0x9e3779b9u;
|
||||
const std::uint32_t subtrahend = (tid + 1u) * 0x85ebca6bu;
|
||||
return {memory, (tid & 3u) == 0u ? subtrahend >> 8u : subtrahend};
|
||||
}
|
||||
|
||||
std::uint32_t SharedPartialStep(std::uint32_t tid) { return tid + 1u; }
|
||||
std::uint32_t SharedExhaustedStep(std::uint32_t tid) { return tid + 100u; }
|
||||
|
||||
std::uint32_t SubtractClamped(std::uint32_t memory, std::uint32_t subtrahend) {
|
||||
return memory >= subtrahend ? memory - subtrahend : 0u;
|
||||
}
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global atomic csub: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, true);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
void Put(std::vector<std::uint8_t>& image, std::uint32_t offset, std::uint32_t value) {
|
||||
for (std::uint32_t byte = 0; byte < 4u; ++byte) image.at(offset + byte) = static_cast<std::uint8_t>(value >> (byte * 8u));
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> Initial() {
|
||||
std::vector<std::uint8_t> image(BlockBytes, Fill);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, tid * 4u, RowOf(tid).memory);
|
||||
}
|
||||
Put(image, SharedOffset, SharedPartial);
|
||||
Put(image, SharedOffset + 4u, SharedExhausted);
|
||||
return image;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> Expected() {
|
||||
auto image = Initial();
|
||||
std::uint32_t partial = SharedPartial;
|
||||
std::uint32_t exhausted = SharedExhausted;
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const Row row = RowOf(tid);
|
||||
Put(image, tid * 4u, SubtractClamped(row.memory, row.subtrahend));
|
||||
partial = SubtractClamped(partial, SharedPartialStep(tid));
|
||||
exhausted = SubtractClamped(exhausted, SharedExhaustedStep(tid));
|
||||
}
|
||||
Require(partial != 0u && exhausted == 0u, "global atomic csub: the shared dwords do not cover both outcomes");
|
||||
Put(image, SharedOffset, partial);
|
||||
Put(image, SharedOffset + 4u, exhausted);
|
||||
return image;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::vector<std::uint32_t> UserData(const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 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);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
return userData;
|
||||
}
|
||||
|
||||
ShaderRecompiler::RecompileResult Recompile(const AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, std::uint32_t waveSize, std::span<const std::uint32_t> userData) {
|
||||
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}, 0, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{waveSize, 0, userData, compute, std::nullopt, std::nullopt, memory},
|
||||
device.Target(),
|
||||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
return ShaderRecompiler::Recompile(request);
|
||||
}
|
||||
|
||||
void CheckChain(const std::string& where, std::uint32_t column, std::uint32_t initial, std::uint32_t (*step)(std::uint32_t)) {
|
||||
std::vector<std::pair<std::uint32_t, std::uint32_t>> order;
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
order.emplace_back(Output[tid * Results + column], tid);
|
||||
}
|
||||
std::sort(order.begin(), order.end(), [](const auto& a, const auto& b) { return a.first > b.first; });
|
||||
std::uint32_t running = initial;
|
||||
for (const auto& [returned, tid] : order) {
|
||||
Require(returned == running, where + " returned " + Hex(returned) + " to thread " + std::to_string(tid) + ", expected " + Hex(running));
|
||||
running = SubtractClamped(running, step(tid));
|
||||
}
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::uint32_t waveSize) {
|
||||
const auto initial = Initial();
|
||||
std::memcpy(guest.Data(), initial.data(), BlockBytes);
|
||||
Input.fill(0u);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Input[tid * Inputs] = RowOf(tid).subtrahend;
|
||||
Input[tid * Inputs + 1u] = SharedPartialStep(tid);
|
||||
Input[tid * Inputs + 2u] = SharedExhaustedStep(tid);
|
||||
}
|
||||
Output.fill(Untouched);
|
||||
const auto userData = UserData(guest.Data());
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const auto result = Recompile(device, code, waveSize, userData);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
|
||||
const auto wave = "global atomic csub: wave" + std::to_string(waveSize) + " ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const Row row = RowOf(tid);
|
||||
const auto returned = Output[tid * Results];
|
||||
Require(returned == row.memory, wave + "thread " + std::to_string(tid) + " returned " + Hex(returned) + ", expected " + Hex(row.memory));
|
||||
for (std::uint32_t j = Written; j < Results; ++j) {
|
||||
Require(Output[tid * Results + j] == Untouched, wave + "thread " + std::to_string(tid) + " result " + std::to_string(j) + " was written");
|
||||
}
|
||||
}
|
||||
CheckChain(wave + "dword shared by all lanes", 1u, SharedPartial, SharedPartialStep);
|
||||
CheckChain(wave + "dword exhausted by all lanes", 2u, SharedExhausted, SharedExhaustedStep);
|
||||
const auto expected = Expected();
|
||||
for (std::uint32_t offset = 0; offset < BlockBytes; ++offset) {
|
||||
const auto actual = guest.Data()[offset];
|
||||
Require(actual == expected[offset], wave + "byte " + std::to_string(offset) + " is " + std::to_string(actual) + ", expected " + std::to_string(expected[offset]));
|
||||
}
|
||||
}
|
||||
|
||||
void CheckRejected(const AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code, const std::string& reason) {
|
||||
const auto userData = UserData(guest.Data());
|
||||
std::string failure;
|
||||
try {
|
||||
static_cast<void>(Recompile(device, code, 32, userData));
|
||||
} catch (const std::exception& error) {
|
||||
failure = error.what();
|
||||
}
|
||||
Require(failure.find(reason) != std::string::npos, "global atomic csub: expected '" + reason + "', got '" + failure + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
Run(*device, guest, 32);
|
||||
Run(*device, guest, 64);
|
||||
CheckRejected(*device, guest, NoReturnCode, "global_atomic_csub without glc is not supported");
|
||||
CheckRejected(*device, guest, FlatSegmentCode, "global_atomic_csub is available only in the global segment");
|
||||
std::puts("global atomic csub tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ using ShaderRecompiler::ShaderStage;
|
|||
|
||||
constexpr std::uint32_t Threads = 64;
|
||||
constexpr std::uint32_t RowsPerOp = 16;
|
||||
constexpr std::uint32_t OpCount = 24;
|
||||
constexpr std::uint32_t OpCount = 13;
|
||||
constexpr std::uint32_t NarrowOps = 13;
|
||||
constexpr std::uint32_t OpStride = 0x200;
|
||||
constexpr std::uint32_t Special = OpCount * OpStride;
|
||||
|
|
@ -36,7 +36,7 @@ constexpr std::uint8_t Fill = 0xcd;
|
|||
alignas(256) std::array<std::uint32_t, OpCount * Threads * 4> Input{};
|
||||
alignas(256) std::array<std::uint32_t, (OpCount + 2) * Threads * 2> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 384> GlobalAtomicsCode{
|
||||
alignas(256) constexpr std::array<std::uint32_t, 187> GlobalAtomicsCode{
|
||||
0x34020083, 0x34040084, 0x340a0083, 0x7e2802ff, 0x05e471e1, 0x7e2a02ff, 0x05e471e1, 0x4a060280,
|
||||
0x4a080480, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0a80, 0xdcc18000, 0x14080a03, 0xbf8c3f70,
|
||||
0xe0701000, 0x80011406, 0x4a0602ff, 0x00000200, 0x4a0804ff, 0x00000400, 0xe0381000, 0x80000a04,
|
||||
|
|
@ -60,31 +60,7 @@ alignas(256) constexpr std::array<std::uint32_t, 384> GlobalAtomicsCode{
|
|||
0x4a0804ff, 0x00002c00, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00001600, 0xdcf18000,
|
||||
0x14080a03, 0xbf8c3f70, 0xe0701000, 0x80011406, 0x4a0602ff, 0x00001800, 0x4a0804ff, 0x00003000,
|
||||
0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00001800, 0xdcf58000, 0x14080a03, 0xbf8c3f70,
|
||||
0xe0701000, 0x80011406, 0x4a0602ff, 0x00001a00, 0x4a0804ff, 0x00003400, 0xe0381000, 0x80000a04,
|
||||
0xbf8c3f70, 0x4a0c0aff, 0x00001a00, 0xdd418000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406,
|
||||
0x4a0602ff, 0x00001c00, 0x4a0804ff, 0x00003800, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff,
|
||||
0x00001c00, 0xdd458000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00001e00,
|
||||
0x4a0804ff, 0x00003c00, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00001e00, 0xdd498000,
|
||||
0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00002000, 0x4a0804ff, 0x00004000,
|
||||
0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00002000, 0xdd4d8000, 0x14080a03, 0xbf8c3f70,
|
||||
0xe0741000, 0x80011406, 0x4a0602ff, 0x00002200, 0x4a0804ff, 0x00004400, 0xe0381000, 0x80000a04,
|
||||
0xbf8c3f70, 0x4a0c0aff, 0x00002200, 0xdd558000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406,
|
||||
0x4a0602ff, 0x00002400, 0x4a0804ff, 0x00004800, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff,
|
||||
0x00002400, 0xdd598000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00002600,
|
||||
0x4a0804ff, 0x00004c00, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00002600, 0xdd5d8000,
|
||||
0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00002800, 0x4a0804ff, 0x00005000,
|
||||
0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00002800, 0xdd618000, 0x14080a03, 0xbf8c3f70,
|
||||
0xe0741000, 0x80011406, 0x4a0602ff, 0x00002a00, 0x4a0804ff, 0x00005400, 0xe0381000, 0x80000a04,
|
||||
0xbf8c3f70, 0x4a0c0aff, 0x00002a00, 0xdd658000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406,
|
||||
0x4a0602ff, 0x00002c00, 0x4a0804ff, 0x00005800, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff,
|
||||
0x00002c00, 0xdd698000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00002e00,
|
||||
0x4a0804ff, 0x00005c00, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00002e00, 0xdd6d8000,
|
||||
0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00003000, 0x7e2802ff, 0x05e471e1,
|
||||
0x4a140081, 0xdcc88000, 0x00080a03, 0xbf8c3f70, 0xd70f6a1e, 0x02020608, 0x7e3e0209, 0x503e3e80,
|
||||
0xd70f6a1e, 0x02023cff, 0x00000200, 0x503e3e80, 0x34140088, 0xdced0000, 0x147d0a1e, 0xbf8c0070,
|
||||
0x4a0c0aff, 0x00003000, 0xe0701000, 0x80011406, 0x7e0602ff, 0x00003400, 0x4a1414ff, 0x00000100,
|
||||
0xdcc98004, 0x14080a03, 0xbf8c3f70, 0x4a0c0aff, 0x00003200, 0xe0701000, 0x80011406, 0x7da80090,
|
||||
0x4a0602ff, 0x00003600, 0x7e1402ff, 0x000000f0, 0xdce88000, 0x00080a03, 0xbf8c3f70, 0xbf810000
|
||||
0xe0701000, 0x80011406, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
|
|
@ -96,7 +72,7 @@ struct Row {
|
|||
std::uint64_t final;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, 384> Rows{{
|
||||
constexpr std::array<Row, 208> Rows{{
|
||||
{0, 0x0ull, 0x1ull, 0x0ull, 0x0ull, 0x1ull},
|
||||
{0, 0x1ull, 0x80000000ull, 0xf9677975ull, 0x1ull, 0x80000000ull},
|
||||
{0, 0x2ull, 0xffffffffull, 0x2ull, 0x2ull, 0xffffffffull},
|
||||
|
|
@ -305,182 +281,6 @@ constexpr std::array<Row, 384> Rows{{
|
|||
{12, 0xf9a9360ull, 0xf9a9360ull, 0xf85b81cdull, 0xf9a9360ull, 0xf9a935full},
|
||||
{12, 0x6e723d5cull, 0x6e723d5dull, 0x6e723d5cull, 0x6e723d5cull, 0x6e723d5bull},
|
||||
{12, 0x1f609b4full, 0x1f609b4full, 0x69d177f8ull, 0x1f609b4full, 0x1f609b4eull},
|
||||
{13, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{13, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{13, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{13, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xb210ee8d643f54e6ull, 0x8000000000000000ull, 0x123456789abcdef0ull},
|
||||
{13, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{13, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{13, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{13, 0xfffffffeffffffffull, 0x1ull, 0xed5fb21be38948d7ull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{13, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{13, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{13, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{13, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xb346daefa27ab170ull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{13, 0x53bb9629497dfb3full, 0xa4abfed10ad2a242ull, 0x53bb9629497dfb3full, 0x53bb9629497dfb3full, 0xa4abfed10ad2a242ull},
|
||||
{13, 0x6c12816965391baaull, 0xce7cd7b44b45eaf3ull, 0x6c12816967391baaull, 0x6c12816965391baaull, 0xce7cd7b44b45eaf3ull},
|
||||
{13, 0xdba996ccffffffffull, 0x10bbe64100000001ull, 0xdba996ccffffffffull, 0xdba996ccffffffffull, 0x10bbe64100000001ull},
|
||||
{13, 0x5a7c138cffffffffull, 0x9c15fed00000001ull, 0x5a7c138cdfffffffull, 0x5a7c138cffffffffull, 0x9c15fed00000001ull},
|
||||
{14, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{14, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{14, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{14, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x166c48c6e9c1b01cull, 0x8000000000000000ull, 0x8000000000000000ull},
|
||||
{14, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{14, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{14, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{14, 0xfffffffeffffffffull, 0x1ull, 0x866b08e67ea9d02cull, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{14, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{14, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{14, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{14, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xa54604e5b9b1311full, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{14, 0xb9a56d03ead2890full, 0x242f2f3b525af861ull, 0xb9a56d03ead2890full, 0xb9a56d03ead2890full, 0x242f2f3b525af861ull},
|
||||
{14, 0x65c783e7e26c0130ull, 0x19a0106761c2f186ull, 0x65c783e7e06c0130ull, 0x65c783e7e26c0130ull, 0x65c783e7e26c0130ull},
|
||||
{14, 0x7bebc240ffffffffull, 0x4da1ba4b00000001ull, 0x7bebc240ffffffffull, 0x7bebc240ffffffffull, 0x4da1ba4b00000001ull},
|
||||
{14, 0x57e3536bffffffffull, 0xd8d033bd00000001ull, 0x57e3536bdfffffffull, 0x57e3536bffffffffull, 0x57e3536bffffffffull},
|
||||
{15, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{15, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xffffffff00000000ull},
|
||||
{15, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{15, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xd4db9193123f6ebaull, 0x8000000000000000ull, 0x923456789abcdef0ull},
|
||||
{15, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xfffffffffffffffeull},
|
||||
{15, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{15, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ffffffffull},
|
||||
{15, 0xfffffffeffffffffull, 0x1ull, 0x25fd502c82facbc0ull, 0xfffffffeffffffffull, 0xffffffff00000000ull},
|
||||
{15, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456799abcdef0ull},
|
||||
{15, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{15, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xffffffff00000000ull},
|
||||
{15, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xf9124f0e4aae24c5ull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{15, 0xc3e86469baffc1dull, 0xc22f0e9d6d69338dull, 0xc3e86469baffc1dull, 0xc3e86469baffc1dull, 0xce6d94e409192faaull},
|
||||
{15, 0xe499e6544c91e53ull, 0x4647904bf55b8053ull, 0xe499e6546c91e53ull, 0xe499e6544c91e53ull, 0x54912eb13a249ea6ull},
|
||||
{15, 0x7a4a48e2ffffffffull, 0x7ccc4b5300000001ull, 0x7a4a48e2ffffffffull, 0x7a4a48e2ffffffffull, 0xf716943600000000ull},
|
||||
{15, 0xa925179dffffffffull, 0xb2b1ac1800000001ull, 0xa925179ddfffffffull, 0xa925179dffffffffull, 0x5bd6c3b600000000ull},
|
||||
{16, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x8000000000000001ull},
|
||||
{16, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x100000002ull},
|
||||
{16, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{16, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x6835bf86a066a97eull, 0x8000000000000000ull, 0x6dcba98765432110ull},
|
||||
{16, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0x0ull},
|
||||
{16, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{16, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ull},
|
||||
{16, 0xfffffffeffffffffull, 0x1ull, 0xbcbca7d9810b83c1ull, 0xfffffffeffffffffull, 0xfffffffefffffffeull},
|
||||
{16, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456779abcdef0ull},
|
||||
{16, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x8000000000000001ull},
|
||||
{16, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x100000002ull},
|
||||
{16, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x663c553a9a16e35ull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{16, 0x63fbf4e8e453a4c5ull, 0xb7a15652045c43f6ull, 0x63fbf4e8e453a4c5ull, 0x63fbf4e8e453a4c5ull, 0xac5a9e96dff760cfull},
|
||||
{16, 0x1603b25645bdd8aaull, 0x1f87b96dd545e1f1ull, 0x1603b25647bdd8aaull, 0x1603b25645bdd8aaull, 0xf67bf8e87077f6b9ull},
|
||||
{16, 0x757fd168ffffffffull, 0x2356488500000001ull, 0x757fd168ffffffffull, 0x757fd168ffffffffull, 0x522988e3fffffffeull},
|
||||
{16, 0x752b2a35ffffffffull, 0x869e617c00000001ull, 0x752b2a35dfffffffull, 0x752b2a35ffffffffull, 0xee8cc8b9fffffffeull},
|
||||
{17, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x0ull},
|
||||
{17, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{17, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{17, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xd286c038892fd9d4ull, 0x8000000000000000ull, 0x8000000000000000ull},
|
||||
{17, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{17, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{17, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{17, 0xfffffffeffffffffull, 0x1ull, 0x80b34c5cb5907e40ull, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{17, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{17, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{17, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{17, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xe7cd1f2260293767ull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{17, 0x8372abbda96ba8eeull, 0x5e71be928ba29363ull, 0x8372abbda96ba8eeull, 0x8372abbda96ba8eeull, 0x8372abbda96ba8eeull},
|
||||
{17, 0xce77c3cdcc677910ull, 0xdf44f6f934647f0eull, 0xce77c3cdce677910ull, 0xce77c3cdcc677910ull, 0xce77c3cdcc677910ull},
|
||||
{17, 0x9b3edbb1ffffffffull, 0xf4f16cf100000001ull, 0x9b3edbb1ffffffffull, 0x9b3edbb1ffffffffull, 0x9b3edbb1ffffffffull},
|
||||
{17, 0xadf3fbf0ffffffffull, 0x8b29592900000001ull, 0xadf3fbf0dfffffffull, 0xadf3fbf0ffffffffull, 0x8b29592900000001ull},
|
||||
{18, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x0ull},
|
||||
{18, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{18, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{18, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xff63cf82d01938e9ull, 0x8000000000000000ull, 0x123456789abcdef0ull},
|
||||
{18, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{18, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{18, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{18, 0xfffffffeffffffffull, 0x1ull, 0x2a88358605f1254ull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{18, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{18, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{18, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x1ull},
|
||||
{18, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xf078418740b4f6d3ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{18, 0x8d4a240ceafb92f2ull, 0xd789c424b5282b1dull, 0x8d4a240ceafb92f2ull, 0x8d4a240ceafb92f2ull, 0x8d4a240ceafb92f2ull},
|
||||
{18, 0x64b3620ed7a9434full, 0x930b9894c3741be0ull, 0x64b3620ed5a9434full, 0x64b3620ed7a9434full, 0x64b3620ed7a9434full},
|
||||
{18, 0x62a12f63ffffffffull, 0x4a1df58400000001ull, 0x62a12f63ffffffffull, 0x62a12f63ffffffffull, 0x4a1df58400000001ull},
|
||||
{18, 0xd0826a0cffffffffull, 0x14fe08aa00000001ull, 0xd0826a0cdfffffffull, 0xd0826a0cffffffffull, 0x14fe08aa00000001ull},
|
||||
{19, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{19, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{19, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{19, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x35f6b71611838017ull, 0x8000000000000000ull, 0x123456789abcdef0ull},
|
||||
{19, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{19, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{19, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x100000000ull},
|
||||
{19, 0xfffffffeffffffffull, 0x1ull, 0x884dcfec36f43da6ull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{19, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull},
|
||||
{19, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{19, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x1ull},
|
||||
{19, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x97e21514d87b299dull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{19, 0x7ae9f54bc19e56ddull, 0x4a6ac7aeb830ed76ull, 0x7ae9f54bc19e56ddull, 0x7ae9f54bc19e56ddull, 0x7ae9f54bc19e56ddull},
|
||||
{19, 0x5b1c8aa1eb9a258cull, 0xf4a0ea8b3badac72ull, 0x5b1c8aa1e99a258cull, 0x5b1c8aa1eb9a258cull, 0x5b1c8aa1eb9a258cull},
|
||||
{19, 0x869f35deffffffffull, 0xdeffa68100000001ull, 0x869f35deffffffffull, 0x869f35deffffffffull, 0xdeffa68100000001ull},
|
||||
{19, 0x5752b4dfffffffffull, 0x2a51ee7e00000001ull, 0x5752b4dfdfffffffull, 0x5752b4dfffffffffull, 0x5752b4dfffffffffull},
|
||||
{20, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{20, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{20, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{20, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xd316f470e2d8993bull, 0x8000000000000000ull, 0x8000000000000000ull},
|
||||
{20, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{20, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{20, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x100000000ull},
|
||||
{20, 0xfffffffeffffffffull, 0x1ull, 0xfc2b7ace1072e7b9ull, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{20, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull},
|
||||
{20, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{20, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{20, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x142c1e683d47a123ull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{20, 0x5ea0e74f0d30cb76ull, 0xecd62560f1407a13ull, 0x5ea0e74f0d30cb76ull, 0x5ea0e74f0d30cb76ull, 0xecd62560f1407a13ull},
|
||||
{20, 0x6f8664b99db31c8bull, 0x77417f9d1c387d00ull, 0x6f8664b99fb31c8bull, 0x6f8664b99db31c8bull, 0x77417f9d1c387d00ull},
|
||||
{20, 0x1e0ce078ffffffffull, 0xc130cf3c00000001ull, 0x1e0ce078ffffffffull, 0x1e0ce078ffffffffull, 0xc130cf3c00000001ull},
|
||||
{20, 0xd160d889ffffffffull, 0x2b456f6800000001ull, 0xd160d889dfffffffull, 0xd160d889ffffffffull, 0xd160d889ffffffffull},
|
||||
{21, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x0ull},
|
||||
{21, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{21, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x0ull},
|
||||
{21, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x691beca72ac31615ull, 0x8000000000000000ull, 0x0ull},
|
||||
{21, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{21, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{21, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x0ull},
|
||||
{21, 0xfffffffeffffffffull, 0x1ull, 0xc89594109911783aull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{21, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x0ull},
|
||||
{21, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{21, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x1ull},
|
||||
{21, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xa69bfe93d6efb4ddull, 0x7fffffffffffffffull, 0x0ull},
|
||||
{21, 0xd5e7cc579d21963aull, 0x93826a1ee8ab2ed1ull, 0xd5e7cc579d21963aull, 0xd5e7cc579d21963aull, 0x9182481688210610ull},
|
||||
{21, 0x657c382c4e1cfcddull, 0x837a0dc63ac35f32ull, 0x657c382c4c1cfcddull, 0x657c382c4e1cfcddull, 0x17808040a005c10ull},
|
||||
{21, 0x7552c284ffffffffull, 0x995c2cf200000001ull, 0x7552c284ffffffffull, 0x7552c284ffffffffull, 0x1150008000000001ull},
|
||||
{21, 0xe20d4f8dffffffffull, 0x4864cdbc00000001ull, 0xe20d4f8ddfffffffull, 0xe20d4f8dffffffffull, 0x40044d8c00000001ull},
|
||||
{22, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{22, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{22, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{22, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xbad3dfdbb007d4ecull, 0x8000000000000000ull, 0x923456789abcdef0ull},
|
||||
{22, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{22, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{22, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ffffffffull},
|
||||
{22, 0xfffffffeffffffffull, 0x1ull, 0xedecea3c6fa0d23full, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{22, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456799abcdef0ull},
|
||||
{22, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{22, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{22, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xf7926675f45d1971ull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{22, 0x360443a82569e20cull, 0x3800d9ff899231faull, 0x360443a82569e20cull, 0x360443a82569e20cull, 0x3e04dbffadfbf3feull},
|
||||
{22, 0xc265df77a6c71a0dull, 0x5e94d6ccc50557f8ull, 0xc265df77a4c71a0dull, 0xc265df77a6c71a0dull, 0xdef5dfffe7c75ffdull},
|
||||
{22, 0x41a90d6bffffffffull, 0x4bb3092400000001ull, 0x41a90d6bffffffffull, 0x41a90d6bffffffffull, 0x4bbb0d6fffffffffull},
|
||||
{22, 0xc54e9269ffffffffull, 0xf536f34000000001ull, 0xc54e9269dfffffffull, 0xc54e9269ffffffffull, 0xf57ef369ffffffffull},
|
||||
{23, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{23, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffefffffffeull},
|
||||
{23, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{23, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xe3b411de678ee5c0ull, 0x8000000000000000ull, 0x923456789abcdef0ull},
|
||||
{23, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0x0ull},
|
||||
{23, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{23, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ffffffffull},
|
||||
{23, 0xfffffffeffffffffull, 0x1ull, 0xe4e171d83c299defull, 0xfffffffeffffffffull, 0xfffffffefffffffeull},
|
||||
{23, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456799abcdef0ull},
|
||||
{23, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{23, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffefffffffeull},
|
||||
{23, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xaa23249b400d9ebdull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{23, 0xc1f06114a97ad060ull, 0x679f7fe64c950a15ull, 0xc1f06114a97ad060ull, 0xc1f06114a97ad060ull, 0xa66f1ef2e5efda75ull},
|
||||
{23, 0x59bdb13042bcfe48ull, 0x1669010b3ea903bbull, 0x59bdb13040bcfe48ull, 0x59bdb13042bcfe48ull, 0x4fd4b03b7c15fdf3ull},
|
||||
{23, 0x701d03a9ffffffffull, 0xf96a081600000001ull, 0x701d03a9ffffffffull, 0x701d03a9ffffffffull, 0x89770bbffffffffeull},
|
||||
{23, 0x9b817862ffffffffull, 0x3c3e50fe00000001ull, 0x9b817862dfffffffull, 0x9b817862ffffffffull, 0xa7bf289cfffffffeull},
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
|
|
@ -539,12 +339,6 @@ std::vector<std::uint8_t> Initial() {
|
|||
Put(image, op * OpStride + tid * 8u, RowOf(op, tid).memory, OpBytes(op));
|
||||
}
|
||||
}
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, Special + tid * 8u, 0x1000u * tid, 4);
|
||||
Put(image, Special + Threads * 8u + tid * 8u, 0xa5a5a5a5u ^ tid, 4);
|
||||
Put(image, Special + Threads * 24u + tid * 8u, 0x0f0f0f00u + tid, 4);
|
||||
}
|
||||
Put(image, Special + Threads * 16u + 4u, 0x11u, 4);
|
||||
return image;
|
||||
}
|
||||
|
||||
|
|
@ -555,14 +349,6 @@ std::vector<std::uint8_t> Expected() {
|
|||
Put(image, op * OpStride + tid * 8u, RowOf(op, tid).final, OpBytes(op));
|
||||
}
|
||||
}
|
||||
std::uint32_t total = 0x11u;
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, Special + tid * 8u, 0x1000u * tid + tid + 1u, 4);
|
||||
Put(image, Special + Threads * 8u + tid * 8u, (0xa5a5a5a5u ^ tid) ^ (tid << 8u), 4);
|
||||
if (tid < 16u) Put(image, Special + Threads * 24u + tid * 8u, (0x0f0f0f00u + tid) | 0xf0u, 4);
|
||||
total += (tid + 1u) << 8u;
|
||||
}
|
||||
Put(image, Special + Threads * 16u + 4u, total, 4);
|
||||
return image;
|
||||
}
|
||||
|
||||
|
|
@ -625,18 +411,6 @@ void RunAtomics(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::uint32_
|
|||
Require(returned == row.returned, wave + "op " + std::to_string(op) + " lane " + std::to_string(tid) + " returned " + Hex(returned) + ", expected " + Hex(row.returned));
|
||||
}
|
||||
}
|
||||
std::vector<std::pair<std::uint32_t, std::uint32_t>> order;
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto flat = Output[(OpCount * Threads + tid) * 2u];
|
||||
Require(flat == (0xa5a5a5a5u ^ tid), wave + "flat xor returned " + Hex(flat) + " to lane " + std::to_string(tid));
|
||||
order.emplace_back(Output[((OpCount + 1u) * Threads + tid) * 2u], tid);
|
||||
}
|
||||
std::sort(order.begin(), order.end());
|
||||
std::uint32_t running = 0x11u;
|
||||
for (const auto& [returned, tid] : order) {
|
||||
Require(returned == running, wave + "contended add returned " + Hex(returned) + " to lane " + std::to_string(tid) + ", expected " + Hex(running));
|
||||
running += (tid + 1u) << 8u;
|
||||
}
|
||||
const auto expected = Expected();
|
||||
for (std::uint32_t offset = 0; offset < BlockBytes; ++offset) {
|
||||
const auto actual = guest.Data()[offset];
|
||||
|
|
@ -644,15 +418,6 @@ void RunAtomics(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::uint32_
|
|||
}
|
||||
}
|
||||
|
||||
void RunReadOnly(AgcDriver::VulkanDevice& device, GuestBlock& guest) {
|
||||
const auto initial = Initial();
|
||||
std::memcpy(guest.Data(), initial.data(), BlockBytes);
|
||||
FillInput();
|
||||
Dispatch(device, 32, guest.Data());
|
||||
for (std::uint32_t offset = 0; offset < BlockBytes; ++offset) {
|
||||
Require(guest.Data()[offset] == initial[offset], "global atomics: an atomic into a read-only range changed byte " + std::to_string(offset));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -661,10 +426,7 @@ int main() {
|
|||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock writable(true);
|
||||
GuestBlock readOnly(false);
|
||||
RunAtomics(*device, writable, 32);
|
||||
RunAtomics(*device, writable, 64);
|
||||
RunReadOnly(*device, readOnly);
|
||||
std::puts("global atomics tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,400 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 64;
|
||||
constexpr std::uint32_t RowsPerOp = 16;
|
||||
constexpr std::uint32_t OpCount = 11;
|
||||
constexpr std::uint32_t NarrowOps = 0;
|
||||
constexpr std::uint32_t OpStride = 0x200;
|
||||
constexpr std::uint32_t Special = OpCount * OpStride;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::uint8_t Fill = 0xcd;
|
||||
alignas(256) std::array<std::uint32_t, OpCount * Threads * 4> Input{};
|
||||
alignas(256) std::array<std::uint32_t, (OpCount + 2) * Threads * 2> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 159> GlobalAtomicsCode{
|
||||
0x34020083, 0x34040084, 0x340a0083, 0x7e2802ff, 0x05e471e1, 0x7e2a02ff, 0x05e471e1, 0x4a060280,
|
||||
0x4a080480, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0a80, 0xdd418000, 0x14080a03, 0xbf8c3f70,
|
||||
0xe0741000, 0x80011406, 0x4a0602ff, 0x00000200, 0x4a0804ff, 0x00000400, 0xe0381000, 0x80000a04,
|
||||
0xbf8c3f70, 0x4a0c0aff, 0x00000200, 0xdd458000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406,
|
||||
0x4a0602ff, 0x00000400, 0x4a0804ff, 0x00000800, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff,
|
||||
0x00000400, 0xdd498000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00000600,
|
||||
0x4a0804ff, 0x00000c00, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00000600, 0xdd4d8000,
|
||||
0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00000800, 0x4a0804ff, 0x00001000,
|
||||
0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00000800, 0xdd558000, 0x14080a03, 0xbf8c3f70,
|
||||
0xe0741000, 0x80011406, 0x4a0602ff, 0x00000a00, 0x4a0804ff, 0x00001400, 0xe0381000, 0x80000a04,
|
||||
0xbf8c3f70, 0x4a0c0aff, 0x00000a00, 0xdd598000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406,
|
||||
0x4a0602ff, 0x00000c00, 0x4a0804ff, 0x00001800, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff,
|
||||
0x00000c00, 0xdd5d8000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00000e00,
|
||||
0x4a0804ff, 0x00001c00, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00000e00, 0xdd618000,
|
||||
0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0x4a0602ff, 0x00001000, 0x4a0804ff, 0x00002000,
|
||||
0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff, 0x00001000, 0xdd658000, 0x14080a03, 0xbf8c3f70,
|
||||
0xe0741000, 0x80011406, 0x4a0602ff, 0x00001200, 0x4a0804ff, 0x00002400, 0xe0381000, 0x80000a04,
|
||||
0xbf8c3f70, 0x4a0c0aff, 0x00001200, 0xdd698000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406,
|
||||
0x4a0602ff, 0x00001400, 0x4a0804ff, 0x00002800, 0xe0381000, 0x80000a04, 0xbf8c3f70, 0x4a0c0aff,
|
||||
0x00001400, 0xdd6d8000, 0x14080a03, 0xbf8c3f70, 0xe0741000, 0x80011406, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::uint32_t op;
|
||||
std::uint64_t memory;
|
||||
std::uint64_t data;
|
||||
std::uint64_t comparator;
|
||||
std::uint64_t returned;
|
||||
std::uint64_t final;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, 176> Rows{{
|
||||
{0, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{0, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{0, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{0, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xb210ee8d643f54e6ull, 0x8000000000000000ull, 0x123456789abcdef0ull},
|
||||
{0, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{0, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{0, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{0, 0xfffffffeffffffffull, 0x1ull, 0xed5fb21be38948d7ull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{0, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{0, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{0, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{0, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xb346daefa27ab170ull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{0, 0x53bb9629497dfb3full, 0xa4abfed10ad2a242ull, 0x53bb9629497dfb3full, 0x53bb9629497dfb3full, 0xa4abfed10ad2a242ull},
|
||||
{0, 0x6c12816965391baaull, 0xce7cd7b44b45eaf3ull, 0x6c12816967391baaull, 0x6c12816965391baaull, 0xce7cd7b44b45eaf3ull},
|
||||
{0, 0xdba996ccffffffffull, 0x10bbe64100000001ull, 0xdba996ccffffffffull, 0xdba996ccffffffffull, 0x10bbe64100000001ull},
|
||||
{0, 0x5a7c138cffffffffull, 0x9c15fed00000001ull, 0x5a7c138cdfffffffull, 0x5a7c138cffffffffull, 0x9c15fed00000001ull},
|
||||
{1, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{1, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{1, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{1, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x166c48c6e9c1b01cull, 0x8000000000000000ull, 0x8000000000000000ull},
|
||||
{1, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{1, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{1, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{1, 0xfffffffeffffffffull, 0x1ull, 0x866b08e67ea9d02cull, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{1, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{1, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{1, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{1, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xa54604e5b9b1311full, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{1, 0xb9a56d03ead2890full, 0x242f2f3b525af861ull, 0xb9a56d03ead2890full, 0xb9a56d03ead2890full, 0x242f2f3b525af861ull},
|
||||
{1, 0x65c783e7e26c0130ull, 0x19a0106761c2f186ull, 0x65c783e7e06c0130ull, 0x65c783e7e26c0130ull, 0x65c783e7e26c0130ull},
|
||||
{1, 0x7bebc240ffffffffull, 0x4da1ba4b00000001ull, 0x7bebc240ffffffffull, 0x7bebc240ffffffffull, 0x4da1ba4b00000001ull},
|
||||
{1, 0x57e3536bffffffffull, 0xd8d033bd00000001ull, 0x57e3536bdfffffffull, 0x57e3536bffffffffull, 0x57e3536bffffffffull},
|
||||
{2, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{2, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xffffffff00000000ull},
|
||||
{2, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{2, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xd4db9193123f6ebaull, 0x8000000000000000ull, 0x923456789abcdef0ull},
|
||||
{2, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xfffffffffffffffeull},
|
||||
{2, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{2, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ffffffffull},
|
||||
{2, 0xfffffffeffffffffull, 0x1ull, 0x25fd502c82facbc0ull, 0xfffffffeffffffffull, 0xffffffff00000000ull},
|
||||
{2, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456799abcdef0ull},
|
||||
{2, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{2, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xffffffff00000000ull},
|
||||
{2, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xf9124f0e4aae24c5ull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{2, 0xc3e86469baffc1dull, 0xc22f0e9d6d69338dull, 0xc3e86469baffc1dull, 0xc3e86469baffc1dull, 0xce6d94e409192faaull},
|
||||
{2, 0xe499e6544c91e53ull, 0x4647904bf55b8053ull, 0xe499e6546c91e53ull, 0xe499e6544c91e53ull, 0x54912eb13a249ea6ull},
|
||||
{2, 0x7a4a48e2ffffffffull, 0x7ccc4b5300000001ull, 0x7a4a48e2ffffffffull, 0x7a4a48e2ffffffffull, 0xf716943600000000ull},
|
||||
{2, 0xa925179dffffffffull, 0xb2b1ac1800000001ull, 0xa925179ddfffffffull, 0xa925179dffffffffull, 0x5bd6c3b600000000ull},
|
||||
{3, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x8000000000000001ull},
|
||||
{3, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x100000002ull},
|
||||
{3, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{3, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x6835bf86a066a97eull, 0x8000000000000000ull, 0x6dcba98765432110ull},
|
||||
{3, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0x0ull},
|
||||
{3, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{3, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ull},
|
||||
{3, 0xfffffffeffffffffull, 0x1ull, 0xbcbca7d9810b83c1ull, 0xfffffffeffffffffull, 0xfffffffefffffffeull},
|
||||
{3, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456779abcdef0ull},
|
||||
{3, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x8000000000000001ull},
|
||||
{3, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x100000002ull},
|
||||
{3, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x663c553a9a16e35ull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{3, 0x63fbf4e8e453a4c5ull, 0xb7a15652045c43f6ull, 0x63fbf4e8e453a4c5ull, 0x63fbf4e8e453a4c5ull, 0xac5a9e96dff760cfull},
|
||||
{3, 0x1603b25645bdd8aaull, 0x1f87b96dd545e1f1ull, 0x1603b25647bdd8aaull, 0x1603b25645bdd8aaull, 0xf67bf8e87077f6b9ull},
|
||||
{3, 0x757fd168ffffffffull, 0x2356488500000001ull, 0x757fd168ffffffffull, 0x757fd168ffffffffull, 0x522988e3fffffffeull},
|
||||
{3, 0x752b2a35ffffffffull, 0x869e617c00000001ull, 0x752b2a35dfffffffull, 0x752b2a35ffffffffull, 0xee8cc8b9fffffffeull},
|
||||
{4, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x0ull},
|
||||
{4, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{4, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{4, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xd286c038892fd9d4ull, 0x8000000000000000ull, 0x8000000000000000ull},
|
||||
{4, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{4, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{4, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{4, 0xfffffffeffffffffull, 0x1ull, 0x80b34c5cb5907e40ull, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{4, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{4, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{4, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{4, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xe7cd1f2260293767ull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{4, 0x8372abbda96ba8eeull, 0x5e71be928ba29363ull, 0x8372abbda96ba8eeull, 0x8372abbda96ba8eeull, 0x8372abbda96ba8eeull},
|
||||
{4, 0xce77c3cdcc677910ull, 0xdf44f6f934647f0eull, 0xce77c3cdce677910ull, 0xce77c3cdcc677910ull, 0xce77c3cdcc677910ull},
|
||||
{4, 0x9b3edbb1ffffffffull, 0xf4f16cf100000001ull, 0x9b3edbb1ffffffffull, 0x9b3edbb1ffffffffull, 0x9b3edbb1ffffffffull},
|
||||
{4, 0xadf3fbf0ffffffffull, 0x8b29592900000001ull, 0xadf3fbf0dfffffffull, 0xadf3fbf0ffffffffull, 0x8b29592900000001ull},
|
||||
{5, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x0ull},
|
||||
{5, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{5, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{5, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xff63cf82d01938e9ull, 0x8000000000000000ull, 0x123456789abcdef0ull},
|
||||
{5, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{5, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{5, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0xffffffffull},
|
||||
{5, 0xfffffffeffffffffull, 0x1ull, 0x2a88358605f1254ull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{5, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x100000000ull},
|
||||
{5, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{5, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x1ull},
|
||||
{5, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xf078418740b4f6d3ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{5, 0x8d4a240ceafb92f2ull, 0xd789c424b5282b1dull, 0x8d4a240ceafb92f2ull, 0x8d4a240ceafb92f2ull, 0x8d4a240ceafb92f2ull},
|
||||
{5, 0x64b3620ed7a9434full, 0x930b9894c3741be0ull, 0x64b3620ed5a9434full, 0x64b3620ed7a9434full, 0x64b3620ed7a9434full},
|
||||
{5, 0x62a12f63ffffffffull, 0x4a1df58400000001ull, 0x62a12f63ffffffffull, 0x62a12f63ffffffffull, 0x4a1df58400000001ull},
|
||||
{5, 0xd0826a0cffffffffull, 0x14fe08aa00000001ull, 0xd0826a0cdfffffffull, 0xd0826a0cffffffffull, 0x14fe08aa00000001ull},
|
||||
{6, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{6, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{6, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{6, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x35f6b71611838017ull, 0x8000000000000000ull, 0x123456789abcdef0ull},
|
||||
{6, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{6, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{6, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x100000000ull},
|
||||
{6, 0xfffffffeffffffffull, 0x1ull, 0x884dcfec36f43da6ull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{6, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull},
|
||||
{6, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{6, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x1ull},
|
||||
{6, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x97e21514d87b299dull, 0x7fffffffffffffffull, 0x7fffffffffffffffull},
|
||||
{6, 0x7ae9f54bc19e56ddull, 0x4a6ac7aeb830ed76ull, 0x7ae9f54bc19e56ddull, 0x7ae9f54bc19e56ddull, 0x7ae9f54bc19e56ddull},
|
||||
{6, 0x5b1c8aa1eb9a258cull, 0xf4a0ea8b3badac72ull, 0x5b1c8aa1e99a258cull, 0x5b1c8aa1eb9a258cull, 0x5b1c8aa1eb9a258cull},
|
||||
{6, 0x869f35deffffffffull, 0xdeffa68100000001ull, 0x869f35deffffffffull, 0x869f35deffffffffull, 0xdeffa68100000001ull},
|
||||
{6, 0x5752b4dfffffffffull, 0x2a51ee7e00000001ull, 0x5752b4dfdfffffffull, 0x5752b4dfffffffffull, 0x5752b4dfffffffffull},
|
||||
{7, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{7, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{7, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{7, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xd316f470e2d8993bull, 0x8000000000000000ull, 0x8000000000000000ull},
|
||||
{7, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{7, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{7, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x100000000ull},
|
||||
{7, 0xfffffffeffffffffull, 0x1ull, 0xfc2b7ace1072e7b9ull, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{7, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull},
|
||||
{7, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{7, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{7, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x142c1e683d47a123ull, 0x7fffffffffffffffull, 0x8000000000000000ull},
|
||||
{7, 0x5ea0e74f0d30cb76ull, 0xecd62560f1407a13ull, 0x5ea0e74f0d30cb76ull, 0x5ea0e74f0d30cb76ull, 0xecd62560f1407a13ull},
|
||||
{7, 0x6f8664b99db31c8bull, 0x77417f9d1c387d00ull, 0x6f8664b99fb31c8bull, 0x6f8664b99db31c8bull, 0x77417f9d1c387d00ull},
|
||||
{7, 0x1e0ce078ffffffffull, 0xc130cf3c00000001ull, 0x1e0ce078ffffffffull, 0x1e0ce078ffffffffull, 0xc130cf3c00000001ull},
|
||||
{7, 0xd160d889ffffffffull, 0x2b456f6800000001ull, 0xd160d889dfffffffull, 0xd160d889ffffffffull, 0xd160d889ffffffffull},
|
||||
{8, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x0ull},
|
||||
{8, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0x1ull},
|
||||
{8, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0x0ull},
|
||||
{8, 0x8000000000000000ull, 0x123456789abcdef0ull, 0x691beca72ac31615ull, 0x8000000000000000ull, 0x0ull},
|
||||
{8, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{8, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0x0ull},
|
||||
{8, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x0ull},
|
||||
{8, 0xfffffffeffffffffull, 0x1ull, 0xc89594109911783aull, 0xfffffffeffffffffull, 0x1ull},
|
||||
{8, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x0ull},
|
||||
{8, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x0ull},
|
||||
{8, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0x1ull},
|
||||
{8, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xa69bfe93d6efb4ddull, 0x7fffffffffffffffull, 0x0ull},
|
||||
{8, 0xd5e7cc579d21963aull, 0x93826a1ee8ab2ed1ull, 0xd5e7cc579d21963aull, 0xd5e7cc579d21963aull, 0x9182481688210610ull},
|
||||
{8, 0x657c382c4e1cfcddull, 0x837a0dc63ac35f32ull, 0x657c382c4c1cfcddull, 0x657c382c4e1cfcddull, 0x17808040a005c10ull},
|
||||
{8, 0x7552c284ffffffffull, 0x995c2cf200000001ull, 0x7552c284ffffffffull, 0x7552c284ffffffffull, 0x1150008000000001ull},
|
||||
{8, 0xe20d4f8dffffffffull, 0x4864cdbc00000001ull, 0xe20d4f8ddfffffffull, 0xe20d4f8dffffffffull, 0x40044d8c00000001ull},
|
||||
{9, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{9, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{9, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{9, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xbad3dfdbb007d4ecull, 0x8000000000000000ull, 0x923456789abcdef0ull},
|
||||
{9, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull},
|
||||
{9, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{9, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ffffffffull},
|
||||
{9, 0xfffffffeffffffffull, 0x1ull, 0xedecea3c6fa0d23full, 0xfffffffeffffffffull, 0xfffffffeffffffffull},
|
||||
{9, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456799abcdef0ull},
|
||||
{9, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{9, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffeffffffffull},
|
||||
{9, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xf7926675f45d1971ull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{9, 0x360443a82569e20cull, 0x3800d9ff899231faull, 0x360443a82569e20cull, 0x360443a82569e20cull, 0x3e04dbffadfbf3feull},
|
||||
{9, 0xc265df77a6c71a0dull, 0x5e94d6ccc50557f8ull, 0xc265df77a4c71a0dull, 0xc265df77a6c71a0dull, 0xdef5dfffe7c75ffdull},
|
||||
{9, 0x41a90d6bffffffffull, 0x4bb3092400000001ull, 0x41a90d6bffffffffull, 0x41a90d6bffffffffull, 0x4bbb0d6fffffffffull},
|
||||
{9, 0xc54e9269ffffffffull, 0xf536f34000000001ull, 0xc54e9269dfffffffull, 0xc54e9269ffffffffull, 0xf57ef369ffffffffull},
|
||||
{10, 0x0ull, 0x7fffffffffffffffull, 0x0ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{10, 0x1ull, 0xfffffffeffffffffull, 0x3ull, 0x1ull, 0xfffffffefffffffeull},
|
||||
{10, 0x7fffffffffffffffull, 0x8000000000000000ull, 0x7fffffffffffffffull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{10, 0x8000000000000000ull, 0x123456789abcdef0ull, 0xe3b411de678ee5c0ull, 0x8000000000000000ull, 0x923456789abcdef0ull},
|
||||
{10, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0xffffffffffffffffull, 0x0ull},
|
||||
{10, 0xffffffffull, 0x0ull, 0xffffffdfull, 0xffffffffull, 0xffffffffull},
|
||||
{10, 0x100000000ull, 0xffffffffull, 0x100000000ull, 0x100000000ull, 0x1ffffffffull},
|
||||
{10, 0xfffffffeffffffffull, 0x1ull, 0xe4e171d83c299defull, 0xfffffffeffffffffull, 0xfffffffefffffffeull},
|
||||
{10, 0x123456789abcdef0ull, 0x100000000ull, 0x123456789abcdef0ull, 0x123456789abcdef0ull, 0x123456799abcdef0ull},
|
||||
{10, 0x0ull, 0x7fffffffffffffffull, 0x200ull, 0x0ull, 0x7fffffffffffffffull},
|
||||
{10, 0x1ull, 0xfffffffeffffffffull, 0x1ull, 0x1ull, 0xfffffffefffffffeull},
|
||||
{10, 0x7fffffffffffffffull, 0x8000000000000000ull, 0xaa23249b400d9ebdull, 0x7fffffffffffffffull, 0xffffffffffffffffull},
|
||||
{10, 0xc1f06114a97ad060ull, 0x679f7fe64c950a15ull, 0xc1f06114a97ad060ull, 0xc1f06114a97ad060ull, 0xa66f1ef2e5efda75ull},
|
||||
{10, 0x59bdb13042bcfe48ull, 0x1669010b3ea903bbull, 0x59bdb13040bcfe48ull, 0x59bdb13042bcfe48ull, 0x4fd4b03b7c15fdf3ull},
|
||||
{10, 0x701d03a9ffffffffull, 0xf96a081600000001ull, 0x701d03a9ffffffffull, 0x701d03a9ffffffffull, 0x89770bbffffffffeull},
|
||||
{10, 0x9b817862ffffffffull, 0x3c3e50fe00000001ull, 0x9b817862dfffffffull, 0x9b817862ffffffffull, 0xa7bf289cfffffffeull},
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
explicit GuestBlock(bool writable) {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global atomics: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
const std::uint8_t* Data() const { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
void Put(std::vector<std::uint8_t>& image, std::uint32_t offset, std::uint64_t value, std::uint32_t bytes) {
|
||||
for (std::uint32_t byte = 0; byte < bytes; ++byte) image.at(offset + byte) = static_cast<std::uint8_t>(value >> (byte * 8u));
|
||||
}
|
||||
|
||||
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::uint64_t value) {
|
||||
char text[24];
|
||||
std::snprintf(text, sizeof(text), "0x%llx", static_cast<unsigned long long>(value));
|
||||
return text;
|
||||
}
|
||||
|
||||
const Row& RowOf(std::uint32_t op, std::uint32_t tid) {
|
||||
return Rows.at(op * RowsPerOp + tid % RowsPerOp);
|
||||
}
|
||||
|
||||
std::uint32_t OpBytes(std::uint32_t op) {
|
||||
return op < NarrowOps ? 4u : 8u;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> Initial() {
|
||||
std::vector<std::uint8_t> image(BlockBytes, Fill);
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, op * OpStride + tid * 8u, RowOf(op, tid).memory, OpBytes(op));
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> Expected() {
|
||||
auto image = Initial();
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, op * OpStride + tid * 8u, RowOf(op, tid).final, OpBytes(op));
|
||||
}
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
void FillInput() {
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& row = RowOf(op, tid);
|
||||
auto* words = &Input[(op * Threads + tid) * 4u];
|
||||
if (OpBytes(op) == 4u) {
|
||||
words[0] = static_cast<std::uint32_t>(row.data);
|
||||
words[1] = static_cast<std::uint32_t>(row.comparator);
|
||||
words[2] = 0u;
|
||||
words[3] = 0u;
|
||||
} else {
|
||||
words[0] = static_cast<std::uint32_t>(row.data);
|
||||
words[1] = static_cast<std::uint32_t>(row.data >> 32u);
|
||||
words[2] = static_cast<std::uint32_t>(row.comparator);
|
||||
words[3] = static_cast<std::uint32_t>(row.comparator >> 32u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 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);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
const std::span<const std::uint32_t> code(GlobalAtomicsCode);
|
||||
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}, 0, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{waveSize, 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 RunAtomics(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::uint32_t waveSize) {
|
||||
const auto initial = Initial();
|
||||
std::memcpy(guest.Data(), initial.data(), BlockBytes);
|
||||
FillInput();
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, waveSize, guest.Data());
|
||||
const auto wave = "global atomics: wave" + std::to_string(waveSize) + " ";
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& row = RowOf(op, tid);
|
||||
const auto* words = &Output[(op * Threads + tid) * 2u];
|
||||
const auto returned = OpBytes(op) == 4u ? static_cast<std::uint64_t>(words[0]) : (static_cast<std::uint64_t>(words[1]) << 32u) | words[0];
|
||||
Require(returned == row.returned, wave + "op " + std::to_string(op) + " lane " + std::to_string(tid) + " returned " + Hex(returned) + ", expected " + Hex(row.returned));
|
||||
}
|
||||
}
|
||||
const auto expected = Expected();
|
||||
for (std::uint32_t offset = 0; offset < BlockBytes; ++offset) {
|
||||
const auto actual = guest.Data()[offset];
|
||||
Require(actual == expected[offset], wave + "byte " + std::to_string(offset) + " is " + std::to_string(actual) + ", expected " + std::to_string(expected[offset]));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock writable(true);
|
||||
RunAtomics(*device, writable, 32);
|
||||
std::puts("global atomics 64 tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 64;
|
||||
constexpr std::uint32_t RowsPerOp = 16;
|
||||
constexpr std::uint32_t OpCount = 0;
|
||||
constexpr std::uint32_t NarrowOps = 0;
|
||||
constexpr std::uint32_t OpStride = 0x200;
|
||||
constexpr std::uint32_t Special = OpCount * OpStride;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::uint8_t Fill = 0xcd;
|
||||
alignas(256) std::array<std::uint32_t, OpCount * Threads * 4> Input{};
|
||||
alignas(256) std::array<std::uint32_t, (OpCount + 2) * Threads * 2> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 57> GlobalAtomicsCode{
|
||||
0x34020083, 0x34040084, 0x340a0083, 0x7e2802ff, 0x05e471e1, 0x7e2a02ff, 0x05e471e1, 0x4a060280,
|
||||
0x7e2802ff, 0x05e471e1, 0x4a140081, 0xdcc88000, 0x00080a03, 0xbf8c3f70, 0xd70f6a1e, 0x02020608,
|
||||
0x7e3e0209, 0x503e3e80, 0xd70f6a1e, 0x02023cff, 0x00000200, 0x503e3e80, 0x34140088, 0xdced0000,
|
||||
0x147d0a1e, 0xbf8c0070, 0x4a0c0a80, 0xe0701000, 0x80011406, 0x7e0602ff, 0x00000400, 0x4a1414ff,
|
||||
0x00000100, 0xdcc98004, 0x14080a03, 0xbf8c3f70, 0x4a0c0aff, 0x00000200, 0xe0701000, 0x80011406,
|
||||
0x4a0602ff, 0x00000800, 0x4a1400ff, 0x00000100, 0x7e160280, 0xdd488000, 0x00080a03, 0xbf8c3f70,
|
||||
0x7da80090, 0x4a0602ff, 0x00000600, 0x7e1402ff, 0x000000f0, 0xdce88000, 0x00080a03, 0xbf8c3f70,
|
||||
0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::uint32_t op;
|
||||
std::uint64_t memory;
|
||||
std::uint64_t data;
|
||||
std::uint64_t comparator;
|
||||
std::uint64_t returned;
|
||||
std::uint64_t final;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, 0> Rows{};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
explicit GuestBlock(bool writable) {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global atomics: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, writable);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
const std::uint8_t* Data() const { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
void Put(std::vector<std::uint8_t>& image, std::uint32_t offset, std::uint64_t value, std::uint32_t bytes) {
|
||||
for (std::uint32_t byte = 0; byte < bytes; ++byte) image.at(offset + byte) = static_cast<std::uint8_t>(value >> (byte * 8u));
|
||||
}
|
||||
|
||||
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::uint64_t value) {
|
||||
char text[24];
|
||||
std::snprintf(text, sizeof(text), "0x%llx", static_cast<unsigned long long>(value));
|
||||
return text;
|
||||
}
|
||||
|
||||
const Row& RowOf(std::uint32_t op, std::uint32_t tid) {
|
||||
return Rows.at(op * RowsPerOp + tid % RowsPerOp);
|
||||
}
|
||||
|
||||
std::uint32_t OpBytes(std::uint32_t op) {
|
||||
return op < NarrowOps ? 4u : 8u;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> Initial() {
|
||||
std::vector<std::uint8_t> image(BlockBytes, Fill);
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, op * OpStride + tid * 8u, RowOf(op, tid).memory, OpBytes(op));
|
||||
}
|
||||
}
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, Special + tid * 8u, 0x1000u * tid, 4);
|
||||
Put(image, Special + Threads * 8u + tid * 8u, 0xa5a5a5a5u ^ tid, 4);
|
||||
Put(image, Special + Threads * 24u + tid * 8u, 0x0f0f0f00u + tid, 4);
|
||||
Put(image, Special + Threads * 32u + tid * 8u, 0x7fffffffffffff00ull + tid, 8);
|
||||
}
|
||||
Put(image, Special + Threads * 16u + 4u, 0x11u, 4);
|
||||
return image;
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> Expected() {
|
||||
auto image = Initial();
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, op * OpStride + tid * 8u, RowOf(op, tid).final, OpBytes(op));
|
||||
}
|
||||
}
|
||||
std::uint32_t total = 0x11u;
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
Put(image, Special + tid * 8u, 0x1000u * tid + tid + 1u, 4);
|
||||
Put(image, Special + Threads * 8u + tid * 8u, (0xa5a5a5a5u ^ tid) ^ (tid << 8u), 4);
|
||||
if (tid < 16u) Put(image, Special + Threads * 24u + tid * 8u, (0x0f0f0f00u + tid) | 0xf0u, 4);
|
||||
Put(image, Special + Threads * 32u + tid * 8u, 0x7fffffffffffff00ull + tid + 0x100u + tid, 8);
|
||||
total += (tid + 1u) << 8u;
|
||||
}
|
||||
Put(image, Special + Threads * 16u + 4u, total, 4);
|
||||
return image;
|
||||
}
|
||||
|
||||
void FillInput() {
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& row = RowOf(op, tid);
|
||||
auto* words = &Input[(op * Threads + tid) * 4u];
|
||||
if (OpBytes(op) == 4u) {
|
||||
words[0] = static_cast<std::uint32_t>(row.data);
|
||||
words[1] = static_cast<std::uint32_t>(row.comparator);
|
||||
words[2] = 0u;
|
||||
words[3] = 0u;
|
||||
} else {
|
||||
words[0] = static_cast<std::uint32_t>(row.data);
|
||||
words[1] = static_cast<std::uint32_t>(row.data >> 32u);
|
||||
words[2] = static_cast<std::uint32_t>(row.comparator);
|
||||
words[3] = static_cast<std::uint32_t>(row.comparator >> 32u);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 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);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
const std::span<const std::uint32_t> code(GlobalAtomicsCode);
|
||||
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}, 0, {false, false, false}, false, 1};
|
||||
ShaderRecompiler::RecompileRequest request{
|
||||
{ShaderStage::Compute, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{waveSize, 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 RunAtomics(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::uint32_t waveSize) {
|
||||
const auto initial = Initial();
|
||||
std::memcpy(guest.Data(), initial.data(), BlockBytes);
|
||||
FillInput();
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, waveSize, guest.Data());
|
||||
const auto wave = "global atomics: wave" + std::to_string(waveSize) + " ";
|
||||
for (std::uint32_t op = 0; op < OpCount; ++op) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& row = RowOf(op, tid);
|
||||
const auto* words = &Output[(op * Threads + tid) * 2u];
|
||||
const auto returned = OpBytes(op) == 4u ? static_cast<std::uint64_t>(words[0]) : (static_cast<std::uint64_t>(words[1]) << 32u) | words[0];
|
||||
Require(returned == row.returned, wave + "op " + std::to_string(op) + " lane " + std::to_string(tid) + " returned " + Hex(returned) + ", expected " + Hex(row.returned));
|
||||
}
|
||||
}
|
||||
std::vector<std::pair<std::uint32_t, std::uint32_t>> order;
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto flat = Output[(OpCount * Threads + tid) * 2u];
|
||||
Require(flat == (0xa5a5a5a5u ^ tid), wave + "flat xor returned " + Hex(flat) + " to lane " + std::to_string(tid));
|
||||
order.emplace_back(Output[((OpCount + 1u) * Threads + tid) * 2u], tid);
|
||||
}
|
||||
std::sort(order.begin(), order.end());
|
||||
std::uint32_t running = 0x11u;
|
||||
for (const auto& [returned, tid] : order) {
|
||||
Require(returned == running, wave + "contended add returned " + Hex(returned) + " to lane " + std::to_string(tid) + ", expected " + Hex(running));
|
||||
running += (tid + 1u) << 8u;
|
||||
}
|
||||
const auto expected = Expected();
|
||||
for (std::uint32_t offset = 0; offset < BlockBytes; ++offset) {
|
||||
const auto actual = guest.Data()[offset];
|
||||
Require(actual == expected[offset], wave + "byte " + std::to_string(offset) + " is " + std::to_string(actual) + ", expected " + std::to_string(expected[offset]));
|
||||
}
|
||||
}
|
||||
|
||||
void RunReadOnly(AgcDriver::VulkanDevice& device, GuestBlock& guest) {
|
||||
const auto initial = Initial();
|
||||
std::memcpy(guest.Data(), initial.data(), BlockBytes);
|
||||
FillInput();
|
||||
Dispatch(device, 32, guest.Data());
|
||||
for (std::uint32_t offset = 0; offset < BlockBytes; ++offset) {
|
||||
Require(guest.Data()[offset] == initial[offset], "global atomics: an atomic into a read-only range changed byte " + std::to_string(offset));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock writable(true);
|
||||
GuestBlock readOnly(false);
|
||||
RunAtomics(*device, writable, 32);
|
||||
RunAtomics(*device, writable, 64);
|
||||
RunReadOnly(*device, readOnly);
|
||||
std::puts("global atomics lanes tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "FlatGlobalLoadsRegion.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::size_t RegionOffset = Threads * 16u;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 78> LoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc208800, 0x0a080020, 0xdc2487ff,
|
||||
0x0b080020, 0xdc288ffd, 0x0c080020, 0xdc2c8001, 0x0d7d0022, 0xdc308fff, 0x0e080020, 0xdc308000,
|
||||
0x18080021, 0xdc208800, 0x197d0022, 0xbf8c0070, 0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010,
|
||||
0x80010e02, 0xe0781020, 0x80011202, 0xe0781030, 0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> input;
|
||||
std::array<std::uint32_t, Results> results;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, Threads> Rows{{
|
||||
{{0x00000000, 0x00000000, 0x3ceb3ffd, 0x00000000}, {0x000000d2, 0x00000029, 0x0000ebf6, 0x00004397, 0x4397357a, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x6526f2d2, 0x000000d2}},
|
||||
{{0x00000001, 0x00000001, 0x97b75093, 0x00000001}, {0x000000f2, 0xffffffdc, 0x00007aeb, 0xffff9d43, 0x9d439735, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xa66526f2, 0x000000f2}},
|
||||
{{0x00000002, 0x00000fa0, 0x8b529b4b, 0x00000002}, {0x00000026, 0xfffffff3, 0x0000357a, 0xffff819d, 0x819d4397, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x0ca66526, 0x00000026}},
|
||||
{{0x00000003, 0x00000f9f, 0x21636369, 0x00000003}, {0x00000065, 0x0000003d, 0x00009735, 0x00003c81, 0x3c819d43, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x120ca665, 0x00000065}},
|
||||
{{0x000003ff, 0x00000002, 0x5eb561a5, 0x000017fc}, {0x00000077, 0x00000072, 0x00007ea7, 0x00003154, 0x31541eca, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xa2731cb1, 0x00000077}},
|
||||
{{0x000003fe, 0x00000003, 0xea7b5bf4, 0x000017fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fd, 0x000007ff, 0x9a9a80fd, 0x000017fa}, {0x00000049, 0xffffffad, 0x000034f9, 0x00001eca, 0x1eca7ea7, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x1cb172ff, 0x00000049}},
|
||||
{{0x00000201, 0x00000801, 0x795b929f, 0x00000ffd}, {0x000000c6, 0xffffff91, 0x00002075, 0xffffb0c1, 0xb0c19888, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xdc295aec, 0x000000c6}},
|
||||
{{0x00000086, 0x000009b0, 0xe8a8529f, 0x0000006b}, {0x000000f1, 0x00000054, 0x00001873, 0xffffdf25, 0xdf25a310, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x7dee2657, 0x000000f1}},
|
||||
{{0x000003c0, 0x00000426, 0x3bfd1d33, 0x000011a0}, {0x000000a8, 0x0000002d, 0x0000a25c, 0xffff9c05, 0x9c0507a5, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xf610a667, 0x000000a8}},
|
||||
{{0x00000188, 0x00000b79, 0x8a7d43b5, 0x00000f0c}, {0x000000d7, 0xffffffb6, 0x00004159, 0xffffb70c, 0xb70c48ee, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x3e052289, 0x000000d7}},
|
||||
{{0x000003cf, 0x0000065a, 0xdc6bf1e1, 0x00001473}, {0x0000003b, 0x00000015, 0x00007b82, 0x000024e5, 0x24e5c17c, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xdebaea1d, 0x0000003b}},
|
||||
{{0x00000134, 0x000003b5, 0x26d0b944, 0x00001450}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000031e, 0x00000bdc, 0xabe19f59, 0x0000007c}, {0x00000021, 0x00000071, 0x00007769, 0xffff8cc2, 0x8cc24bff, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x7f9859b1, 0x00000021}},
|
||||
{{0x00000083, 0x0000028c, 0x0af438d3, 0x000012ea}, {0x00000011, 0x00000016, 0x0000b53e, 0x00001018, 0x10187326, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x224cb259, 0x00000011}},
|
||||
{{0x00000268, 0x00000c7b, 0xd2d58443, 0x000000fe}, {0x00000065, 0xffffff90, 0x0000764b, 0xffff9a41, 0x9a412405, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x99571c29, 0x00000065}},
|
||||
{{0x00000227, 0x00000790, 0xb804d821, 0x00001308}, {0x00000053, 0x00000067, 0x00004431, 0xffffd3b4, 0xd3b4c14d, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x034ab01d, 0x00000053}},
|
||||
{{0x00000319, 0x00000b6d, 0x651c5253, 0x00000da9}, {0x000000fd, 0x00000072, 0x0000d4a3, 0x000069d0, 0x69d0cbd1, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x15602efe, 0x000000fd}},
|
||||
{{0x0000038e, 0x00000f6c, 0xe0fd67dd, 0x0000044a}, {0x00000086, 0xfffffffe, 0x000070d6, 0xffff8e1d, 0x8e1de1ab, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x65d656c0, 0x00000086}},
|
||||
{{0x000002ec, 0x0000018f, 0x22cedafa, 0x00000125}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003f5, 0x00000378, 0xf729b4c9, 0x00000841}, {0x00000019, 0x00000057, 0x00005567, 0xffffdf45, 0xdf45fb80, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xd14b0cf5, 0x00000019}},
|
||||
{{0x0000037d, 0x00000c76, 0xdaf0105b, 0x0000140d}, {0x0000009e, 0xffffff91, 0x000017c8, 0xffff8ce4, 0x8ce4e6ab, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x1d426570, 0x0000009e}},
|
||||
{{0x00000268, 0x000006bd, 0xd55ec1a5, 0x0000103b}, {0x00000065, 0xffffff90, 0x0000764b, 0xffff9a41, 0x9a412405, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x79fec2ec, 0x00000065}},
|
||||
{{0x00000316, 0x0000092f, 0x88bafad9, 0x00000b3a}, {0x000000a2, 0x0000001c, 0x00005a25, 0xffffd1d4, 0xd1d4a3aa, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x524da73e, 0x000000a2}},
|
||||
{{0x00000342, 0x00000959, 0xe779c471, 0x0000076f}, {0x0000008c, 0x00000017, 0x00006d7c, 0xffffa815, 0xa815a39f, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x660a3790, 0x0000008c}},
|
||||
{{0x000002b1, 0x00000ae9, 0xdb3d1151, 0x000000ea}, {0x00000047, 0x0000000d, 0x0000d463, 0x00001bf9, 0x1bf9e87d, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0xaedff3c7, 0x00000047}},
|
||||
{{0x0000023c, 0x000009b1, 0xb2109306, 0x0000157b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000014e, 0x00000b2d, 0xf6f22f41, 0x00000a71}, {0x000000c7, 0xffffffdb, 0x0000b20a, 0x0000100b, 0x100bbc11, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x92b36eda, 0x000000c7}},
|
||||
{{0x000000d5, 0x00000b6b, 0x360c4979, 0x000014f9}, {0x00000025, 0x0000002b, 0x00006fd8, 0x00001477, 0x1477e9be, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x63779354, 0x00000025}},
|
||||
{{0x00000222, 0x0000048f, 0x103ef3c3, 0x000003fb}, {0x000000c2, 0xffffffd1, 0x0000e2a4, 0x00003181, 0x31813cb2, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x764984b5, 0x000000c2}},
|
||||
{{0x000003db, 0x00000da9, 0xfd63ed5b, 0x00001470}, {0x00000049, 0xfffffff9, 0x00001856, 0x0000575d, 0x575da8dc, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x1d9033df, 0x00000049}},
|
||||
{{0x000003de, 0x0000016a, 0xccf3d0b2, 0x00000b02}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global loads: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
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%x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
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}, 0, {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 Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code) {
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, code, guest.Data());
|
||||
const std::string wave = "global loads: lane ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& expected = Rows[tid].results;
|
||||
for (std::uint32_t result = 0; result < Results; ++result) {
|
||||
const auto actual = Output[tid * Results + result];
|
||||
Require(actual == expected[result], wave + std::to_string(tid) + " v" + std::to_string(10u + result) + " is " + Hex(actual) + ", expected " + Hex(expected[result]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
std::memset(guest.Data(), 0, BlockBytes);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
std::memcpy(guest.Data() + tid * 16u, Rows[tid].input.data(), 16u);
|
||||
}
|
||||
std::memcpy(guest.Data() + RegionOffset, FlatGlobalLoadsRegion.data(), FlatGlobalLoadsRegion.size());
|
||||
Run(*device, guest, LoadsCode);
|
||||
std::puts("global loads tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "FlatGlobalLoadsRegion.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::size_t RegionOffset = Threads * 16u;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 68> LoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc348ffa, 0x0f7d0022, 0xdc3c8003,
|
||||
0x11080020, 0xbf8c0070, 0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010, 0x80010e02, 0xe0781020,
|
||||
0x80011202, 0xe0781030, 0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> input;
|
||||
std::array<std::uint32_t, Results> results;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, Threads> Rows{{
|
||||
{{0x00000000, 0x00000000, 0x3ceb3ffd, 0x00000000}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xf6804124, 0x97357aeb, 0x513c819d, 0x2e32095f, 0xefa22967, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000001, 0x00000001, 0x97b75093, 0x00000001}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xebf68041, 0x4397357a, 0x5f513c81, 0x672e3209, 0x47efa229, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000002, 0x00000fa0, 0x8b529b4b, 0x00000002}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x7aebf680, 0x9d439735, 0x095f513c, 0x29672e32, 0xad47efa2, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000003, 0x00000f9f, 0x21636369, 0x00000003}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x357aebf6, 0x819d4397, 0x32095f51, 0xa229672e, 0x53ad47ef, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003ff, 0x00000002, 0x5eb561a5, 0x000017fc}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xa734f958, 0x541eca7e, 0x204cb651, 0x16a2f996, 0x660affc8, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fe, 0x00000003, 0xea7b5bf4, 0x000017fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fd, 0x000007ff, 0x9a9a80fd, 0x000017fa}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xf95881df, 0xca7ea734, 0xb6513154, 0xf996204c, 0xffc816a2, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000201, 0x00000801, 0x795b929f, 0x00000ffd}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x75f13ba1, 0xc1988820, 0x08a59ac0, 0x85539459, 0x73d7de27, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000086, 0x000009b0, 0xe8a8529f, 0x0000006b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x7326b53e, 0x25a31018, 0x6645c8aa, 0x02f743cf, 0x8fd2a50e, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003c0, 0x00000426, 0x3bfd1d33, 0x000011a0}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5ca32e13, 0x0507a5a2, 0xeebcae0b, 0xfbcf54ff, 0x7c7b8218, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000188, 0x00000b79, 0x8a7d43b5, 0x00000f0c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5905426c, 0x0c48ee41, 0x52e95ec2, 0x809af6c4, 0x9e49d979, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003cf, 0x0000065a, 0xdc6bf1e1, 0x00001473}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x8218fbcf, 0xe5c17c7b, 0x6ab73608, 0x185620a0, 0x575da8dc, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000134, 0x000003b5, 0x26d0b944, 0x00001450}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000031e, 0x00000bdc, 0xabe19f59, 0x0000007c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x69d0cbd1, 0xc24bff77, 0xd5c720a6, 0xd9c85a78, 0x60b4443a, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000083, 0x0000028c, 0x0af438d3, 0x000012ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x3ecdef03, 0x187326b5, 0xaadf25a3, 0xcf6645c8, 0x0e02f743, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x00000c7b, 0xd2d58443, 0x000000fe}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x4ba1fb80, 0x41240576, 0xbd0167bc, 0x6edae83e, 0xbf9692b3, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000227, 0x00000790, 0xb804d821, 0x00001308}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x31813cb2, 0xb4c14d44, 0xb9279ed7, 0xb93ff927, 0x59859a53, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000319, 0x00000b6d, 0x651c5253, 0x00000da9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xa3aa5a25, 0xd0cbd1d4, 0xc24bff77, 0xc720a68c, 0xc85a78d5, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000038e, 0x00000f6c, 0xe0fd67dd, 0x0000044a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xd6bd1487, 0x1de1ab70, 0x3b6b431e, 0x7e7923d3, 0x777b0e8e, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002ec, 0x0000018f, 0x22cedafa, 0x00000125}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003f5, 0x00000378, 0xf729b4c9, 0x00000841}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x677ed35a, 0x45fb8055, 0x34f95881, 0x1eca7ea7, 0xb6513154, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000037d, 0x00000c76, 0xdaf0105b, 0x0000140d}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xc8fa9bb0, 0xe4e6ab17, 0x4cd6a2c9, 0x36b17e32, 0xd6bd1487, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x000006bd, 0xd55ec1a5, 0x0000103b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x4ba1fb80, 0x41240576, 0xbd0167bc, 0x6edae83e, 0xbf9692b3, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000316, 0x0000092f, 0x88bafad9, 0x00000b3a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x25f6d039, 0xd4a3aa5a, 0x7769d0cb, 0x8cc24bff, 0xd5c720a6, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000342, 0x00000959, 0xe779c471, 0x0000076f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x7c7a524d, 0x15a39f6d, 0xed275ce5, 0x0e62da4d, 0xe790d315, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002b1, 0x00000ae9, 0xdb3d1151, 0x000000ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x6302c753, 0xf9e87dd4, 0x378b4009, 0xf3c8b729, 0x598433f0, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000023c, 0x000009b1, 0xb2109306, 0x0000157b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000014e, 0x00000b2d, 0xf6f22f41, 0x00000a71}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x0aa2a4b1, 0x0bbc11b2, 0x5dc397db, 0xd1f4d133, 0x10aae488, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000000d5, 0x00000b6b, 0x360c4979, 0x000014f9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xd8600189, 0x77e9be6f, 0x2c73a7bd, 0x421aff39, 0x1f09a43b, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000222, 0x0000048f, 0x103ef3c3, 0x000003fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0xa4765520, 0x813cb2e2, 0xb4c14d44, 0x279ed7d3, 0x3ff927b9, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003db, 0x00000da9, 0xfd63ed5b, 0x00001470}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5620a06a, 0x5da8dc18, 0x8d86c779, 0x4835e9c5, 0x406c576f, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003de, 0x0000016a, 0xccf3d0b2, 0x00000b02}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global loads x2 x3: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
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%x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
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}, 0, {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 Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code) {
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, code, guest.Data());
|
||||
const std::string wave = "global loads x2 x3: lane ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& expected = Rows[tid].results;
|
||||
for (std::uint32_t result = 0; result < Results; ++result) {
|
||||
const auto actual = Output[tid * Results + result];
|
||||
Require(actual == expected[result], wave + std::to_string(tid) + " v" + std::to_string(10u + result) + " is " + Hex(actual) + ", expected " + Hex(expected[result]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
std::memset(guest.Data(), 0, BlockBytes);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
std::memcpy(guest.Data() + tid * 16u, Rows[tid].input.data(), 16u);
|
||||
}
|
||||
std::memcpy(guest.Data() + RegionOffset, FlatGlobalLoadsRegion.data(), FlatGlobalLoadsRegion.size());
|
||||
Run(*device, guest, LoadsCode);
|
||||
std::puts("global loads x2 x3 tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "FlatGlobalLoadsRegion.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Sentinel = 0x05e471e1;
|
||||
constexpr std::size_t BlockBytes = 65536;
|
||||
constexpr std::size_t RegionOffset = Threads * 16u;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 66> LoadsCode{
|
||||
0x34020084, 0x34040086, 0xdc388000, 0x04080001, 0xbf8c3f70, 0x7e1402ff, 0x5a5a0000, 0x7e1602ff,
|
||||
0x5a5a0001, 0x7e1802ff, 0x5a5a0002, 0x7e1a02ff, 0x5a5a0003, 0x7e1c02ff, 0x5a5a0004, 0x7e1e02ff,
|
||||
0x5a5a0005, 0x7e2002ff, 0x5a5a0006, 0x7e2202ff, 0x5a5a0007, 0x7e2402ff, 0x5a5a0008, 0x7e2602ff,
|
||||
0x5a5a0009, 0x7e2802ff, 0x5a5a000a, 0x7e2a02ff, 0x5a5a000b, 0x7e2c02ff, 0x5a5a000c, 0x7e2e02ff,
|
||||
0x5a5a000d, 0x7e3002ff, 0x5a5a000e, 0x7e3202ff, 0x5a5a000f, 0x4a4008ff, 0x00000a00, 0x4a420eff,
|
||||
0x00000200, 0xd70f6a22, 0x02024008, 0x7e460209, 0x50464680, 0x4a4c0aff, 0x00000200, 0xd70f6a24,
|
||||
0x02024c08, 0x7e4a0209, 0x504a4a80, 0x36500c81, 0x7daa5080, 0xdc3887f8, 0x147d0022, 0xbf8c0070,
|
||||
0xbefe04c1, 0xe0781000, 0x80010a02, 0xe0781010, 0x80010e02, 0xe0781020, 0x80011202, 0xe0781030,
|
||||
0x80011602, 0xbf810000
|
||||
};
|
||||
|
||||
struct Row {
|
||||
std::array<std::uint32_t, 4> input;
|
||||
std::array<std::uint32_t, Results> results;
|
||||
};
|
||||
|
||||
constexpr std::array<Row, Threads> Rows{{
|
||||
{{0x00000000, 0x00000000, 0x3ceb3ffd, 0x00000000}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x6595f862, 0x295aec03, 0x523df3dc, 0x457d538e, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000001, 0x00000001, 0x97b75093, 0x00000001}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x036595f8, 0xdc295aec, 0x8e523df3, 0x48457d53, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000002, 0x00000fa0, 0x8b529b4b, 0x00000002}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xec036595, 0xf3dc295a, 0x538e523d, 0xe048457d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000003, 0x00000f9f, 0x21636369, 0x00000003}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5aec0365, 0x3df3dc29, 0x7d538e52, 0xfce04845, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003ff, 0x00000002, 0x5eb561a5, 0x000017fc}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x30d907a2, 0x72bdad38, 0xa92515b0, 0x948e5f94, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fe, 0x00000003, 0xea7b5bf4, 0x000017fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003fd, 0x000007ff, 0x9a9a80fd, 0x000017fa}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x07a2e287, 0xad3830d9, 0x15b072bd, 0x5f94a925, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000201, 0x00000801, 0x795b929f, 0x00000ffd}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x62c3c5bc, 0x91b7a807, 0x63034f25, 0x2db116b5, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000086, 0x000009b0, 0xe8a8529f, 0x0000006b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x3b946093, 0x54ebd216, 0x9bd7f852, 0x53f53ed6, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003c0, 0x00000426, 0x3bfd1d33, 0x000011a0}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x02701056, 0x2dd3f4aa, 0x602ab9e7, 0xcd71014b, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000188, 0x00000b79, 0x8a7d43b5, 0x00000f0c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x693895b7, 0xb6e0664f, 0xdeca057c, 0x2b2c163e, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003cf, 0x0000065a, 0xdc6bf1e1, 0x00001473}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x59ac90cd, 0x15783291, 0x7584528a, 0xe888f86d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000134, 0x000003b5, 0x26d0b944, 0x00001450}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000031e, 0x00000bdc, 0xabe19f59, 0x0000007c}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xf6724fb3, 0x7153291c, 0x4a5c9177, 0x0b128e2b, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000083, 0x0000028c, 0x0af438d3, 0x000012ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x936f25cd, 0x163b9460, 0x5254ebd2, 0xd69bd7f8, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x00000c7b, 0xd2d58443, 0x000000fe}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xa14f8d0a, 0x902df1a3, 0x7f913ad6, 0xec4185b7, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000227, 0x00000790, 0xb804d821, 0x00001308}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xb7d12049, 0x675b4866, 0xc676e8d8, 0xdca0e1a0, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000319, 0x00000b6d, 0x651c5253, 0x00000da9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x324d47e5, 0x724fb31c, 0x53291cf6, 0x5c917771, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000038e, 0x00000f6c, 0xe0fd67dd, 0x0000044a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x6c7e37f1, 0xfe28bb7f, 0xa0949a4c, 0x3ab02414, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002ec, 0x0000018f, 0x22cedafa, 0x00000125}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003f5, 0x00000378, 0xf729b4c9, 0x00000841}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xa5a87b5e, 0x57dd4c23, 0x07a2e287, 0xad3830d9, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000037d, 0x00000c76, 0xdaf0105b, 0x0000140d}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x3d40d4d6, 0x911b0a0e, 0xd1eba0cd, 0xe767b4ff, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000268, 0x000006bd, 0xd55ec1a5, 0x0000103b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xa14f8d0a, 0x902df1a3, 0x7f913ad6, 0xec4185b7, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000316, 0x0000092f, 0x88bafad9, 0x00000b3a}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xe50f0b34, 0x1c324d47, 0xf6724fb3, 0x7153291c, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000342, 0x00000959, 0xe779c471, 0x0000076f}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x528bc830, 0x17eb5b02, 0x9da049a4, 0xb3a7bbef, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000002b1, 0x00000ae9, 0xdb3d1151, 0x000000ea}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xa0d6d4b0, 0x0d8273a0, 0x6d34b2ad, 0xedd883ac, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000023c, 0x000009b1, 0xb2109306, 0x0000157b}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x0000014e, 0x00000b2d, 0xf6f22f41, 0x00000a71}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x082b465a, 0xdb19a044, 0x1095f2e7, 0x9f733159, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000000d5, 0x00000b6b, 0x360c4979, 0x000014f9}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x87b15796, 0x2b17d0bf, 0xfa5d515c, 0x834fd313, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x00000222, 0x0000048f, 0x103ef3c3, 0x000003fb}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x164fb710, 0xd1204939, 0x5b4866b7, 0x76e8d867, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003db, 0x00000da9, 0xfd63ed5b, 0x00001470}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0xe888f86d, 0xf927dda0, 0x9e9bf666, 0x0fcfcf14, 0x5a5a000e, 0x5a5a000f}},
|
||||
{{0x000003de, 0x0000016a, 0xccf3d0b2, 0x00000b02}, {0x5a5a0000, 0x5a5a0001, 0x5a5a0002, 0x5a5a0003, 0x5a5a0004, 0x5a5a0005, 0x5a5a0006, 0x5a5a0007, 0x5a5a0008, 0x5a5a0009, 0x5a5a000a, 0x5a5a000b, 0x5a5a000c, 0x5a5a000d, 0x5a5a000e, 0x5a5a000f}}
|
||||
}};
|
||||
|
||||
class GuestBlock {
|
||||
public:
|
||||
GuestBlock() {
|
||||
#ifdef _WIN32
|
||||
block = static_cast<std::uint8_t*>(VirtualAlloc(nullptr, BlockBytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
|
||||
#else
|
||||
block = static_cast<std::uint8_t*>(std::aligned_alloc(BlockBytes, BlockBytes));
|
||||
#endif
|
||||
Require(block != nullptr, "global loads x4: cannot allocate the guest block");
|
||||
GuestAllocations::Mutation().Add(block, BlockBytes, true, false);
|
||||
}
|
||||
|
||||
~GuestBlock() {
|
||||
GuestAllocations::Mutation().Remove(block);
|
||||
#ifdef _WIN32
|
||||
VirtualFree(block, 0, MEM_RELEASE);
|
||||
#else
|
||||
std::free(block);
|
||||
#endif
|
||||
}
|
||||
|
||||
GuestBlock(const GuestBlock&) = delete;
|
||||
GuestBlock& operator=(const GuestBlock&) = delete;
|
||||
|
||||
std::uint8_t* Data() { return block; }
|
||||
|
||||
private:
|
||||
std::uint8_t* block = nullptr;
|
||||
};
|
||||
|
||||
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%x", value);
|
||||
return text;
|
||||
}
|
||||
|
||||
void Dispatch(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code, const std::uint8_t* base) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(base));
|
||||
std::vector<std::uint32_t> userData(10, 0u);
|
||||
const auto output = BufferDescriptor(Output.data(), static_cast<std::uint32_t>(Output.size() * 4u));
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
userData[8] = static_cast<std::uint32_t>(address);
|
||||
userData[9] = static_cast<std::uint32_t>(address >> 32u);
|
||||
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}, 0, {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 Run(AgcDriver::VulkanDevice& device, GuestBlock& guest, std::span<const std::uint32_t> code) {
|
||||
Output.fill(Sentinel);
|
||||
Dispatch(device, code, guest.Data());
|
||||
const std::string wave = "global loads x4: lane ";
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto& expected = Rows[tid].results;
|
||||
for (std::uint32_t result = 0; result < Results; ++result) {
|
||||
const auto actual = Output[tid * Results + result];
|
||||
Require(actual == expected[result], wave + std::to_string(tid) + " v" + std::to_string(10u + result) + " is " + Hex(actual) + ", expected " + Hex(expected[result]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
GuestBlock guest;
|
||||
std::memset(guest.Data(), 0, BlockBytes);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
std::memcpy(guest.Data() + tid * 16u, Rows[tid].input.data(), 16u);
|
||||
}
|
||||
std::memcpy(guest.Data() + RegionOffset, FlatGlobalLoadsRegion.data(), FlatGlobalLoadsRegion.size());
|
||||
Run(*device, guest, LoadsCode);
|
||||
std::puts("global loads x4 tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/TextureTiling.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 32;
|
||||
constexpr std::uint32_t Words = 32;
|
||||
constexpr std::uint32_t Size = 16;
|
||||
constexpr std::uint32_t Levels = 5;
|
||||
constexpr std::uint32_t Format8888UNorm = 56;
|
||||
constexpr std::uint32_t Type2D = 9;
|
||||
constexpr std::uint32_t ArrayInput = 0;
|
||||
constexpr std::uint32_t ArrayResult = 8;
|
||||
constexpr std::uint32_t PlainInput = 16;
|
||||
constexpr std::uint32_t PlainResult = 24;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Words> Buffer{};
|
||||
alignas(256) std::array<std::uint8_t, 16384> Texels{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 71> Code{
|
||||
0x34020087, 0xe0301000, 0x80000201, 0xe0301004, 0x80000301, 0xe0301008, 0x80000401, 0xe030100c,
|
||||
0x80000501, 0xe0301010, 0x80000601, 0xe0301014, 0x80000701, 0xe0301018, 0x80000801, 0xe030101c,
|
||||
0x80000901, 0xe0301040, 0x80001001, 0xe0301044, 0x80001101, 0xe0301048, 0x80001201, 0xe030104c,
|
||||
0x80001301, 0xe0301050, 0x80001401, 0xe0301054, 0x80001501, 0xbf8c3f70, 0xf0900f28, 0x00610c02,
|
||||
0xe0701020, 0x80000c01, 0xe0701024, 0x80000d01, 0xe0701028, 0x80000e01, 0xe070102c, 0x80000f01,
|
||||
0xf0041f28, 0x00010c06, 0xe0701030, 0x80000c01, 0xe0701034, 0x80000d01, 0xe0701038, 0x80000e01,
|
||||
0xe070103c, 0x80000f01, 0xf0900f08, 0x00610c10, 0xe0701060, 0x80000c01, 0xe0701064, 0x80000d01,
|
||||
0xe0701068, 0x80000e01, 0xe070106c, 0x80000f01, 0xf0041f08, 0x00010c13, 0xe0701070, 0x80000c01,
|
||||
0xe0701074, 0x80000d01, 0xe0701078, 0x80000e01, 0xe070107c, 0x80000f01, 0xbf810000,
|
||||
};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 11> NarrowCode{
|
||||
0x34020087, 0xe0301040, 0x80001001, 0xe0301044, 0x80001101, 0xbf8c3f70, 0xf0900f00, 0x00610c10,
|
||||
0xe0701070, 0x80000c01, 0xbf810000,
|
||||
};
|
||||
|
||||
struct Sample {
|
||||
std::uint32_t level;
|
||||
std::uint32_t x;
|
||||
std::uint32_t y;
|
||||
};
|
||||
|
||||
Sample SampleOf(std::uint32_t tid) {
|
||||
return {tid % Levels, (tid * 7u + 3u) % Size, (tid * 5u + 1u) % Size};
|
||||
}
|
||||
|
||||
std::uint32_t Bits(float value) {
|
||||
return std::bit_cast<std::uint32_t>(value);
|
||||
}
|
||||
|
||||
void FillInput() {
|
||||
Buffer.fill(0xdeadbeefu);
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto sample = SampleOf(tid);
|
||||
const auto u = Bits((static_cast<float>(sample.x) + 0.5f) / static_cast<float>(Size));
|
||||
const auto v = Bits((static_cast<float>(sample.y) + 0.5f) / static_cast<float>(Size));
|
||||
const auto lod = Bits(static_cast<float>(sample.level));
|
||||
const auto x = sample.x >> sample.level;
|
||||
const auto y = sample.y >> sample.level;
|
||||
auto* words = &Buffer[tid * Words];
|
||||
const std::array<std::uint32_t, 8> array{u, v, Bits(0.0f), lod, x, y, 0u, sample.level};
|
||||
const std::array<std::uint32_t, 6> plain{u, v, lod, x, y, sample.level};
|
||||
std::copy(array.begin(), array.end(), words + ArrayInput);
|
||||
std::copy(plain.begin(), plain.end(), words + PlainInput);
|
||||
}
|
||||
}
|
||||
|
||||
void FillTexture() {
|
||||
const auto mips = AgcDriver::Graphics::ComputeMipLayout(AgcDriver::Graphics::TextureTileMode::kLinear, Format8888UNorm, Size, Size, Levels);
|
||||
Require(AgcDriver::Graphics::ComputeSurfaceSize(mips, 1) <= Texels.size(), "image address dimension: the mip chain does not fit the texel storage");
|
||||
Texels.fill(0xeeu);
|
||||
for (std::uint32_t level = 0; level < Levels; ++level) {
|
||||
const auto& mip = mips[level];
|
||||
for (std::uint32_t y = 0; y < mip.height; ++y) {
|
||||
for (std::uint32_t x = 0; x < mip.width; ++x) {
|
||||
auto* texel = &Texels[mip.tiledOffset + static_cast<std::uint64_t>(y) * mip.pitchBytes + x * 4u];
|
||||
texel[0] = static_cast<std::uint8_t>(level);
|
||||
texel[1] = static_cast<std::uint8_t>(x);
|
||||
texel[2] = static_cast<std::uint8_t>(y);
|
||||
texel[3] = 255u;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::array<std::uint32_t, 8> TextureDescriptor(const void* data) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(data));
|
||||
return {
|
||||
static_cast<std::uint32_t>(address >> 8u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (Format8888UNorm << 20u) | (((Size - 1u) & 3u) << 30u),
|
||||
((Size - 1u) >> 2u) | ((Size - 1u) << 14u),
|
||||
0xfacu | ((Levels - 1u) << 16u) | (Type2D << 28u),
|
||||
0u,
|
||||
(Levels - 1u) << 4u,
|
||||
0u,
|
||||
0u,
|
||||
};
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 4> SamplerDescriptor() {
|
||||
return {0u, 0xfffu << 12u, 1u << 26u, 0u};
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code) {
|
||||
std::vector<std::uint32_t> userData(16, 0u);
|
||||
const auto buffer = BufferDescriptor(Buffer.data(), static_cast<std::uint32_t>(Buffer.size() * 4u));
|
||||
const auto texture = TextureDescriptor(Texels.data());
|
||||
const auto sampler = SamplerDescriptor();
|
||||
std::copy(buffer.begin(), buffer.end(), userData.begin());
|
||||
std::copy(texture.begin(), texture.end(), userData.begin() + 4);
|
||||
std::copy(sampler.begin(), sampler.end(), userData.begin() + 12);
|
||||
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() {
|
||||
constexpr std::array<const char*, 4> names{"image_sample_l 2d_array", "image_load_mip 2d_array", "image_sample_l 2d", "image_load_mip 2d"};
|
||||
constexpr std::array<std::uint32_t, 4> results{ArrayResult, ArrayResult + 4u, PlainResult, PlainResult + 4u};
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto sample = SampleOf(tid);
|
||||
const std::array<std::uint32_t, 4> expected{sample.level, sample.x >> sample.level, sample.y >> sample.level, 255u};
|
||||
for (std::uint32_t index = 0; index < names.size(); ++index) {
|
||||
for (std::uint32_t component = 0; component < 4u; ++component) {
|
||||
const float value = std::bit_cast<float>(Buffer[tid * Words + results[index] + component]) * 255.0f;
|
||||
Require(std::lround(value) == static_cast<long>(expected[component]), std::string(names[index]) + " on a 2D texture: thread " + std::to_string(tid) + " component " + std::to_string(component) + " is " + std::to_string(value) + ", expected " + std::to_string(expected[component]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RequireRefused(AgcDriver::VulkanDevice& device) {
|
||||
std::string refusal;
|
||||
try {
|
||||
Run(device, NarrowCode);
|
||||
} catch (const std::exception& error) {
|
||||
refusal = error.what();
|
||||
}
|
||||
Require(refusal.find("too few coordinate components") != std::string::npos, "image_sample_l 1d on a 2D texture was not refused: " + refusal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
FillInput();
|
||||
FillTexture();
|
||||
Run(*device, Code);
|
||||
Check();
|
||||
RequireRefused(*device);
|
||||
std::puts("image address dimension tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,8 @@ constexpr std::uint32_t Results = 16;
|
|||
constexpr std::uint32_t Operations = 6;
|
||||
constexpr std::uint32_t TextureHeight = 8;
|
||||
constexpr std::uint32_t Format32UInt = 20;
|
||||
constexpr std::uint32_t Format32SInt = 21;
|
||||
constexpr std::uint32_t Format32Float = 22;
|
||||
constexpr std::uint32_t Type2D = 9;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
|
|
@ -71,24 +73,24 @@ std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t by
|
|||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x01016facu};
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 8> TextureDescriptor(const void* data, std::uint32_t width, std::uint32_t height) {
|
||||
std::array<std::uint32_t, 8> TextureDescriptor(const void* data, std::uint32_t width, std::uint32_t height, std::uint32_t format) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(data));
|
||||
return {
|
||||
static_cast<std::uint32_t>(address >> 8u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (Format32UInt << 20u) | (((width - 1u) & 3u) << 30u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (format << 20u) | (((width - 1u) & 3u) << 30u),
|
||||
((width - 1u) >> 2u) | ((height - 1u) << 14u),
|
||||
0xfacu | (Type2D << 28u),
|
||||
0u, 0u, 0u, 0u,
|
||||
};
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
void Run(AgcDriver::VulkanDevice& device, std::uint32_t format) {
|
||||
Output.fill(0xdeadbeefu);
|
||||
Texels.fill(0xdeadbeefu);
|
||||
std::vector<std::uint32_t> userData(16, 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));
|
||||
const auto texture = TextureDescriptor(Texels.data(), Threads, TextureHeight);
|
||||
const auto texture = TextureDescriptor(Texels.data(), Threads, TextureHeight, format);
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
std::copy(texture.begin(), texture.end(), userData.begin() + 8);
|
||||
|
|
@ -107,7 +109,7 @@ void Run(AgcDriver::VulkanDevice& device) {
|
|||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void Check() {
|
||||
void Check(std::uint32_t format) {
|
||||
constexpr std::array<const char*, Operations> names{"image_atomic_sub", "image_atomic_smin", "image_atomic_smax", "image_atomic_inc", "image_atomic_dec", "image_atomic_cmpswap"};
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto* in = &Input[tid * Inputs];
|
||||
|
|
@ -127,8 +129,8 @@ void Check() {
|
|||
for (std::uint32_t j = 0; j < Operations; ++j) {
|
||||
const std::uint32_t returned = Output[tid * Results + 2u * j];
|
||||
const std::uint32_t stored = Output[tid * Results + 2u * j + 1u];
|
||||
Require(returned == a, std::string(names[j]) + ": thread " + std::to_string(tid) + " returned " + std::to_string(returned) + ", expected " + std::to_string(a));
|
||||
Require(stored == expected[j], std::string(names[j]) + ": thread " + std::to_string(tid) + " stored " + std::to_string(stored) + ", expected " + std::to_string(expected[j]));
|
||||
Require(returned == a, std::string(names[j]) + ", format " + std::to_string(format) + ": thread " + std::to_string(tid) + " returned " + std::to_string(returned) + ", expected " + std::to_string(a));
|
||||
Require(stored == expected[j], std::string(names[j]) + ", format " + std::to_string(format) + ": thread " + std::to_string(tid) + " stored " + std::to_string(stored) + ", expected " + std::to_string(expected[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -140,8 +142,10 @@ int main() {
|
|||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
FillInput();
|
||||
Run(*device);
|
||||
Check();
|
||||
for (const auto format : {Format32UInt, Format32SInt, Format32Float}) {
|
||||
Run(*device, format);
|
||||
Check(format);
|
||||
}
|
||||
std::puts("image atomics tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
#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 <cstdint>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Threads = 64;
|
||||
constexpr std::uint32_t Inputs = 4;
|
||||
constexpr std::uint32_t Results = 16;
|
||||
constexpr std::uint32_t Operations = 5;
|
||||
constexpr std::uint32_t TextureHeight = 8;
|
||||
constexpr std::uint32_t Format32UInt = 20;
|
||||
constexpr std::uint32_t Type2D = 9;
|
||||
alignas(256) std::array<std::uint32_t, Threads * Inputs> Input{};
|
||||
alignas(256) std::array<std::uint32_t, Threads * Results> Output{};
|
||||
alignas(4096) std::array<std::uint32_t, Threads * TextureHeight> Texels{};
|
||||
|
||||
alignas(256) constexpr std::array<std::uint32_t, 92> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0x7e100300, 0x7e120280, 0x7e140304,
|
||||
0xf03c0108, 0x00020a08, 0x7e160305, 0xf0602108, 0x00020b08, 0x7e180280, 0xf0442108, 0x00020c08,
|
||||
0xbf8c3f70, 0x7e28030b, 0x7e2a030c, 0x7e120281, 0x7e140304, 0xf03c0108, 0x00020a08, 0x7e160305,
|
||||
0xf0642108, 0x00020b08, 0x7e180280, 0xf0442108, 0x00020c08, 0xbf8c3f70, 0x7e2c030b, 0x7e2e030c,
|
||||
0x7e120282, 0x7e140304, 0xf03c0108, 0x00020a08, 0x7e160305, 0xf0682108, 0x00020b08, 0x7e180280,
|
||||
0xf0442108, 0x00020c08, 0xbf8c3f70, 0x7e30030b, 0x7e32030c, 0x7e120283, 0x7e140304, 0xf03c0108,
|
||||
0x00020a08, 0x7e160305, 0xf0542108, 0x00020b08, 0x7e180280, 0xf0442108, 0x00020c08, 0xbf8c3f70,
|
||||
0x7e34030b, 0x7e36030c, 0x7e120284, 0x7e140304, 0xf03c0108, 0x00020a08, 0x7e160305, 0xf05c2108,
|
||||
0x00020b08, 0x7e180280, 0xf0442108, 0x00020c08, 0xbf8c3f70, 0x7e38030b, 0x7e3a030c, 0xe0701000,
|
||||
0x80011403, 0xe0701004, 0x80011503, 0xe0701008, 0x80011603, 0xe070100c, 0x80011703, 0xe0701010,
|
||||
0x80011803, 0xe0701014, 0x80011903, 0xe0701018, 0x80011a03, 0xe070101c, 0x80011b03, 0xe0701020,
|
||||
0x80011c03, 0xe0701024, 0x80011d03, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::array<std::array<std::uint32_t, 2>, 14> Edges{{
|
||||
{0x0u, 0x0u}, {0x0u, 0xffffffffu}, {0xffffffffu, 0x0u}, {0xffffffffu, 0xffffffffu}, {0x7fffffffu, 0x80000000u}, {0x80000000u, 0x7fffffffu},
|
||||
{0xffffffffu, 0x1u}, {0x1u, 0xffffffffu}, {0xaaaaaaaau, 0x55555555u}, {0xf0f0f0f0u, 0xff00ff00u}, {0x5u, 0x5u}, {0x4u, 0x5u},
|
||||
{0x6u, 0x5u}, {0x80000000u, 0x80000000u},
|
||||
}};
|
||||
|
||||
void FillInput() {
|
||||
std::uint64_t state = 0x9e3779b97f4a7c15ull;
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
auto* words = &Input[tid * Inputs];
|
||||
for (std::uint32_t j = 0; j < 2u; ++j) {
|
||||
state = state * 6364136223846793005ull + 1442695040888963407ull;
|
||||
words[j] = static_cast<std::uint32_t>(state >> 32u);
|
||||
}
|
||||
if (tid < Edges.size()) {
|
||||
words[0] = Edges[tid][0];
|
||||
words[1] = Edges[tid][1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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::array<std::uint32_t, 8> TextureDescriptor(const void* data, std::uint32_t width, std::uint32_t height) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(data));
|
||||
return {
|
||||
static_cast<std::uint32_t>(address >> 8u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (Format32UInt << 20u) | (((width - 1u) & 3u) << 30u),
|
||||
((width - 1u) >> 2u) | ((height - 1u) << 14u),
|
||||
0xfacu | (Type2D << 28u),
|
||||
0u, 0u, 0u, 0u,
|
||||
};
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const ShaderRecompiler::SpirvTarget& target) {
|
||||
Output.fill(0xdeadbeefu);
|
||||
Texels.fill(0xdeadbeefu);
|
||||
std::vector<std::uint32_t> userData(16, 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));
|
||||
const auto texture = TextureDescriptor(Texels.data(), Threads, TextureHeight);
|
||||
std::copy(input.begin(), input.end(), userData.begin());
|
||||
std::copy(output.begin(), output.end(), userData.begin() + 4);
|
||||
std::copy(texture.begin(), texture.end(), userData.begin() + 8);
|
||||
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, {}},
|
||||
{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<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void Check(const char* run) {
|
||||
constexpr std::array<const char*, Operations> names{"image_atomic_and", "image_atomic_or", "image_atomic_xor", "image_atomic_umin", "image_atomic_umax"};
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const auto* in = &Input[tid * Inputs];
|
||||
const std::uint32_t a = in[0];
|
||||
const std::uint32_t b = in[1];
|
||||
const std::array<std::uint32_t, Operations> expected{a & b, a | b, a ^ b, std::min(a, b), std::max(a, b)};
|
||||
for (std::uint32_t j = 0; j < Operations; ++j) {
|
||||
const std::uint32_t returned = Output[tid * Results + 2u * j];
|
||||
const std::uint32_t stored = Output[tid * Results + 2u * j + 1u];
|
||||
const auto where = std::string(names[j]) + " " + run + ": thread " + std::to_string(tid);
|
||||
Require(returned == a, where + " returned " + std::to_string(returned) + ", expected " + std::to_string(a));
|
||||
Require(stored == expected[j], where + " stored " + std::to_string(stored) + ", expected " + std::to_string(expected[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
FillInput();
|
||||
Run(*device, 32, device->Target());
|
||||
Check("wave32");
|
||||
Run(*device, 64, device->Target());
|
||||
Check("wave64");
|
||||
Run(*device, 64, device->ComputeTarget(32));
|
||||
Check("wave64 split");
|
||||
std::puts("image atomics bitwise tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,9 @@ constexpr std::uint32_t Rows = 800;
|
|||
constexpr std::uint32_t TextureWidth = 64;
|
||||
constexpr std::uint32_t TextureHeight = 4;
|
||||
constexpr std::uint32_t Format32UInt = 20;
|
||||
constexpr std::uint32_t Format32SInt = 21;
|
||||
constexpr std::uint32_t Format32Float = 22;
|
||||
constexpr std::uint32_t Format16_16Float = 29;
|
||||
constexpr std::uint32_t Type2D = 9;
|
||||
alignas(256) std::array<std::uint32_t, MaxLanes * (Inputs + Results)> Buffer{};
|
||||
alignas(4096) std::array<std::uint32_t, 4096> Texels{};
|
||||
|
|
@ -474,22 +477,22 @@ std::array<std::uint32_t, 4> BufferDescriptor(const void* data, std::uint32_t by
|
|||
return {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>((address >> 32u) & 0xffffu), bytes, 0x01016facu};
|
||||
}
|
||||
|
||||
std::array<std::uint32_t, 8> TextureDescriptor(const void* data) {
|
||||
std::array<std::uint32_t, 8> TextureDescriptor(const void* data, std::uint32_t format) {
|
||||
const auto address = static_cast<std::uint64_t>(reinterpret_cast<std::uintptr_t>(data));
|
||||
return {
|
||||
static_cast<std::uint32_t>(address >> 8u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (Format32UInt << 20u) | (((TextureWidth - 1u) & 3u) << 30u),
|
||||
static_cast<std::uint32_t>((address >> 40u) & 0xffu) | (format << 20u) | (((TextureWidth - 1u) & 3u) << 30u),
|
||||
((TextureWidth - 1u) >> 2u) | ((TextureHeight - 1u) << 14u),
|
||||
0xfacu | (Type2D << 28u),
|
||||
0u, 0u, 0u, 0u,
|
||||
};
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const ShaderRecompiler::SpirvTarget& target, const char* name) {
|
||||
ShaderRecompiler::RecompileResult Compile(std::uint32_t waveSize, const ShaderRecompiler::SpirvTarget& target, std::uint32_t format) {
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
std::vector<std::uint32_t> userData(16, 0u);
|
||||
const auto buffer = BufferDescriptor(Buffer.data(), static_cast<std::uint32_t>(Buffer.size() * 4u));
|
||||
const auto texture = TextureDescriptor(Texels.data());
|
||||
const auto texture = TextureDescriptor(Texels.data(), format);
|
||||
std::copy(buffer.begin(), buffer.end(), userData.begin());
|
||||
std::copy(texture.begin(), texture.end(), userData.begin() + 4);
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> memory{{{reinterpret_cast<std::uintptr_t>(code.data()), std::as_bytes(code)}}};
|
||||
|
|
@ -501,7 +504,12 @@ void Run(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const ShaderRe
|
|||
{0, 0, 0, 128}
|
||||
};
|
||||
request.useCache = false;
|
||||
const auto result = ShaderRecompiler::Recompile(request);
|
||||
return ShaderRecompiler::Recompile(request);
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const ShaderRecompiler::SpirvTarget& target, const char* name, std::uint32_t format) {
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const auto result = Compile(waveSize, target, format);
|
||||
Texels.fill(0xdeadbeefu);
|
||||
for (std::uint32_t first = 0; first < Rows; first += waveSize) {
|
||||
Buffer.fill(0xdeadbeefu);
|
||||
|
|
@ -521,7 +529,7 @@ void Run(AgcDriver::VulkanDevice& device, std::uint32_t waveSize, const ShaderRe
|
|||
for (std::uint32_t j = 0; j < Checked; ++j) {
|
||||
const auto actual = Buffer[MaxLanes * Inputs + lane * Results + j];
|
||||
char message[192];
|
||||
std::snprintf(message, sizeof(message), "image float atomics %s: row %u %s is 0x%08x, expected 0x%08x", name, row, names[j], actual, expected[j]);
|
||||
std::snprintf(message, sizeof(message), "image float atomics %s, format %u: row %u %s is 0x%08x, expected 0x%08x", name, format, row, names[j], actual, expected[j]);
|
||||
Require(actual == expected[j], message);
|
||||
}
|
||||
}
|
||||
|
|
@ -534,9 +542,18 @@ int main() {
|
|||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
Run(*device, 32, device->Target(), "wave32");
|
||||
Run(*device, 64, device->Target(), "wave64");
|
||||
Run(*device, 64, device->ComputeTarget(32), "wave64 split");
|
||||
for (const auto format : {Format32UInt, Format32SInt, Format32Float}) {
|
||||
Run(*device, 32, device->Target(), "wave32", format);
|
||||
Run(*device, 64, device->Target(), "wave64", format);
|
||||
Run(*device, 64, device->ComputeTarget(32), "wave64 split", format);
|
||||
}
|
||||
bool refused = false;
|
||||
try {
|
||||
static_cast<void>(Compile(32, device->Target(), Format16_16Float));
|
||||
} catch (const std::exception& error) {
|
||||
refused = std::string(error.what()).find("atomic image descriptor uses an unsupported format 29") != std::string::npos;
|
||||
}
|
||||
Require(refused, "image float atomics on a 16_16 float surface were not refused");
|
||||
std::puts("image float atomics tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
#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, 50> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0x06140af9, 0x06000604, 0x7e160307,
|
||||
0x08160af9, 0x05061504, 0x0a180af9, 0x06142a04, 0x101a0af9, 0x03260404, 0x0e1c0af9, 0x06010604,
|
||||
0x1e1e0af9, 0x160a0604, 0x7e200307, 0x20200af9, 0x08061104, 0x20220af9, 0x060d2604, 0x64240af9,
|
||||
0x05010004, 0x66260af9, 0x02150d04, 0x7e280307, 0x68280af9, 0x24031304, 0x6a2a0af9, 0x00040604,
|
||||
0x7e2c0307, 0x742c0af9, 0x05081404, 0x722e0af9, 0x19050204, 0x06300af9, 0x06052b04, 0x6a320af9,
|
||||
0x06020904, 0xe0781000, 0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020, 0x80011203, 0xe0781030,
|
||||
0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[32][4] = {
|
||||
{0x00000000u, 0x00000000u, 0x40404040u, 0x8b2af49fu},
|
||||
{0x00000000u, 0x10663f9du, 0x8b35e743u, 0x7d7d9db4u},
|
||||
{0x0008dbf2u, 0x47004700u, 0x3c000000u, 0x80000000u},
|
||||
{0x05c21fabu, 0x00470047u, 0x80000000u, 0x47004700u},
|
||||
{0x1a0e7cdeu, 0x00000000u, 0xefc2742bu, 0xcd8d3db8u},
|
||||
{0xc4de998au, 0xaf1fba34u, 0x0000bc00u, 0xbc00bc00u},
|
||||
{0x00000000u, 0x00470047u, 0xc2c2c2c2u, 0xfda0095du},
|
||||
{0x3c000000u, 0x80808080u, 0x5960b098u, 0xadd5eff7u},
|
||||
{0xbc00bc00u, 0x00000000u, 0x42a502c0u, 0x3c000000u},
|
||||
{0x80808080u, 0x1a64a58eu, 0xfe242714u, 0x3c003c00u},
|
||||
{0x00000000u, 0x7c007c00u, 0x7f7f7f7fu, 0x3c003c00u},
|
||||
{0x00470047u, 0x00000000u, 0x3468787du, 0x7e7103e1u},
|
||||
{0x00470047u, 0x80000000u, 0x702bd672u, 0x47004700u},
|
||||
{0x00000000u, 0x00800080u, 0x4659ff82u, 0xc2c2c2c2u},
|
||||
{0x7f800000u, 0x00000000u, 0x01000100u, 0x1b1c3f27u},
|
||||
{0x80000000u, 0x00800080u, 0xbf800000u, 0x829ea49cu},
|
||||
{0x00000000u, 0x0000bc00u, 0x3343e632u, 0x13e60ef5u},
|
||||
{0x00000000u, 0x00470047u, 0xb5a54b0bu, 0x6769ec45u},
|
||||
{0x00000000u, 0x00800080u, 0xa2e7068bu, 0x871c3c9cu},
|
||||
{0x00000000u, 0x00800080u, 0xafe5c4b5u, 0x3c003c00u},
|
||||
{0x00000000u, 0x00ff00ffu, 0x0000bc00u, 0x40404040u},
|
||||
{0x00000000u, 0x00ff00ffu, 0x7f800000u, 0x00ff00ffu},
|
||||
{0x00000000u, 0x00ff00ffu, 0xb4ad5866u, 0xe4ea7accu},
|
||||
{0x00000000u, 0x00ff00ffu, 0xd03c7dbeu, 0x5de25876u},
|
||||
{0x00000000u, 0x01000100u, 0x52eff50fu, 0x00000000u},
|
||||
{0x00000000u, 0x182f8e4au, 0xe117e1fau, 0x0000bc00u},
|
||||
{0x00000000u, 0x20d8e2bcu, 0xe73074b1u, 0xbf800000u},
|
||||
{0x00000000u, 0x2333ad9cu, 0x00800080u, 0x3f800000u},
|
||||
{0x00000000u, 0x24f70eabu, 0xfdb88e95u, 0x17e6487au},
|
||||
{0x00000000u, 0x2a778095u, 0x00470047u, 0x7c007c00u},
|
||||
{0x00000000u, 0x2b119b05u, 0x0000bc00u, 0x4ce5144fu},
|
||||
{0x00000000u, 0x2b5d55fdu, 0x03f55439u, 0x7f7f7f7fu}
|
||||
};
|
||||
constexpr std::uint32_t Expected[32][16] = {
|
||||
{0x00000000u, 0x0000f49fu, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x8b2a009fu, 0x00000000u, 0x00000000u, 0x80000000u, 0x002af49fu, 0x00000000u, 0x8b2a0000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x10663f9du, 0x10669db4u, 0xff9d0000u, 0x00000000u, 0x00000000u, 0x90663f9du, 0x7d7d00b4u, 0x10663f9du, 0x00000066u, 0x80660000u, 0x9d7d9db4u, 0x00000000u, 0x7d7d0000u, 0x00000000u, 0x9d000000u, 0x00000000u},
|
||||
{0x47004700u, 0x94f20000u, 0x00000000u, 0x00000000u, 0x006dbcbdu, 0xc7004700u, 0x8000f200u, 0x3f800000u, 0x00000000u, 0x80080000u, 0x00000000u, 0x00008000u, 0x80004700u, 0x00080000u, 0x00000000u, 0x00003800u},
|
||||
{0x004700f2u, 0x1fab4700u, 0xfff20000u, 0x00000000u, 0x00000000u, 0x80470047u, 0x4700ab00u, 0x00470047u, 0x00000066u, 0x86090000u, 0x42004700u, 0x00000001u, 0x47000047u, 0x00c20000u, 0x09000000u, 0x00000000u},
|
||||
{0x000000deu, 0x7cde3db8u, 0xffde0000u, 0x00000000u, 0x00000000u, 0x80000000u, 0xcd8ddeb8u, 0x00001a0eu, 0x0000007cu, 0x9a0e0000u, 0x1a8d3db8u, 0x00007edeu, 0xcd8d0000u, 0x000e0000u, 0x0e000000u, 0x00000000u},
|
||||
{0xaf1fba34u, 0x998abc00u, 0x00000000u, 0x0000c158u, 0x80000000u, 0x2f1fba34u, 0xbc003400u, 0x00000000u, 0x0000001fu, 0x44de0000u, 0x3400bc00u, 0x00008000u, 0xbc00af1fu, 0x00de0000u, 0x00000000u, 0xffffac00u},
|
||||
{0x00470047u, 0x0047095du, 0x00470000u, 0x00000000u, 0x00000000u, 0x80470047u, 0xfda0475du, 0x00470047u, 0x00000047u, 0x80470000u, 0x47a0095du, 0x00000000u, 0xfda00000u, 0x00000000u, 0x47000000u, 0x00000000u},
|
||||
{0x80808080u, 0x0000eff7u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u, 0xadd500f7u, 0x00003c00u, 0x00000080u, 0xbc000000u, 0x44d5eff7u, 0x00000000u, 0xadd58080u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000000u, 0xbc000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x3c000000u, 0x00000000u, 0x000000bcu, 0x3c000000u, 0xbc000000u, 0x00008000u, 0x3c000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x1a64a58eu, 0x9ae43c00u, 0xff8e0000u, 0x00000000u, 0x00000000u, 0x9a64a58eu, 0x3c008000u, 0x1a64a58eu, 0x00000068u, 0x001c0000u, 0x8e003c00u, 0x00008000u, 0x3c001a64u, 0x00800000u, 0x8e000000u, 0x00000300u},
|
||||
{0x7c007c00u, 0x7c003c00u, 0x00000000u, 0x00000000u, 0x00000000u, 0xfc007c00u, 0x3c000000u, 0x3f800000u, 0x00000000u, 0x80000000u, 0x00003c00u, 0x00000000u, 0x3c000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00000047u, 0x004703e1u, 0x00470000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x7e7147e1u, 0x00000047u, 0x00000000u, 0x80470000u, 0x007103e1u, 0x00000000u, 0x7e710000u, 0x00470000u, 0x47000000u, 0x00000000u},
|
||||
{0x00000047u, 0x80474700u, 0x00470000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x47004700u, 0x00000047u, 0x00000000u, 0x80470000u, 0x00004700u, 0x00000000u, 0x47008000u, 0x00470000u, 0x47000000u, 0x00000000u},
|
||||
{0x00800080u, 0x0080c2c2u, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0xc2c200c2u, 0x00800080u, 0x00000080u, 0x80800000u, 0x80c2c2c2u, 0x00000000u, 0xc2c20000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x00000000u, 0x00003f27u, 0x00000000u, 0x00000000u, 0x00000000u, 0x80000000u, 0x1b1c0027u, 0x00007f80u, 0x00000000u, 0xff800000u, 0x7f1c3f27u, 0x00000000u, 0x1b1c0000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x00800080u, 0x0080a49cu, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0x829e009cu, 0x00800080u, 0x00000080u, 0x80800000u, 0x009ea49cu, 0x00000000u, 0x829e0000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x0000bc00u, 0x00000ef5u, 0x00000000u, 0x00000000u, 0x00000000u, 0x8000bc00u, 0x13e600f5u, 0x0000bc00u, 0x00000000u, 0x80000000u, 0x00e60ef5u, 0x00000000u, 0x13e60000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x00470047u, 0x0047ec45u, 0x00470000u, 0x00000000u, 0x00000000u, 0x80470047u, 0x67694745u, 0x00470047u, 0x00000047u, 0x80470000u, 0x4769ec45u, 0x00000000u, 0x67690000u, 0x00000000u, 0x47000000u, 0x00000000u},
|
||||
{0x00800080u, 0x00803c9cu, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0x871c009cu, 0x00800080u, 0x00000080u, 0x80800000u, 0x801c3c9cu, 0x00000000u, 0x871c0000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x00800080u, 0x00803c00u, 0xff800000u, 0x00000000u, 0x00000000u, 0x80800080u, 0x3c000000u, 0x00800080u, 0x00000080u, 0x80800000u, 0x80003c00u, 0x00000000u, 0x3c000000u, 0x00000000u, 0x80000000u, 0x00000000u},
|
||||
{0x00ff00ffu, 0x00ff4040u, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0x40400040u, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xff404040u, 0x00000000u, 0x40400000u, 0x00000000u, 0xff000000u, 0x00000000u},
|
||||
{0x00ff00ffu, 0x00ff00ffu, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0x00ff00ffu, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xffff00ffu, 0x00000000u, 0x00ff0000u, 0x00000000u, 0xff000000u, 0x00000000u},
|
||||
{0x00ff00ffu, 0x00ff7accu, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0xe4ea00ccu, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xffea7accu, 0x00000000u, 0xe4ea0000u, 0x00000000u, 0xff000000u, 0x00000000u},
|
||||
{0x00ff00ffu, 0x00ff5876u, 0xffff0000u, 0x00000000u, 0x00000000u, 0x80ff00ffu, 0x5de20076u, 0x00ff00ffu, 0x000000ffu, 0x80ff0000u, 0xffe25876u, 0x00000000u, 0x5de20000u, 0x00000000u, 0xff000000u, 0x00000000u},
|
||||
{0x01000100u, 0x01000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x81000100u, 0x00000000u, 0x01000100u, 0x00000000u, 0x80000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x182f8e4au, 0x182fbc00u, 0x004a0000u, 0x00000000u, 0x00000000u, 0x982f8e4au, 0x00004a00u, 0x182f8e4au, 0x0000002fu, 0x802f0000u, 0x4a00bc00u, 0x00000000u, 0x00000000u, 0x00000000u, 0x4a000000u, 0x00000000u},
|
||||
{0x20d8e2bcu, 0x20d80000u, 0xffbc0000u, 0x00000000u, 0x00000000u, 0xa0d8e2bcu, 0xbf800000u, 0x20d8e2bcu, 0x000000d8u, 0x80d80000u, 0xbc800000u, 0x00000000u, 0xbf800000u, 0x00000000u, 0xbc000000u, 0x00000000u},
|
||||
{0x2333ad9cu, 0x23330000u, 0xff9c0000u, 0x00000000u, 0x00000000u, 0xa333ad9cu, 0x3f800000u, 0x2333ad9cu, 0x00000033u, 0x80330000u, 0x9c800000u, 0x00000000u, 0x3f800000u, 0x00000000u, 0x9c000000u, 0x00000000u},
|
||||
{0x24f70eabu, 0x24f7487au, 0xffab0000u, 0x00000000u, 0x00000000u, 0xa4f70eabu, 0x17e6007au, 0x24f70eabu, 0x000000f7u, 0x80f70000u, 0xabe6487au, 0x00000000u, 0x17e60000u, 0x00000000u, 0xab000000u, 0x00000000u},
|
||||
{0x2a778095u, 0x2a777c00u, 0xff950000u, 0x00000000u, 0x00000000u, 0xaa778095u, 0x7c000000u, 0x2a778095u, 0x00000077u, 0x80770000u, 0x95007c00u, 0x00000000u, 0x7c000000u, 0x00000000u, 0x95000000u, 0x00000000u},
|
||||
{0x2b119b05u, 0x2b11144fu, 0x00050000u, 0x00000000u, 0x00000000u, 0xab119b05u, 0x4ce5054fu, 0x2b119b05u, 0x00000011u, 0x80110000u, 0x05e5144fu, 0x00000000u, 0x4ce50000u, 0x00000000u, 0x05000000u, 0x00000000u},
|
||||
{0x2b5d55fdu, 0x2b5d7f7fu, 0xfffd0000u, 0x00000000u, 0x00000000u, 0xab5d55fdu, 0x7f7f007fu, 0x2b5d55fdu, 0x0000005du, 0x805d0000u, 0xfd7f7f7fu, 0x00000000u, 0x7f7f0000u, 0x00000000u, 0xfd000000u, 0x00000000u}
|
||||
};
|
||||
constexpr std::uint32_t Checked[32] = {0xffffu, 0xfdfdu, 0x5dadu, 0xa05au, 0xb27au, 0x7fa7u, 0xb818u, 0xea77u, 0xfaffu, 0x5cfdu, 0x7ffdu, 0x9d38u, 0x9d38u, 0xf8fdu, 0xb977u, 0xfcfdu, 0xff5eu, 0xb818u, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xf8fdu, 0xfffdu, 0xfdbdu, 0xfdfdu, 0xfdfdu, 0xfdfdu, 0xf9fdu, 0xfdbdu, 0xfdfdu};
|
||||
constexpr const char* Names[16] = {
|
||||
"add_f32 BYTE_0/DWORD -> DWORD",
|
||||
"sub_f32 DWORD/WORD_1 -> WORD_1",
|
||||
"subrev_f32 WORD_0/DWORD -> BYTE_2",
|
||||
"mul_f32 DWORD/BYTE_3 -> WORD_0",
|
||||
"mul_legacy_f32 BYTE_1/DWORD -> DWORD",
|
||||
"min_f32 BYTE_2/DWORD -> DWORD",
|
||||
"max_f32 DWORD/BYTE_0 -> BYTE_1",
|
||||
"max_f32 WORD_1/DWORD -> DWORD",
|
||||
"add_f16 BYTE_1/WORD_1 -> BYTE_0",
|
||||
"sub_f16 WORD_1/BYTE_2 -> WORD_1",
|
||||
"subrev_f16 BYTE_3/WORD_0 -> BYTE_3",
|
||||
"mul_f16 WORD_0/BYTE_0 -> DWORD",
|
||||
"min_f16 BYTE_0/WORD_1 -> WORD_0",
|
||||
"max_f16 WORD_1/BYTE_1 -> BYTE_2",
|
||||
"add_f32 WORD_1/DWORD -> BYTE_3",
|
||||
"mul_f16 BYTE_2/DWORD -> BYTE_1",
|
||||
};
|
||||
|
||||
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("sdwa float selectors: lane ") + std::to_string(tid) + " " + name + " is " + Hex(actual) + ", expected " + Hex(expected));
|
||||
}
|
||||
|
||||
ShaderRecompiler::RecompileResult Compile(AgcDriver::VulkanDevice& device, std::span<const std::uint32_t> code) {
|
||||
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::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;
|
||||
return ShaderRecompiler::Recompile(request);
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) Fill(tid, &Input[tid * Inputs]);
|
||||
Output.fill(0xdeadbeefu);
|
||||
const std::span<const std::uint32_t> code(Code);
|
||||
const auto result = Compile(device, code);
|
||||
device.Dispatch(result, 1, 1, 1, {}, reinterpret_cast<std::uintptr_t>(code.data()));
|
||||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void CheckByteSelectorClampRefused(AgcDriver::VulkanDevice& device) {
|
||||
constexpr std::array<std::array<std::uint32_t, 2>, 6> forms{{
|
||||
{0x640a0cf9u, 0x04052004u},
|
||||
{0x660a0cf9u, 0x04022504u},
|
||||
{0x680a0cf9u, 0x03042604u},
|
||||
{0x6a0a0cf9u, 0x05043304u},
|
||||
{0x740a0cf9u, 0x06012404u},
|
||||
{0x720a0cf9u, 0x00062604u},
|
||||
}};
|
||||
for (const auto& form : forms) {
|
||||
alignas(256) const std::array<std::uint32_t, 3> code{form[0], form[1], 0xbf810000u};
|
||||
std::string refusal;
|
||||
try {
|
||||
static_cast<void>(Compile(device, code));
|
||||
} catch (const std::exception& error) {
|
||||
refusal = error.what();
|
||||
}
|
||||
Require(refusal.find("VOP2 SDWA clamp with byte selectors is not implemented") != std::string::npos, "f16 SDWA form " + Hex(form[0]) + " " + Hex(form[1]) + " with clamp was not refused");
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
CheckByteSelectorClampRefused(*device);
|
||||
std::puts("sdwa float selectors tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
#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, 48> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0xd543800a, 0x041a0b04, 0xd542800b,
|
||||
0x041a0b04, 0xd740800c, 0x041a0b04, 0xd75e800d, 0x041a0b04, 0xd773800e, 0x041a0b04, 0xd775800f,
|
||||
0x041a0b04, 0xd55a8010, 0x041a0b04, 0xd55b8011, 0x041a0b04, 0xd55c8012, 0x041a0b04, 0xd55d8013,
|
||||
0x041a0b04, 0xd5718014, 0x041a0b04, 0x7e2a0307, 0xd740d815, 0x041a0b04, 0xd75eb016, 0x041a0b04,
|
||||
0xd7758817, 0x041a0b04, 0xd7739018, 0x041a0b04, 0x7e320307, 0xd75ef819, 0x041a0b04, 0xe0781000,
|
||||
0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020, 0x80011203, 0xe0781030, 0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[32][4] = {
|
||||
{0x00000000u, 0x00000000u, 0x00000001u, 0x0000ffffu},
|
||||
{0x00000000u, 0x00007fffu, 0xffffffffu, 0x0000fff0u},
|
||||
{0x01010101u, 0x01010101u, 0xffffffffu, 0xff00ff00u},
|
||||
{0x00000001u, 0xff00ff00u, 0x80000000u, 0x7fffffffu},
|
||||
{0x00000000u, 0x00000000u, 0x506377feu, 0x09418c53u},
|
||||
{0x00000000u, 0x00000000u, 0xad078efau, 0x00000002u},
|
||||
{0x00000000u, 0x00000001u, 0x00000002u, 0x293b6032u},
|
||||
{0x00000000u, 0x00000001u, 0x0000fff0u, 0x00ff00ffu},
|
||||
{0x00000000u, 0x00000001u, 0x00ff00ffu, 0xdbd16e44u},
|
||||
{0x00000000u, 0x00000001u, 0x671b91d7u, 0xb1836b5au},
|
||||
{0x00000000u, 0x00000001u, 0xb51b0523u, 0x54b074b8u},
|
||||
{0x00000000u, 0x00000001u, 0xff0ec345u, 0x00007fffu},
|
||||
{0x00000000u, 0x00000002u, 0x00000000u, 0xfefefefeu},
|
||||
{0x00000000u, 0x0000007fu, 0x00000002u, 0xcee69ed0u},
|
||||
{0x00000000u, 0x0000007fu, 0x12345678u, 0x40778188u},
|
||||
{0x00000000u, 0x0000007fu, 0x1bf35776u, 0x12345678u},
|
||||
{0x00000000u, 0x0000007fu, 0x29c0ba3bu, 0x48e98a0au},
|
||||
{0x00000000u, 0x0000007fu, 0x9d299c7bu, 0x39cdd549u},
|
||||
{0x00000000u, 0x0000007fu, 0x9ff9949eu, 0x00ffffffu},
|
||||
{0x00000000u, 0x00000080u, 0x000000ffu, 0x12345678u},
|
||||
{0x00000000u, 0x00000080u, 0x00008000u, 0x80000001u},
|
||||
{0x00000000u, 0x00000080u, 0x0000fff0u, 0xae15989du},
|
||||
{0x00000000u, 0x00000080u, 0x0000ffffu, 0x00000080u},
|
||||
{0x00000000u, 0x00000080u, 0x80000001u, 0x0000007fu},
|
||||
{0x00000000u, 0x00000080u, 0xaf4a9e38u, 0xd42344f4u},
|
||||
{0x00000000u, 0x00000080u, 0xea4d8c45u, 0x00625618u},
|
||||
{0x00000000u, 0x00000080u, 0xfd4fb563u, 0xff00ff00u},
|
||||
{0x00000000u, 0x000000ffu, 0x00000001u, 0x310733d9u},
|
||||
{0x00000000u, 0x000000ffu, 0x2f3bacc0u, 0xffff0000u},
|
||||
{0x00000000u, 0x000000ffu, 0x85f55b11u, 0xffff0000u},
|
||||
{0x00000000u, 0x000000ffu, 0xff00ff00u, 0x9fc408e0u},
|
||||
{0x00000000u, 0x000000ffu, 0xffff0000u, 0xffff0000u}
|
||||
};
|
||||
constexpr std::uint32_t Expected[32][16] = {
|
||||
{0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x0001ffffu, 0x00000000u, 0x00000001u, 0x00000001u, 0x0000ffffu},
|
||||
{0xffffffffu, 0xffffffffu, 0x0000ffffu, 0x0000ffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xfffffff0u, 0x0000ffffu, 0xffffffffu, 0xffffffffu, 0xfffffff0u},
|
||||
{0xffffffffu, 0x7fffffffu, 0x0000ffffu, 0x00007fffu, 0xffffffffu, 0x00010200u, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffff00u, 0x00007fffu, 0x00010200u, 0xffffffffu, 0x7fffff00u},
|
||||
{0x8000ff00u, 0x8000ff00u, 0x0000ff00u, 0x0000ff00u, 0x8000ff00u, 0x80000000u, 0x800001ffu, 0x81ff0000u, 0x8001fdffu, 0xffffffffu, 0x800001feu, 0x0000ffffu, 0x00008000u, 0x80000000u, 0x8000ff00u, 0x8000ffffu},
|
||||
{0x506377feu, 0x506377feu, 0x000077feu, 0x000077feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x506377feu, 0x77fe8c53u, 0x00005063u, 0x506377feu, 0x506377feu, 0x50638c53u},
|
||||
{0xad078efau, 0xad078efau, 0x00008efau, 0x00008efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0xad078efau, 0x8efa0002u, 0x0000ad07u, 0xad078efau, 0xad078efau, 0xad070002u},
|
||||
{0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000003u, 0x00010002u, 0x00000003u, 0x00000003u, 0x00000003u, 0x00026032u, 0x00000000u, 0x00000002u, 0x00000002u, 0x00006032u},
|
||||
{0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff1u, 0x0001fff0u, 0x0000fff1u, 0x0000fff1u, 0x0000fff1u, 0xfff000ffu, 0x00000000u, 0x0000fff0u, 0x0000fff0u, 0x000000ffu},
|
||||
{0x00ff00ffu, 0x00ff00ffu, 0x000000ffu, 0x000000ffu, 0x00ff00ffu, 0x00ff00ffu, 0x00ff0100u, 0x010000ffu, 0x00ff0100u, 0x00ff0100u, 0x00ff0100u, 0x00ff6e44u, 0x000000ffu, 0x00ff00ffu, 0x00ff00ffu, 0x00ff6e44u},
|
||||
{0x671b91d7u, 0x671b91d7u, 0x000091d7u, 0x000091d7u, 0x671b91d7u, 0x671b91d7u, 0x671b91d8u, 0x671c91d7u, 0x671b91d8u, 0x671b91d8u, 0x671b91d8u, 0x91d76b5au, 0x0000671bu, 0x671b91d7u, 0x671b91d7u, 0x671b6b5au},
|
||||
{0xb51b0523u, 0xb51b0523u, 0x00000523u, 0x00000523u, 0xb51b0523u, 0xb51b0523u, 0xb51b0524u, 0xb51c0523u, 0xb51b0524u, 0xb51b0524u, 0xb51b0524u, 0x052374b8u, 0x0000b51bu, 0xb51b0523u, 0xb51b0523u, 0xb51b74b8u},
|
||||
{0xff0ec345u, 0xff0ec345u, 0x0000c345u, 0x0000c345u, 0xff0ec345u, 0xff0ec345u, 0xff0ec346u, 0xff0fc345u, 0xff0ec346u, 0xff0ec346u, 0xff0ec346u, 0xc3457fffu, 0x0000ff0eu, 0xff0ec345u, 0xff0ec345u, 0xff0e7fffu},
|
||||
{0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000002u, 0x00020000u, 0x00000002u, 0x00000002u, 0x00000002u, 0x0000fefeu, 0x00000000u, 0x00000000u, 0x00000000u, 0x0000fefeu},
|
||||
{0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000002u, 0x00000081u, 0x007f0002u, 0x00000081u, 0x00000081u, 0x00000081u, 0x00029ed0u, 0x00000000u, 0x00000002u, 0x00000002u, 0x00009ed0u},
|
||||
{0x12345678u, 0x12345678u, 0x00005678u, 0x00005678u, 0x12345678u, 0x12345678u, 0x123456f7u, 0x12b35678u, 0x123456f7u, 0x123456f7u, 0x123456f7u, 0x56788188u, 0x00001234u, 0x12345678u, 0x12345678u, 0x12348188u},
|
||||
{0x1bf35776u, 0x1bf35776u, 0x00005776u, 0x00005776u, 0x1bf35776u, 0x1bf35776u, 0x1bf357f5u, 0x1c725776u, 0x1bf357f5u, 0x1bf357f5u, 0x1bf357f5u, 0x57765678u, 0x00001bf3u, 0x1bf35776u, 0x1bf35776u, 0x1bf35678u},
|
||||
{0x29c0ba3bu, 0x29c0ba3bu, 0x0000ba3bu, 0x0000ba3bu, 0x29c0ba3bu, 0x29c0ba3bu, 0x29c0babau, 0x2a3fba3bu, 0x29c0babau, 0x29c0babau, 0x29c0babau, 0xba3b8a0au, 0x000029c0u, 0x29c0ba3bu, 0x29c0ba3bu, 0x29c08a0au},
|
||||
{0x9d299c7bu, 0x9d299c7bu, 0x00009c7bu, 0x00009c7bu, 0x9d299c7bu, 0x9d299c7bu, 0x9d299cfau, 0x9da89c7bu, 0x9d299cfau, 0x9d299cfau, 0x9d299cfau, 0x9c7bd549u, 0x00009d29u, 0x9d299c7bu, 0x9d299c7bu, 0x9d29d549u},
|
||||
{0x9ff9949eu, 0x9ff9949eu, 0x0000949eu, 0x0000949eu, 0x9ff9949eu, 0x9ff9949eu, 0x9ff9951du, 0xa078949eu, 0x9ff9951du, 0x9ff9951du, 0x9ff9951du, 0x949effffu, 0x00009ff9u, 0x9ff9949eu, 0x9ff9949eu, 0x9ff9ffffu},
|
||||
{0x000000ffu, 0x000000ffu, 0x000000ffu, 0x000000ffu, 0x000000ffu, 0x000000ffu, 0x0000017fu, 0x008000ffu, 0x0000017fu, 0x0000017fu, 0x0000017fu, 0x00ff5678u, 0x00000000u, 0x000000ffu, 0x000000ffu, 0x00005678u},
|
||||
{0x00008000u, 0x00008000u, 0x00008000u, 0x00008000u, 0x00008000u, 0x00008000u, 0x00008080u, 0x00808000u, 0x00008080u, 0x00008080u, 0x00008080u, 0x80000001u, 0x00000000u, 0x00008000u, 0x00008000u, 0x00000001u},
|
||||
{0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x0000fff0u, 0x00010070u, 0x0080fff0u, 0x00010070u, 0x00010070u, 0x00010070u, 0xfff0989du, 0x00000000u, 0x0000fff0u, 0x0000fff0u, 0x0000989du},
|
||||
{0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0001007fu, 0x0080ffffu, 0x0001007fu, 0x0001007fu, 0x0001007fu, 0xffff0080u, 0x00000000u, 0x0000ffffu, 0x0000ffffu, 0x00000080u},
|
||||
{0x80000001u, 0x80000001u, 0x00000001u, 0x00000001u, 0x80000001u, 0x80000001u, 0x80000081u, 0x80800001u, 0x80000081u, 0x80000081u, 0x80000081u, 0x0001007fu, 0x00008000u, 0x80000001u, 0x80000001u, 0x8000007fu},
|
||||
{0xaf4a9e38u, 0xaf4a9e38u, 0x00009e38u, 0x00009e38u, 0xaf4a9e38u, 0xaf4a9e38u, 0xaf4a9eb8u, 0xafca9e38u, 0xaf4a9eb8u, 0xaf4a9eb8u, 0xaf4a9eb8u, 0x9e3844f4u, 0x0000af4au, 0xaf4a9e38u, 0xaf4a9e38u, 0xaf4a44f4u},
|
||||
{0xea4d8c45u, 0xea4d8c45u, 0x00008c45u, 0x00008c45u, 0xea4d8c45u, 0xea4d8c45u, 0xea4d8cc5u, 0xeacd8c45u, 0xea4d8cc5u, 0xea4d8cc5u, 0xea4d8cc5u, 0x8c455618u, 0x0000ea4du, 0xea4d8c45u, 0xea4d8c45u, 0xea4d5618u},
|
||||
{0xfd4fb563u, 0xfd4fb563u, 0x0000b563u, 0x0000b563u, 0xfd4fb563u, 0xfd4fb563u, 0xfd4fb5e3u, 0xfdcfb563u, 0xfd4fb5e3u, 0xfd4fb5e3u, 0xfd4fb5e3u, 0xb563ff00u, 0x0000fd4fu, 0xfd4fb563u, 0xfd4fb563u, 0xfd4fff00u},
|
||||
{0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000001u, 0x00000100u, 0x00ff0001u, 0x00000100u, 0x00000100u, 0x00000100u, 0x000133d9u, 0x00000000u, 0x00000001u, 0x00000001u, 0x000033d9u},
|
||||
{0x2f3bacc0u, 0x2f3bacc0u, 0x0000acc0u, 0x0000acc0u, 0x2f3bacc0u, 0x2f3bacc0u, 0x2f3badbfu, 0x303aacc0u, 0x2f3badbfu, 0x2f3badbfu, 0x2f3badbfu, 0xacc00000u, 0x00002f3bu, 0x2f3bacc0u, 0x2f3bacc0u, 0x2f3b0000u},
|
||||
{0x85f55b11u, 0x85f55b11u, 0x00005b11u, 0x00005b11u, 0x85f55b11u, 0x85f55b11u, 0x85f55c10u, 0x86f45b11u, 0x85f55c10u, 0x85f55c10u, 0x85f55c10u, 0x5b110000u, 0x000085f5u, 0x85f55b11u, 0x85f55b11u, 0x85f50000u},
|
||||
{0xff00ff00u, 0xff00ff00u, 0x0000ff00u, 0x0000ff00u, 0xff00ff00u, 0xff00ff00u, 0xff00ffffu, 0xffffff00u, 0xff00ffffu, 0xff00ffffu, 0xff00ffffu, 0xff0008e0u, 0x0000ff00u, 0xff00ff00u, 0xff00ff00u, 0xff0008e0u},
|
||||
{0xffff0000u, 0xffff0000u, 0x00000000u, 0x00000000u, 0xffff0000u, 0xffff0000u, 0xffff00ffu, 0xffffffffu, 0xffff00ffu, 0xffff00ffu, 0xffff00ffu, 0x00000000u, 0x0000ffffu, 0xffff0000u, 0xffff0000u, 0xffff0000u}
|
||||
};
|
||||
constexpr const char* Names[16] = {
|
||||
"mad_u32_u24",
|
||||
"mad_i32_i24",
|
||||
"mad_u16",
|
||||
"mad_i16",
|
||||
"mad_u32_u16",
|
||||
"mad_i32_i16",
|
||||
"sad_u8",
|
||||
"sad_hi_u8",
|
||||
"sad_u16",
|
||||
"sad_u32",
|
||||
"msad_u8",
|
||||
"mad_u16 op_sel",
|
||||
"mad_i16 op_sel",
|
||||
"mad_i32_i16 op_sel",
|
||||
"mad_u32_u16 op_sel",
|
||||
"mad_i16 op_sel",
|
||||
};
|
||||
|
||||
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("vop3 integer 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) {
|
||||
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("vop3 integer clamp tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
#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, 36> Code{
|
||||
0x34020084, 0x34060086, 0xe0381000, 0x80000401, 0xbf8c3f70, 0xd572800a, 0x041a0d04, 0xd573800c,
|
||||
0x041a0d04, 0xd575800e, 0x04120d04, 0xd7558012, 0x041a0b04, 0xd7568013, 0x041a0b04, 0xd7528014,
|
||||
0x041a0b04, 0xd7538015, 0x041a0b04, 0xd7588016, 0x041a0b04, 0xd7598017, 0x041a0b04, 0xd54e8018,
|
||||
0x041a0b04, 0xd54f8019, 0x041a0b04, 0xe0781000, 0x80010a03, 0xe0781010, 0x80010e03, 0xe0781020,
|
||||
0x80011203, 0xe0781030, 0x80011603, 0xbf810000,
|
||||
};
|
||||
|
||||
constexpr std::uint32_t Rows[32][4] = {
|
||||
{0x00000000u, 0x00000000u, 0x00800000u, 0x0000ffffu},
|
||||
{0x0000007fu, 0xe3718038u, 0xfffffffeu, 0xfd7c84feu},
|
||||
{0x0000007fu, 0xfffffffeu, 0x0000007fu, 0xfffffffeu},
|
||||
{0xfffffffeu, 0x00000002u, 0xb93201bfu, 0x00000000u},
|
||||
{0x00000000u, 0x00000000u, 0x3ff51543u, 0x8ca197b1u},
|
||||
{0x00000000u, 0x00000001u, 0x007fffffu, 0x29813b74u},
|
||||
{0x00000000u, 0x00000001u, 0x00ff00ffu, 0x00007fffu},
|
||||
{0x00000000u, 0x00000001u, 0x01010101u, 0xa48d7f36u},
|
||||
{0x00000000u, 0x00000001u, 0x1ef5acc3u, 0x5d780492u},
|
||||
{0x00000000u, 0x00000001u, 0x41f8bfb7u, 0x3f57a9d3u},
|
||||
{0x00000000u, 0x00000001u, 0xfefefefeu, 0x0000007fu},
|
||||
{0x00000000u, 0x00000002u, 0x00ffffffu, 0x80000000u},
|
||||
{0x00000000u, 0x00000002u, 0x7351a059u, 0x00007fffu},
|
||||
{0x00000000u, 0x00000002u, 0xcb50b50fu, 0x7fffffffu},
|
||||
{0x00000000u, 0x0000007fu, 0x0000ffffu, 0x01010101u},
|
||||
{0x00000000u, 0x0000007fu, 0x0ac13011u, 0xffff0000u},
|
||||
{0x00000000u, 0x0000007fu, 0x4b88f735u, 0x000000ffu},
|
||||
{0x00000000u, 0x0000007fu, 0xffffffffu, 0x0000fff0u},
|
||||
{0x00000000u, 0x00000080u, 0x00000000u, 0x00ffffffu},
|
||||
{0x00000000u, 0x00000080u, 0xffffffffu, 0xde945808u},
|
||||
{0x00000000u, 0x000000ffu, 0x000000ffu, 0x00000080u},
|
||||
{0x00000000u, 0x000000ffu, 0x7fffffffu, 0xca9c52c9u},
|
||||
{0x00000000u, 0x000000ffu, 0x80000001u, 0x0000007fu},
|
||||
{0x00000000u, 0x000000ffu, 0xffff0000u, 0x00007fffu},
|
||||
{0x00000000u, 0x000000ffu, 0xffffffffu, 0xffffffffu},
|
||||
{0x00000000u, 0x00007fffu, 0x01010101u, 0xcff6ab04u},
|
||||
{0x00000000u, 0x00007fffu, 0x44e9da39u, 0x63548e6fu},
|
||||
{0x00000000u, 0x00007fffu, 0x4944fa2au, 0xf5524d50u},
|
||||
{0x00000000u, 0x00007fffu, 0xa1dfdb1eu, 0xa9e05a10u},
|
||||
{0x00000000u, 0x00007fffu, 0xffff0000u, 0x01010101u},
|
||||
{0x00000000u, 0x00007fffu, 0xffffffffu, 0x0000007fu},
|
||||
{0x00000000u, 0x0000fff0u, 0x00000080u, 0x01010101u}
|
||||
};
|
||||
constexpr std::uint32_t Expected[32][16] = {
|
||||
{0x01000080u, 0x0080ffffu, 0x01000080u, 0x0080ffffu, 0x00000080u, 0x00000080u, 0x00800080u, 0x0001007fu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0xffffffffu, 0xffff8841u, 0xffffffffu, 0xffff8841u, 0x000003fbu, 0xe37183fbu, 0xffffffffu, 0xfd7c87d0u, 0x0000007fu, 0x0000fffeu, 0x00008038u, 0x0000007fu, 0x0000fffeu, 0x00008038u, 0x000001ffu, 0x007fe371u},
|
||||
{0x017d007fu, 0xffffffffu, 0x007f007fu, 0xffffffffu, 0x0000007fu, 0xffffffffu, 0x000000feu, 0xffffffffu, 0x0000007fu, 0x0000fffeu, 0x0000fffeu, 0x0000007fu, 0x0000007fu, 0x0000007fu, 0x000000ffu, 0x00007fffu},
|
||||
{0xbbf4040fu, 0x012c0227u, 0xbbf4040fu, 0x012c0227u, 0xffffffffu, 0x000002c4u, 0xb93203e6u, 0x0000012cu, 0x000001bfu, 0x0000fffeu, 0x0000fffeu, 0x00000002u, 0x00000002u, 0x000001bfu, 0xfffffffcu, 0xfffffe00u},
|
||||
{0x418116cfu, 0x8e2d993du, 0x418116cfu, 0x8e2d993du, 0x0000018cu, 0x0000018cu, 0x3ff516cfu, 0x8ca1993du, 0x00001543u, 0x00001543u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u},
|
||||
{0x02fdffffu, 0x2bfd3df0u, 0x02fcffffu, 0x2bfd3df0u, 0x0000027du, 0x0000027eu, 0x0080027bu, 0x29813df0u, 0x00000001u, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x02fe02fdu, 0x01ff81fcu, 0x02fd02fdu, 0x01fe81fcu, 0x000001feu, 0x000001ffu, 0x00ff02fcu, 0x000081fdu, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x01040105u, 0xa4907f39u, 0x01040105u, 0xa4907f39u, 0x00000004u, 0x00000004u, 0x01010104u, 0xa48d7f39u, 0x00000101u, 0x00000101u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x2176af45u, 0x5ff90713u, 0x2176af45u, 0x5ff90713u, 0x00000282u, 0x00000282u, 0x1ef5af44u, 0x5d780713u, 0x00000001u, 0x0000acc3u, 0x0000acc3u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x44a6c266u, 0x4205ac81u, 0x44a6c266u, 0x4205ac81u, 0x000002afu, 0x000002afu, 0x41f8c265u, 0x3f57ac81u, 0x00000001u, 0x0000bfb7u, 0x0000bfb7u, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0xffffffffu, 0x03f70476u, 0xffffffffu, 0x03f70476u, 0x000003f8u, 0x000003f8u, 0xfeff02f5u, 0x00000476u, 0x00000001u, 0x0000fefeu, 0x0000fefeu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000000u, 0x00000000u},
|
||||
{0x03feffffu, 0x82fb02fbu, 0x03fcffffu, 0x82fb02fbu, 0x000002fdu, 0x000002ffu, 0x010002fau, 0x800002fbu, 0x00000002u, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00000002u, 0x00000000u, 0x00000000u},
|
||||
{0x750ca216u, 0x01bb81bau, 0x750ca216u, 0x01bb81bau, 0x000001bdu, 0x000001bdu, 0x7351a214u, 0x000081bau, 0x00000002u, 0x0000a059u, 0x0000a059u, 0x00000000u, 0x00000000u, 0x00000002u, 0x00000000u, 0x00000000u},
|
||||
{0xcd2db6eeu, 0x81dcffffu, 0xcd2db6eeu, 0x81dcffffu, 0x000001dfu, 0x000001dfu, 0xcb50b6ecu, 0x800001dcu, 0x00000002u, 0x0000b50fu, 0x0000b50fu, 0x00000000u, 0x00000000u, 0x00000002u, 0x00000000u, 0x00000000u},
|
||||
{0x027dffffu, 0x0280037eu, 0x01feffffu, 0x028002ffu, 0x000001feu, 0x0000027du, 0x000101fdu, 0x01010280u, 0x0000007fu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0x0c38311du, 0xffff008du, 0x0c38311du, 0xffff008du, 0x0000010cu, 0x000001f6u, 0x0ac1309eu, 0xffff012bu, 0x00003011u, 0x00003011u, 0x00000000u, 0x00000000u, 0x0000007fu, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0x4d70f934u, 0x0180027fu, 0x4d70f934u, 0x0180027fu, 0x000001ffu, 0x00000267u, 0x4b88f8b5u, 0x0000027fu, 0x0000007fu, 0x0000f735u, 0x0000f735u, 0x00000000u, 0x00000000u, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0xffffffffu, 0x037dffffu, 0xffffffffu, 0x037dffffu, 0x000003fcu, 0x000003fcu, 0xffffffffu, 0x0001036du, 0x0000007fu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x0000007fu, 0x00000000u, 0x00000000u},
|
||||
{0x00800000u, 0x017fffffu, 0x00000000u, 0x00ffffffu, 0x00000000u, 0x00000080u, 0x00000000u, 0x00ffffffu, 0x00000080u, 0x00000080u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000080u, 0x00000080u},
|
||||
{0xffffffffu, 0xe2105b84u, 0xffffffffu, 0xe2105b84u, 0x000003fcu, 0x000003fcu, 0xffffffffu, 0xde945b84u, 0x00000080u, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00000080u, 0x00000000u, 0x00000000u},
|
||||
{0x01fe01feu, 0x01fe027eu, 0x00ff01feu, 0x00ff017fu, 0x000000ffu, 0x000001feu, 0x000001feu, 0x0000017fu, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u},
|
||||
{0x837cffffu, 0xcd195546u, 0x837cffffu, 0xcd195546u, 0x0000037cu, 0x0000047cu, 0x8000027cu, 0xca9c5546u, 0x000000ffu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x000000ffu, 0x00000000u, 0x00000000u},
|
||||
{0x80800082u, 0x018001ffu, 0x80800082u, 0x00810100u, 0x00000081u, 0x0000017fu, 0x80000082u, 0x00000100u, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x00000001u, 0x00000001u, 0x0000007fu, 0x00000000u},
|
||||
{0xffff01feu, 0x02fd80feu, 0xffff01feu, 0x01fe80feu, 0x000001feu, 0x000001feu, 0xffff00ffu, 0x000081fdu, 0x000000ffu, 0x000000ffu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x000000ffu, 0x000000ffu},
|
||||
{0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0x000003fcu, 0x000003fcu, 0xffffffffu, 0xffffffffu, 0x000000ffu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x000000ffu, 0x00000000u, 0x00000000u},
|
||||
{0x02020105u, 0xd174ac82u, 0x02020105u, 0xd174ac82u, 0x00000004u, 0x00008100u, 0x0101027fu, 0xcff6ac82u, 0x00007fffu, 0x00007fffu, 0x00000000u, 0x00000000u, 0x00000101u, 0x00000101u, 0x00003fffu, 0x0000007fu},
|
||||
{0x47a0dc79u, 0x64608fd3u, 0x47a0dc79u, 0x64608fd3u, 0x00000240u, 0x000082b6u, 0x44e9db9du, 0x63548f7bu, 0x00007fffu, 0x0000da39u, 0x0000da39u, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00000000u, 0x0000007fu},
|
||||
{0x4b62fbdbu, 0xf6054f65u, 0x4b62fbdbu, 0xf6054f65u, 0x000001b1u, 0x0000821du, 0x4944fc3fu, 0xf5524e03u, 0x00007fffu, 0x0000fa2au, 0x0000fa2au, 0x00000000u, 0x00000000u, 0x00007fffu, 0x0000001fu, 0x00000000u},
|
||||
{0xa415dd97u, 0xab235b4bu, 0xa415dd97u, 0xab235b4bu, 0x00000279u, 0x00008235u, 0xa1dfdc59u, 0xa9e05b53u, 0x00007fffu, 0x0000db1eu, 0x0000db1eu, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00000000u, 0x00000000u},
|
||||
{0xffff01feu, 0x037f0181u, 0xffff01feu, 0x02800181u, 0x000001feu, 0x000080feu, 0xffff0080u, 0x01010280u, 0x00007fffu, 0x00007fffu, 0x00000000u, 0x00000000u, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00007fffu},
|
||||
{0xffffffffu, 0x027e02fdu, 0xffffffffu, 0x027e02fdu, 0x000003fcu, 0x000082fcu, 0xffffffffu, 0x000002fdu, 0x00007fffu, 0x0000ffffu, 0x0000ffffu, 0x00000000u, 0x00000000u, 0x00007fffu, 0x00000000u, 0x00000000u},
|
||||
{0x01700100u, 0x03700370u, 0x00800100u, 0x01810181u, 0x00000080u, 0x00010070u, 0x00000100u, 0x01010181u, 0x00000080u, 0x0000fff0u, 0x0000fff0u, 0x00000000u, 0x00000000u, 0x00000080u, 0x0000fff0u, 0x0000fff0u}
|
||||
};
|
||||
constexpr const char* Names[16] = {
|
||||
"qsad_pk_u16_u8 0",
|
||||
"qsad_pk_u16_u8 1",
|
||||
"mqsad_pk_u16_u8 0",
|
||||
"mqsad_pk_u16_u8 1",
|
||||
"mqsad_u32_u8 0",
|
||||
"mqsad_u32_u8 1",
|
||||
"mqsad_u32_u8 2",
|
||||
"mqsad_u32_u8 3",
|
||||
"max3_i16",
|
||||
"max3_u16",
|
||||
"min3_i16",
|
||||
"min3_u16",
|
||||
"med3_i16",
|
||||
"med3_u16",
|
||||
"alignbit_b32",
|
||||
"alignbyte_b32",
|
||||
};
|
||||
|
||||
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("vop3 integer clamp wide: 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) {
|
||||
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("vop3 integer clamp wide tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -90,19 +90,6 @@ void Run(AgcDriver::VulkanDevice& device) {
|
|||
device.WaitIdle();
|
||||
}
|
||||
|
||||
void CheckClampRefused(AgcDriver::VulkanDevice& device) {
|
||||
for (const std::uint32_t opcode : {0x15au, 0x15bu, 0x15cu, 0x171u}) {
|
||||
alignas(256) const std::array<std::uint32_t, 3> code{0xd400800au | (opcode << 16u), 0x041a0b04u, 0xbf810000u};
|
||||
std::string refusal;
|
||||
try {
|
||||
static_cast<void>(Compile(device, code));
|
||||
} catch (const std::exception& error) {
|
||||
refusal = error.what();
|
||||
}
|
||||
Require(refusal.find("VOP3 source modifiers are not implemented") != std::string::npos, "VOP3 opcode " + Hex(opcode) + " with clamp was not refused");
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t Sad(std::uint32_t lhs, std::uint32_t rhs, std::uint32_t fieldBits, bool masked) {
|
||||
const std::uint32_t fieldMask = (1u << fieldBits) - 1u;
|
||||
std::uint32_t sum = 0u;
|
||||
|
|
@ -154,7 +141,6 @@ int main() {
|
|||
FillInput();
|
||||
Run(*device);
|
||||
Check();
|
||||
CheckClampRefused(*device);
|
||||
std::puts("vop3 sad tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ extern "C" {
|
|||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
|
@ -26,6 +27,7 @@ extern "C" {
|
|||
namespace {
|
||||
|
||||
constexpr int SCE_AJM_ERROR_INVALID_INSTANCE = static_cast<int>(0x80930003);
|
||||
constexpr int SCE_AJM_ERROR_INVALID_BATCH = static_cast<int>(0x80930004);
|
||||
constexpr int SCE_AJM_ERROR_INVALID_PARAMETER = static_cast<int>(0x80930005);
|
||||
constexpr int SCE_AJM_ERROR_OUT_OF_RESOURCES = static_cast<int>(0x80930007);
|
||||
|
||||
|
|
@ -127,6 +129,8 @@ std::map<std::uint32_t, std::unique_ptr<Instance>> g_instances;
|
|||
std::atomic<std::uint32_t> g_nextContext{1};
|
||||
std::atomic<std::uint32_t> g_nextInstance{1};
|
||||
std::atomic<std::uint32_t> g_nextBatch{1};
|
||||
std::mutex g_batchLock;
|
||||
std::set<std::uint32_t> g_batches;
|
||||
|
||||
enum class JobKind : std::uint32_t {
|
||||
Initialize = 1,
|
||||
|
|
@ -985,14 +989,22 @@ int APS5_VABI sceAjmBatchStart(uint32_t context, const AjmBatchInfo* info, int p
|
|||
cursor += record.bytes;
|
||||
}
|
||||
if (error) std::memset(error, 0, sizeof(*error));
|
||||
*batch = g_nextBatch.fetch_add(1, std::memory_order_relaxed);
|
||||
const auto id = g_nextBatch.fetch_add(1, std::memory_order_relaxed);
|
||||
{
|
||||
std::lock_guard lock(g_batchLock);
|
||||
g_batches.insert(id);
|
||||
}
|
||||
*batch = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmBatchWait(uint32_t context, uint32_t batch, uint32_t timeout, AjmBatchError* error) {
|
||||
(void)context;
|
||||
(void)batch;
|
||||
(void)timeout;
|
||||
{
|
||||
std::lock_guard lock(g_batchLock);
|
||||
if (g_batches.erase(batch) == 0) return SCE_AJM_ERROR_INVALID_BATCH;
|
||||
}
|
||||
if (error) std::memset(error, 0, sizeof(*error));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,4 +52,14 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(audio_out_last_output_time PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAudioOut>")
|
||||
endif()
|
||||
|
||||
add_test_executable(audio_out2_latency_tests tests/AudioOut2Latency.cpp)
|
||||
target_include_directories(audio_out2_latency_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out2_latency_tests PRIVATE libSceAudioOut libc)
|
||||
configure_windows_unwind(audio_out2_latency_tests)
|
||||
add_test(NAME audio_out2_latency COMMAND audio_out2_latency_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(audio_out2_latency PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAudioOut>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@
|
|||
extern "C" {
|
||||
|
||||
int APS5_VABI sceAudioOut2MasteringInit(uint32_t flags) {
|
||||
(void)flags;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
if (flags != 0) NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,21 @@
|
|||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
static constexpr int USER_ID_SYSTEM = 0xFF;
|
||||
static constexpr std::uint32_t SUPPORTED_3D_LATENCY = 2;
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceAudioOut2Initialize(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudioOut2Set3DLatency(int userId, std::uint32_t latency) {
|
||||
if (userId != USER_ID_SYSTEM || latency != SUPPORTED_3D_LATENCY) NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudioOut2GetSystemState(AudioOut2SystemState* state) {
|
||||
if (!state) return static_cast<int>(0x80260502);
|
||||
state->loudness = 0.0f;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceAudioOut2Initialize();
|
||||
int APS5_VABI sceAudioOut2Set3DLatency(int, std::uint32_t);
|
||||
int APS5_VABI sceAudioOut2MasteringInit(std::uint32_t);
|
||||
}
|
||||
|
||||
static void Require(bool value, const char* message) {
|
||||
if (value) return;
|
||||
std::fprintf(stderr, "%s\n", message);
|
||||
std::abort();
|
||||
}
|
||||
|
||||
template<typename TFunction>
|
||||
static bool ThrowsRuntimeError(TFunction function) {
|
||||
try {
|
||||
function();
|
||||
} catch (const std::runtime_error&) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int systemUser = 0xFF;
|
||||
constexpr int user = 0x10000000;
|
||||
|
||||
void TestSet3DLatency() {
|
||||
Require(sceAudioOut2Set3DLatency(systemUser, 2) == 0, "latency 2 for the system user must be accepted");
|
||||
Require(sceAudioOut2Set3DLatency(systemUser, 2) == 0, "latency 2 must be accepted again");
|
||||
Require(ThrowsRuntimeError([] { sceAudioOut2Set3DLatency(systemUser, 1); }), "latency 1 must throw");
|
||||
Require(ThrowsRuntimeError([] { sceAudioOut2Set3DLatency(systemUser, 3); }), "latency 3 must throw");
|
||||
Require(ThrowsRuntimeError([] { sceAudioOut2Set3DLatency(user, 2); }), "a user other than the system user must throw");
|
||||
}
|
||||
|
||||
void TestMasteringInit() {
|
||||
Require(sceAudioOut2MasteringInit(0) == 0, "flags 0 must be accepted");
|
||||
Require(ThrowsRuntimeError([] { sceAudioOut2MasteringInit(1); }), "flags 1 must throw");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
Require(sceAudioOut2Initialize() == 0, "initialization must succeed");
|
||||
TestSet3DLatency();
|
||||
TestMasteringInit();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
add_library(libSceHttp SHARED EXCLUDE_FROM_ALL Export.cpp src/Uri.cpp)
|
||||
add_library(libSceHttp SHARED EXCLUDE_FROM_ALL Export.cpp src/Parse.cpp src/Uri.cpp)
|
||||
target_include_directories(libSceHttp PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceHttp)
|
||||
|
||||
|
|
|
|||
|
|
@ -246,15 +246,14 @@ int APS5_VABI sceHttpSetChunkedTransferEnabled(int id, int enable) {
|
|||
}
|
||||
|
||||
|
||||
APS5_EXPORT("i9mhafzkEi8", sceHttpUnknown00);
|
||||
int APS5_VABI sceHttpUnknown00(void) {
|
||||
NotImplemented_nid_no_patch("i9mhafzkEi8");
|
||||
int APS5_VABI sceHttpSetInflateGZIPEnabled(int id, int enable) {
|
||||
(void)id;
|
||||
if (static_cast<uint32_t>(enable) > 1) return ERROR_INVALID_VALUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("vO4B-42ef-k", sceHttpUnknown01);
|
||||
int APS5_VABI sceHttpUnknown01(void) {
|
||||
NotImplemented_nid_no_patch("vO4B-42ef-k");
|
||||
int APS5_VABI sceHttpSetRequestStatusCallback(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,5 +5,7 @@ inline constexpr int ERROR_OUT_OF_MEMORY = static_cast<int>(0x80431022);
|
|||
inline constexpr int ERROR_NETWORK = static_cast<int>(0x80431063);
|
||||
inline constexpr int ERROR_INVALID_VALUE = static_cast<int>(0x804311FE);
|
||||
inline constexpr int ERROR_INVALID_URL = static_cast<int>(0x80433060);
|
||||
inline constexpr int ERROR_PARSE_HTTP_INVALID_RESPONSE = static_cast<int>(0x80432060);
|
||||
inline constexpr int ERROR_PARSE_HTTP_INVALID_VALUE = static_cast<int>(0x804321FE);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libSceHttp/src/HttpErrors.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
bool isAsciiDigit(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
bool parseVersionNumber(const char* line, size_t lineLen, size_t& index, int32_t* value) {
|
||||
if (index >= lineLen || !isAsciiDigit(line[index])) return false;
|
||||
uint32_t number = 0;
|
||||
while (index < lineLen && isAsciiDigit(line[index])) {
|
||||
number = number * 10 + static_cast<uint32_t>(line[index] - '0');
|
||||
++index;
|
||||
}
|
||||
*value = static_cast<int32_t>(number);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceHttpParseStatusLine(const char* statusLine, size_t lineLen, int32_t* httpMajorVer, int32_t* httpMinorVer,
|
||||
int32_t* responseCode, const char** reasonPhrase, size_t* phraseLen) {
|
||||
if (!statusLine) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (!httpMajorVer || !httpMinorVer || !responseCode || !reasonPhrase || !phraseLen) return ERROR_PARSE_HTTP_INVALID_VALUE;
|
||||
|
||||
*httpMajorVer = 0;
|
||||
*httpMinorVer = 0;
|
||||
if (lineLen < 8 || std::memcmp(statusLine, "HTTP/", 5) != 0) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
|
||||
size_t index = 5;
|
||||
if (!parseVersionNumber(statusLine, lineLen, index, httpMajorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (index >= lineLen || statusLine[index] != '.') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
++index;
|
||||
if (!parseVersionNumber(statusLine, lineLen, index, httpMinorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (index >= lineLen || statusLine[index] != ' ') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
++index;
|
||||
|
||||
if (lineLen - index < 3) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (!isAsciiDigit(statusLine[index]) || !isAsciiDigit(statusLine[index + 1]) || !isAsciiDigit(statusLine[index + 2])) {
|
||||
return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
}
|
||||
*responseCode = (statusLine[index] - '0') * 100 + (statusLine[index + 1] - '0') * 10 + (statusLine[index + 2] - '0');
|
||||
index += 3;
|
||||
|
||||
const char* phrase = statusLine + index;
|
||||
const void* lineFeed = std::memchr(phrase, '\n', lineLen - index);
|
||||
if (!lineFeed) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
|
||||
size_t length = static_cast<size_t>(static_cast<const char*>(lineFeed) - phrase);
|
||||
const size_t consumed = index + length + 1;
|
||||
if (consumed > static_cast<size_t>(INT32_MAX)) {
|
||||
NotImplemented_nid_no_patch("sceHttpParseStatusLine: status line longer than INT32_MAX");
|
||||
}
|
||||
if (length > 0 && phrase[length - 1] == '\r') --length;
|
||||
|
||||
*reasonPhrase = phrase;
|
||||
*phraseLen = length;
|
||||
return static_cast<int>(consumed);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
add_library(libSceLibcInternal SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libSceLibcInternal PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(libSceLibcInternal PRIVATE ${CMAKE_DL_LIBS})
|
||||
configure_windows_unwind(libSceLibcInternal)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_thread_atexit_tests ${LIBS_INCLUDE_DIR}/tests/GuestThreadAtexit.cpp)
|
||||
target_include_directories(guest_thread_atexit_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_thread_atexit_tests PRIVATE libSceLibcInternal libkernel libc)
|
||||
configure_windows_unwind(guest_thread_atexit_tests)
|
||||
add_test(NAME guest_thread_atexit COMMAND guest_thread_atexit_tests)
|
||||
set_tests_properties(guest_thread_atexit PROPERTIES TIMEOUT 20)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_thread_atexit PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibcInternal>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -1,5 +1,69 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include "prx/libc/include/HeapDiagnostics.hpp"
|
||||
#include "prx/libc/include/HostThreadLocal.hpp"
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
extern "C" void APS5_VABI sceKernelSetThreadDtors(thread_dtors_func_t dtors);
|
||||
|
||||
namespace {
|
||||
|
||||
using ThreadDestructorFunction = void (APS5_VABI*)(void*);
|
||||
|
||||
struct ThreadDestructor {
|
||||
ThreadDestructorFunction function;
|
||||
void* object;
|
||||
void* dsoSymbol;
|
||||
};
|
||||
|
||||
struct ThreadDestructorsTag {};
|
||||
|
||||
std::vector<ThreadDestructor>& ThreadDestructors() {
|
||||
return HostThreadLocal<std::vector<ThreadDestructor>, ThreadDestructorsTag>();
|
||||
}
|
||||
|
||||
bool IsInLoadedImage(const void* address) {
|
||||
if (address == nullptr)
|
||||
return false;
|
||||
#ifdef _WIN32
|
||||
HMODULE module = nullptr;
|
||||
return GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, static_cast<LPCSTR>(address), &module) != 0;
|
||||
#else
|
||||
Dl_info info{};
|
||||
return dladdr(address, &info) != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void APS5_VABI RunThreadDestructors_nid_no_patch() {
|
||||
auto& destructors = ThreadDestructors();
|
||||
while (!destructors.empty()) {
|
||||
const ThreadDestructor destructor = destructors.back();
|
||||
destructors.pop_back();
|
||||
const auto* function = reinterpret_cast<const void*>(destructor.function);
|
||||
if (!IsInLoadedImage(function)) {
|
||||
std::ostringstream message;
|
||||
message << "thread_local destructor " << function << " of dso " << destructor.dsoSymbol << " is not in a loaded image";
|
||||
throw std::runtime_error(message.str());
|
||||
}
|
||||
destructor.function(destructor.object);
|
||||
}
|
||||
}
|
||||
|
||||
void RegisterThreadExitHook() {
|
||||
[[maybe_unused]] static const bool registered = [] {
|
||||
sceKernelSetThreadDtors(RunThreadDestructors_nid_no_patch);
|
||||
return true;
|
||||
}();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
|
@ -13,4 +77,20 @@ void APS5_VABI sceLibcHeapGetTraceInfo_nid_postfix(Info* info) {
|
|||
LibcHeapTraceInfo_nid_no_patch(info);
|
||||
}
|
||||
|
||||
int APS5_VABI _sceLibcInternalThreadAtexit_nid_postfix(ThreadDestructorFunction destructor, void* object, void* dsoSymbol) {
|
||||
RegisterThreadExitHook();
|
||||
ThreadDestructors().push_back({destructor, object, dsoSymbol});
|
||||
return 0;
|
||||
}
|
||||
|
||||
void APS5_VABI _sceLibcInternalThreadDtors_nid_postfix() {
|
||||
RunThreadDestructors_nid_no_patch();
|
||||
}
|
||||
|
||||
int APS5_VABI _sceLibcInternalForceTlsDestructor_nid_postfix(KernelModule handle) {
|
||||
(void)handle;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
add_library(libSceMsgDialog.native SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libSceMsgDialog.native PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceMsgDialog.native)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_msg_dialog_native_tests ${LIBS_INCLUDE_DIR}/tests/GuestMsgDialogNative.cpp)
|
||||
target_include_directories(guest_msg_dialog_native_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_msg_dialog_native_tests PRIVATE libSceMsgDialog.native)
|
||||
add_test(NAME guest_msg_dialog_native COMMAND guest_msg_dialog_native_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_msg_dialog_native PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceMsgDialog.native>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -8,10 +8,12 @@
|
|||
namespace {
|
||||
std::atomic<int> g_status{0};
|
||||
|
||||
constexpr int COMMON_DIALOG_STATUS_RUNNING = 2;
|
||||
constexpr int COMMON_DIALOG_STATUS_FINISHED = 3;
|
||||
constexpr int COMMON_DIALOG_RESULT_OK = 0;
|
||||
constexpr int COMMON_DIALOG_ERROR_NOT_INITIALIZED = static_cast<int>(0x80B80003u);
|
||||
constexpr int COMMON_DIALOG_ERROR_NOT_FINISHED = static_cast<int>(0x80B80005u);
|
||||
constexpr int COMMON_DIALOG_ERROR_NOT_RUNNING = static_cast<int>(0x80B8000Bu);
|
||||
constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);
|
||||
constexpr int BUTTON_ID_OK = 1;
|
||||
}
|
||||
|
|
@ -20,6 +22,12 @@ extern "C" {
|
|||
|
||||
int SceMsgDialogNativeModuleLoaded_nid_no_patch = 1;
|
||||
|
||||
int APS5_VABI sceMsgDialogClose(void) {
|
||||
int expected = COMMON_DIALOG_STATUS_RUNNING;
|
||||
if (!g_status.compare_exchange_strong(expected, COMMON_DIALOG_STATUS_FINISHED)) return COMMON_DIALOG_ERROR_NOT_RUNNING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceMsgDialogGetResult(MsgDialogResult* result) {
|
||||
const int status = g_status.load();
|
||||
if (status == 0) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
|
||||
|
|
|
|||
|
|
@ -74,4 +74,9 @@ int APS5_VABI sceNpCommerceShowPsStoreIcon(int pos) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpCommerceSetPsStoreIconLayout(int layout) {
|
||||
(void)layout;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
add_library(libSceNpSessionSignaling SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libSceNpSessionSignaling PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceNpSessionSignaling)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_np_session_signaling_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpSessionSignaling.cpp)
|
||||
target_include_directories(guest_np_session_signaling_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_np_session_signaling_tests PRIVATE libSceNpSessionSignaling)
|
||||
add_test(NAME guest_np_session_signaling COMMAND guest_np_session_signaling_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_np_session_signaling PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpSessionSignaling>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -69,9 +69,14 @@ int32_t APS5_VABI sceNpSessionSignalingGetConnectionStatus(int32_t context_id, i
|
|||
|
||||
int32_t APS5_VABI sceNpSessionSignalingGetLocalNetInfo(int32_t context_id, void* info) {
|
||||
(void)context_id;
|
||||
(void)info;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (!info) return SCE_NP_SESSION_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
return SCE_NP_SESSION_SIGNALING_ERROR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpSessionSignalingRequestPrepare(uint32_t contextId, uint32_t* requestId) {
|
||||
(void)contextId;
|
||||
if (!requestId) return SCE_NP_SESSION_SIGNALING_ERROR_INVALID_ARGUMENT;
|
||||
return SCE_NP_SESSION_SIGNALING_ERROR_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpSessionSignalingGetMemoryInfo(void) {
|
||||
|
|
|
|||
|
|
@ -11,3 +11,21 @@ target_include_directories(libSceNpTrophy2 PRIVATE
|
|||
)
|
||||
target_link_libraries(libSceNpTrophy2 PRIVATE libc)
|
||||
configure_windows_unwind(libSceNpTrophy2)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_nptrophy2_tests ${LIBS_INCLUDE_DIR}/tests/GuestNpTrophy2.cpp)
|
||||
target_include_directories(guest_nptrophy2_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_nptrophy2_tests PRIVATE libSceNpTrophy2 libc)
|
||||
configure_windows_unwind(guest_nptrophy2_tests)
|
||||
add_test(NAME guest_nptrophy2 COMMAND guest_nptrophy2_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_nptrophy2 PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpTrophy2>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ int APS5_VABI sceNpTrophy2RegisterContext(int context, int handle, uint64_t opti
|
|||
}
|
||||
|
||||
int APS5_VABI sceNpTrophy2UnregisterUnlockCallback() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return SCE_NP_TROPHY2_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,10 +74,8 @@ int APS5_VABI scePlayGoDialogGetResult(void* result) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("NOAMxY2EGS0", scePlayGoDialogUnknown00);
|
||||
int APS5_VABI scePlayGoDialogUnknown00(void) {
|
||||
NotImplemented_nid_no_patch("NOAMxY2EGS0");
|
||||
return 0;
|
||||
int APS5_VABI scePlayGoDialogGetStatus(void) {
|
||||
return g_status.load();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
add_library(libScePsml_debug SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libScePsml_debug PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libScePsml_debug)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_psml_tests ${LIBS_INCLUDE_DIR}/tests/GuestPsml.cpp)
|
||||
target_include_directories(guest_psml_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_psml_tests PRIVATE libScePsml_debug)
|
||||
add_test(NAME guest_psml COMMAND guest_psml_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_psml PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libScePsml_debug>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -3,22 +3,45 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::int32_t SCE_PSML_ERROR_NOT_INITIALIZED = static_cast<std::int32_t>(0x8A810001);
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
std::int32_t APS5_VABI scePsmlMfsrGetContextBufferRequirement1100(void* requirement, const void* param) {
|
||||
(void)requirement;
|
||||
(void)param;
|
||||
return SCE_PSML_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
std::int32_t APS5_VABI scePsmlMfsrCreateContext1100(void** context, const void* param) {
|
||||
(void)context;
|
||||
(void)param;
|
||||
return SCE_PSML_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
std::int32_t APS5_VABI scePsmlMfsrGetDispatchMfsrPacket1100(void* context, void* commandBuffer, const void* param) {
|
||||
(void)context;
|
||||
(void)commandBuffer;
|
||||
(void)param;
|
||||
return SCE_PSML_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
APS5_EXPORT("+2KpvixvL6E", scePsmlUnknown__P2KpvixvL6E);
|
||||
int APS5_VABI scePsmlUnknown__P2KpvixvL6E() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("3WVD91e12ZQ", scePsmlUnknown_3WVD91e12ZQ);
|
||||
int APS5_VABI scePsmlUnknown_3WVD91e12ZQ() {
|
||||
int APS5_VABI scePsmlMfsrInit() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("AHalTX9wFZY", scePsmlUnknown_AHalTX9wFZY);
|
||||
int APS5_VABI scePsmlUnknown_AHalTX9wFZY() {
|
||||
int APS5_VABI scePsmlMfsrGetDispatchMfsrPacketSizeInDwords() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -47,8 +70,7 @@ int APS5_VABI scePsmlUnknown_GJY0MvuTcs8() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("JaLBe0P3jSU", scePsmlUnknown_JaLBe0P3jSU);
|
||||
int APS5_VABI scePsmlUnknown_JaLBe0P3jSU() {
|
||||
int APS5_VABI scePsmlMfsrReleaseContext() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,4 +24,15 @@ int APS5_VABI sceRazorCpuJobManagerSequence(const void* args) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceRazorCpuPushMarkerStatic(const char* name, uint32_t color, uint32_t flags) {
|
||||
(void)name;
|
||||
(void)color;
|
||||
(void)flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceRazorCpuPopMarker(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -272,6 +272,7 @@ int APS5_VABI sceRtcSetWin32FileTime(RtcDateTime* time, uint64_t win32_time) {
|
|||
|
||||
int APS5_VABI sceRtcFormatRFC3339(char* date_time, const RtcTick* utc, int time_zone_minutes) {
|
||||
if (!date_time || !utc) return SCE_RTC_ERROR_INVALID_POINTER;
|
||||
if (time_zone_minutes < -1439 || time_zone_minutes > 1439) return SCE_RTC_ERROR_INVALID_VALUE;
|
||||
RtcTick local{};
|
||||
if (const int result = addTicks(&local, utc, time_zone_minutes, TICKS_PER_MINUTE); result != 0) return result;
|
||||
const RtcDateTime time = fromTick(local.tick);
|
||||
|
|
|
|||
|
|
@ -17,4 +17,14 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(guest_savedata_delete PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSaveData.native>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_savedata_ps4_tests ${LIBS_INCLUDE_DIR}/tests/GuestSaveDataPs4.cpp)
|
||||
target_include_directories(guest_savedata_ps4_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_savedata_ps4_tests PRIVATE libSceSaveData.native libc)
|
||||
configure_windows_unwind(guest_savedata_ps4_tests)
|
||||
add_test(NAME guest_savedata_ps4 COMMAND guest_savedata_ps4_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_savedata_ps4 PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceSaveData.native>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -699,16 +699,24 @@ int APS5_VABI sceSaveDataUmount2(uint32_t mode, const SaveDataMountPoint* mount_
|
|||
return rc;
|
||||
}
|
||||
|
||||
|
||||
APS5_EXPORT("RjMlsR8EXrw", sceSaveDataUnknown00);
|
||||
int APS5_VABI sceSaveDataUnknown00(void) {
|
||||
NotImplemented_nid_no_patch("RjMlsR8EXrw");
|
||||
return 0;
|
||||
int APS5_VABI sceSaveDataTransferringMountPs4(const SaveDataTransferringMount* mount, SaveDataMountResult* mount_result) {
|
||||
const int rc = transferringMount(mount, mount_result);
|
||||
SAVEDATA_TRACE("transferringMountPs4 -> 0x%08x", static_cast<unsigned>(rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
APS5_EXPORT("X4MYzukPc3g", sceSaveDataUnknown01);
|
||||
int APS5_VABI sceSaveDataUnknown01(void) {
|
||||
NotImplemented_nid_no_patch("X4MYzukPc3g");
|
||||
return 0;
|
||||
static int dirNameSearchPs4(const SaveDataDirNameSearchCond* cond, SaveDataDirNameSearchResult* result) {
|
||||
if (cond == nullptr || result == nullptr) {
|
||||
throw std::runtime_error("sceSaveDataDirNameSearchPs4: null argument");
|
||||
}
|
||||
result->hit_num = 0;
|
||||
result->set_num = 0;
|
||||
return SAVE_DATA_OK;
|
||||
}
|
||||
|
||||
int APS5_VABI sceSaveDataDirNameSearchPs4(const SaveDataDirNameSearchCond* cond, SaveDataDirNameSearchResult* result) {
|
||||
const int rc = dirNameSearchPs4(cond, result);
|
||||
SAVEDATA_TRACE("dirNameSearchPs4 user=%d -> 0x%08x", cond->user_id, static_cast<unsigned>(rc));
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
add_library(libSceShare SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libSceShare PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceShare)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_share_tests ${LIBS_INCLUDE_DIR}/tests/GuestShare.cpp)
|
||||
target_include_directories(guest_share_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_share_tests PRIVATE libSceShare)
|
||||
add_test(NAME guest_share COMMAND guest_share_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_share PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceShare>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -5,6 +5,13 @@
|
|||
|
||||
// Capture and sharing are not emulated; policy and parameter calls are accepted.
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::int32_t ERROR_NOT_SUPPORTED = static_cast<std::int32_t>(0x81960007);
|
||||
constexpr std::int32_t REQUEST_ID_INVALID = -1;
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceShareCaptureScreenshot(const void* param, int32_t* req_id) {
|
||||
|
|
@ -85,10 +92,12 @@ int APS5_VABI sceShareUnregisterContentEventCallback(void* callback) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("GQTObcITIXI", sceShareUnknown_GQTObcITIXI);
|
||||
int32_t APS5_VABI sceShareUnknown_GQTObcITIXI(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceShareCaptureScreenshotExtended(const void* extended_param, int32_t* req_id) {
|
||||
(void)extended_param;
|
||||
if (req_id != nullptr) {
|
||||
*req_id = REQUEST_ID_INVALID;
|
||||
}
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,12 +80,19 @@ int APS5_VABI sceSystemServiceParamGetInt(int paramId, int* value) {
|
|||
return SYSTEM_SERVICE_OK;
|
||||
}
|
||||
|
||||
int APS5_VABI sceSystemServiceParamGetString(int param_id, char* buf, size_t buf_size) {
|
||||
(void)param_id;
|
||||
(void)buf;
|
||||
(void)buf_size;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceSystemServiceParamGetString(int paramId, char* buf, size_t bufSize) {
|
||||
if (buf == nullptr || bufSize == 0) {
|
||||
return SYSTEM_SERVICE_ERROR_PARAMETER;
|
||||
}
|
||||
if (paramId != SYSTEM_SERVICE_PARAM_ID_SYSTEM_NAME) {
|
||||
NotImplemented_nid_no_patch("sceSystemServiceParamGetString: parameter other than the system name");
|
||||
}
|
||||
if (bufSize < SYSTEM_SERVICE_MAX_SYSTEM_NAME_LENGTH) {
|
||||
NotImplemented_nid_no_patch("sceSystemServiceParamGetString: buffer shorter than 65 bytes");
|
||||
}
|
||||
constexpr char SystemName[] = "PS5";
|
||||
std::memcpy(buf, SystemName, sizeof(SystemName));
|
||||
return SYSTEM_SERVICE_OK;
|
||||
}
|
||||
|
||||
int APS5_VABI sceSystemServicePowerTick(void) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef CORE_LIBS_PRX_LIBSCESYSTEMSERVICE_SYSTEMSERVICE_HPP
|
||||
#define CORE_LIBS_PRX_LIBSCESYSTEMSERVICE_SYSTEMSERVICE_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
constexpr int SYSTEM_SERVICE_OK = 0;
|
||||
|
|
@ -12,9 +13,12 @@ constexpr int SYSTEM_SERVICE_PARAM_ID_DATE_FORMAT = 2;
|
|||
constexpr int SYSTEM_SERVICE_PARAM_ID_TIME_FORMAT = 3;
|
||||
constexpr int SYSTEM_SERVICE_PARAM_ID_TIME_ZONE = 4;
|
||||
constexpr int SYSTEM_SERVICE_PARAM_ID_SUMMERTIME = 5;
|
||||
constexpr int SYSTEM_SERVICE_PARAM_ID_SYSTEM_NAME = 6;
|
||||
constexpr int SYSTEM_SERVICE_PARAM_ID_GAME_PARENTAL_LEVEL = 7;
|
||||
constexpr int SYSTEM_SERVICE_PARAM_ID_ENTER_BUTTON_ASSIGN = 1000;
|
||||
|
||||
constexpr std::size_t SYSTEM_SERVICE_MAX_SYSTEM_NAME_LENGTH = 65;
|
||||
|
||||
constexpr int SYSTEM_SERVICE_PARAM_LANG_ENGLISH_US = 1;
|
||||
constexpr int SYSTEM_SERVICE_PARAM_DATE_FORMAT_DDMMYYYY = 1;
|
||||
constexpr int SYSTEM_SERVICE_PARAM_TIME_FORMAT_24HOUR = 1;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ static constexpr std::size_t VIDEO_OUT_FLIP_QUEUE_CAPACITY = 16;
|
|||
|
||||
static constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_UNCOMPRESSED = 0;
|
||||
static constexpr int VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_COMPRESSED = 1;
|
||||
static constexpr std::uint64_t VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE = 0;
|
||||
static constexpr std::uint64_t VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY = 8;
|
||||
|
||||
static constexpr int VIDEO_OUT_EVENT_FLIP = 0;
|
||||
static constexpr int VIDEO_OUT_EVENT_VBLANK = 1;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
|
@ -10,7 +11,7 @@
|
|||
AgcDriver::DisplayBuffer DescribeVideoOutBuffer(const VideoOutBuffer& buffer, const BufferAttributeGroup& group) {
|
||||
const auto& attribute = group.attribute;
|
||||
if (attribute.reserved0 != 0 || attribute.pad0 != 0 || attribute.reserved1[0] != 0 || attribute.reserved1[1] != 0 || attribute.reserved1[2] != 0) throw std::runtime_error("VideoOut: reserved buffer attribute bits are set");
|
||||
if (attribute.tiling_mode > 1 || (attribute.tiling_mode == 0 && attribute.pitch_in_pixel != 0) || attribute.aspect_ratio != 0 || attribute.option != 0) throw std::runtime_error("VideoOut: unsupported tiling, pitch, aspect ratio or buffer option");
|
||||
if (attribute.tiling_mode > 1 || (attribute.tiling_mode == 0 && attribute.pitch_in_pixel != 0) || attribute.aspect_ratio != 0 || (attribute.option != VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE && attribute.option != VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY)) throw std::runtime_error("VideoOut: unsupported tiling " + std::to_string(attribute.tiling_mode) + ", pitch " + std::to_string(attribute.pitch_in_pixel) + ", aspect ratio " + std::to_string(attribute.aspect_ratio) + " or buffer option " + std::to_string(attribute.option));
|
||||
if (group.category != VIDEO_OUT_BUFFER_ATTRIBUTE_CATEGORY_UNCOMPRESSED || buffer.metadataAddress != 0 || attribute.dcc_control != 0 || attribute.dcc_cb_register_clear_color != 0) throw std::runtime_error("VideoOut: DCC presentation is not implemented");
|
||||
const AgcDriver::DisplayBuffer result{buffer.dataAddress, attribute.pixel_format, attribute.width, attribute.height, attribute.tiling_mode, attribute.pitch_in_pixel};
|
||||
static_cast<void>(AgcDriverDisplayBufferSize_nid_postfix(result));
|
||||
|
|
|
|||
|
|
@ -162,6 +162,18 @@ void testDecode() {
|
|||
expectFailure([&] { AgcDriver::ReadDisplayBuffer(buffer); });
|
||||
buffer.address = std::numeric_limits<uint64_t>::max() & ~uint64_t{65535};
|
||||
expectFailure([&] { AgcDriver::DisplayBufferSize(buffer); });
|
||||
const VideoOutBuffer registered{0, reinterpret_cast<uint64_t>(tiled.data()), 0};
|
||||
BufferAttributeGroup group{};
|
||||
sceVideoOutSetBufferAttribute2(&group.attribute, 0x8000000000000000ull, 0, 259, 137, VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_NONE, 0, 0);
|
||||
group.occupied = true;
|
||||
const auto plain = DescribeVideoOutBuffer(registered, group);
|
||||
group.attribute.option = VIDEO_OUT_BUFFER_ATTRIBUTE_OPTION_STRICT_COLORIMETRY;
|
||||
const auto strict = DescribeVideoOutBuffer(registered, group);
|
||||
check(strict.address == plain.address && strict.pixelFormat == plain.pixelFormat && strict.width == plain.width && strict.height == plain.height && strict.tilingMode == plain.tilingMode && strict.pitchInPixel == plain.pitchInPixel, "the STRICT_COLORIMETRY option changed the described buffer");
|
||||
for (const uint64_t option : {1ull, 32ull, 40ull}) {
|
||||
group.attribute.option = option;
|
||||
check(expectFailure([&] { DescribeVideoOutBuffer(registered, group); }).find("buffer option " + std::to_string(option)) != std::string::npos, "an unsupported buffer option was accepted");
|
||||
}
|
||||
}
|
||||
|
||||
void testOpenParam() {
|
||||
|
|
|
|||
|
|
@ -13,4 +13,59 @@ int APS5_VABI sceVoiceQoSInit(void* mem_block, uint32_t mem_size, int32_t app_ty
|
|||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSEnd() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSCreateLocalEndpoint() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSDeleteLocalEndpoint() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSCreateRemoteEndpoint() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSDeleteRemoteEndpoint() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSConnect() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSDisconnect() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSSetLocalEndpointAttribute() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSSetRemoteEndpointAttribute() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSReadPacket() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceVoiceQoSWritePacket() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -176,6 +176,15 @@ if(BUILD_TESTING)
|
|||
set_tests_properties(guest_strings PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test_executable(guest_wcsrtombs_s_tests ${LIBS_INCLUDE_DIR}/tests/GuestWcsrtombsS.cpp)
|
||||
target_include_directories(guest_wcsrtombs_s_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_wcsrtombs_s_tests PRIVATE libc)
|
||||
configure_windows_unwind(guest_wcsrtombs_s_tests)
|
||||
add_test(NAME guest_wcsrtombs_s COMMAND guest_wcsrtombs_s_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_wcsrtombs_s PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
if(UNIX)
|
||||
add_test_executable(exception_runtime_tests ${LIBS_INCLUDE_DIR}/tests/ExceptionRuntime.cpp)
|
||||
target_include_directories(exception_runtime_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
|
|
|
|||
|
|
@ -30,12 +30,6 @@ extern "C" {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("Pu0Ecyk-7FU", libcUnknown_Pu0Ecyk_M7FU);
|
||||
int APS5_VABI libcUnknown_Pu0Ecyk_M7FU() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Dead import of Cyberpunk 2077 (PPSA04029): no call sites, but the
|
||||
// Windows loader resolves imports strictly, so it must be present.
|
||||
APS5_EXPORT("u2tMGOLaqnE", libcUnknown_u2tMGOLaqnE);
|
||||
|
|
@ -70,12 +64,6 @@ int APS5_VABI libcCyberUnknown19(void) {
|
|||
}
|
||||
|
||||
|
||||
APS5_EXPORT("2gbcltk3swE", libcCyberUnknown00);
|
||||
std::uint64_t APS5_VABI libcCyberUnknown00(void) {
|
||||
NotImplemented_nid_no_patch("2gbcltk3swE");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("DiGVep5yB5w", libcCyberUnknown01);
|
||||
std::uint64_t APS5_VABI libcCyberUnknown01(void) {
|
||||
NotImplemented_nid_no_patch("DiGVep5yB5w");
|
||||
|
|
@ -94,24 +82,12 @@ std::uint64_t APS5_VABI libcCyberUnknown03(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("79s2tnYQI6I", libcCyberUnknown04);
|
||||
std::uint64_t APS5_VABI libcCyberUnknown04(void) {
|
||||
NotImplemented_nid_no_patch("79s2tnYQI6I");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("7yMFgcS8EPA", libcCyberUnknown05);
|
||||
std::uint64_t APS5_VABI libcCyberUnknown05(void) {
|
||||
NotImplemented_nid_no_patch("7yMFgcS8EPA");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("Cj+Fw5q1tUo", libcCyberUnknown06);
|
||||
std::uint64_t APS5_VABI libcCyberUnknown06(void) {
|
||||
NotImplemented_nid_no_patch("Cj+Fw5q1tUo");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("CyXs2l-1kNA", libcCyberUnknown07);
|
||||
std::uint64_t APS5_VABI libcCyberUnknown07(void) {
|
||||
NotImplemented_nid_no_patch("CyXs2l-1kNA");
|
||||
|
|
|
|||
|
|
@ -30,6 +30,10 @@ char* APS5_VABI strndup_nid_postfix(const char* source, std::size_t limit) {
|
|||
}
|
||||
}
|
||||
|
||||
char* APS5_VABI strdup_nid_postfix(const char* source) {
|
||||
return strndup_nid_postfix(source, static_cast<std::size_t>(-1));
|
||||
}
|
||||
|
||||
int APS5_VABI asprintf_nid_postfix(char** destination, const char* format, ...) {
|
||||
if (!destination) { errno = 22; return -1; }
|
||||
*destination = nullptr;
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace {
|
|||
constexpr std::uintptr_t ArenaStart = 0x0000000200000000ull;
|
||||
constexpr std::uintptr_t SystemReservedStart = 0x00000007FFFFC000ull;
|
||||
constexpr std::uintptr_t SystemReservedEnd = 0x0000001000000000ull;
|
||||
constexpr std::size_t ArenaSize = 0x0000007000000000ull;
|
||||
constexpr std::uintptr_t ApplicationAreaEnd = 0x000000FC00000000ull;
|
||||
|
||||
std::uintptr_t alignUp(std::uintptr_t value, std::size_t alignment) {
|
||||
return (value + alignment - 1) & ~(static_cast<std::uintptr_t>(alignment) - 1);
|
||||
|
|
@ -69,8 +69,11 @@ public:
|
|||
std::lock_guard lock(_lock);
|
||||
const auto start = reinterpret_cast<std::uintptr_t>(pointer);
|
||||
const auto next = _used.lower_bound(start);
|
||||
if ((next != _used.end() && next->first < start + bytes) || (next != _used.begin() && std::prev(next)->second > start))
|
||||
throw std::runtime_error("fixed guest mapping overlaps a guest arena range");
|
||||
if ((next != _used.end() && next->first < start + bytes) || (next != _used.begin() && std::prev(next)->second > start)) {
|
||||
char message[160];
|
||||
std::snprintf(message, sizeof(message), "fixed guest mapping 0x%llx+0x%zx overlaps %s", static_cast<unsigned long long>(start), bytes, OverlapsHostRegion(start, bytes) ? "a host region in the guest arena" : "a guest arena range");
|
||||
throw std::runtime_error(message);
|
||||
}
|
||||
_used.emplace(start, start + bytes);
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +106,7 @@ private:
|
|||
SYSTEM_INFO system{};
|
||||
GetSystemInfo(&system);
|
||||
const std::uintptr_t granularity = system.dwAllocationGranularity;
|
||||
const std::uintptr_t end = ArenaStart + ArenaSize;
|
||||
const std::uintptr_t end = ApplicationAreaEnd;
|
||||
for (std::uintptr_t cursor = ArenaStart; cursor < end;) {
|
||||
MEMORY_BASIC_INFORMATION info{};
|
||||
if (VirtualQuery(reinterpret_cast<const void*>(cursor), &info, sizeof(info)) == 0) throw std::system_error(static_cast<int>(GetLastError()), std::system_category(), "query the guest arena range");
|
||||
|
|
@ -197,18 +200,28 @@ bool GuestArenaHostRegionOverlaps_nid_postfix(std::uintptr_t address, std::size_
|
|||
return Arena::Get().OverlapsHostRegion(address, bytes);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::invalid_argument OutsideArena(const char* operation, const void* pointer, std::size_t bytes) {
|
||||
char message[128];
|
||||
std::snprintf(message, sizeof(message), "%s 0x%llx+0x%zx outside the guest arena", operation, static_cast<unsigned long long>(reinterpret_cast<std::uintptr_t>(pointer)), bytes);
|
||||
return std::invalid_argument(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GuestArenaCommit_nid_postfix(void* pointer, std::size_t bytes, std::uint32_t protection, std::size_t granule) {
|
||||
if (!Arena::Get().Contains(pointer, bytes)) throw std::invalid_argument("commit outside the guest arena");
|
||||
if (!Arena::Get().Contains(pointer, bytes)) throw OutsideArena("commit", pointer, bytes);
|
||||
WindowsMappings::Get().Commit(pointer, bytes, protection, granule, Arena::Get().WriteWatched());
|
||||
}
|
||||
|
||||
void GuestArenaReset_nid_postfix(void* pointer, std::size_t bytes) {
|
||||
if (!Arena::Get().Contains(pointer, bytes)) throw std::invalid_argument("reset outside the guest arena");
|
||||
if (!Arena::Get().Contains(pointer, bytes)) throw OutsideArena("reset", pointer, bytes);
|
||||
WindowsMappings::Get().Reset(pointer, bytes);
|
||||
}
|
||||
|
||||
void GuestArenaMap_nid_postfix(void* pointer, std::size_t bytes, void* section, std::uint64_t offset, std::uint32_t protection) {
|
||||
if (!Arena::Get().Contains(pointer, bytes)) throw std::invalid_argument("shared mapping outside the guest arena");
|
||||
if (!Arena::Get().Contains(pointer, bytes)) throw OutsideArena("shared mapping", pointer, bytes);
|
||||
WindowsMappings::Get().Map(pointer, bytes, section, offset, protection);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
#include <cstdint>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
|
|
@ -13,6 +15,7 @@ float APS5_VABI acosf_nid_postfix(float x) { return std::acos(x); }
|
|||
float APS5_VABI atan2f_nid_postfix(float y, float x) { return std::atan2(y, x); }
|
||||
float APS5_VABI tanf_nid_postfix(float x) { return std::tan(x); }
|
||||
float APS5_VABI log10f_nid_postfix(float x) { return std::log10(x); }
|
||||
float APS5_VABI logbf_nid_postfix(float x) { return std::logb(x); }
|
||||
double APS5_VABI exp2_nid_postfix(double x) { return std::exp2(x); }
|
||||
double APS5_VABI ldexp_nid_postfix(double x, int exponent) { return std::ldexp(x, exponent); }
|
||||
double APS5_VABI scalbn_nid_postfix(double x, int exponent) { return std::scalbn(x, exponent); }
|
||||
|
|
@ -78,6 +81,22 @@ double APS5_VABI tanh_nid_postfix(double x) { return std::tanh(x); }
|
|||
float APS5_VABI tanhf_nid_postfix(float x) { return std::tanh(x); }
|
||||
float APS5_VABI _FSinh_nid_postfix(float x, float y) { return y * std::sinh(x); }
|
||||
float APS5_VABI _FCosh_nid_postfix(float x, float y) { return y * std::cosh(x); }
|
||||
|
||||
struct alignas(16) LibcFloatConstant { std::uint32_t bits[4]; };
|
||||
LibcFloatConstant _FInf_nid_postfix {{0x7f800000u, 0, 0, 0}};
|
||||
LibcFloatConstant _FNan_nid_postfix {{0x7fc00000u, 0, 0, 0}};
|
||||
|
||||
short APS5_VABI _FDtest_nid_postfix(const float* value) {
|
||||
constexpr short Denormal = -2, Finite = -1, Zero = 0, Infinite = 1, NotANumber = 2;
|
||||
if (value == nullptr) throw std::invalid_argument("_FDtest: null value");
|
||||
std::uint32_t bits;
|
||||
std::memcpy(&bits, value, sizeof(bits));
|
||||
const auto exponent = bits & 0x7f800000u;
|
||||
const auto fraction = bits & 0x007fffffu;
|
||||
if (exponent == 0x7f800000u) return fraction != 0 ? NotANumber : Infinite;
|
||||
if (exponent == 0) return fraction != 0 ? Denormal : Zero;
|
||||
return Finite;
|
||||
}
|
||||
int APS5_VABI __isnanf_nid_postfix(float x) { return std::isnan(x) ? 1 : 0; }
|
||||
int APS5_VABI __signbitf_nid_postfix(float x) { return std::signbit(x) ? 1 : 0; }
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <climits>
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
|
@ -47,6 +48,78 @@ std::size_t APS5_VABI wcrtomb_nid_postfix(char* destination, std::uint16_t value
|
|||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI wcsrtombs_s_nid_postfix(
|
||||
std::size_t* result, char* destination, std::size_t capacity, const std::uint16_t** source, std::size_t limit,
|
||||
void* state
|
||||
) {
|
||||
constexpr int GuestEinval = 22;
|
||||
constexpr int GuestErange = 34;
|
||||
constexpr int GuestEilseq = 86;
|
||||
constexpr auto Failed = static_cast<std::size_t>(-1);
|
||||
if (!result || !source || !state || !*source || (destination && (static_cast<std::int64_t>(capacity) <= 0
|
||||
|| static_cast<std::int64_t>(limit) < 0))) {
|
||||
if (destination && static_cast<std::int64_t>(capacity) > 0) destination[0] = '\0';
|
||||
if (result) *result = Failed;
|
||||
return GuestEinval;
|
||||
}
|
||||
if (!destination && capacity) {
|
||||
*result = Failed;
|
||||
return GuestEinval;
|
||||
}
|
||||
const auto* wide = *source;
|
||||
char bytes[MB_LEN_MAX];
|
||||
if (!destination) {
|
||||
std::size_t total = 0;
|
||||
for (;; ++wide) {
|
||||
const auto length = wcrtomb_nid_postfix(bytes, *wide, state);
|
||||
if (length == Failed) {
|
||||
*result = Failed;
|
||||
return GuestEilseq;
|
||||
}
|
||||
if (length && bytes[length - 1] == '\0') {
|
||||
*result = total + length - 1;
|
||||
return 0;
|
||||
}
|
||||
total += length;
|
||||
}
|
||||
}
|
||||
std::size_t written = 0;
|
||||
while (limit) {
|
||||
const auto length = wcrtomb_nid_postfix(bytes, *wide, state);
|
||||
if (length == Failed) {
|
||||
destination[written] = '\0';
|
||||
*result = Failed;
|
||||
return GuestEilseq;
|
||||
}
|
||||
if (length > limit || length > capacity) {
|
||||
*source = wide;
|
||||
destination[0] = '\0';
|
||||
*result = Failed;
|
||||
return GuestErange;
|
||||
}
|
||||
std::memcpy(destination + written, bytes, length);
|
||||
written += length;
|
||||
if (length && destination[written - 1] == '\0') {
|
||||
*source = nullptr;
|
||||
*result = written - 1;
|
||||
return 0;
|
||||
}
|
||||
++wide;
|
||||
capacity -= length;
|
||||
if (!capacity) {
|
||||
*source = wide;
|
||||
destination[0] = '\0';
|
||||
*result = Failed;
|
||||
return GuestErange;
|
||||
}
|
||||
limit -= length;
|
||||
}
|
||||
*source = wide;
|
||||
destination[written] = '\0';
|
||||
*result = written;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t APS5_VABI mbsrtowcs_nid_postfix(std::uint16_t* destination, const char** source, std::size_t capacity, void*) {
|
||||
if (!destination) return std::strlen(*source);
|
||||
std::size_t converted = 0;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ unsigned int APS5_VABI _Atomic_load_4_nid_postfix(volatile unsigned int* target,
|
|||
return GccAtomicLoad(target);
|
||||
}
|
||||
|
||||
std::intmax_t APS5_VABI strtoimax_nid_postfix(const char* str, char** endptr, int base) {
|
||||
return std::strtoimax(str, endptr, base);
|
||||
}
|
||||
|
||||
std::uintmax_t APS5_VABI strtoumax_nid_postfix(const char* str, char** endptr, int base) {
|
||||
return std::strtoumax(str, endptr, base);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
#include "prx/libc/include/ApplicationHeap.hpp"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
|
@ -114,6 +113,10 @@ int APS5_VABI atoi_nid_postfix(const char* str) {
|
|||
return std::atoi(str);
|
||||
}
|
||||
|
||||
std::div_t APS5_VABI div_nid_postfix(int numerator, int denominator) {
|
||||
return std::div(numerator, denominator);
|
||||
}
|
||||
|
||||
const wchar_t* APS5_VABI wmemchr_nid_postfix(const wchar_t* s, wchar_t c, size_t n) {
|
||||
return std::wmemchr(s, c, n);
|
||||
}
|
||||
|
|
@ -156,13 +159,6 @@ int APS5_VABI strncasecmp_nid_postfix(const char* s1, const char* s2, size_t n)
|
|||
return static_cast<unsigned char>(*s1) - static_cast<unsigned char>(*s2);
|
||||
}
|
||||
|
||||
char* APS5_VABI strdup_nid_postfix(const char* s) {
|
||||
std::size_t len = std::strlen(s) + 1;
|
||||
char* copy = static_cast<char*>(ApplicationHeapAllocate_nid_no_patch(len));
|
||||
std::memcpy(copy, s, len);
|
||||
return copy;
|
||||
}
|
||||
|
||||
int APS5_VABI bcmp_nid_postfix(const void* s1, const void* s2, size_t n) {
|
||||
return std::memcmp(s1, s2, n);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,19 @@ int64_t APS5_VABI time_nid_postfix(int64_t* timer) {
|
|||
return libc_time_nid_postfix(timer);
|
||||
}
|
||||
|
||||
int64_t APS5_VABI _Xtime_get_ticks_nid_postfix() {
|
||||
#ifdef _WIN32
|
||||
FILETIME ft{};
|
||||
GetSystemTimePreciseAsFileTime(&ft);
|
||||
const uint64_t t = ((static_cast<uint64_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000ULL;
|
||||
return static_cast<int64_t>(t / 10);
|
||||
#else
|
||||
timespec now{};
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
return static_cast<int64_t>(now.tv_sec) * 1000000 + now.tv_nsec / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
double APS5_VABI libc_difftime_nid_postfix(int64_t time1, int64_t time0) {
|
||||
return std::difftime(static_cast<std::time_t>(time1), static_cast<std::time_t>(time0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -267,6 +267,12 @@ void APS5_VABI _ZNSt11regex_errorC1ERKS__nid_postfix(LibcException::ExceptionObj
|
|||
void APS5_VABI _ZNSt11regex_errorC2ERKS__nid_postfix(LibcException::ExceptionObject* self, const LibcException::ExceptionObject* source) { LibcException::Copy(self, source, _ZTVSt11regex_error_nid_postfix); }
|
||||
LibcException::ExceptionObject* APS5_VABI _ZNSt11regex_erroraSERKS__nid_postfix(LibcException::ExceptionObject* self, const LibcException::ExceptionObject* source) { return LibcException::Assign(self, source); }
|
||||
|
||||
LibcException::TypeRecord _ZTISt11range_error_nid_postfix {LibcException::SingleTypeVtable + 2, "St11range_error", &_ZTISt13runtime_error_nid_postfix};
|
||||
LibcException::ExceptionVtable _ZTVSt11range_error_nid_postfix {0, &_ZTISt11range_error_nid_postfix, LibcException::DestroyMessage, LibcException::DeleteMessage, LibcException::MessageWhat};
|
||||
void APS5_VABI _ZNSt11range_errorD1Ev_nid_postfix(LibcException::ExceptionObject* self) { LibcException::DestroyMessage(self); }
|
||||
void APS5_VABI _ZNSt11range_errorD2Ev_nid_postfix(LibcException::ExceptionObject* self) { LibcException::DestroyMessage(self); }
|
||||
void APS5_VABI _ZNSt11range_errorD0Ev_nid_postfix(LibcException::ExceptionObject* self) { LibcException::DeleteMessage(self); }
|
||||
|
||||
LibcException::TypeRecord _ZTINSt8ios_base7failureE_nid_postfix {LibcException::SingleTypeVtable + 2, "NSt8ios_base7failureE", &_ZTISt12system_error_nid_postfix};
|
||||
LibcException::ExceptionVtable _ZTVNSt8ios_base7failureE_nid_postfix {0, &_ZTINSt8ios_base7failureE_nid_postfix, LibcException::DestroyMessage, LibcException::DeleteMessage, LibcException::MessageWhat};
|
||||
void APS5_VABI _ZNSt8ios_base7failureD1Ev_nid_postfix(LibcException::ExceptionObject* self) { LibcException::DestroyMessage(self); }
|
||||
|
|
@ -281,6 +287,7 @@ const char* APS5_VABI _ZNKSt8ios_base7failure4whatEv_nid_postfix(const LibcExcep
|
|||
[[noreturn]] void APS5_VABI _ZSt14_Xout_of_rangePKc_nid_postfix(const char* message) { LibcException::ThrowMessage(_ZTVSt12out_of_range_nid_postfix, message); }
|
||||
[[noreturn]] void APS5_VABI _ZSt14_Xlength_errorPKc_nid_postfix(const char* message) { LibcException::ThrowMessage(_ZTVSt12length_error_nid_postfix, message); }
|
||||
[[noreturn]] void APS5_VABI _ZSt18_Xinvalid_argumentPKc_nid_postfix(const char* message) { LibcException::ThrowMessage(_ZTVSt16invalid_argument_nid_postfix, message); }
|
||||
[[noreturn]] void APS5_VABI _ZSt13_Xrange_errorPKc_nid_postfix(const char* message) { LibcException::ThrowMessage(_ZTVSt11range_error_nid_postfix, message); }
|
||||
[[noreturn]] void APS5_VABI _ZSt19_Xbad_function_callv_nid_postfix() { LibcException::ThrowPlain(_ZTVSt17bad_function_call_nid_postfix); }
|
||||
[[noreturn]] void APS5_VABI _ZSt13_Xregex_errorNSt15regex_constants10error_typeE_nid_postfix(std::regex_constants::error_type code) {
|
||||
struct RegexObject { LibcException::ExceptionObject base; std::regex_constants::error_type code; };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "prx/libkernel/AppMetadata/include/ParamJsonParser.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <charconv>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
|
@ -21,6 +22,7 @@ struct JsonValue {
|
|||
JsonType type = JsonType::Null;
|
||||
bool boolValue = false;
|
||||
double numberValue = 0.0;
|
||||
std::string numberText;
|
||||
std::string stringValue;
|
||||
JsonArray arrayValue;
|
||||
JsonObject objectValue;
|
||||
|
|
@ -193,7 +195,8 @@ JsonValue parseJsonNumber(const std::string& text, std::size_t& position) {
|
|||
}
|
||||
JsonValue value;
|
||||
value.type = JsonType::Number;
|
||||
value.numberValue = std::stod(text.substr(start, position - start));
|
||||
value.numberText = text.substr(start, position - start);
|
||||
value.numberValue = std::stod(value.numberText);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
@ -261,7 +264,14 @@ ParsedParamJson parseParamJson(const std::filesystem::path& paramJsonPath) {
|
|||
result.titleId = titleId;
|
||||
if (const JsonValue* downloadData = findObjectMember(root, "downloadDataSize")) {
|
||||
if (downloadData->type != JsonType::Number || downloadData->numberValue < 0) throw std::runtime_error("param.json downloadDataSize is not a size");
|
||||
result.downloadDataSizeMiB = static_cast<std::uint64_t>(downloadData->numberValue);
|
||||
if (downloadData->numberText.find_first_of("-.eE") == std::string::npos) {
|
||||
const auto& number = downloadData->numberText;
|
||||
const auto parsed = std::from_chars(number.data(), number.data() + number.size(), result.downloadDataSizeMiB);
|
||||
if (parsed.ec != std::errc{} || parsed.ptr != number.data() + number.size()) throw std::runtime_error("param.json downloadDataSize exceeds uint64 range");
|
||||
} else {
|
||||
if (downloadData->numberValue >= 0x1p64) throw std::runtime_error("param.json downloadDataSize exceeds uint64 range");
|
||||
result.downloadDataSizeMiB = static_cast<std::uint64_t>(downloadData->numberValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -70,6 +70,15 @@ if(MINGW)
|
|||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(param_json_parser_tests ${LIBS_INCLUDE_DIR}/tests/ParamJsonParser.cpp)
|
||||
target_include_directories(param_json_parser_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(param_json_parser_tests PRIVATE libkernel libc)
|
||||
configure_windows_unwind(param_json_parser_tests)
|
||||
add_test(NAME param_json_parser COMMAND param_json_parser_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(param_json_parser PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_test_executable(guest_posix_sem_tests ${LIBS_INCLUDE_DIR}/tests/GuestPosixSem.cpp)
|
||||
target_include_directories(guest_posix_sem_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_posix_sem_tests PRIVATE libkernel libc)
|
||||
|
|
|
|||
|
|
@ -226,7 +226,12 @@ public:
|
|||
#ifdef _WIN32
|
||||
const auto size = static_cast<std::uint64_t>(bytes);
|
||||
section = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_EXECUTE_READWRITE, static_cast<DWORD>(size >> 32), static_cast<DWORD>(size), nullptr);
|
||||
if (!section) throw std::system_error(static_cast<int>(GetLastError()), std::system_category(), "create direct memory backing");
|
||||
if (!section) {
|
||||
const auto error = static_cast<int>(GetLastError());
|
||||
char message[96];
|
||||
std::snprintf(message, sizeof(message), "create direct memory backing of 0x%llx bytes (%llu MiB)", static_cast<unsigned long long>(size), static_cast<unsigned long long>((size + 0xFFFFF) >> 20));
|
||||
throw std::system_error(error, std::system_category(), message);
|
||||
}
|
||||
#else
|
||||
file = memfd_create("direct memory", MFD_CLOEXEC);
|
||||
if (file < 0) throw std::system_error(errno, std::generic_category(), "create direct memory backing");
|
||||
|
|
|
|||
|
|
@ -25,23 +25,16 @@ struct AddressWaiter {
|
|||
std::mutex g_waitersLock;
|
||||
std::unordered_map<std::uintptr_t, std::list<AddressWaiter*>> g_waiters;
|
||||
|
||||
bool IsWordAddress(std::uintptr_t address) {
|
||||
return address != 0 && address % alignof(std::uint32_t) == 0;
|
||||
template <class TValue>
|
||||
bool IsAlignedAddress(std::uintptr_t address) {
|
||||
return address != 0 && address % alignof(TValue) == 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceKernelSyncOnAddressWait(std::uint32_t* address, std::uint32_t expected, const KernelUseconds* timeout, const char* name) {
|
||||
(void)name;
|
||||
template <class TValue>
|
||||
int WaitOnAddress(TValue* address, TValue expected, const KernelUseconds* timeout, const void* caller) {
|
||||
const auto key = reinterpret_cast<std::uintptr_t>(address);
|
||||
if (!IsWordAddress(key)) {
|
||||
APS5_INVALID_ARG_EX;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(g_waitersLock);
|
||||
if (std::atomic_ref<std::uint32_t>(*address).load() != expected) {
|
||||
if (std::atomic_ref<TValue>(*address).load() != expected) {
|
||||
return SYNC_ON_ADDRESS_OK;
|
||||
}
|
||||
|
||||
|
|
@ -65,13 +58,41 @@ int APS5_VABI sceKernelSyncOnAddressWait(std::uint32_t* address, std::uint32_t e
|
|||
}
|
||||
}
|
||||
lock.unlock();
|
||||
KernelTraceWait_nid_postfix("addr", __builtin_return_address(0), static_cast<std::uint64_t>(waited.count()), !woken);
|
||||
KernelTraceWait_nid_postfix("addr", caller, static_cast<std::uint64_t>(waited.count()), !woken);
|
||||
return woken ? SYNC_ON_ADDRESS_OK : SCE_KERNEL_ERROR_ETIMEDOUT;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceKernelSyncOnAddressWait(std::uint32_t* address, std::uint32_t expected, const KernelUseconds* timeout, const char* name) {
|
||||
(void)name;
|
||||
if (!IsAlignedAddress<std::uint32_t>(reinterpret_cast<std::uintptr_t>(address))) {
|
||||
APS5_INVALID_ARG_EX;
|
||||
}
|
||||
return WaitOnAddress(address, expected, timeout, __builtin_return_address(0));
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelSyncOnAddressWait32(std::uint32_t* address, std::uint32_t expected, const KernelUseconds* timeout, const char* name) {
|
||||
(void)name;
|
||||
if (!IsAlignedAddress<std::uint32_t>(reinterpret_cast<std::uintptr_t>(address))) {
|
||||
APS5_INVALID_ARG_EX;
|
||||
}
|
||||
return WaitOnAddress(address, expected, timeout, __builtin_return_address(0));
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelSyncOnAddressWait64(std::uint64_t* address, std::uint64_t expected, const KernelUseconds* timeout, const char* name) {
|
||||
(void)name;
|
||||
if (!IsAlignedAddress<std::uint64_t>(reinterpret_cast<std::uintptr_t>(address))) {
|
||||
APS5_INVALID_ARG_EX;
|
||||
}
|
||||
return WaitOnAddress(address, expected, timeout, __builtin_return_address(0));
|
||||
}
|
||||
|
||||
int APS5_VABI sceKernelSyncOnAddressWake(void* address, std::int32_t count) {
|
||||
const auto key = reinterpret_cast<std::uintptr_t>(address);
|
||||
if (!IsWordAddress(key) || count < 0) {
|
||||
if (!IsAlignedAddress<std::uint32_t>(key) || count < 0) {
|
||||
APS5_INVALID_ARG_EX;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ int APS5_VABI sceKernelDebugWriteCppExceptionInfo(const void* exception, uint64_
|
|||
}
|
||||
|
||||
|
||||
APS5_EXPORT("5nc2gdLNsok", sceCoredumpUnknown00);
|
||||
int APS5_VABI sceCoredumpUnknown00(void) {
|
||||
int APS5_VABI sceCoredumpAttachUserFile(void) {
|
||||
NotImplemented_nid_no_patch("5nc2gdLNsok");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -43,26 +42,22 @@ int APS5_VABI sceCoredumpUnknown01(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("MEJ7tc7ThwM", sceCoredumpUnknown02);
|
||||
int APS5_VABI sceCoredumpUnknown02(void) {
|
||||
int APS5_VABI sceCoredumpAttachMemoryRegionAsUserFile(void) {
|
||||
NotImplemented_nid_no_patch("MEJ7tc7ThwM");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("Uxqkdta7wEg", sceCoredumpUnknown03);
|
||||
int APS5_VABI sceCoredumpUnknown03(void) {
|
||||
int APS5_VABI sceCoredumpSetUserDataType(void) {
|
||||
NotImplemented_nid_no_patch("Uxqkdta7wEg");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("dei8oUx6DbU", sceCoredumpUnknown04);
|
||||
int APS5_VABI sceCoredumpUnknown04(void) {
|
||||
int APS5_VABI sceCoredumpDebugTextOut(void) {
|
||||
NotImplemented_nid_no_patch("dei8oUx6DbU");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("kK0DUW1Ukgc", sceCoredumpUnknown05);
|
||||
int APS5_VABI sceCoredumpUnknown05(void) {
|
||||
int APS5_VABI sceCoredumpGetStopInfoCpu(void) {
|
||||
NotImplemented_nid_no_patch("kK0DUW1Ukgc");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,12 @@ int APS5_VABI sceCoredumpWriteUserData() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("vNe1w4diLCs", sceKernelUnknown00);
|
||||
int APS5_VABI sceKernelUnknown00(void) {
|
||||
int APS5_VABI __tls_get_addr_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch("vNe1w4diLCs");
|
||||
return 0;
|
||||
}
|
||||
|
||||
APS5_EXPORT("teiItL2boFw", sceKernelUnknown01);
|
||||
int APS5_VABI sceKernelUnknown01(void) {
|
||||
int APS5_VABI sceKernelReleaseFlexibleMemory(void) {
|
||||
NotImplemented_nid_no_patch("teiItL2boFw");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -25,8 +23,7 @@ int APS5_VABI sceKernelUnknown01(void) {
|
|||
// Canonical lib is libScePosix (dead import of Cyberpunk 2077): 35 of its
|
||||
// 36 sibling imports resolve to libkernel, and libScePosix is not in the
|
||||
// game's NEEDED list so only a NEEDED module can satisfy the loader here.
|
||||
APS5_EXPORT("0D4-FVvEikw", sceKernelUnknown02);
|
||||
int APS5_VABI sceKernelUnknown02(void) {
|
||||
int APS5_VABI pthread_cancel_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch("0D4-FVvEikw");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
add_library(ulobjmgr SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(ulobjmgr PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(ulobjmgr)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_ulobjmgr_tests ${LIBS_INCLUDE_DIR}/tests/GuestUlobjmgr.cpp)
|
||||
target_include_directories(guest_ulobjmgr_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_ulobjmgr_tests PRIVATE ulobjmgr)
|
||||
add_test(NAME guest_ulobjmgr COMMAND guest_ulobjmgr_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_ulobjmgr PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:ulobjmgr>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -3,17 +3,23 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int ULOBJMGR_EINVAL = 22;
|
||||
constexpr std::uint32_t ULOBJMGR_ID_LIMIT = 0x4000;
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI _sceUlobjmgrRegisterObject(void* object) {
|
||||
(void)object;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI _sceUlobjmgrRegisterObject(std::uint64_t object, std::int32_t kind, std::uint32_t* id) {
|
||||
if (object == 0 || kind == 0 || id == nullptr) return ULOBJMGR_EINVAL;
|
||||
*id = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _sceUlobjmgrUnregisterObject(void* object) {
|
||||
(void)object;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI _sceUlobjmgrUnregisterObject(std::uint32_t id) {
|
||||
if (id >= ULOBJMGR_ID_LIMIT) return ULOBJMGR_EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ void APS5_VABI _ZdlPv_nid_postfix(void*);
|
|||
void APS5_VABI _ZdaPv_nid_postfix(void*);
|
||||
void APS5_VABI _ZdlPvSt11align_val_t_nid_postfix(void*, std::size_t);
|
||||
void* ApplicationHeapRealign_nid_no_patch(void*, std::size_t, std::size_t);
|
||||
char* APS5_VABI strdup_nid_postfix(const char*);
|
||||
char* APS5_VABI strndup_nid_postfix(const char*, std::size_t);
|
||||
int* APS5_VABI __error_nid_postfix();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
|
@ -192,4 +195,23 @@ int main(int argc, char** argv) {
|
|||
reject([] { ApplicationHeapAllocate_nid_no_patch(64); });
|
||||
recurse = false;
|
||||
require(ApplicationHeapAllocate_nid_no_patch(64) == storage.data());
|
||||
const char text[] = "guest string";
|
||||
char* copy = strdup_nid_postfix(text);
|
||||
require(copy == reinterpret_cast<char*>(storage.data()) && lastSize == sizeof(text));
|
||||
require(std::strcmp(copy, text) == 0 && copy != text);
|
||||
ApplicationHeapFree_nid_no_patch(copy);
|
||||
copy = strdup_nid_postfix("");
|
||||
require(lastSize == 1 && copy[0] == '\0');
|
||||
ApplicationHeapFree_nid_no_patch(copy);
|
||||
copy = strndup_nid_postfix(text, 5);
|
||||
require(lastSize == 6 && std::strcmp(copy, "guest") == 0);
|
||||
ApplicationHeapFree_nid_no_patch(copy);
|
||||
fail = true;
|
||||
*__error_nid_postfix() = 0;
|
||||
require(strdup_nid_postfix(text) == nullptr && *__error_nid_postfix() == 12);
|
||||
*__error_nid_postfix() = 0;
|
||||
require(strdup_nid_postfix("") == nullptr && *__error_nid_postfix() == 12);
|
||||
*__error_nid_postfix() = 0;
|
||||
require(strndup_nid_postfix(text, 5) == nullptr && *__error_nid_postfix() == 12);
|
||||
fail = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ extern "C" void __cxa_decrement_exception_refcount_nid_postfix(void*);
|
|||
extern "C" void __cxa_rethrow_primary_exception_nid_postfix(void*);
|
||||
|
||||
extern "C" [[noreturn]] void _ZSt14_Xout_of_rangePKc_nid_postfix(const char*);
|
||||
extern "C" [[noreturn]] void _ZSt13_Xrange_errorPKc_nid_postfix(const char*);
|
||||
extern "C" [[noreturn]] void __cxa_bad_cast_nid_postfix();
|
||||
extern "C" [[noreturn]] void _ZNKSt9exception6_RaiseEv_nid_postfix(const void*);
|
||||
extern "C" void* __cxa_vec_new3_nid_postfix(std::size_t, std::size_t, std::size_t, void(*)(void*), void(*)(void*), void*(*)(std::size_t), void(*)(void*, std::size_t));
|
||||
|
|
@ -190,6 +191,13 @@ int main() {
|
|||
try { throw Virtual(); } catch (Base& value) { assert(value.value == 7); }
|
||||
try { _ZSt14_Xout_of_rangePKc_nid_postfix("test message"); }
|
||||
catch (const std::logic_error& value) { assert(std::strcmp(value.what(), "test message") == 0); }
|
||||
try { _ZSt13_Xrange_errorPKc_nid_postfix("range message"); }
|
||||
catch (const std::range_error& value) { if (std::strcmp(value.what(), "range message") != 0) std::abort(); }
|
||||
try { _ZSt13_Xrange_errorPKc_nid_postfix(nullptr); }
|
||||
catch (const std::runtime_error& value) { if (std::strcmp(value.what(), "") != 0) std::abort(); }
|
||||
try { _ZSt13_Xrange_errorPKc_nid_postfix("not a logic error"); }
|
||||
catch (const std::logic_error&) { std::abort(); }
|
||||
catch (const std::range_error&) {}
|
||||
try { __cxa_bad_cast_nid_postfix(); }
|
||||
catch (const std::exception& value) { assert(value.what() != nullptr); }
|
||||
try { _ZNKSt9exception6_RaiseEv_nid_postfix(nullptr); assert(false); }
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue