First Commit
This commit is contained in:
75
tests/ctest/core/CMakeLists.txt
Normal file
75
tests/ctest/core/CMakeLists.txt
Normal file
@@ -0,0 +1,75 @@
|
||||
add_pcsx2_test(core_test
|
||||
StubHost.cpp
|
||||
)
|
||||
|
||||
set(multi_isa_sources
|
||||
GS/swizzle_test_main.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(core_test PUBLIC
|
||||
PCSX2_FLAGS
|
||||
PCSX2
|
||||
common
|
||||
)
|
||||
|
||||
if(DISABLE_ADVANCE_SIMD)
|
||||
if(WIN32)
|
||||
set(compile_options_avx2 /arch:AVX2)
|
||||
set(compile_options_avx /arch:AVX)
|
||||
elseif(USE_GCC)
|
||||
# GCC can't inline into multi-isa functions if we use march and mtune, but can if we use feature flags
|
||||
set(compile_options_avx2 -msse4.1 -mavx -mavx2 -mbmi -mbmi2 -mfma)
|
||||
set(compile_options_avx -msse4.1 -mavx)
|
||||
set(compile_options_sse4 -msse4.1)
|
||||
else()
|
||||
set(compile_options_avx2 -march=haswell -mtune=haswell)
|
||||
set(compile_options_avx -march=sandybridge -mtune=sandybridge)
|
||||
set(compile_options_sse4 -msse4.1 -mtune=nehalem)
|
||||
endif()
|
||||
|
||||
# This breaks when running on Apple Silicon, because even though we skip the test itself, the
|
||||
# gtest constructor still generates AVX code, and that's a global object which gets constructed
|
||||
# at binary load time. So, for now, only compile SSE4 if running on ARM64.
|
||||
if (NOT APPLE OR "${CMAKE_HOST_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
|
||||
set(isa_list "sse4" "avx" "avx2")
|
||||
else()
|
||||
set(isa_list "sse4")
|
||||
endif()
|
||||
|
||||
# ODR violation time!
|
||||
# Everything would be fine if we only defined things in cpp files, but C++ tends to like inline functions (STL anyone?)
|
||||
# Each ISA will bring with it its own copies of these inline header functions, and the linker gets to choose whichever one it wants! Not fun if the linker chooses the avx2 version and uses it with everything
|
||||
# Thankfully, most linkers don't choose at random. When presented with a bunch of .o files, most linkers seem to choose the first implementation they see, so make sure you order these from oldest to newest
|
||||
# Note: ld64 (macOS's linker) does not act the same way when presented with .a files, unless linked with `-force_load` (cmake WHOLE_ARCHIVE).
|
||||
set(is_first_isa "1")
|
||||
foreach(isa IN LISTS isa_list)
|
||||
add_library(core_test_${isa} STATIC ${multi_isa_sources})
|
||||
target_link_libraries(core_test_${isa} PRIVATE PCSX2_FLAGS gtest)
|
||||
target_compile_definitions(core_test_${isa} PRIVATE MULTI_ISA_UNSHARED_COMPILATION=isa_${isa} MULTI_ISA_IS_FIRST=${is_first_isa} ${pcsx2_defs_${isa}})
|
||||
target_compile_options(core_test_${isa} PRIVATE ${compile_options_${isa}})
|
||||
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.24)
|
||||
target_link_libraries(core_test PRIVATE $<LINK_LIBRARY:WHOLE_ARCHIVE,core_test_${isa}>)
|
||||
elseif(APPLE)
|
||||
message(FATAL_ERROR "MacOS builds with DISABLE_ADVANCE_SIMD=ON require CMake 3.24")
|
||||
else()
|
||||
target_link_libraries(core_test PRIVATE core_test_${isa})
|
||||
endif()
|
||||
set(is_first_isa "0")
|
||||
endforeach()
|
||||
else()
|
||||
target_sources(core_test PRIVATE ${multi_isa_sources})
|
||||
endif()
|
||||
|
||||
if(WIN32 AND TARGET SDL3::SDL3)
|
||||
# Copy SDL3 DLL to binary directory.
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
get_property(SDL3_DLL_PATH TARGET SDL3::SDL3 PROPERTY IMPORTED_LOCATION_DEBUG)
|
||||
else()
|
||||
get_property(SDL3_DLL_PATH TARGET SDL3::SDL3 PROPERTY IMPORTED_LOCATION_RELEASE)
|
||||
endif()
|
||||
if(SDL3_DLL_PATH)
|
||||
add_custom_command(TARGET core_test POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E make_directory "$<TARGET_FILE_DIR:core_test>"
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${SDL3_DLL_PATH}" "$<TARGET_FILE_DIR:core_test>")
|
||||
endif()
|
||||
endif()
|
||||
590
tests/ctest/core/GS/swizzle_test_main.cpp
Normal file
590
tests/ctest/core/GS/swizzle_test_main.cpp
Normal file
@@ -0,0 +1,590 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "pcsx2/GS/GSBlock.h"
|
||||
#include "pcsx2/GS/GSClut.h"
|
||||
#include "pcsx2/GS/MultiISA.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "cpuinfo.h"
|
||||
|
||||
#ifdef MULTI_ISA_UNSHARED_COMPILATION
|
||||
|
||||
enum class TestISA
|
||||
{
|
||||
isa_sse4,
|
||||
isa_avx,
|
||||
isa_avx2,
|
||||
isa_native,
|
||||
};
|
||||
|
||||
static bool CheckCapabilities(TestISA required_caps)
|
||||
{
|
||||
cpuinfo_initialize();
|
||||
if (required_caps == TestISA::isa_avx && !cpuinfo_has_x86_avx())
|
||||
return false;
|
||||
if (required_caps == TestISA::isa_avx2 && !cpuinfo_has_x86_avx2())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define MULTI_ISA_STRINGIZE_(x) #x
|
||||
#define MULTI_ISA_STRINGIZE(x) MULTI_ISA_STRINGIZE_(x)
|
||||
|
||||
#define MULTI_ISA_CONCAT_(a, b) a##b
|
||||
#define MULTI_ISA_CONCAT(a, b) MULTI_ISA_CONCAT_(a, b)
|
||||
|
||||
#define MULTI_ISA_TEST(group, name) TEST(MULTI_ISA_CONCAT(MULTI_ISA_CONCAT(MULTI_ISA_UNSHARED_COMPILATION, _), group), name)
|
||||
#define SKIP_IF_UNSUPPORTED() \
|
||||
if (!CheckCapabilities(TestISA::MULTI_ISA_UNSHARED_COMPILATION)) { \
|
||||
GTEST_SKIP() << "Host CPU does not support " MULTI_ISA_STRINGIZE(MULTI_ISA_UNSHARED_COMPILATION); \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define MULTI_ISA_TEST(group, name) TEST(group, name)
|
||||
#define SKIP_IF_UNSUPPORTED()
|
||||
|
||||
#endif
|
||||
|
||||
MULTI_ISA_UNSHARED_START
|
||||
|
||||
static void swizzle(const u8* table, u8* dst, const u8* src, int bpp, bool deswizzle)
|
||||
{
|
||||
int pxbytes = bpp / 8;
|
||||
for (int i = 0; i < (256 / pxbytes); i++)
|
||||
{
|
||||
int soff = (deswizzle ? table[i] : i) * pxbytes;
|
||||
int doff = (deswizzle ? i : table[i]) * pxbytes;
|
||||
memcpy(&dst[doff], &src[soff], pxbytes);
|
||||
}
|
||||
}
|
||||
|
||||
static void swizzle4(const u16* table, u8* dst, const u8* src, bool deswizzle)
|
||||
{
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
int soff = (deswizzle ? table[i] : i);
|
||||
int doff = (deswizzle ? i : table[i]);
|
||||
int spx = src[soff >> 1] >> ((soff & 1) * 4) & 0xF;
|
||||
u8* dpx = &dst[doff >> 1];
|
||||
int dshift = (doff & 1) * 4;
|
||||
*dpx &= (0xF0 >> dshift);
|
||||
*dpx |= (spx << dshift);
|
||||
}
|
||||
}
|
||||
|
||||
static void swizzleH(const u8* table, u32* dst, const u8* src, int bpp, int shift)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
int spx;
|
||||
if (bpp == 8)
|
||||
spx = src[i];
|
||||
else
|
||||
spx = (src[i >> 1] >> ((i & 1) * 4)) & 0xF;
|
||||
spx <<= shift;
|
||||
dst[table[i]] = spx;
|
||||
}
|
||||
}
|
||||
|
||||
static void expand16(u32* dst, const u16* src, const GIFRegTEXA& texa)
|
||||
{
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
int r = (src[i] << 3) & 0x0000F8;
|
||||
int g = (src[i] << 6) & 0x00F800;
|
||||
int b = (src[i] << 9) & 0xF80000;
|
||||
dst[i] = r | g | b;
|
||||
if (src[i] & 0x8000)
|
||||
{
|
||||
dst[i] |= texa.TA1 << 24;
|
||||
}
|
||||
else if (!texa.AEM || src[i])
|
||||
{
|
||||
dst[i] |= texa.TA0 << 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void expand8(u32* dst, const u8* src, const u32* palette)
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
dst[i] = palette[src[i]];
|
||||
}
|
||||
}
|
||||
|
||||
static void expand4(u32* dst, const u8* src, const u32* palette)
|
||||
{
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
dst[i] = palette[(src[i >> 1] >> ((i & 1) * 4)) & 0xF];
|
||||
}
|
||||
}
|
||||
|
||||
static void expand4P(u8* dst, const u8* src)
|
||||
{
|
||||
for (int i = 0; i < 512; i++)
|
||||
{
|
||||
dst[i] = (src[i >> 1] >> ((i & 1) * 4)) & 0xF;
|
||||
}
|
||||
}
|
||||
|
||||
static void expandH(u32* dst, const u32* src, const u32* palette, int shift, int mask)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
dst[i] = palette[(src[i] >> shift) & mask];
|
||||
}
|
||||
}
|
||||
|
||||
static void expandHP(u8* dst, const u32* src, int shift, int mask)
|
||||
{
|
||||
for (int i = 0; i < 64; i++)
|
||||
{
|
||||
dst[i] = (src[i] >> shift) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string image2hex(const u8* bin, int rows, int columns, int bpp)
|
||||
{
|
||||
std::string out;
|
||||
const char* hex = "0123456789ABCDEF";
|
||||
|
||||
for (int y = 0; y < rows; y++)
|
||||
{
|
||||
if (y != 0)
|
||||
out.push_back('\n');
|
||||
for (int x = 0; x < columns; x++)
|
||||
{
|
||||
if (x != 0)
|
||||
out.push_back(' ');
|
||||
if (bpp == 4)
|
||||
{
|
||||
if (x & 1)
|
||||
{
|
||||
out.push_back(hex[*bin >> 4]);
|
||||
bin++;
|
||||
}
|
||||
else
|
||||
{
|
||||
out.push_back(hex[*bin & 0xF]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int z = 0; z < (bpp / 8); z++)
|
||||
{
|
||||
out.push_back(hex[*bin >> 4]);
|
||||
out.push_back(hex[*bin & 0xF]);
|
||||
bin++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct TestData
|
||||
{
|
||||
alignas(64) u8 block[256];
|
||||
alignas(64) u8 output[256 * (32 / 4)];
|
||||
alignas(64) u32 clut32[256];
|
||||
alignas(64) u64 clut64[256];
|
||||
|
||||
/// Get some input data with pixel values counting up from 0
|
||||
static TestData Linear()
|
||||
{
|
||||
TestData output;
|
||||
memset(output.output, 0, sizeof(output.output));
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
output.block[i] = i;
|
||||
output.clut32[i] = i | (i << 16);
|
||||
}
|
||||
GSClut::ExpandCLUT64_T32_I8(output.clut32, output.clut64);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Get some input data with random-ish (but consistent across runs) pixel values
|
||||
static TestData Random()
|
||||
{
|
||||
srand(0);
|
||||
TestData output;
|
||||
memset(output.output, 0, sizeof(output.output));
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
output.block[i] = rand();
|
||||
output.clut32[i] = rand();
|
||||
}
|
||||
GSClut::ExpandCLUT64_T32_I8(output.clut32, output.clut64);
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Move data from output back to block to run an expand
|
||||
TestData prepareExpand()
|
||||
{
|
||||
TestData output = *this;
|
||||
memcpy(output.block, output.output, sizeof(output.block));
|
||||
return output;
|
||||
}
|
||||
};
|
||||
|
||||
static TestData swizzle(const u8* table, TestData data, int bpp, bool deswizzle)
|
||||
{
|
||||
swizzle(table, data.output, data.block, bpp, deswizzle);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData swizzle4(const u16* table, TestData data, bool deswizzle)
|
||||
{
|
||||
swizzle4(table, data.output, data.block, deswizzle);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData swizzleH(const u8* table, TestData data, int bpp, int shift)
|
||||
{
|
||||
swizzleH(table, reinterpret_cast<u32*>(data.output), data.block, bpp, shift);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData expand16(TestData data, const GIFRegTEXA& texa)
|
||||
{
|
||||
expand16(reinterpret_cast<u32*>(data.output), reinterpret_cast<const u16*>(data.block), texa);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData expand8(TestData data)
|
||||
{
|
||||
expand8(reinterpret_cast<u32*>(data.output), data.block, data.clut32);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData expand4(TestData data)
|
||||
{
|
||||
expand4(reinterpret_cast<u32*>(data.output), data.block, data.clut32);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData expand4P(TestData data)
|
||||
{
|
||||
expand4P(data.output, data.block);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData expandH(TestData data, int shift, int mask)
|
||||
{
|
||||
expandH(reinterpret_cast<u32*>(data.output), reinterpret_cast<const u32*>(data.block), data.clut32, shift, mask);
|
||||
return data;
|
||||
}
|
||||
|
||||
static TestData expandHP(TestData data, int shift, int mask)
|
||||
{
|
||||
expandHP(data.output, reinterpret_cast<u32*>(data.block), shift, mask);
|
||||
return data;
|
||||
}
|
||||
|
||||
static void runTest(void (*fn)(TestData))
|
||||
{
|
||||
fn(TestData::Linear());
|
||||
fn(TestData::Random());
|
||||
}
|
||||
|
||||
static void assertEqual(const TestData& expected, const TestData& actual, const char* name, int rows, int columns, int bpp)
|
||||
{
|
||||
std::string estr = image2hex(expected.output, rows, columns, bpp);
|
||||
std::string astr = image2hex(actual.output, rows, columns, bpp);
|
||||
EXPECT_STREQ(estr.c_str(), astr.c_str()) << "Unexpected " << name;
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read32)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, true);
|
||||
GSBlock::ReadBlock32(data.block, data.output, 32);
|
||||
assertEqual(expected, data, "Read32", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(WriteTest, Write32)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, false);
|
||||
GSBlock::WriteBlock32<32, 0xFFFFFFFF>(data.output, data.block, 32);
|
||||
assertEqual(expected, data, "Write32", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read16)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable16[0][0], data, 16, true);
|
||||
GSBlock::ReadBlock16(data.block, data.output, 32);
|
||||
assertEqual(expected, data, "Read16", 8, 16, 16);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadAndExpandTest, Read16)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
GIFRegTEXA texa = {0};
|
||||
texa.TA0 = 1;
|
||||
texa.TA1 = 2;
|
||||
TestData expected = swizzle(&columnTable16[0][0], data, 16, true);
|
||||
expected = expand16(expected.prepareExpand(), texa);
|
||||
GSBlock::ReadAndExpandBlock16<false>(data.block, data.output, 64, texa);
|
||||
assertEqual(expected, data, "ReadAndExpand16", 8, 16, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadAndExpandTest, Read16AEM)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
// Actually test AEM
|
||||
u8 idx = data.block[0] >> 1;
|
||||
data.block[idx * 2 + 0] = 0;
|
||||
data.block[idx * 2 + 1] = 0;
|
||||
GIFRegTEXA texa = {0};
|
||||
texa.TA0 = 1;
|
||||
texa.TA1 = 2;
|
||||
texa.AEM = 1;
|
||||
TestData expected = swizzle(&columnTable16[0][0], data, 16, true);
|
||||
expected = expand16(expected.prepareExpand(), texa);
|
||||
GSBlock::ReadAndExpandBlock16<true>(data.block, data.output, 64, texa);
|
||||
assertEqual(expected, data, "ReadAndExpand16AEM", 8, 16, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(WriteTest, Write16)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable16[0][0], data, 16, false);
|
||||
GSBlock::WriteBlock16<32>(data.output, data.block, 32);
|
||||
assertEqual(expected, data, "Read16", 8, 16, 16);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read8)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable8[0][0], data, 8, true);
|
||||
GSBlock::ReadBlock8(data.block, data.output, 16);
|
||||
assertEqual(expected, data, "Read8", 16, 16, 8);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadAndExpandTest, Read8)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable8[0][0], data, 8, true);
|
||||
expected = expand8(expected.prepareExpand());
|
||||
GSBlock::ReadAndExpandBlock8_32(data.block, data.output, 64, data.clut32);
|
||||
assertEqual(expected, data, "ReadAndExpand8", 16, 16, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(WriteTest, Write8)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable8[0][0], data, 8, false);
|
||||
GSBlock::WriteBlock8<32>(data.output, data.block, 16);
|
||||
assertEqual(expected, data, "Write8", 16, 16, 8);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read8H)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, true);
|
||||
expected = expandHP(expected.prepareExpand(), 24, 0xFF);
|
||||
GSBlock::ReadBlock8HP(data.block, data.output, 8);
|
||||
assertEqual(expected, data, "Read8H", 8, 8, 8);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadAndExpandTest, Read8H)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, true);
|
||||
expected = expandH(expected.prepareExpand(), 24, 0xFF);
|
||||
GSBlock::ReadAndExpandBlock8H_32(data.block, data.output, 32, data.clut32);
|
||||
assertEqual(expected, data, "ReadAndExpand8H", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(WriteTest, Write8H)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzleH(&columnTable32[0][0], data, 8, 24);
|
||||
GSBlock::UnpackAndWriteBlock8H(data.block, 8, data.output);
|
||||
assertEqual(expected, data, "Write8H", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read4)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle4(&columnTable4[0][0], data, true);
|
||||
GSBlock::ReadBlock4(data.block, data.output, 16);
|
||||
assertEqual(expected, data, "Read4", 16, 32, 4);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read4P)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle4(&columnTable4[0][0], data, true);
|
||||
expected = expand4P(expected.prepareExpand());
|
||||
GSBlock::ReadBlock4P(data.block, data.output, 32);
|
||||
assertEqual(expected, data, "Read4P", 16, 32, 8);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadAndExpandTest, Read4)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle4(&columnTable4[0][0], data, true);
|
||||
expected = expand4(expected.prepareExpand());
|
||||
GSBlock::ReadAndExpandBlock4_32(data.block, data.output, 128, data.clut32);
|
||||
assertEqual(expected, data, "ReadAndExpand4", 16, 32, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(WriteTest, Write4)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle4(&columnTable4[0][0], data, false);
|
||||
GSBlock::WriteBlock4<32>(data.output, data.block, 16);
|
||||
assertEqual(expected, data, "Write4", 16, 16, 4);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read4HH)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, true);
|
||||
expected = expandHP(expected.prepareExpand(), 28, 0xF);
|
||||
GSBlock::ReadBlock4HHP(data.block, data.output, 8);
|
||||
assertEqual(expected, data, "Read4HH", 8, 8, 8);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadAndExpandTest, Read4HH)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, true);
|
||||
expected = expandH(expected.prepareExpand(), 28, 0xF);
|
||||
GSBlock::ReadAndExpandBlock4HH_32(data.block, data.output, 32, data.clut32);
|
||||
assertEqual(expected, data, "ReadAndExpand4HH", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(WriteTest, Write4HH)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzleH(&columnTable32[0][0], data, 4, 28);
|
||||
GSBlock::UnpackAndWriteBlock4HH(data.block, 4, data.output);
|
||||
assertEqual(expected, data, "Write4HH", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadTest, Read4HL)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, true);
|
||||
expected = expandHP(expected.prepareExpand(), 24, 0xF);
|
||||
GSBlock::ReadBlock4HLP(data.block, data.output, 8);
|
||||
assertEqual(expected, data, "Read4HL", 8, 8, 8);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(ReadAndExpandTest, Read4HL)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzle(&columnTable32[0][0], data, 32, true);
|
||||
expected = expandH(expected.prepareExpand(), 24, 0xF);
|
||||
GSBlock::ReadAndExpandBlock4HL_32(data.block, data.output, 32, data.clut32);
|
||||
assertEqual(expected, data, "ReadAndExpand4HL", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_TEST(WriteTest, Write4HL)
|
||||
{
|
||||
SKIP_IF_UNSUPPORTED();
|
||||
|
||||
runTest([](TestData data)
|
||||
{
|
||||
TestData expected = swizzleH(&columnTable32[0][0], data, 4, 24);
|
||||
GSBlock::UnpackAndWriteBlock4HL(data.block, 4, data.output);
|
||||
assertEqual(expected, data, "Write4HL", 8, 8, 32);
|
||||
});
|
||||
}
|
||||
|
||||
MULTI_ISA_UNSHARED_END
|
||||
287
tests/ctest/core/StubHost.cpp
Normal file
287
tests/ctest/core/StubHost.cpp
Normal file
@@ -0,0 +1,287 @@
|
||||
// SPDX-FileCopyrightText: 2002-2025 PCSX2 Dev Team
|
||||
// SPDX-License-Identifier: GPL-3.0+
|
||||
|
||||
#include "pcsx2/Achievements.h"
|
||||
#include "pcsx2/GS.h"
|
||||
#include "pcsx2/GameList.h"
|
||||
#include "pcsx2/Host.h"
|
||||
#include "pcsx2/ImGui/FullscreenUI.h"
|
||||
#include "pcsx2/ImGui/ImGuiAnimated.h"
|
||||
#include "pcsx2/ImGui/ImGuiFullscreen.h"
|
||||
#include "pcsx2/ImGui/ImGuiManager.h"
|
||||
#include "pcsx2/Input/InputManager.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
#include "common/ProgressCallback.h"
|
||||
|
||||
void Host::CommitBaseSettingChanges()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::LoadSettings(SettingsInterface& si, std::unique_lock<std::mutex>& lock)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::CheckForSettingsChanges(const Pcsx2Config& old_config)
|
||||
{
|
||||
}
|
||||
|
||||
bool Host::RequestResetSettings(bool folders, bool core, bool controllers, bool hotkeys, bool ui)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Host::SetDefaultUISettings(SettingsInterface& si)
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<ProgressCallback> Host::CreateHostProgressCallback()
|
||||
{
|
||||
return ProgressCallback::CreateNullProgressCallback();
|
||||
}
|
||||
|
||||
void Host::ReportInfoAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::ReportErrorAsync(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
}
|
||||
|
||||
bool Host::ConfirmMessage(const std::string_view title, const std::string_view message)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Host::OpenURL(const std::string_view url)
|
||||
{
|
||||
}
|
||||
|
||||
bool Host::InBatchMode()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Host::InNoGUIMode()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Host::CopyTextToClipboard(const std::string_view text)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Host::BeginTextInput()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::EndTextInput()
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> Host::GetTopLevelWindowInfo()
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Host::OnInputDeviceConnected(const std::string_view identifier, const std::string_view device_name)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnInputDeviceDisconnected(const InputBindingKey key, const std::string_view identifier)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::SetMouseMode(bool relative_mode, bool hide_cursor)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<WindowInfo> Host::AcquireRenderWindow(bool recreate_window)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void Host::ReleaseRenderWindow()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::BeginPresentFrame()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RequestResizeHostDisplay(s32 width, s32 height)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnVMStarting()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnVMStarted()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnVMDestroyed()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnVMPaused()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnVMResumed()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnGameChanged(const std::string& title, const std::string& elf_override, const std::string& disc_path,
|
||||
const std::string& disc_serial, u32 disc_crc, u32 current_crc)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnPerformanceMetricsUpdated()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnSaveStateLoading(const std::string_view filename)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnSaveStateLoaded(const std::string_view filename, bool was_successful)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnSaveStateSaved(const std::string_view filename)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RefreshGameListAsync(bool invalidate_cache)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::CancelGameListRefresh()
|
||||
{
|
||||
}
|
||||
|
||||
bool Host::IsFullscreen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Host::SetFullscreen(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnCaptureStarted(const std::string& filename)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnCaptureStopped()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RequestExitApplication(bool allow_confirm)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RequestExitBigPicture()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::PumpMessagesOnCPUThread()
|
||||
{
|
||||
}
|
||||
|
||||
s32 Host::Internal::GetTranslatedStringImpl(
|
||||
const std::string_view context, const std::string_view msg, char* tbuf, size_t tbuf_space)
|
||||
{
|
||||
if (msg.size() > tbuf_space)
|
||||
return -1;
|
||||
else if (msg.empty())
|
||||
return 0;
|
||||
|
||||
std::memcpy(tbuf, msg.data(), msg.size());
|
||||
return static_cast<s32>(msg.size());
|
||||
}
|
||||
|
||||
std::string Host::TranslatePluralToString(const char* context, const char* msg, const char* disambiguation, int count)
|
||||
{
|
||||
TinyString count_str = TinyString::from_format("{}", count);
|
||||
|
||||
std::string ret(msg);
|
||||
for (;;)
|
||||
{
|
||||
std::string::size_type pos = ret.find("%n");
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
ret.replace(pos, pos + 2, count_str.view());
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Host::OnAchievementsLoginRequested(Achievements::LoginRequestReason reason)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnAchievementsLoginSuccess(const char* username, u32 points, u32 sc_points, u32 unread_messages)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnAchievementsRefreshed()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnAchievementsHardcoreModeChanged(bool enabled)
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnCoverDownloaderOpenRequested()
|
||||
{
|
||||
}
|
||||
|
||||
void Host::OnCreateMemoryCardOpenRequested()
|
||||
{
|
||||
}
|
||||
|
||||
bool Host::LocaleCircleConfirm()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Host::ShouldPreferHostFileSelector()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void Host::OpenHostFileSelectorAsync(std::string_view title, bool select_directory, FileSelectorCallback callback,
|
||||
FileSelectorFilters filters, std::string_view initial_directory)
|
||||
{
|
||||
callback(std::string());
|
||||
}
|
||||
|
||||
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::string_view str)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::string> InputManager::ConvertHostKeyboardCodeToString(u32 code)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const char* InputManager::ConvertHostKeyboardCodeToIcon(u32 code)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
BEGIN_HOTKEY_LIST(g_host_hotkeys)
|
||||
END_HOTKEY_LIST()
|
||||
Reference in New Issue
Block a user