mirror of
https://github.com/dolphin-emu/hwtests.git
synced 2026-01-31 01:05:17 +01:00
Reformat all code using clang-format
This commit is contained in:
@@ -75,62 +75,57 @@
|
||||
* correctly, e.g. printf("Value: %d", (s32)some_register.some_signed_fields);
|
||||
*
|
||||
*/
|
||||
template<std::size_t position, std::size_t bits, typename T>
|
||||
template <std::size_t position, std::size_t bits, typename T>
|
||||
struct BitField
|
||||
{
|
||||
private:
|
||||
// This constructor might be considered ambiguous:
|
||||
// Would it initialize the storage or just the bitfield?
|
||||
// Hence, delete it. Use the assignment operator to set bitfield values!
|
||||
BitField(T val) = delete;
|
||||
// This constructor might be considered ambiguous:
|
||||
// Would it initialize the storage or just the bitfield?
|
||||
// Hence, delete it. Use the assignment operator to set bitfield values!
|
||||
BitField(T val) = delete;
|
||||
|
||||
public:
|
||||
// Force default constructor to be created
|
||||
// so that we can use this within unions
|
||||
BitField() = default;
|
||||
// Force default constructor to be created
|
||||
// so that we can use this within unions
|
||||
BitField() = default;
|
||||
|
||||
BitField& operator = (T val)
|
||||
{
|
||||
storage = (storage & ~GetMask()) | ((val<<position) & GetMask());
|
||||
return *this;
|
||||
}
|
||||
BitField& operator=(T val)
|
||||
{
|
||||
storage = (storage & ~GetMask()) | ((val << position) & GetMask());
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator T() const
|
||||
{
|
||||
if (std::numeric_limits<T>::is_signed)
|
||||
{
|
||||
std::size_t shift = 8 * sizeof(T) - bits;
|
||||
return (T)(((storage & GetMask()) << (shift - position)) >> shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (T)((storage & GetMask()) >> position);
|
||||
}
|
||||
}
|
||||
operator T() const
|
||||
{
|
||||
if (std::numeric_limits<T>::is_signed)
|
||||
{
|
||||
std::size_t shift = 8 * sizeof(T) - bits;
|
||||
return (T)(((storage & GetMask()) << (shift - position)) >> shift);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (T)((storage & GetMask()) >> position);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// StorageType is T for non-enum types and the underlying type of T if
|
||||
// T is an enumeration. Note that T is wrapped within an enable_if in the
|
||||
// former case to workaround compile errors which arise when using
|
||||
// std::underlying_type<T>::type directly.
|
||||
typedef typename std::conditional<std::is_enum<T>::value,
|
||||
std::underlying_type<T>,
|
||||
std::enable_if<true,T>>::type::type StorageType;
|
||||
// StorageType is T for non-enum types and the underlying type of T if
|
||||
// T is an enumeration. Note that T is wrapped within an enable_if in the
|
||||
// former case to workaround compile errors which arise when using
|
||||
// std::underlying_type<T>::type directly.
|
||||
typedef typename std::conditional<std::is_enum<T>::value, std::underlying_type<T>,
|
||||
std::enable_if<true, T>>::type::type StorageType;
|
||||
|
||||
// Unsigned version of StorageType
|
||||
typedef typename std::make_unsigned<StorageType>::type StorageTypeU;
|
||||
// Unsigned version of StorageType
|
||||
typedef typename std::make_unsigned<StorageType>::type StorageTypeU;
|
||||
|
||||
StorageType GetMask() const
|
||||
{
|
||||
return ((~(StorageTypeU)0) >> (8*sizeof(T) - bits)) << position;
|
||||
}
|
||||
StorageType GetMask() const { return ((~(StorageTypeU)0) >> (8 * sizeof(T) - bits)) << position; }
|
||||
StorageType storage;
|
||||
|
||||
StorageType storage;
|
||||
static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range");
|
||||
|
||||
static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range");
|
||||
|
||||
// And, you know, just in case people specify something stupid like bits=position=0x80000000
|
||||
static_assert(position < 8 * sizeof(T), "Invalid position");
|
||||
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
|
||||
static_assert(bits > 0, "Invalid number of bits");
|
||||
// And, you know, just in case people specify something stupid like bits=position=0x80000000
|
||||
static_assert(position < 8 * sizeof(T), "Invalid position");
|
||||
static_assert(bits <= 8 * sizeof(T), "Invalid number of bits");
|
||||
static_assert(bits > 0, "Invalid number of bits");
|
||||
};
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
#ifndef _rotl
|
||||
static inline u32 _rotl(u32 x, int shift)
|
||||
{
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
return (x << shift) | (x >> (32 - shift));
|
||||
shift &= 31;
|
||||
if (!shift)
|
||||
return x;
|
||||
return (x << shift) | (x >> (32 - shift));
|
||||
}
|
||||
|
||||
static inline u32 _rotr(u32 x, int shift)
|
||||
{
|
||||
shift &= 31;
|
||||
if (!shift) return x;
|
||||
return (x >> shift) | (x << (32 - shift));
|
||||
shift &= 31;
|
||||
if (!shift)
|
||||
return x;
|
||||
return (x >> shift) | (x << (32 - shift));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
|
||||
// This header contains type definitions that are shared between the Dolphin core and
|
||||
// other parts of the code. Any definitions that are only used by the core should be
|
||||
// placed in "Common.h" instead.
|
||||
@@ -15,12 +14,12 @@
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
@@ -29,12 +28,12 @@ typedef int64_t s64;
|
||||
|
||||
//#ifndef GEKKO
|
||||
|
||||
typedef uint8_t u8;
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
@@ -44,4 +43,4 @@ typedef int64_t s64;
|
||||
#define TCHAR char
|
||||
#define LONG int
|
||||
|
||||
#endif // _WIN32
|
||||
#endif // _WIN32
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
|
||||
struct TestStatus
|
||||
{
|
||||
TestStatus(const char* file, int line) : num_passes(0), num_failures(0), num_subtests(0), file(file), line(line)
|
||||
{
|
||||
}
|
||||
TestStatus(const char* file, int line)
|
||||
: num_passes(0), num_failures(0), num_subtests(0), file(file), line(line)
|
||||
{
|
||||
}
|
||||
|
||||
long long num_passes;
|
||||
long long num_failures;
|
||||
long long num_subtests;
|
||||
long long num_passes;
|
||||
long long num_failures;
|
||||
long long num_subtests;
|
||||
|
||||
const char* file;
|
||||
int line;
|
||||
const char* file;
|
||||
int line;
|
||||
};
|
||||
|
||||
static TestStatus status(NULL, 0);
|
||||
@@ -22,98 +23,99 @@ int server_socket;
|
||||
|
||||
void network_vprintf(const char* str, va_list args)
|
||||
{
|
||||
char buffer[4096];
|
||||
// int len = vsnprintf(buffer, 4096, str, args);
|
||||
int len = vsprintf(buffer, str, args);
|
||||
net_send(client_socket, buffer, len+1, 0);
|
||||
char buffer[4096];
|
||||
// int len = vsnprintf(buffer, 4096, str, args);
|
||||
int len = vsprintf(buffer, str, args);
|
||||
net_send(client_socket, buffer, len + 1, 0);
|
||||
}
|
||||
|
||||
void network_printf(const char* str, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
network_vprintf(str, args);
|
||||
va_end(args);
|
||||
va_list args;
|
||||
va_start(args, str);
|
||||
network_vprintf(str, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void privStartTest(const char* file, int line)
|
||||
{
|
||||
status = TestStatus(file, line);
|
||||
status = TestStatus(file, line);
|
||||
|
||||
number_of_tests++;
|
||||
number_of_tests++;
|
||||
}
|
||||
|
||||
void privDoTest(bool condition, const char* file, int line, const char* fail_msg, ...)
|
||||
{
|
||||
va_list arglist;
|
||||
va_start(arglist, fail_msg);
|
||||
va_list arglist;
|
||||
va_start(arglist, fail_msg);
|
||||
|
||||
++status.num_subtests;
|
||||
++status.num_subtests;
|
||||
|
||||
if (condition)
|
||||
{
|
||||
++status.num_passes;
|
||||
}
|
||||
else
|
||||
{
|
||||
++status.num_failures;
|
||||
if (condition)
|
||||
{
|
||||
++status.num_passes;
|
||||
}
|
||||
else
|
||||
{
|
||||
++status.num_failures;
|
||||
|
||||
// TODO: vprintf forwarding doesn't seem to work?
|
||||
network_printf("Subtest %lld failed in %s on line %d: ", status.num_subtests, file, line);
|
||||
network_vprintf(fail_msg, arglist);
|
||||
network_printf("\n");
|
||||
}
|
||||
va_end(arglist);
|
||||
// TODO: vprintf forwarding doesn't seem to work?
|
||||
network_printf("Subtest %lld failed in %s on line %d: ", status.num_subtests, file, line);
|
||||
network_vprintf(fail_msg, arglist);
|
||||
network_printf("\n");
|
||||
}
|
||||
va_end(arglist);
|
||||
}
|
||||
|
||||
void privEndTest()
|
||||
{
|
||||
if (0 == status.num_failures)
|
||||
{
|
||||
network_printf("Test %d passed (%lld subtests)\n", number_of_tests, status.num_subtests);
|
||||
}
|
||||
else
|
||||
{
|
||||
network_printf("Test %d failed (%lld subtests, %lld failures)\n", number_of_tests, status.num_subtests, status.num_failures);
|
||||
}
|
||||
if (0 == status.num_failures)
|
||||
{
|
||||
network_printf("Test %d passed (%lld subtests)\n", number_of_tests, status.num_subtests);
|
||||
}
|
||||
else
|
||||
{
|
||||
network_printf("Test %d failed (%lld subtests, %lld failures)\n", number_of_tests,
|
||||
status.num_subtests, status.num_failures);
|
||||
}
|
||||
}
|
||||
|
||||
void privSimpleTest(bool condition, const char* file, int line, const char* fail_msg, ...)
|
||||
{
|
||||
// TODO
|
||||
// TODO
|
||||
}
|
||||
|
||||
#define SERVER_PORT 16784
|
||||
|
||||
void network_init()
|
||||
{
|
||||
struct sockaddr_in my_name;
|
||||
struct sockaddr_in my_name;
|
||||
|
||||
my_name.sin_family = AF_INET;
|
||||
my_name.sin_port = htons(SERVER_PORT);
|
||||
my_name.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
my_name.sin_family = AF_INET;
|
||||
my_name.sin_port = htons(SERVER_PORT);
|
||||
my_name.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
|
||||
net_init();
|
||||
net_init();
|
||||
|
||||
server_socket = net_socket(AF_INET, SOCK_STREAM, 0);
|
||||
int yes = 1;
|
||||
net_setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
|
||||
server_socket = net_socket(AF_INET, SOCK_STREAM, 0);
|
||||
int yes = 1;
|
||||
net_setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
|
||||
|
||||
while(net_bind(server_socket, (struct sockaddr*)&my_name, sizeof(my_name)) < 0)
|
||||
{
|
||||
}
|
||||
while (net_bind(server_socket, (struct sockaddr*)&my_name, sizeof(my_name)) < 0)
|
||||
{
|
||||
}
|
||||
|
||||
net_listen(server_socket, 0);
|
||||
net_listen(server_socket, 0);
|
||||
|
||||
struct sockaddr_in client_info;
|
||||
socklen_t ssize = sizeof(client_info);
|
||||
client_socket = net_accept(server_socket, (struct sockaddr*)&client_info, &ssize);
|
||||
struct sockaddr_in client_info;
|
||||
socklen_t ssize = sizeof(client_info);
|
||||
client_socket = net_accept(server_socket, (struct sockaddr*)&client_info, &ssize);
|
||||
|
||||
network_printf("Hello world!\n");
|
||||
network_printf("Hello world!\n");
|
||||
}
|
||||
|
||||
void network_shutdown()
|
||||
{
|
||||
net_close(client_socket);
|
||||
net_close(server_socket);
|
||||
net_close(client_socket);
|
||||
net_close(server_socket);
|
||||
}
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <network.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SERVER_PORT 16784
|
||||
|
||||
#define START_TEST() privStartTest(__FILE__, __LINE__)
|
||||
#define DO_TEST(condition, fail_msg, ...) privDoTest(condition, __FILE__, __LINE__, fail_msg, ##__VA_ARGS__)
|
||||
#define DO_TEST(condition, fail_msg, ...) \
|
||||
privDoTest(condition, __FILE__, __LINE__, fail_msg, ##__VA_ARGS__)
|
||||
#define END_TEST() privEndTest()
|
||||
#define SIMPLE_TEST()
|
||||
|
||||
@@ -20,13 +21,13 @@ void privStartTest(const char* file, int line);
|
||||
void privDoTest(bool condition, const char* file, int line, const char* fail_msg, ...);
|
||||
void privEndTest();
|
||||
// TODO: Not implemented, yet
|
||||
//void privSimpleTest(bool condition, const char* file, int line, const char* fail_msg, ...);
|
||||
// void privSimpleTest(bool condition, const char* file, int line, const char* fail_msg, ...);
|
||||
|
||||
void network_init();
|
||||
void network_shutdown();
|
||||
void network_vprintf(const char* str, va_list args);
|
||||
void network_printf(const char* str, ...)
|
||||
#ifndef _MSC_VER
|
||||
__attribute__((__format__(printf, 1, 2)))
|
||||
__attribute__((__format__(printf, 1, 2)))
|
||||
#endif
|
||||
;
|
||||
;
|
||||
|
||||
@@ -5,44 +5,45 @@
|
||||
// Float Convert To Integer Word with round-to-Zero
|
||||
static void FctiwzTest()
|
||||
{
|
||||
START_TEST();
|
||||
u64 values[][2] = {
|
||||
// input expected output
|
||||
{0x0000000000000000, 0xfff8000000000000}, // +0
|
||||
{0x8000000000000000, 0xfff8000100000000}, // -0 (!)
|
||||
{0x0000000000000001, 0xfff8000000000000}, // smallest positive subnormal
|
||||
{0x000fffffffffffff, 0xfff8000000000000}, // largest subnormal
|
||||
{0x3ff0000000000000, 0xfff8000000000001}, // +1
|
||||
{0xbff0000000000000, 0xfff80000ffffffff}, // -1
|
||||
{0xc1e0000000000000, 0xfff8000080000000}, // -(2^31)
|
||||
{0x41dfffffffc00000, 0xfff800007fffffff}, // 2^31 - 1
|
||||
{0x7ff0000000000000, 0xfff800007fffffff}, // +infinity
|
||||
{0xfff0000000000000, 0xfff8000080000000}, // -infinity
|
||||
{0xfff8000000000000, 0xfff8000080000000}, // a QNaN
|
||||
{0xfff4000000000000, 0xfff8000080000000}, // a SNaN
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u64 input = values[i][0];
|
||||
u64 expected = values[i][1];
|
||||
u64 result = 0;
|
||||
asm("fctiwz %0, %1" : "=f" (result) : "f" (input));
|
||||
DO_TEST(result == expected, "fctiwz(0x%016llx):\n"
|
||||
" got 0x%016llx\n"
|
||||
"expected 0x%016llx", input, result, expected);
|
||||
}
|
||||
END_TEST();
|
||||
START_TEST();
|
||||
u64 values[][2] = {
|
||||
// input expected output
|
||||
{0x0000000000000000, 0xfff8000000000000}, // +0
|
||||
{0x8000000000000000, 0xfff8000100000000}, // -0 (!)
|
||||
{0x0000000000000001, 0xfff8000000000000}, // smallest positive subnormal
|
||||
{0x000fffffffffffff, 0xfff8000000000000}, // largest subnormal
|
||||
{0x3ff0000000000000, 0xfff8000000000001}, // +1
|
||||
{0xbff0000000000000, 0xfff80000ffffffff}, // -1
|
||||
{0xc1e0000000000000, 0xfff8000080000000}, // -(2^31)
|
||||
{0x41dfffffffc00000, 0xfff800007fffffff}, // 2^31 - 1
|
||||
{0x7ff0000000000000, 0xfff800007fffffff}, // +infinity
|
||||
{0xfff0000000000000, 0xfff8000080000000}, // -infinity
|
||||
{0xfff8000000000000, 0xfff8000080000000}, // a QNaN
|
||||
{0xfff4000000000000, 0xfff8000080000000}, // a SNaN
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u64 input = values[i][0];
|
||||
u64 expected = values[i][1];
|
||||
u64 result = 0;
|
||||
asm("fctiwz %0, %1" : "=f"(result) : "f"(input));
|
||||
DO_TEST(result == expected, "fctiwz(0x%016llx):\n"
|
||||
" got 0x%016llx\n"
|
||||
"expected 0x%016llx",
|
||||
input, result, expected);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
FctiwzTest();
|
||||
FctiwzTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,47 +6,48 @@
|
||||
// TODO: check ps1
|
||||
static void FrspTest()
|
||||
{
|
||||
START_TEST();
|
||||
u64 values[][3] = {
|
||||
// input expected output NI RN
|
||||
{0x0000000000000000, 0x0000000000000000, 0b000}, // +0
|
||||
{0x8000000000000000, 0x8000000000000000, 0b000}, // -0
|
||||
{0x0000000000000001, 0x0000000000000000, 0b000}, // smallest positive double subnormal
|
||||
{0x000fffffffffffff, 0x0000000000000000, 0b000}, // largest double subnormal
|
||||
{0x3690000000000000, 0x0000000000000000, 0b000}, // largest number rounded to zero
|
||||
{0x3690000000000001, 0x36a0000000000000, 0b000}, // smallest positive single subnormal
|
||||
{0x380fffffffffffff, 0x0000000000000000, 0b100}, // largest single subnormal
|
||||
{0x3810000000000000, 0x3810000000000000, 0b100}, // smallest positive single normal
|
||||
{0x7ff0000000000000, 0x7ff0000000000000, 0b000}, // +infinity
|
||||
{0xfff0000000000000, 0xfff0000000000000, 0b000}, // -infinity
|
||||
{0xfff7ffffffffffff, 0xfff7ffffe0000000, 0b000}, // a SNaN
|
||||
{0xffffffffffffffff, 0xffffffffe0000000, 0b000}, // a QNaN
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
// Set FPSCR[NI] and FPSCR[RN] (and FPSCR[XE] but that's okay).
|
||||
asm("mtfsf 7, %0" :: "f" (values[i][2]));
|
||||
START_TEST();
|
||||
u64 values[][3] = {
|
||||
// input expected output NI RN
|
||||
{0x0000000000000000, 0x0000000000000000, 0b000}, // +0
|
||||
{0x8000000000000000, 0x8000000000000000, 0b000}, // -0
|
||||
{0x0000000000000001, 0x0000000000000000, 0b000}, // smallest positive double subnormal
|
||||
{0x000fffffffffffff, 0x0000000000000000, 0b000}, // largest double subnormal
|
||||
{0x3690000000000000, 0x0000000000000000, 0b000}, // largest number rounded to zero
|
||||
{0x3690000000000001, 0x36a0000000000000, 0b000}, // smallest positive single subnormal
|
||||
{0x380fffffffffffff, 0x0000000000000000, 0b100}, // largest single subnormal
|
||||
{0x3810000000000000, 0x3810000000000000, 0b100}, // smallest positive single normal
|
||||
{0x7ff0000000000000, 0x7ff0000000000000, 0b000}, // +infinity
|
||||
{0xfff0000000000000, 0xfff0000000000000, 0b000}, // -infinity
|
||||
{0xfff7ffffffffffff, 0xfff7ffffe0000000, 0b000}, // a SNaN
|
||||
{0xffffffffffffffff, 0xffffffffe0000000, 0b000}, // a QNaN
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
// Set FPSCR[NI] and FPSCR[RN] (and FPSCR[XE] but that's okay).
|
||||
asm("mtfsf 7, %0" ::"f"(values[i][2]));
|
||||
|
||||
u64 input = values[i][0];
|
||||
u64 expected = values[i][1];
|
||||
u64 result = 0;
|
||||
asm("frsp %0, %1" : "=f" (result) : "f" (input));
|
||||
DO_TEST(result == expected, "frsp(0x%016llx, NI=%lld):\n"
|
||||
" got 0x%016llx\n"
|
||||
"expected 0x%016llx", input, values[i][2] >> 2, result, expected);
|
||||
}
|
||||
END_TEST();
|
||||
u64 input = values[i][0];
|
||||
u64 expected = values[i][1];
|
||||
u64 result = 0;
|
||||
asm("frsp %0, %1" : "=f"(result) : "f"(input));
|
||||
DO_TEST(result == expected, "frsp(0x%016llx, NI=%lld):\n"
|
||||
" got 0x%016llx\n"
|
||||
"expected 0x%016llx",
|
||||
input, values[i][2] >> 2, result, expected);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
FrspTest();
|
||||
FrspTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
701
cputest/load.cpp
701
cputest/load.cpp
@@ -4,478 +4,437 @@
|
||||
|
||||
static void lwzTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u32 values[] =
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0x00000000,
|
||||
0x41414141,
|
||||
0x11111111,
|
||||
};
|
||||
u32 values[] = {
|
||||
0xFFFFFFFF, 0x00000000, 0x41414141, 0x11111111,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lwz %0, 0(%1)" : "=r" (result) : "r" (address));
|
||||
DO_TEST(result == values[i], "lwz(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lwz %0, 0(%1)" : "=r"(result) : "r"(address));
|
||||
DO_TEST(result == values[i], "lwz(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lwzuTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u32 values[] =
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0x00000000,
|
||||
0x41414141,
|
||||
0x11111111,
|
||||
};
|
||||
u32 values[] = {
|
||||
0xFFFFFFFF, 0x00000000, 0x41414141, 0x11111111,
|
||||
};
|
||||
|
||||
#define CONST_LWZU(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u32 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
asm("lwzu %0, " #offset "(%1)" : "=r" (result) , "+r" (address)); \
|
||||
DO_TEST(result == values[index], "lwzu(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", index, result, values[index]); \
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lwzu(%d):\n" \
|
||||
"\tgot 0x%08x\n" \
|
||||
"\texpected 0x%08x", index, address, ((u32)&values[0] + offset)); \
|
||||
} while(0)
|
||||
#define CONST_LWZU(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u32 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
asm("lwzu %0, " #offset "(%1)" : "=r"(result), "+r"(address)); \
|
||||
DO_TEST(result == values[index], "lwzu(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", \
|
||||
index, result, values[index]); \
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lwzu(%d):\n" \
|
||||
"\tgot 0x%08x\n" \
|
||||
"\texpected 0x%08x", \
|
||||
index, address, ((u32)&values[0] + offset)); \
|
||||
} while (0)
|
||||
|
||||
CONST_LWZU(0, 0);
|
||||
CONST_LWZU(4, 1);
|
||||
CONST_LWZU(8, 2);
|
||||
CONST_LWZU(12, 3);
|
||||
END_TEST();
|
||||
CONST_LWZU(0, 0);
|
||||
CONST_LWZU(4, 1);
|
||||
CONST_LWZU(8, 2);
|
||||
CONST_LWZU(12, 3);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lwzxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u32 values[] =
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0x00000000,
|
||||
0x41414141,
|
||||
0x11111111,
|
||||
};
|
||||
u32 values[] = {
|
||||
0xFFFFFFFF, 0x00000000, 0x41414141, 0x11111111,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lwzx %0, %1, %2" : "=r" (result) , "+r" (offset) : "r" (address));
|
||||
DO_TEST(result == values[i], "lwzx(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lwzx %0, %1, %2" : "=r"(result), "+r"(offset) : "r"(address));
|
||||
DO_TEST(result == values[i], "lwzx(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lwzuxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u32 values[] =
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0x00000000,
|
||||
0x41414141,
|
||||
0x11111111,
|
||||
};
|
||||
u32 values[] = {
|
||||
0xFFFFFFFF, 0x00000000, 0x41414141, 0x11111111,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lwzux %0, %1, %2" : "=r" (result) , "+r" (offset) : "r" (address));
|
||||
DO_TEST(result == values[i], "lwzux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
DO_TEST(offset == (u32)&values[i], "lwzux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x", i, offset, (u32)&values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lwzux %0, %1, %2" : "=r"(result), "+r"(offset) : "r"(address));
|
||||
DO_TEST(result == values[i], "lwzux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
DO_TEST(offset == (u32)&values[i], "lwzux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x",
|
||||
i, offset, (u32)&values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhzTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u16 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lhz %0, 0(%1)" : "=r" (result) : "r" (address));
|
||||
DO_TEST(result == values[i], "lhz(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u16 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lhz %0, 0(%1)" : "=r"(result) : "r"(address));
|
||||
DO_TEST(result == values[i], "lhz(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhzxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u16 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lhzx %0, %1, %2" : "=r" (result) : "r" (address), "r" (offset));
|
||||
DO_TEST(result == values[i], "lhzx(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u16 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lhzx %0, %1, %2" : "=r"(result) : "r"(address), "r"(offset));
|
||||
DO_TEST(result == values[i], "lhzx(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhzuTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
|
||||
#define CONST_LHZU(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u16 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
asm("lhzu %0, " #offset "(%1)" : "=r" (result) , "+r" (address)); \
|
||||
DO_TEST(result == values[index], "lhzu(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", index, result, values[index]); \
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lhzu(%d):\n" \
|
||||
"\tgot 0x%08x\n" \
|
||||
"\texpected 0x%08x", index, address, ((u32)&values[0] + offset)); \
|
||||
} while(0)
|
||||
#define CONST_LHZU(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u16 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
asm("lhzu %0, " #offset "(%1)" : "=r"(result), "+r"(address)); \
|
||||
DO_TEST(result == values[index], "lhzu(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", \
|
||||
index, result, values[index]); \
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lhzu(%d):\n" \
|
||||
"\tgot 0x%08x\n" \
|
||||
"\texpected 0x%08x", \
|
||||
index, address, ((u32)&values[0] + offset)); \
|
||||
} while (0)
|
||||
|
||||
CONST_LHZU(0, 0);
|
||||
CONST_LHZU(2, 1);
|
||||
CONST_LHZU(4, 2);
|
||||
CONST_LHZU(6, 3);
|
||||
CONST_LHZU(8, 4);
|
||||
CONST_LHZU(10, 5);
|
||||
END_TEST();
|
||||
CONST_LHZU(0, 0);
|
||||
CONST_LHZU(2, 1);
|
||||
CONST_LHZU(4, 2);
|
||||
CONST_LHZU(6, 3);
|
||||
CONST_LHZU(8, 4);
|
||||
CONST_LHZU(10, 5);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhzuxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u16 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lhzux %0, %1, %2" : "=r" (result) , "+r" (offset) : "r" (address));
|
||||
DO_TEST(result == values[i], "lhzux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
DO_TEST(offset == (u32)&values[i], "lhzux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x", i, offset, (u32)&values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u16 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lhzux %0, %1, %2" : "=r"(result), "+r"(offset) : "r"(address));
|
||||
DO_TEST(result == values[i], "lhzux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
DO_TEST(offset == (u32)&values[i], "lhzux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x",
|
||||
i, offset, (u32)&values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhaTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
|
||||
#define CONST_LHA(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u32 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
u32 expected = (u32)(s32)(s16)values[index]; \
|
||||
asm("lha %0, " #offset "(%1)" : "=r" (result) , "+r" (address)); \
|
||||
DO_TEST(result == expected, "lha(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", index, result, expected); \
|
||||
} while(0)
|
||||
#define CONST_LHA(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u32 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
u32 expected = (u32)(s32)(s16)values[index]; \
|
||||
asm("lha %0, " #offset "(%1)" : "=r"(result), "+r"(address)); \
|
||||
DO_TEST(result == expected, "lha(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", \
|
||||
index, result, expected); \
|
||||
} while (0)
|
||||
|
||||
CONST_LHA(0, 0);
|
||||
CONST_LHA(2, 1);
|
||||
CONST_LHA(4, 2);
|
||||
CONST_LHA(6, 3);
|
||||
CONST_LHA(8, 4);
|
||||
CONST_LHA(10, 5);
|
||||
END_TEST();
|
||||
CONST_LHA(0, 0);
|
||||
CONST_LHA(2, 1);
|
||||
CONST_LHA(4, 2);
|
||||
CONST_LHA(6, 3);
|
||||
CONST_LHA(8, 4);
|
||||
CONST_LHA(10, 5);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhaxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
u32 expected = (u32)(s32)(s16)values[i];
|
||||
asm("lhax %0, %1, %2" : "=r" (result) : "r" (address), "r" (offset));
|
||||
DO_TEST(result == expected, "lhax(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, expected);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
u32 expected = (u32)(s32)(s16)values[i];
|
||||
asm("lhax %0, %1, %2" : "=r"(result) : "r"(address), "r"(offset));
|
||||
DO_TEST(result == expected, "lhax(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, expected);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhauTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
|
||||
#define CONST_LHAU(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u32 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
u32 expected = (u32)(s32)(s16)values[index]; \
|
||||
asm("lhau %0, " #offset "(%1)" : "=r" (result) , "+r" (address)); \
|
||||
DO_TEST(result == expected, "lhau(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", index, result, expected); \
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lhau(%d):\n" \
|
||||
"\tgot 0x%08x\n" \
|
||||
"\texpected 0x%08x", index, address, ((u32)&values[0] + offset)); \
|
||||
} while(0)
|
||||
#define CONST_LHAU(offset, index) \
|
||||
do \
|
||||
{ \
|
||||
u32 result = 0; \
|
||||
u32 address = (u32)&values[0]; \
|
||||
u32 expected = (u32)(s32)(s16)values[index]; \
|
||||
asm("lhau %0, " #offset "(%1)" : "=r"(result), "+r"(address)); \
|
||||
DO_TEST(result == expected, "lhau(%d):\n" \
|
||||
"\tgot %d\n" \
|
||||
"\texpected %d", \
|
||||
index, result, expected); \
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lhau(%d):\n" \
|
||||
"\tgot 0x%08x\n" \
|
||||
"\texpected 0x%08x", \
|
||||
index, address, ((u32)&values[0] + offset)); \
|
||||
} while (0)
|
||||
|
||||
CONST_LHAU(0, 0);
|
||||
CONST_LHAU(2, 1);
|
||||
CONST_LHAU(4, 2);
|
||||
CONST_LHAU(6, 3);
|
||||
CONST_LHAU(8, 4);
|
||||
CONST_LHAU(10, 5);
|
||||
END_TEST();
|
||||
CONST_LHAU(0, 0);
|
||||
CONST_LHAU(2, 1);
|
||||
CONST_LHAU(4, 2);
|
||||
CONST_LHAU(6, 3);
|
||||
CONST_LHAU(8, 4);
|
||||
CONST_LHAU(10, 5);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lhauxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u16 values[] =
|
||||
{
|
||||
0xFFFF,
|
||||
0xF000,
|
||||
0x0000,
|
||||
0x0F0F,
|
||||
0xF0F0,
|
||||
0x8888,
|
||||
};
|
||||
u16 values[] = {
|
||||
0xFFFF, 0xF000, 0x0000, 0x0F0F, 0xF0F0, 0x8888,
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
u32 expected = (u32)(s32)(s16)values[i];
|
||||
asm("lhaux %0, %1, %2" : "=r" (result) , "+r" (address) : "r" (offset));
|
||||
DO_TEST(result == expected, "lhaux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, expected);
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lhaux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x", i, offset, ((u32)&values[0] + offset));
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u32 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
u32 expected = (u32)(s32)(s16)values[i];
|
||||
asm("lhaux %0, %1, %2" : "=r"(result), "+r"(address) : "r"(offset));
|
||||
DO_TEST(result == expected, "lhaux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, expected);
|
||||
DO_TEST(address == ((u32)&values[0] + offset), "lhaux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x",
|
||||
i, offset, ((u32)&values[0] + offset));
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lbzTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lbz %0, 0(%1)" : "=r" (result) : "r" (address));
|
||||
DO_TEST(result == values[i], "lbz(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lbz %0, 0(%1)" : "=r"(result) : "r"(address));
|
||||
DO_TEST(result == values[i], "lbz(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lbzxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lbzx %0, %1, %2" : "=r" (result) : "r" (address), "r" (offset));
|
||||
DO_TEST(result == values[i], "lbzx(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lbzx %0, %1, %2" : "=r"(result) : "r"(address), "r"(offset));
|
||||
DO_TEST(result == values[i], "lbzx(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lbzuTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lbzu %0, 0(%1)" : "=r" (result) , "+r" (address));
|
||||
DO_TEST(result == values[i], "lbzu(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
DO_TEST(address == (u32)&values[i], "lbzu(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x", i, address, (u32)&values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[i];
|
||||
asm("lbzu %0, 0(%1)" : "=r"(result), "+r"(address));
|
||||
DO_TEST(result == values[i], "lbzu(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
DO_TEST(address == (u32)&values[i], "lbzu(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x",
|
||||
i, address, (u32)&values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void lbzuxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
u8 values[256];
|
||||
for (int i = 0; i < 256; ++i)
|
||||
values[i] = i;
|
||||
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lbzux %0, %1, %2" : "=r" (result) , "+r" (offset) : "r" (address));
|
||||
DO_TEST(result == values[i], "lbzux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d", i, result, values[i]);
|
||||
DO_TEST(offset == (u32)&values[i], "lbzux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x", i, offset, (u32)&values[i]);
|
||||
|
||||
}
|
||||
END_TEST();
|
||||
for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
{
|
||||
u8 result = 0;
|
||||
u32 address = (u32)&values[0];
|
||||
u32 offset = (u32)&values[i] - address;
|
||||
asm("lbzux %0, %1, %2" : "=r"(result), "+r"(offset) : "r"(address));
|
||||
DO_TEST(result == values[i], "lbzux(%d):\n"
|
||||
"\tgot %d\n"
|
||||
"\texpected %d",
|
||||
i, result, values[i]);
|
||||
DO_TEST(offset == (u32)&values[i], "lbzux(%d):\n"
|
||||
"\tgot 0x%08x\n"
|
||||
"\texpected 0x%08x",
|
||||
i, offset, (u32)&values[i]);
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
network_init();
|
||||
|
||||
lwzTest();
|
||||
lwzuTest();
|
||||
lwzxTest();
|
||||
lwzuxTest();
|
||||
lwzTest();
|
||||
lwzuTest();
|
||||
lwzxTest();
|
||||
lwzuxTest();
|
||||
|
||||
lhzTest();
|
||||
lhzxTest();
|
||||
lhzuTest();
|
||||
lhzuxTest();
|
||||
lhaTest();
|
||||
lhaxTest();
|
||||
lhauTest();
|
||||
lhauxTest();
|
||||
lhzTest();
|
||||
lhzxTest();
|
||||
lhzuTest();
|
||||
lhzuxTest();
|
||||
lhaTest();
|
||||
lhaxTest();
|
||||
lhauTest();
|
||||
lhauxTest();
|
||||
|
||||
lbzTest();
|
||||
lbzxTest();
|
||||
lbzuTest();
|
||||
lbzuxTest();
|
||||
lbzTest();
|
||||
lbzxTest();
|
||||
lbzuTest();
|
||||
lbzuxTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -7,49 +7,45 @@
|
||||
// Some games do this (e.g. Dirt 2) and rely on correct emulation behavior.
|
||||
static void GQRUnusedBitsTest()
|
||||
{
|
||||
START_TEST();
|
||||
uint32_t output;
|
||||
// based on hwtest on Wii
|
||||
uint32_t expected = 0xFFFFFFFF;
|
||||
asm(
|
||||
"li %0, -1;"
|
||||
"mtspr 914, %0;"
|
||||
"mfspr %0, 914;"
|
||||
: "=r"(output)
|
||||
);
|
||||
START_TEST();
|
||||
uint32_t output;
|
||||
// based on hwtest on Wii
|
||||
uint32_t expected = 0xFFFFFFFF;
|
||||
asm("li %0, -1;"
|
||||
"mtspr 914, %0;"
|
||||
"mfspr %0, 914;"
|
||||
: "=r"(output));
|
||||
|
||||
DO_TEST(output == expected, "got %x, expected %x", output, expected);
|
||||
END_TEST();
|
||||
DO_TEST(output == expected, "got %x, expected %x", output, expected);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
// Check what the Broadway does if we set reserved bits in the XER (fixed-point exception) register.
|
||||
static void XERUnusedBitsTest()
|
||||
{
|
||||
START_TEST();
|
||||
uint32_t output;
|
||||
// based on hwtest on Wii
|
||||
uint32_t expected = 0xE000FF7F;
|
||||
asm(
|
||||
"li %0, -1;"
|
||||
"mtspr 1, %0;"
|
||||
"mfspr %0, 1;"
|
||||
: "=r"(output)
|
||||
);
|
||||
START_TEST();
|
||||
uint32_t output;
|
||||
// based on hwtest on Wii
|
||||
uint32_t expected = 0xE000FF7F;
|
||||
asm("li %0, -1;"
|
||||
"mtspr 1, %0;"
|
||||
"mfspr %0, 1;"
|
||||
: "=r"(output));
|
||||
|
||||
DO_TEST(output == expected, "got %x, expected %x", output, expected);
|
||||
END_TEST();
|
||||
DO_TEST(output == expected, "got %x, expected %x", output, expected);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
GQRUnusedBitsTest();
|
||||
XERUnusedBitsTest();
|
||||
GQRUnusedBitsTest();
|
||||
XERUnusedBitsTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -14,195 +14,183 @@
|
||||
|
||||
static double fres_expected(double val)
|
||||
{
|
||||
static const int estimate_base[] = {
|
||||
0x7ff800, 0x783800, 0x70ea00, 0x6a0800,
|
||||
0x638800, 0x5d6200, 0x579000, 0x520800,
|
||||
0x4cc800, 0x47ca00, 0x430800, 0x3e8000,
|
||||
0x3a2c00, 0x360800, 0x321400, 0x2e4a00,
|
||||
0x2aa800, 0x272c00, 0x23d600, 0x209e00,
|
||||
0x1d8800, 0x1a9000, 0x17ae00, 0x14f800,
|
||||
0x124400, 0x0fbe00, 0x0d3800, 0x0ade00,
|
||||
0x088400, 0x065000, 0x041c00, 0x020c00,
|
||||
};
|
||||
static const int estimate_dec[] = {
|
||||
0x3e1, 0x3a7, 0x371, 0x340,
|
||||
0x313, 0x2ea, 0x2c4, 0x2a0,
|
||||
0x27f, 0x261, 0x245, 0x22a,
|
||||
0x212, 0x1fb, 0x1e5, 0x1d1,
|
||||
0x1be, 0x1ac, 0x19b, 0x18b,
|
||||
0x17c, 0x16e, 0x15b, 0x15b,
|
||||
0x143, 0x143, 0x12d, 0x12d,
|
||||
0x11a, 0x11a, 0x108, 0x106,
|
||||
};
|
||||
static const int estimate_base[] = {
|
||||
0x7ff800, 0x783800, 0x70ea00, 0x6a0800, 0x638800, 0x5d6200, 0x579000, 0x520800,
|
||||
0x4cc800, 0x47ca00, 0x430800, 0x3e8000, 0x3a2c00, 0x360800, 0x321400, 0x2e4a00,
|
||||
0x2aa800, 0x272c00, 0x23d600, 0x209e00, 0x1d8800, 0x1a9000, 0x17ae00, 0x14f800,
|
||||
0x124400, 0x0fbe00, 0x0d3800, 0x0ade00, 0x088400, 0x065000, 0x041c00, 0x020c00,
|
||||
};
|
||||
static const int estimate_dec[] = {
|
||||
0x3e1, 0x3a7, 0x371, 0x340, 0x313, 0x2ea, 0x2c4, 0x2a0, 0x27f, 0x261, 0x245,
|
||||
0x22a, 0x212, 0x1fb, 0x1e5, 0x1d1, 0x1be, 0x1ac, 0x19b, 0x18b, 0x17c, 0x16e,
|
||||
0x15b, 0x15b, 0x143, 0x143, 0x12d, 0x12d, 0x11a, 0x11a, 0x108, 0x106,
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
double valf;
|
||||
s64 vali;
|
||||
};
|
||||
valf = val;
|
||||
s64 mantissa = vali & ((1LL << 52) - 1);
|
||||
s64 sign = vali & (1ULL << 63);
|
||||
s64 exponent = vali & (0x7FFLL << 52);
|
||||
union
|
||||
{
|
||||
double valf;
|
||||
s64 vali;
|
||||
};
|
||||
valf = val;
|
||||
s64 mantissa = vali & ((1LL << 52) - 1);
|
||||
s64 sign = vali & (1ULL << 63);
|
||||
s64 exponent = vali & (0x7FFLL << 52);
|
||||
|
||||
// Special case 0
|
||||
if (mantissa == 0 && exponent == 0)
|
||||
return sign ? -std::numeric_limits<double>::infinity() :
|
||||
std::numeric_limits<double>::infinity();
|
||||
// Special case NaN-ish numbers
|
||||
if (exponent == (0x7FFLL << 52))
|
||||
{
|
||||
if (mantissa == 0)
|
||||
return sign ? -0.0 : 0.0;
|
||||
return 0.0 + valf;
|
||||
}
|
||||
// Special case small inputs
|
||||
if (exponent < (895LL << 52))
|
||||
return sign ? -FLT_MAX : FLT_MAX;
|
||||
// Special case large inputs
|
||||
if (exponent >= (1149LL << 52))
|
||||
return sign ? -0.0f : 0.0f;
|
||||
// Special case 0
|
||||
if (mantissa == 0 && exponent == 0)
|
||||
return sign ? -std::numeric_limits<double>::infinity() :
|
||||
std::numeric_limits<double>::infinity();
|
||||
// Special case NaN-ish numbers
|
||||
if (exponent == (0x7FFLL << 52))
|
||||
{
|
||||
if (mantissa == 0)
|
||||
return sign ? -0.0 : 0.0;
|
||||
return 0.0 + valf;
|
||||
}
|
||||
// Special case small inputs
|
||||
if (exponent < (895LL << 52))
|
||||
return sign ? -FLT_MAX : FLT_MAX;
|
||||
// Special case large inputs
|
||||
if (exponent >= (1149LL << 52))
|
||||
return sign ? -0.0f : 0.0f;
|
||||
|
||||
exponent = (0x7FDLL << 52) - exponent;
|
||||
exponent = (0x7FDLL << 52) - exponent;
|
||||
|
||||
int i = (int)(mantissa >> 37);
|
||||
vali = sign | exponent;
|
||||
vali |= (s64)(estimate_base[i / 1024] - (estimate_dec[i / 1024] * (i % 1024) + 1) / 2) << 29;
|
||||
return valf;
|
||||
int i = (int)(mantissa >> 37);
|
||||
vali = sign | exponent;
|
||||
vali |= (s64)(estimate_base[i / 1024] - (estimate_dec[i / 1024] * (i % 1024) + 1) / 2) << 29;
|
||||
return valf;
|
||||
}
|
||||
|
||||
static double frsqrte_expected(double val)
|
||||
{
|
||||
static const int estimate_base[] = {
|
||||
0x3ffa000, 0x3c29000, 0x38aa000, 0x3572000,
|
||||
0x3279000, 0x2fb7000, 0x2d26000, 0x2ac0000,
|
||||
0x2881000, 0x2665000, 0x2468000, 0x2287000,
|
||||
0x20c1000, 0x1f12000, 0x1d79000, 0x1bf4000,
|
||||
0x1a7e800, 0x17cb800, 0x1552800, 0x130c000,
|
||||
0x10f2000, 0x0eff000, 0x0d2e000, 0x0b7c000,
|
||||
0x09e5000, 0x0867000, 0x06ff000, 0x05ab800,
|
||||
0x046a000, 0x0339800, 0x0218800, 0x0105800,
|
||||
};
|
||||
static const int estimate_dec[] = {
|
||||
0x7a4, 0x700, 0x670, 0x5f2,
|
||||
0x584, 0x524, 0x4cc, 0x47e,
|
||||
0x43a, 0x3fa, 0x3c2, 0x38e,
|
||||
0x35e, 0x332, 0x30a, 0x2e6,
|
||||
0x568, 0x4f3, 0x48d, 0x435,
|
||||
0x3e7, 0x3a2, 0x365, 0x32e,
|
||||
0x2fc, 0x2d0, 0x2a8, 0x283,
|
||||
0x261, 0x243, 0x226, 0x20b,
|
||||
};
|
||||
static const int estimate_base[] = {
|
||||
0x3ffa000, 0x3c29000, 0x38aa000, 0x3572000, 0x3279000, 0x2fb7000, 0x2d26000, 0x2ac0000,
|
||||
0x2881000, 0x2665000, 0x2468000, 0x2287000, 0x20c1000, 0x1f12000, 0x1d79000, 0x1bf4000,
|
||||
0x1a7e800, 0x17cb800, 0x1552800, 0x130c000, 0x10f2000, 0x0eff000, 0x0d2e000, 0x0b7c000,
|
||||
0x09e5000, 0x0867000, 0x06ff000, 0x05ab800, 0x046a000, 0x0339800, 0x0218800, 0x0105800,
|
||||
};
|
||||
static const int estimate_dec[] = {
|
||||
0x7a4, 0x700, 0x670, 0x5f2, 0x584, 0x524, 0x4cc, 0x47e, 0x43a, 0x3fa, 0x3c2,
|
||||
0x38e, 0x35e, 0x332, 0x30a, 0x2e6, 0x568, 0x4f3, 0x48d, 0x435, 0x3e7, 0x3a2,
|
||||
0x365, 0x32e, 0x2fc, 0x2d0, 0x2a8, 0x283, 0x261, 0x243, 0x226, 0x20b,
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
double valf;
|
||||
s64 vali;
|
||||
};
|
||||
valf = val;
|
||||
s64 mantissa = vali & ((1LL << 52) - 1);
|
||||
s64 sign = vali & (1ULL << 63);
|
||||
s64 exponent = vali & (0x7FFLL << 52);
|
||||
union
|
||||
{
|
||||
double valf;
|
||||
s64 vali;
|
||||
};
|
||||
valf = val;
|
||||
s64 mantissa = vali & ((1LL << 52) - 1);
|
||||
s64 sign = vali & (1ULL << 63);
|
||||
s64 exponent = vali & (0x7FFLL << 52);
|
||||
|
||||
// Special case 0
|
||||
if (mantissa == 0 && exponent == 0)
|
||||
return sign ? -std::numeric_limits<double>::infinity() :
|
||||
std::numeric_limits<double>::infinity();
|
||||
// Special case NaN-ish numbers
|
||||
if (exponent == (0x7FFLL << 52))
|
||||
{
|
||||
if (mantissa == 0)
|
||||
{
|
||||
if (sign)
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
return 0.0;
|
||||
}
|
||||
return 0.0 + valf;
|
||||
}
|
||||
// Negative numbers return NaN
|
||||
if (sign)
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
// Special case 0
|
||||
if (mantissa == 0 && exponent == 0)
|
||||
return sign ? -std::numeric_limits<double>::infinity() :
|
||||
std::numeric_limits<double>::infinity();
|
||||
// Special case NaN-ish numbers
|
||||
if (exponent == (0x7FFLL << 52))
|
||||
{
|
||||
if (mantissa == 0)
|
||||
{
|
||||
if (sign)
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
return 0.0;
|
||||
}
|
||||
return 0.0 + valf;
|
||||
}
|
||||
// Negative numbers return NaN
|
||||
if (sign)
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
|
||||
if (!exponent)
|
||||
{
|
||||
// "Normalize" denormal values
|
||||
do
|
||||
{
|
||||
exponent -= 1LL << 52;
|
||||
mantissa <<= 1;
|
||||
} while (!(mantissa & (1LL << 52)));
|
||||
mantissa &= (1LL << 52) - 1;
|
||||
exponent += 1LL << 52;
|
||||
}
|
||||
if (!exponent)
|
||||
{
|
||||
// "Normalize" denormal values
|
||||
do
|
||||
{
|
||||
exponent -= 1LL << 52;
|
||||
mantissa <<= 1;
|
||||
} while (!(mantissa & (1LL << 52)));
|
||||
mantissa &= (1LL << 52) - 1;
|
||||
exponent += 1LL << 52;
|
||||
}
|
||||
|
||||
bool odd_exponent = !(exponent & (1LL << 52));
|
||||
exponent = ((0x3FFLL << 52) - ((exponent - (0x3FELL << 52)) / 2)) & (0x7FFLL << 52);
|
||||
bool odd_exponent = !(exponent & (1LL << 52));
|
||||
exponent = ((0x3FFLL << 52) - ((exponent - (0x3FELL << 52)) / 2)) & (0x7FFLL << 52);
|
||||
|
||||
int i = (int)(mantissa >> 37);
|
||||
vali = sign | exponent;
|
||||
int index = i / 2048 + (odd_exponent ? 16 : 0);
|
||||
vali |= (s64)(estimate_base[index] - estimate_dec[index] * (i % 2048)) << 26;
|
||||
return valf;
|
||||
int i = (int)(mantissa >> 37);
|
||||
vali = sign | exponent;
|
||||
int index = i / 2048 + (odd_exponent ? 16 : 0);
|
||||
vali |= (s64)(estimate_base[index] - estimate_dec[index] * (i % 2048)) << 26;
|
||||
return valf;
|
||||
}
|
||||
|
||||
static inline double
|
||||
fres_intrinsic(double val)
|
||||
static inline double fres_intrinsic(double val)
|
||||
{
|
||||
double estimate;
|
||||
__asm__("fres %0,%1"
|
||||
/* outputs: */ : "=f" (estimate)
|
||||
/* inputs: */ : "f" (val));
|
||||
return estimate;
|
||||
double estimate;
|
||||
__asm__("fres %0,%1"
|
||||
/* outputs: */
|
||||
: "=f"(estimate)
|
||||
/* inputs: */
|
||||
: "f"(val));
|
||||
return estimate;
|
||||
}
|
||||
|
||||
static void ReciprocalTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
for (unsigned long long i = 0; i < 0x100000000LL; i += 1)
|
||||
{
|
||||
union {
|
||||
long long testi;
|
||||
double testf;
|
||||
};
|
||||
union {
|
||||
double expectedf;
|
||||
long long expectedi;
|
||||
};
|
||||
testi = i << 32;
|
||||
expectedf = frsqrte_expected(testf);
|
||||
testf = __frsqrte(testf);
|
||||
DO_TEST(testi == expectedi, "Bad frsqrte %lld %.10f %llx %.10f %llx", i, testf, testi, expectedf, expectedi);
|
||||
if (testi != expectedi) break;
|
||||
for (unsigned long long i = 0; i < 0x100000000LL; i += 1)
|
||||
{
|
||||
union
|
||||
{
|
||||
long long testi;
|
||||
double testf;
|
||||
};
|
||||
union
|
||||
{
|
||||
double expectedf;
|
||||
long long expectedi;
|
||||
};
|
||||
testi = i << 32;
|
||||
expectedf = frsqrte_expected(testf);
|
||||
testf = __frsqrte(testf);
|
||||
DO_TEST(testi == expectedi, "Bad frsqrte %lld %.10f %llx %.10f %llx", i, testf, testi,
|
||||
expectedf, expectedi);
|
||||
if (testi != expectedi)
|
||||
break;
|
||||
|
||||
testi = i << 32;
|
||||
expectedf = fres_expected(testf);
|
||||
testf = fres_intrinsic(testf);
|
||||
DO_TEST(testi == expectedi, "Bad fres %lld %.10f %llx %.10f %llx", i, testf, testi, expectedf, expectedi);
|
||||
if (testi != expectedi) break;
|
||||
testi = i << 32;
|
||||
expectedf = fres_expected(testf);
|
||||
testf = fres_intrinsic(testf);
|
||||
DO_TEST(testi == expectedi, "Bad fres %lld %.10f %llx %.10f %llx", i, testf, testi, expectedf,
|
||||
expectedi);
|
||||
if (testi != expectedi)
|
||||
break;
|
||||
|
||||
if (!(i & ((1 << 22) - 1)))
|
||||
{
|
||||
network_printf("Progress %lld\n", i);
|
||||
WPAD_ScanPads();
|
||||
if (!(i & ((1 << 22) - 1)))
|
||||
{
|
||||
network_printf("Progress %lld\n", i);
|
||||
WPAD_ScanPads();
|
||||
|
||||
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_TEST();
|
||||
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
|
||||
break;
|
||||
}
|
||||
}
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
ReciprocalTest();
|
||||
ReciprocalTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
340
cputest/rlw.cpp
340
cputest/rlw.cpp
@@ -9,208 +9,194 @@
|
||||
// Copied from Dolphin's Interpreter integer operations.
|
||||
static u32 GetHelperMask(int mb, int me)
|
||||
{
|
||||
// first make 001111111111111 part
|
||||
// then make 000000000001111 part, which is used to flip the bits of the first one
|
||||
// do the bitflip
|
||||
// and invert if backwards
|
||||
u32 begin = 0xFFFFFFFF >> mb;
|
||||
u32 end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0;
|
||||
u32 mask = begin ^ end;
|
||||
if (me < mb)
|
||||
return ~mask;
|
||||
else
|
||||
return mask;
|
||||
// first make 001111111111111 part
|
||||
// then make 000000000001111 part, which is used to flip the bits of the first one
|
||||
// do the bitflip
|
||||
// and invert if backwards
|
||||
u32 begin = 0xFFFFFFFF >> mb;
|
||||
u32 end = me < 31 ? (0xFFFFFFFF >> (me + 1)) : 0;
|
||||
u32 mask = begin ^ end;
|
||||
if (me < mb)
|
||||
return ~mask;
|
||||
else
|
||||
return mask;
|
||||
}
|
||||
|
||||
static void rlwimixTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u32 values[][2] =
|
||||
{
|
||||
{0xFFFFFFFF, 0x41414141},
|
||||
{0x44444444, 0xFFFFFFFF},
|
||||
{0x41414141, 0x22222222},
|
||||
};
|
||||
u32 values[][2] = {
|
||||
{0xFFFFFFFF, 0x41414141}, {0x44444444, 0xFFFFFFFF}, {0x41414141, 0x22222222},
|
||||
};
|
||||
|
||||
#define RLWIMIX_TEST(sh, mb, me) \
|
||||
do { \
|
||||
for (int i = 0; i < (sizeof(values) / sizeof(values[0])); ++i)\
|
||||
{ \
|
||||
u32 mask = GetHelperMask(mb, me); \
|
||||
u32 computed_result = (values[i][0] & ~mask) | (_rotl(values[i][1], sh) & mask); \
|
||||
\
|
||||
u32 valueA = values[i][0]; \
|
||||
u32 valueS = values[i][1]; \
|
||||
\
|
||||
asm ("rlwimi %0, %1, " #sh ", " #mb ", " #me \
|
||||
: "+r" (valueA) \
|
||||
: "r" (valueS)); \
|
||||
DO_TEST(valueA == computed_result, "rlwimi %08x, %08x, " #sh ", " #mb ", " #me "\n" \
|
||||
"\tgot: %08x\n" \
|
||||
"\texpected: %08x\n", values[i][0], values[i][1], valueA, computed_result); \
|
||||
} \
|
||||
} while(0)
|
||||
#define RLWIMIX_TEST(sh, mb, me) \
|
||||
do \
|
||||
{ \
|
||||
for (int i = 0; i < (sizeof(values) / sizeof(values[0])); ++i) \
|
||||
{ \
|
||||
u32 mask = GetHelperMask(mb, me); \
|
||||
u32 computed_result = (values[i][0] & ~mask) | (_rotl(values[i][1], sh) & mask); \
|
||||
\
|
||||
u32 valueA = values[i][0]; \
|
||||
u32 valueS = values[i][1]; \
|
||||
\
|
||||
asm("rlwimi %0, %1, " #sh ", " #mb ", " #me : "+r"(valueA) : "r"(valueS)); \
|
||||
DO_TEST(valueA == computed_result, "rlwimi %08x, %08x, " #sh ", " #mb ", " #me "\n" \
|
||||
"\tgot: %08x\n" \
|
||||
"\texpected: %08x\n", \
|
||||
values[i][0], values[i][1], valueA, computed_result); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
RLWIMIX_TEST(0, 0, 0);
|
||||
RLWIMIX_TEST(0, 0, 15);
|
||||
RLWIMIX_TEST(0, 0, 31);
|
||||
RLWIMIX_TEST(0, 15, 0);
|
||||
RLWIMIX_TEST(0, 15, 15);
|
||||
RLWIMIX_TEST(0, 15, 31);
|
||||
RLWIMIX_TEST(0, 31, 0);
|
||||
RLWIMIX_TEST(15, 0, 0);
|
||||
RLWIMIX_TEST(15, 0, 15);
|
||||
RLWIMIX_TEST(15, 0, 31);
|
||||
RLWIMIX_TEST(15, 15, 0);
|
||||
RLWIMIX_TEST(15, 15, 15);
|
||||
RLWIMIX_TEST(15, 15, 31);
|
||||
RLWIMIX_TEST(15, 31, 0);
|
||||
RLWIMIX_TEST(15, 31, 15);
|
||||
RLWIMIX_TEST(15, 31, 31);
|
||||
RLWIMIX_TEST(31, 0, 0);
|
||||
RLWIMIX_TEST(31, 0, 15);
|
||||
RLWIMIX_TEST(31, 0, 31);
|
||||
RLWIMIX_TEST(31, 15, 0);
|
||||
RLWIMIX_TEST(31, 15, 15);
|
||||
RLWIMIX_TEST(31, 15, 31);
|
||||
RLWIMIX_TEST(31, 31, 0);
|
||||
RLWIMIX_TEST(31, 31, 15);
|
||||
RLWIMIX_TEST(31, 31, 31);
|
||||
END_TEST();
|
||||
RLWIMIX_TEST(0, 0, 0);
|
||||
RLWIMIX_TEST(0, 0, 15);
|
||||
RLWIMIX_TEST(0, 0, 31);
|
||||
RLWIMIX_TEST(0, 15, 0);
|
||||
RLWIMIX_TEST(0, 15, 15);
|
||||
RLWIMIX_TEST(0, 15, 31);
|
||||
RLWIMIX_TEST(0, 31, 0);
|
||||
RLWIMIX_TEST(15, 0, 0);
|
||||
RLWIMIX_TEST(15, 0, 15);
|
||||
RLWIMIX_TEST(15, 0, 31);
|
||||
RLWIMIX_TEST(15, 15, 0);
|
||||
RLWIMIX_TEST(15, 15, 15);
|
||||
RLWIMIX_TEST(15, 15, 31);
|
||||
RLWIMIX_TEST(15, 31, 0);
|
||||
RLWIMIX_TEST(15, 31, 15);
|
||||
RLWIMIX_TEST(15, 31, 31);
|
||||
RLWIMIX_TEST(31, 0, 0);
|
||||
RLWIMIX_TEST(31, 0, 15);
|
||||
RLWIMIX_TEST(31, 0, 31);
|
||||
RLWIMIX_TEST(31, 15, 0);
|
||||
RLWIMIX_TEST(31, 15, 15);
|
||||
RLWIMIX_TEST(31, 15, 31);
|
||||
RLWIMIX_TEST(31, 31, 0);
|
||||
RLWIMIX_TEST(31, 31, 15);
|
||||
RLWIMIX_TEST(31, 31, 31);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void rlwinmxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u32 values[] =
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0x44444444,
|
||||
0x41414141,
|
||||
0x12345678,
|
||||
0x90ABCDEF,
|
||||
};
|
||||
u32 values[] = {
|
||||
0xFFFFFFFF, 0x44444444, 0x41414141, 0x12345678, 0x90ABCDEF,
|
||||
};
|
||||
|
||||
#define RLWINMX_TEST(sh, mb, me) \
|
||||
do { \
|
||||
for (int i = 0; i < (sizeof(values) / sizeof(values[0])); ++i)\
|
||||
{ \
|
||||
u32 mask = GetHelperMask(mb, me); \
|
||||
u32 computed_result = _rotl(values[i], sh) & mask; \
|
||||
\
|
||||
u32 result = 0; \
|
||||
u32 valueS = values[i]; \
|
||||
\
|
||||
asm ("rlwinm %0, %1, " #sh ", " #mb ", " #me \
|
||||
: "=r" (result) \
|
||||
: "r" (valueS)); \
|
||||
DO_TEST(result == computed_result, "rlwinm %08x, " #sh ", " #mb ", " #me "\n" \
|
||||
"\tgot: %08x\n" \
|
||||
"\texpected: %08x\n", values[i], result, computed_result); \
|
||||
} \
|
||||
} while(0)
|
||||
#define RLWINMX_TEST(sh, mb, me) \
|
||||
do \
|
||||
{ \
|
||||
for (int i = 0; i < (sizeof(values) / sizeof(values[0])); ++i) \
|
||||
{ \
|
||||
u32 mask = GetHelperMask(mb, me); \
|
||||
u32 computed_result = _rotl(values[i], sh) & mask; \
|
||||
\
|
||||
u32 result = 0; \
|
||||
u32 valueS = values[i]; \
|
||||
\
|
||||
asm("rlwinm %0, %1, " #sh ", " #mb ", " #me : "=r"(result) : "r"(valueS)); \
|
||||
DO_TEST(result == computed_result, "rlwinm %08x, " #sh ", " #mb ", " #me "\n" \
|
||||
"\tgot: %08x\n" \
|
||||
"\texpected: %08x\n", \
|
||||
values[i], result, computed_result); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
RLWINMX_TEST(0, 0, 0);
|
||||
RLWINMX_TEST(0, 0, 15);
|
||||
RLWINMX_TEST(0, 0, 31);
|
||||
RLWINMX_TEST(0, 15, 0);
|
||||
RLWINMX_TEST(0, 15, 15);
|
||||
RLWINMX_TEST(0, 15, 31);
|
||||
RLWINMX_TEST(0, 31, 0);
|
||||
RLWINMX_TEST(15, 0, 0);
|
||||
RLWINMX_TEST(15, 0, 15);
|
||||
RLWINMX_TEST(15, 0, 31);
|
||||
RLWINMX_TEST(15, 15, 0);
|
||||
RLWINMX_TEST(15, 15, 15);
|
||||
RLWINMX_TEST(15, 15, 31);
|
||||
RLWINMX_TEST(15, 31, 0);
|
||||
RLWINMX_TEST(15, 31, 15);
|
||||
RLWINMX_TEST(15, 31, 31);
|
||||
RLWINMX_TEST(31, 0, 0);
|
||||
RLWINMX_TEST(31, 0, 15);
|
||||
RLWINMX_TEST(31, 0, 31);
|
||||
RLWINMX_TEST(31, 15, 0);
|
||||
RLWINMX_TEST(31, 15, 15);
|
||||
RLWINMX_TEST(31, 15, 31);
|
||||
RLWINMX_TEST(31, 31, 0);
|
||||
RLWINMX_TEST(31, 31, 15);
|
||||
RLWINMX_TEST(31, 31, 31);
|
||||
END_TEST();
|
||||
RLWINMX_TEST(0, 0, 0);
|
||||
RLWINMX_TEST(0, 0, 15);
|
||||
RLWINMX_TEST(0, 0, 31);
|
||||
RLWINMX_TEST(0, 15, 0);
|
||||
RLWINMX_TEST(0, 15, 15);
|
||||
RLWINMX_TEST(0, 15, 31);
|
||||
RLWINMX_TEST(0, 31, 0);
|
||||
RLWINMX_TEST(15, 0, 0);
|
||||
RLWINMX_TEST(15, 0, 15);
|
||||
RLWINMX_TEST(15, 0, 31);
|
||||
RLWINMX_TEST(15, 15, 0);
|
||||
RLWINMX_TEST(15, 15, 15);
|
||||
RLWINMX_TEST(15, 15, 31);
|
||||
RLWINMX_TEST(15, 31, 0);
|
||||
RLWINMX_TEST(15, 31, 15);
|
||||
RLWINMX_TEST(15, 31, 31);
|
||||
RLWINMX_TEST(31, 0, 0);
|
||||
RLWINMX_TEST(31, 0, 15);
|
||||
RLWINMX_TEST(31, 0, 31);
|
||||
RLWINMX_TEST(31, 15, 0);
|
||||
RLWINMX_TEST(31, 15, 15);
|
||||
RLWINMX_TEST(31, 15, 31);
|
||||
RLWINMX_TEST(31, 31, 0);
|
||||
RLWINMX_TEST(31, 31, 15);
|
||||
RLWINMX_TEST(31, 31, 31);
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
static void rlwnmxTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
u32 values[] =
|
||||
{
|
||||
0xFFFFFFFF,
|
||||
0x44444444,
|
||||
0x41414141,
|
||||
0x12345678,
|
||||
0x90ABCDEF,
|
||||
};
|
||||
u32 values[] = {
|
||||
0xFFFFFFFF, 0x44444444, 0x41414141, 0x12345678, 0x90ABCDEF,
|
||||
};
|
||||
|
||||
#define RLWNMX_TEST(mb, me) \
|
||||
do { \
|
||||
for (int sh = 0; sh < 32; ++sh) \
|
||||
for (int i = 0; i < (sizeof(values) / sizeof(values[0])); ++i)\
|
||||
{ \
|
||||
u32 mask = GetHelperMask(mb, me); \
|
||||
u32 computed_result = _rotl(values[i], sh & 0x1F) & mask; \
|
||||
\
|
||||
u32 result = 0; \
|
||||
u32 valueS = values[i]; \
|
||||
\
|
||||
asm ("rlwnm %0, %1, %2, " #mb ", " #me \
|
||||
: "=r" (result) \
|
||||
: "r" (valueS), \
|
||||
"r" (sh)); \
|
||||
DO_TEST(result == computed_result, "rlwnm %08x, %d, " #mb ", " #me "\n" \
|
||||
"\tgot: %08x\n" \
|
||||
"\texpected: %08x\n", values[i], sh, result, computed_result); \
|
||||
} \
|
||||
} while(0)
|
||||
#define RLWNMX_TEST(mb, me) \
|
||||
do \
|
||||
{ \
|
||||
for (int sh = 0; sh < 32; ++sh) \
|
||||
for (int i = 0; i < (sizeof(values) / sizeof(values[0])); ++i) \
|
||||
{ \
|
||||
u32 mask = GetHelperMask(mb, me); \
|
||||
u32 computed_result = _rotl(values[i], sh & 0x1F) & mask; \
|
||||
\
|
||||
u32 result = 0; \
|
||||
u32 valueS = values[i]; \
|
||||
\
|
||||
asm("rlwnm %0, %1, %2, " #mb ", " #me : "=r"(result) : "r"(valueS), "r"(sh)); \
|
||||
DO_TEST(result == computed_result, "rlwnm %08x, %d, " #mb ", " #me "\n" \
|
||||
"\tgot: %08x\n" \
|
||||
"\texpected: %08x\n", \
|
||||
values[i], sh, result, computed_result); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
RLWNMX_TEST(0, 0);
|
||||
RLWNMX_TEST(0, 7);
|
||||
RLWNMX_TEST(0, 15);
|
||||
RLWNMX_TEST(0, 23);
|
||||
RLWNMX_TEST(0, 31);
|
||||
RLWNMX_TEST(7, 0);
|
||||
RLWNMX_TEST(7, 7);
|
||||
RLWNMX_TEST(7, 15);
|
||||
RLWNMX_TEST(7, 23);
|
||||
RLWNMX_TEST(7, 31);
|
||||
RLWNMX_TEST(15, 0);
|
||||
RLWNMX_TEST(15, 7);
|
||||
RLWNMX_TEST(15, 15);
|
||||
RLWNMX_TEST(15, 23);
|
||||
RLWNMX_TEST(15, 31);
|
||||
RLWNMX_TEST(23, 0);
|
||||
RLWNMX_TEST(23, 7);
|
||||
RLWNMX_TEST(23, 15);
|
||||
RLWNMX_TEST(23, 23);
|
||||
RLWNMX_TEST(23, 31);
|
||||
RLWNMX_TEST(31, 0);
|
||||
RLWNMX_TEST(31, 7);
|
||||
RLWNMX_TEST(31, 15);
|
||||
RLWNMX_TEST(31, 23);
|
||||
RLWNMX_TEST(31, 31);
|
||||
END_TEST();
|
||||
RLWNMX_TEST(0, 0);
|
||||
RLWNMX_TEST(0, 7);
|
||||
RLWNMX_TEST(0, 15);
|
||||
RLWNMX_TEST(0, 23);
|
||||
RLWNMX_TEST(0, 31);
|
||||
RLWNMX_TEST(7, 0);
|
||||
RLWNMX_TEST(7, 7);
|
||||
RLWNMX_TEST(7, 15);
|
||||
RLWNMX_TEST(7, 23);
|
||||
RLWNMX_TEST(7, 31);
|
||||
RLWNMX_TEST(15, 0);
|
||||
RLWNMX_TEST(15, 7);
|
||||
RLWNMX_TEST(15, 15);
|
||||
RLWNMX_TEST(15, 23);
|
||||
RLWNMX_TEST(15, 31);
|
||||
RLWNMX_TEST(23, 0);
|
||||
RLWNMX_TEST(23, 7);
|
||||
RLWNMX_TEST(23, 15);
|
||||
RLWNMX_TEST(23, 23);
|
||||
RLWNMX_TEST(23, 31);
|
||||
RLWNMX_TEST(31, 0);
|
||||
RLWNMX_TEST(31, 7);
|
||||
RLWNMX_TEST(31, 15);
|
||||
RLWNMX_TEST(31, 23);
|
||||
RLWNMX_TEST(31, 31);
|
||||
END_TEST();
|
||||
}
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
network_init();
|
||||
|
||||
rlwimixTest();
|
||||
rlwinmxTest();
|
||||
rlwnmxTest();
|
||||
rlwimixTest();
|
||||
rlwinmxTest();
|
||||
rlwnmxTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,76 +1,77 @@
|
||||
#include <gctypes.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include "common/hwtests.h"
|
||||
|
||||
static int GetCarry(int value, int shift)
|
||||
{
|
||||
if (shift == 0) return 0;
|
||||
return (value < 0) && (((value >> shift) << shift) != value);
|
||||
if (shift == 0)
|
||||
return 0;
|
||||
return (value < 0) && (((value >> shift) << shift) != value);
|
||||
}
|
||||
|
||||
#define SRAWIX_TEST(shift)\
|
||||
do\
|
||||
{\
|
||||
for(int i = 0; i < 0x1000; i++)\
|
||||
{\
|
||||
s32 input = i ? rand() : INT_MIN;\
|
||||
s32 output = input;\
|
||||
s32 carry = 0;\
|
||||
asm(\
|
||||
"srawi %0, %0, %2;"\
|
||||
"addze %1, %1;"\
|
||||
: "+r"(output), "+r"(carry)\
|
||||
: "i"(shift)\
|
||||
);\
|
||||
DO_TEST(carry == GetCarry(input, shift), "(%x >> %d), got carry = %x, expected %x", input, shift, carry, GetCarry(input, shift));\
|
||||
DO_TEST(output == (input >> shift), "(%x >> %d), got %x, expected %x", input, shift, output, (input >> shift));\
|
||||
}\
|
||||
} while(0)
|
||||
#define SRAWIX_TEST(shift) \
|
||||
do \
|
||||
{ \
|
||||
for (int i = 0; i < 0x1000; i++) \
|
||||
{ \
|
||||
s32 input = i ? rand() : INT_MIN; \
|
||||
s32 output = input; \
|
||||
s32 carry = 0; \
|
||||
asm("srawi %0, %0, %2;" \
|
||||
"addze %1, %1;" \
|
||||
: "+r"(output), "+r"(carry) \
|
||||
: "i"(shift)); \
|
||||
DO_TEST(carry == GetCarry(input, shift), "(%x >> %d), got carry = %x, expected %x", input, \
|
||||
shift, carry, GetCarry(input, shift)); \
|
||||
DO_TEST(output == (input >> shift), "(%x >> %d), got %x, expected %x", input, shift, output, \
|
||||
(input >> shift)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
START_TEST();
|
||||
SRAWIX_TEST(0);
|
||||
SRAWIX_TEST(1);
|
||||
SRAWIX_TEST(2);
|
||||
SRAWIX_TEST(3);
|
||||
SRAWIX_TEST(4);
|
||||
SRAWIX_TEST(5);
|
||||
SRAWIX_TEST(6);
|
||||
SRAWIX_TEST(7);
|
||||
SRAWIX_TEST(8);
|
||||
SRAWIX_TEST(9);
|
||||
SRAWIX_TEST(10);
|
||||
SRAWIX_TEST(11);
|
||||
SRAWIX_TEST(12);
|
||||
SRAWIX_TEST(13);
|
||||
SRAWIX_TEST(14);
|
||||
SRAWIX_TEST(15);
|
||||
SRAWIX_TEST(16);
|
||||
SRAWIX_TEST(17);
|
||||
SRAWIX_TEST(18);
|
||||
SRAWIX_TEST(19);
|
||||
SRAWIX_TEST(20);
|
||||
SRAWIX_TEST(21);
|
||||
SRAWIX_TEST(22);
|
||||
SRAWIX_TEST(23);
|
||||
SRAWIX_TEST(24);
|
||||
SRAWIX_TEST(25);
|
||||
SRAWIX_TEST(26);
|
||||
SRAWIX_TEST(27);
|
||||
SRAWIX_TEST(28);
|
||||
SRAWIX_TEST(29);
|
||||
SRAWIX_TEST(30);
|
||||
SRAWIX_TEST(31);
|
||||
END_TEST();
|
||||
START_TEST();
|
||||
SRAWIX_TEST(0);
|
||||
SRAWIX_TEST(1);
|
||||
SRAWIX_TEST(2);
|
||||
SRAWIX_TEST(3);
|
||||
SRAWIX_TEST(4);
|
||||
SRAWIX_TEST(5);
|
||||
SRAWIX_TEST(6);
|
||||
SRAWIX_TEST(7);
|
||||
SRAWIX_TEST(8);
|
||||
SRAWIX_TEST(9);
|
||||
SRAWIX_TEST(10);
|
||||
SRAWIX_TEST(11);
|
||||
SRAWIX_TEST(12);
|
||||
SRAWIX_TEST(13);
|
||||
SRAWIX_TEST(14);
|
||||
SRAWIX_TEST(15);
|
||||
SRAWIX_TEST(16);
|
||||
SRAWIX_TEST(17);
|
||||
SRAWIX_TEST(18);
|
||||
SRAWIX_TEST(19);
|
||||
SRAWIX_TEST(20);
|
||||
SRAWIX_TEST(21);
|
||||
SRAWIX_TEST(22);
|
||||
SRAWIX_TEST(23);
|
||||
SRAWIX_TEST(24);
|
||||
SRAWIX_TEST(25);
|
||||
SRAWIX_TEST(26);
|
||||
SRAWIX_TEST(27);
|
||||
SRAWIX_TEST(28);
|
||||
SRAWIX_TEST(29);
|
||||
SRAWIX_TEST(30);
|
||||
SRAWIX_TEST(31);
|
||||
END_TEST();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
1324
gxtest/BPMemory.h
1324
gxtest/BPMemory.h
File diff suppressed because it is too large
Load Diff
@@ -11,304 +11,304 @@
|
||||
// Vertex array numbers
|
||||
enum
|
||||
{
|
||||
ARRAY_POSITION = 0,
|
||||
ARRAY_NORMAL = 1,
|
||||
ARRAY_COLOR = 2,
|
||||
ARRAY_COLOR2 = 3,
|
||||
ARRAY_TEXCOORD0 = 4,
|
||||
ARRAY_POSITION = 0,
|
||||
ARRAY_NORMAL = 1,
|
||||
ARRAY_COLOR = 2,
|
||||
ARRAY_COLOR2 = 3,
|
||||
ARRAY_TEXCOORD0 = 4,
|
||||
};
|
||||
|
||||
// Vertex components
|
||||
enum
|
||||
{
|
||||
NOT_PRESENT = 0,
|
||||
DIRECT = 1,
|
||||
INDEX8 = 2,
|
||||
INDEX16 = 3,
|
||||
NOT_PRESENT = 0,
|
||||
DIRECT = 1,
|
||||
INDEX8 = 2,
|
||||
INDEX16 = 3,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FORMAT_UBYTE = 0, // 2 Cmp
|
||||
FORMAT_BYTE = 1, // 3 Cmp
|
||||
FORMAT_USHORT = 2,
|
||||
FORMAT_SHORT = 3,
|
||||
FORMAT_FLOAT = 4,
|
||||
FORMAT_UBYTE = 0, // 2 Cmp
|
||||
FORMAT_BYTE = 1, // 3 Cmp
|
||||
FORMAT_USHORT = 2,
|
||||
FORMAT_SHORT = 3,
|
||||
FORMAT_FLOAT = 4,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FORMAT_16B_565 = 0, // NA
|
||||
FORMAT_24B_888 = 1,
|
||||
FORMAT_32B_888x = 2,
|
||||
FORMAT_16B_4444 = 3,
|
||||
FORMAT_24B_6666 = 4,
|
||||
FORMAT_32B_8888 = 5,
|
||||
FORMAT_16B_565 = 0, // NA
|
||||
FORMAT_24B_888 = 1,
|
||||
FORMAT_32B_888x = 2,
|
||||
FORMAT_16B_4444 = 3,
|
||||
FORMAT_24B_6666 = 4,
|
||||
FORMAT_32B_8888 = 5,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VAT_0_FRACBITS = 0x3e0001f0,
|
||||
VAT_1_FRACBITS = 0x07c3e1f0,
|
||||
VAT_2_FRACBITS = 0xf87c3e1f,
|
||||
VAT_0_FRACBITS = 0x3e0001f0,
|
||||
VAT_1_FRACBITS = 0x07c3e1f0,
|
||||
VAT_2_FRACBITS = 0xf87c3e1f,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VA_PTNMTXIDX = 0,
|
||||
VA_TEX0MTXIDX = 1,
|
||||
VA_TEX1MTXIDX = 2,
|
||||
VA_TEX2MTXIDX = 3,
|
||||
VA_TEX3MTXIDX = 4,
|
||||
VA_TEX4MTXIDX = 5,
|
||||
VA_TEX5MTXIDX = 6,
|
||||
VA_TEX6MTXIDX = 7,
|
||||
VA_TEX7MTXIDX = 8,
|
||||
VA_POS = 9,
|
||||
VA_NRM = 10,
|
||||
VA_CLR0 = 11,
|
||||
VA_CLR1 = 12,
|
||||
VA_TEX0 = 13,
|
||||
VA_TEX1 = 14,
|
||||
VA_TEX2 = 15,
|
||||
VA_TEX3 = 16,
|
||||
VA_TEX4 = 17,
|
||||
VA_TEX5 = 18,
|
||||
VA_TEX6 = 19,
|
||||
VA_TEX7 = 20,
|
||||
VA_POSMTXARRAY = 21,
|
||||
VA_NRMMTXARRAY = 22,
|
||||
VA_TEXMTXARRAY = 23,
|
||||
VA_LIGHTARRAY = 24,
|
||||
VA_NBT = 25,
|
||||
VA_MAXATTR = 26,
|
||||
VA_NULL = 0xff
|
||||
VA_PTNMTXIDX = 0,
|
||||
VA_TEX0MTXIDX = 1,
|
||||
VA_TEX1MTXIDX = 2,
|
||||
VA_TEX2MTXIDX = 3,
|
||||
VA_TEX3MTXIDX = 4,
|
||||
VA_TEX4MTXIDX = 5,
|
||||
VA_TEX5MTXIDX = 6,
|
||||
VA_TEX6MTXIDX = 7,
|
||||
VA_TEX7MTXIDX = 8,
|
||||
VA_POS = 9,
|
||||
VA_NRM = 10,
|
||||
VA_CLR0 = 11,
|
||||
VA_CLR1 = 12,
|
||||
VA_TEX0 = 13,
|
||||
VA_TEX1 = 14,
|
||||
VA_TEX2 = 15,
|
||||
VA_TEX3 = 16,
|
||||
VA_TEX4 = 17,
|
||||
VA_TEX5 = 18,
|
||||
VA_TEX6 = 19,
|
||||
VA_TEX7 = 20,
|
||||
VA_POSMTXARRAY = 21,
|
||||
VA_NRMMTXARRAY = 22,
|
||||
VA_TEXMTXARRAY = 23,
|
||||
VA_LIGHTARRAY = 24,
|
||||
VA_NBT = 25,
|
||||
VA_MAXATTR = 26,
|
||||
VA_NULL = 0xff
|
||||
};
|
||||
|
||||
// Vertex attribute component format
|
||||
enum
|
||||
{
|
||||
VA_FMT_U8 = 0,
|
||||
VA_FMT_S8 = 1,
|
||||
VA_FMT_U16 = 2,
|
||||
VA_FMT_S16 = 3,
|
||||
VA_FMT_F32 = 4
|
||||
VA_FMT_U8 = 0,
|
||||
VA_FMT_S8 = 1,
|
||||
VA_FMT_U16 = 2,
|
||||
VA_FMT_S16 = 3,
|
||||
VA_FMT_F32 = 4
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VA_FMT_RGB565 = 0,
|
||||
VA_FMT_RGB8 = 1,
|
||||
VA_FMT_RGBX8 = 2,
|
||||
VA_FMT_RGBA4 = 3,
|
||||
VA_FMT_RGBA6 = 4,
|
||||
VA_FMT_RGBA8 = 5
|
||||
VA_FMT_RGB565 = 0,
|
||||
VA_FMT_RGB8 = 1,
|
||||
VA_FMT_RGBX8 = 2,
|
||||
VA_FMT_RGBA4 = 3,
|
||||
VA_FMT_RGBA6 = 4,
|
||||
VA_FMT_RGBA8 = 5
|
||||
};
|
||||
|
||||
// Vertex attribute component types
|
||||
enum
|
||||
{
|
||||
VA_TYPE_POS_XY = 0,
|
||||
VA_TYPE_POS_XYZ = 1
|
||||
VA_TYPE_POS_XY = 0,
|
||||
VA_TYPE_POS_XYZ = 1
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VA_TYPE_NRM_XYZ = 0,
|
||||
VA_TYPE_NRM_NBT = 1,
|
||||
VA_TYPE_NRM_NBT3 = 2
|
||||
VA_TYPE_NRM_XYZ = 0,
|
||||
VA_TYPE_NRM_NBT = 1,
|
||||
VA_TYPE_NRM_NBT3 = 2
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VA_TYPE_CLR_RGB = 0,
|
||||
VA_TYPE_CLR_RGBA = 1,
|
||||
VA_TYPE_CLR_RGB = 0,
|
||||
VA_TYPE_CLR_RGBA = 1,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VA_TYPE_TEX_S = 0,
|
||||
VA_TYPE_TEX_ST = 1,
|
||||
VA_TYPE_TEX_S = 0,
|
||||
VA_TYPE_TEX_ST = 1,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
VTXATTR_NONE = 0,
|
||||
VTXATTR_DIRECT = 1,
|
||||
VTXATTR_INDEX8 = 2,
|
||||
VTXATTR_INDEX16 = 3
|
||||
VTXATTR_NONE = 0,
|
||||
VTXATTR_DIRECT = 1,
|
||||
VTXATTR_INDEX8 = 2,
|
||||
VTXATTR_INDEX16 = 3
|
||||
};
|
||||
|
||||
#pragma pack(4)
|
||||
union TVtxDesc
|
||||
{
|
||||
u64 Hex;
|
||||
u64 Hex;
|
||||
|
||||
BitField< 0,32,u64> Hex0;
|
||||
BitField<32,32,u64> Hex1;
|
||||
BitField<0, 32, u64> Hex0;
|
||||
BitField<32, 32, u64> Hex1;
|
||||
|
||||
// Note: Access to this array is not endianness-independent.
|
||||
u8 byte[8];
|
||||
// Note: Access to this array is not endianness-independent.
|
||||
u8 byte[8];
|
||||
|
||||
BitField<0,1,u64> PosMatIdx;
|
||||
BitField<1,1,u64> Tex0MatIdx;
|
||||
BitField<2,1,u64> Tex1MatIdx;
|
||||
BitField<3,1,u64> Tex2MatIdx;
|
||||
BitField<4,1,u64> Tex3MatIdx;
|
||||
BitField<5,1,u64> Tex4MatIdx;
|
||||
BitField<6,1,u64> Tex5MatIdx;
|
||||
BitField<7,1,u64> Tex6MatIdx;
|
||||
BitField<8,1,u64> Tex7MatIdx;
|
||||
BitField<9,2,u64> Position;
|
||||
BitField<11,2,u64> Normal;
|
||||
BitField<13,2,u64> Color0;
|
||||
BitField<15,2,u64> Color1;
|
||||
BitField<17,2,u64> Tex0Coord;
|
||||
BitField<19,2,u64> Tex1Coord;
|
||||
BitField<21,2,u64> Tex2Coord;
|
||||
BitField<23,2,u64> Tex3Coord;
|
||||
BitField<25,2,u64> Tex4Coord;
|
||||
BitField<27,2,u64> Tex5Coord;
|
||||
BitField<29,2,u64> Tex6Coord;
|
||||
BitField<31,2,u64> Tex7Coord;
|
||||
// 31 unused bits follow
|
||||
BitField<0, 1, u64> PosMatIdx;
|
||||
BitField<1, 1, u64> Tex0MatIdx;
|
||||
BitField<2, 1, u64> Tex1MatIdx;
|
||||
BitField<3, 1, u64> Tex2MatIdx;
|
||||
BitField<4, 1, u64> Tex3MatIdx;
|
||||
BitField<5, 1, u64> Tex4MatIdx;
|
||||
BitField<6, 1, u64> Tex5MatIdx;
|
||||
BitField<7, 1, u64> Tex6MatIdx;
|
||||
BitField<8, 1, u64> Tex7MatIdx;
|
||||
BitField<9, 2, u64> Position;
|
||||
BitField<11, 2, u64> Normal;
|
||||
BitField<13, 2, u64> Color0;
|
||||
BitField<15, 2, u64> Color1;
|
||||
BitField<17, 2, u64> Tex0Coord;
|
||||
BitField<19, 2, u64> Tex1Coord;
|
||||
BitField<21, 2, u64> Tex2Coord;
|
||||
BitField<23, 2, u64> Tex3Coord;
|
||||
BitField<25, 2, u64> Tex4Coord;
|
||||
BitField<27, 2, u64> Tex5Coord;
|
||||
BitField<29, 2, u64> Tex6Coord;
|
||||
BitField<31, 2, u64> Tex7Coord;
|
||||
// 31 unused bits follow
|
||||
};
|
||||
|
||||
union UVAT_group0
|
||||
{
|
||||
BitField<0,1,u32> PosElements;
|
||||
BitField<1,3,u32> PosFormat;
|
||||
BitField<4,5,u32> PosFrac;
|
||||
BitField<0, 1, u32> PosElements;
|
||||
BitField<1, 3, u32> PosFormat;
|
||||
BitField<4, 5, u32> PosFrac;
|
||||
|
||||
BitField<9,1,u32> NormalElements;
|
||||
BitField<10,3,u32> NormalFormat;
|
||||
BitField<9, 1, u32> NormalElements;
|
||||
BitField<10, 3, u32> NormalFormat;
|
||||
|
||||
BitField<13,1,u32> Color0Elements;
|
||||
BitField<14,3,u32> Color0Comp;
|
||||
BitField<13, 1, u32> Color0Elements;
|
||||
BitField<14, 3, u32> Color0Comp;
|
||||
|
||||
BitField<17,1,u32> Color1Elements;
|
||||
BitField<18,3,u32> Color1Comp;
|
||||
BitField<17, 1, u32> Color1Elements;
|
||||
BitField<18, 3, u32> Color1Comp;
|
||||
|
||||
BitField<21,1,u32> Tex0CoordElements;
|
||||
BitField<22,3,u32> Tex0CoordFormat;
|
||||
BitField<25,5,u32> Tex0Frac;
|
||||
BitField<21, 1, u32> Tex0CoordElements;
|
||||
BitField<22, 3, u32> Tex0CoordFormat;
|
||||
BitField<25, 5, u32> Tex0Frac;
|
||||
|
||||
BitField<30,1,u32> ByteDequant;
|
||||
BitField<31,1,u32> NormalIndex3;
|
||||
BitField<30, 1, u32> ByteDequant;
|
||||
BitField<31, 1, u32> NormalIndex3;
|
||||
|
||||
u32 Hex;
|
||||
u32 Hex;
|
||||
};
|
||||
|
||||
union UVAT_group1
|
||||
{
|
||||
BitField<0,1,u32> Tex1CoordElements;
|
||||
BitField<1,3,u32> Tex1CoordFormat;
|
||||
BitField<4,5,u32> Tex1Frac;
|
||||
BitField<0, 1, u32> Tex1CoordElements;
|
||||
BitField<1, 3, u32> Tex1CoordFormat;
|
||||
BitField<4, 5, u32> Tex1Frac;
|
||||
|
||||
BitField<9,1,u32> Tex2CoordElements;
|
||||
BitField<10,3,u32> Tex2CoordFormat;
|
||||
BitField<13,5,u32> Tex2Frac;
|
||||
BitField<9, 1, u32> Tex2CoordElements;
|
||||
BitField<10, 3, u32> Tex2CoordFormat;
|
||||
BitField<13, 5, u32> Tex2Frac;
|
||||
|
||||
BitField<18,1,u32> Tex3CoordElements;
|
||||
BitField<19,3,u32> Tex3CoordFormat;
|
||||
BitField<22,5,u32> Tex3Frac;
|
||||
BitField<18, 1, u32> Tex3CoordElements;
|
||||
BitField<19, 3, u32> Tex3CoordFormat;
|
||||
BitField<22, 5, u32> Tex3Frac;
|
||||
|
||||
BitField<27,1,u32> Tex4CoordElements;
|
||||
BitField<28,3,u32> Tex4CoordFormat;
|
||||
// 1 bit unused
|
||||
BitField<27, 1, u32> Tex4CoordElements;
|
||||
BitField<28, 3, u32> Tex4CoordFormat;
|
||||
// 1 bit unused
|
||||
|
||||
u32 Hex;
|
||||
u32 Hex;
|
||||
};
|
||||
|
||||
union UVAT_group2
|
||||
{
|
||||
BitField<0,5,u32> Tex4Frac;
|
||||
BitField<0, 5, u32> Tex4Frac;
|
||||
|
||||
BitField<5,1,u32> Tex5CoordElements;
|
||||
BitField<6,3,u32> Tex5CoordFormat;
|
||||
BitField<9,5,u32> Tex5Frac;
|
||||
BitField<5, 1, u32> Tex5CoordElements;
|
||||
BitField<6, 3, u32> Tex5CoordFormat;
|
||||
BitField<9, 5, u32> Tex5Frac;
|
||||
|
||||
BitField<14,1,u32> Tex6CoordElements;
|
||||
BitField<15,3,u32> Tex6CoordFormat;
|
||||
BitField<18,5,u32> Tex6Frac;
|
||||
BitField<14, 1, u32> Tex6CoordElements;
|
||||
BitField<15, 3, u32> Tex6CoordFormat;
|
||||
BitField<18, 5, u32> Tex6Frac;
|
||||
|
||||
BitField<23,1,u32> Tex7CoordElements;
|
||||
BitField<24,3,u32> Tex7CoordFormat;
|
||||
BitField<27,5,u32> Tex7Frac;
|
||||
BitField<23, 1, u32> Tex7CoordElements;
|
||||
BitField<24, 3, u32> Tex7CoordFormat;
|
||||
BitField<27, 5, u32> Tex7Frac;
|
||||
|
||||
u32 Hex;
|
||||
u32 Hex;
|
||||
};
|
||||
|
||||
struct ColorAttr
|
||||
{
|
||||
u8 Elements;
|
||||
u8 Comp;
|
||||
u8 Elements;
|
||||
u8 Comp;
|
||||
};
|
||||
|
||||
struct TexAttr
|
||||
{
|
||||
u8 Elements;
|
||||
u8 Format;
|
||||
u8 Frac;
|
||||
u8 Elements;
|
||||
u8 Format;
|
||||
u8 Frac;
|
||||
};
|
||||
|
||||
struct TVtxAttr
|
||||
{
|
||||
u8 PosElements;
|
||||
u8 PosFormat;
|
||||
u8 PosFrac;
|
||||
u8 NormalElements;
|
||||
u8 NormalFormat;
|
||||
ColorAttr color[2];
|
||||
TexAttr texCoord[8];
|
||||
u8 ByteDequant;
|
||||
u8 NormalIndex3;
|
||||
u8 PosElements;
|
||||
u8 PosFormat;
|
||||
u8 PosFrac;
|
||||
u8 NormalElements;
|
||||
u8 NormalFormat;
|
||||
ColorAttr color[2];
|
||||
TexAttr texCoord[8];
|
||||
u8 ByteDequant;
|
||||
u8 NormalIndex3;
|
||||
};
|
||||
|
||||
// Matrix indices
|
||||
union TMatrixIndexA
|
||||
{
|
||||
BitField<0,6,u32> PosNormalMtxIdx;
|
||||
BitField<6,6,u32> Tex0MtxIdx;
|
||||
BitField<12,6,u32> Tex1MtxIdx;
|
||||
BitField<18,6,u32> Tex2MtxIdx;
|
||||
BitField<24,6,u32> Tex3MtxIdx;
|
||||
BitField<0, 6, u32> PosNormalMtxIdx;
|
||||
BitField<6, 6, u32> Tex0MtxIdx;
|
||||
BitField<12, 6, u32> Tex1MtxIdx;
|
||||
BitField<18, 6, u32> Tex2MtxIdx;
|
||||
BitField<24, 6, u32> Tex3MtxIdx;
|
||||
|
||||
BitField<0,30,u32> Hex;
|
||||
BitField<0, 30, u32> Hex;
|
||||
};
|
||||
|
||||
union TMatrixIndexB
|
||||
{
|
||||
BitField<0,6,u32> Tex4MtxIdx;
|
||||
BitField<6,6,u32> Tex5MtxIdx;
|
||||
BitField<12,6,u32> Tex6MtxIdx;
|
||||
BitField<18,6,u32> Tex7MtxIdx;
|
||||
BitField<0, 6, u32> Tex4MtxIdx;
|
||||
BitField<6, 6, u32> Tex5MtxIdx;
|
||||
BitField<12, 6, u32> Tex6MtxIdx;
|
||||
BitField<18, 6, u32> Tex7MtxIdx;
|
||||
|
||||
BitField<0,24,u32> Hex;
|
||||
BitField<0, 24, u32> Hex;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
extern u32 arraybases[16];
|
||||
extern u8 *cached_arraybases[16];
|
||||
extern u8* cached_arraybases[16];
|
||||
extern u32 arraystrides[16];
|
||||
extern TMatrixIndexA MatrixIndexA;
|
||||
extern TMatrixIndexB MatrixIndexB;
|
||||
|
||||
struct VAT
|
||||
{
|
||||
UVAT_group0 g0;
|
||||
UVAT_group1 g1;
|
||||
UVAT_group2 g2;
|
||||
UVAT_group0 g0;
|
||||
UVAT_group1 g1;
|
||||
UVAT_group2 g2;
|
||||
};
|
||||
|
||||
extern TVtxDesc g_VtxDesc;
|
||||
extern VAT g_VtxAttr[8];
|
||||
|
||||
// Might move this into its own file later.
|
||||
//void LoadCPReg(u32 SubCmd, u32 Value);
|
||||
// void LoadCPReg(u32 SubCmd, u32 Value);
|
||||
|
||||
// Fills memory with data from CP regs
|
||||
//void FillCPMemoryArray(u32 *memory);
|
||||
// void FillCPMemoryArray(u32 *memory);
|
||||
|
||||
#endif // _CPMEMORY_H
|
||||
#endif // _CPMEMORY_H
|
||||
|
||||
@@ -6,18 +6,18 @@
|
||||
|
||||
union LitChannel
|
||||
{
|
||||
BitField<0,1,u32> matsource;
|
||||
BitField<1,1,u32> enablelighting;
|
||||
BitField<2,4,u32> lightMask0_3;
|
||||
BitField<6,1,u32> ambsource;
|
||||
BitField<7,2,u32> diffusefunc; // LIGHTDIF_X
|
||||
BitField<9,2,u32> attnfunc; // LIGHTATTN_X
|
||||
BitField<11,4,u32> lightMask4_7;
|
||||
// 17 bits unused
|
||||
BitField<0, 1, u32> matsource;
|
||||
BitField<1, 1, u32> enablelighting;
|
||||
BitField<2, 4, u32> lightMask0_3;
|
||||
BitField<6, 1, u32> ambsource;
|
||||
BitField<7, 2, u32> diffusefunc; // LIGHTDIF_X
|
||||
BitField<9, 2, u32> attnfunc; // LIGHTATTN_X
|
||||
BitField<11, 4, u32> lightMask4_7;
|
||||
// 17 bits unused
|
||||
|
||||
u32 hex;
|
||||
unsigned int GetFullLightMask() const
|
||||
{
|
||||
return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0;
|
||||
}
|
||||
u32 hex;
|
||||
unsigned int GetFullLightMask() const
|
||||
{
|
||||
return enablelighting ? (lightMask0_3 | (lightMask4_7 << 4)) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,56 +3,56 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <initializer_list>
|
||||
#include "common/hwtests.h"
|
||||
#include <math.h>
|
||||
#include <ogcsys.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include "common/hwtests.h"
|
||||
#include "gxtest/cgx.h"
|
||||
#include "gxtest/cgx_defaults.h"
|
||||
#include "gxtest/util.h"
|
||||
#include <ogcsys.h>
|
||||
|
||||
void BitfieldTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
TevReg reg;
|
||||
reg.hex = 0;
|
||||
reg.low = 0x345678;
|
||||
DO_TEST(reg.alpha == 837, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -392, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.low = 0x4BC6A8;
|
||||
DO_TEST(reg.alpha == -836, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -344, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.hex = 0;
|
||||
reg.alpha = -263;
|
||||
reg.red = -345;
|
||||
DO_TEST(reg.alpha == -263, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -345, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.alpha = 15;
|
||||
reg.red = -619;
|
||||
DO_TEST(reg.alpha == 15, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -619, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.alpha = 523;
|
||||
reg.red = 176;
|
||||
DO_TEST(reg.alpha == 523, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == 176, "Values don't match (have: %d)", (s32)reg.red);
|
||||
TevReg reg;
|
||||
reg.hex = 0;
|
||||
reg.low = 0x345678;
|
||||
DO_TEST(reg.alpha == 837, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -392, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.low = 0x4BC6A8;
|
||||
DO_TEST(reg.alpha == -836, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -344, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.hex = 0;
|
||||
reg.alpha = -263;
|
||||
reg.red = -345;
|
||||
DO_TEST(reg.alpha == -263, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -345, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.alpha = 15;
|
||||
reg.red = -619;
|
||||
DO_TEST(reg.alpha == 15, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == -619, "Values don't match (have: %d)", (s32)reg.red);
|
||||
reg.alpha = 523;
|
||||
reg.red = 176;
|
||||
DO_TEST(reg.alpha == 523, "Values don't match (have: %d)", (s32)reg.alpha);
|
||||
DO_TEST(reg.red == 176, "Values don't match (have: %d)", (s32)reg.red);
|
||||
|
||||
END_TEST();
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
GXTest::Init();
|
||||
GXTest::Init();
|
||||
|
||||
BitfieldTest();
|
||||
BitfieldTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
304
gxtest/cgx.cpp
304
gxtest/cgx.cpp
@@ -4,12 +4,12 @@
|
||||
|
||||
#include <assert.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <ogc/system.h>
|
||||
#include <ogc/cache.h>
|
||||
#include <ogc/gx.h>
|
||||
#include <ogc/irq.h>
|
||||
#include <ogc/machine/processor.h>
|
||||
#include <ogc/system.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "common/CommonTypes.h"
|
||||
#include "gxtest/BPMemory.h"
|
||||
@@ -22,82 +22,83 @@ typedef float f32;
|
||||
|
||||
typedef union
|
||||
{
|
||||
volatile u8 U8;
|
||||
volatile s8 S8;
|
||||
volatile u16 U16;
|
||||
volatile s16 S16;
|
||||
volatile u32 U32;
|
||||
volatile s32 S32;
|
||||
volatile f32 F32;
|
||||
volatile u8 U8;
|
||||
volatile s8 S8;
|
||||
volatile u16 U16;
|
||||
volatile s16 S16;
|
||||
volatile u32 U32;
|
||||
volatile s32 S32;
|
||||
volatile f32 F32;
|
||||
} CWGPipe;
|
||||
|
||||
//static CWGPipe* const wgPipe = (CWGPipe*)0xCC008000;
|
||||
// static CWGPipe* const wgPipe = (CWGPipe*)0xCC008000;
|
||||
|
||||
// TODO: Get rid of these definitions!
|
||||
//struct GXFifoObj;
|
||||
extern "C"
|
||||
{
|
||||
// struct GXFifoObj;
|
||||
extern "C" {
|
||||
GXFifoObj* GX_Init(void* base, u32 size);
|
||||
}
|
||||
|
||||
static void __CGXFinishInterruptHandler(u32 irq,void *ctx);
|
||||
static void __CGXFinishInterruptHandler(u32 irq, void* ctx);
|
||||
static vu16* const _peReg = (u16*)0xCC001000;
|
||||
static lwpq_t _cgxwaitfinish;
|
||||
static vu32 _cgxfinished = 0;
|
||||
|
||||
#define CGX_LOAD_BP_REG(x) \
|
||||
do { \
|
||||
wgPipe->U8 = 0x61; \
|
||||
wgPipe->U32 = (u32)(x); \
|
||||
} while(0)
|
||||
#define CGX_LOAD_BP_REG(x) \
|
||||
do \
|
||||
{ \
|
||||
wgPipe->U8 = 0x61; \
|
||||
wgPipe->U32 = (u32)(x); \
|
||||
} while (0)
|
||||
|
||||
#define CGX_LOAD_CP_REG(x, y) \
|
||||
do { \
|
||||
wgPipe->U8 = 0x08; \
|
||||
wgPipe->U8 = (u8)(x); \
|
||||
wgPipe->U32 = (u32)(y); \
|
||||
} while(0)
|
||||
#define CGX_LOAD_CP_REG(x, y) \
|
||||
do \
|
||||
{ \
|
||||
wgPipe->U8 = 0x08; \
|
||||
wgPipe->U8 = (u8)(x); \
|
||||
wgPipe->U32 = (u32)(y); \
|
||||
} while (0)
|
||||
|
||||
#define CGX_BEGIN_LOAD_XF_REGS(x, n) \
|
||||
do { \
|
||||
wgPipe->U8 = 0x10; \
|
||||
wgPipe->U32 = (u32)(((((n)&0xffff)-1)<<16)|((x)&0xffff)); \
|
||||
} while(0)
|
||||
#define CGX_BEGIN_LOAD_XF_REGS(x, n) \
|
||||
do \
|
||||
{ \
|
||||
wgPipe->U8 = 0x10; \
|
||||
wgPipe->U32 = (u32)(((((n)&0xffff) - 1) << 16) | ((x)&0xffff)); \
|
||||
} while (0)
|
||||
|
||||
void CGX_Init()
|
||||
{
|
||||
// TODO: Is this leaking memory?
|
||||
void *gp_fifo = NULL;
|
||||
gp_fifo = memalign(32, 256*1024);
|
||||
memset(gp_fifo, 0, 256*1024);
|
||||
// TODO: Is this leaking memory?
|
||||
void* gp_fifo = NULL;
|
||||
gp_fifo = memalign(32, 256 * 1024);
|
||||
memset(gp_fifo, 0, 256 * 1024);
|
||||
|
||||
GX_Init(gp_fifo, 256*1024);
|
||||
GX_Init(gp_fifo, 256 * 1024);
|
||||
|
||||
LWP_InitQueue(&_cgxwaitfinish);
|
||||
LWP_InitQueue(&_cgxwaitfinish);
|
||||
|
||||
IRQ_Request(IRQ_PI_PEFINISH,__CGXFinishInterruptHandler,NULL);
|
||||
__UnmaskIrq(IRQMASK(IRQ_PI_PEFINISH));
|
||||
_peReg[5] = 0x0F;
|
||||
IRQ_Request(IRQ_PI_PEFINISH, __CGXFinishInterruptHandler, NULL);
|
||||
__UnmaskIrq(IRQMASK(IRQ_PI_PEFINISH));
|
||||
_peReg[5] = 0x0F;
|
||||
}
|
||||
|
||||
void CGX_SetViewport(float origin_x, float origin_y, float width, float height, float near, f32 far)
|
||||
{
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x101a,6);
|
||||
wgPipe->F32 = width*0.5f;
|
||||
wgPipe->F32 = -height*0.5f;
|
||||
wgPipe->F32 = (far-near)*16777215.0f;
|
||||
wgPipe->F32 = 342.0f+origin_x+width*0.5f;
|
||||
wgPipe->F32 = 342.0f+origin_y+height*0.5f;
|
||||
wgPipe->F32 = far*16777215.0f;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x101a, 6);
|
||||
wgPipe->F32 = width * 0.5f;
|
||||
wgPipe->F32 = -height * 0.5f;
|
||||
wgPipe->F32 = (far - near) * 16777215.0f;
|
||||
wgPipe->F32 = 342.0f + origin_x + width * 0.5f;
|
||||
wgPipe->F32 = 342.0f + origin_y + height * 0.5f;
|
||||
wgPipe->F32 = far * 16777215.0f;
|
||||
}
|
||||
|
||||
static inline void WriteMtxPS4x2(register f32 mt[3][4], register void* wgpipe)
|
||||
{
|
||||
// Untested
|
||||
register f32 tmp0, tmp1, tmp2, tmp3;
|
||||
// Untested
|
||||
register f32 tmp0, tmp1, tmp2, tmp3;
|
||||
|
||||
__asm__ __volatile__
|
||||
("psq_l %0,0(%4),0,0\n\
|
||||
__asm__ __volatile__("psq_l %0,0(%4),0,0\n\
|
||||
psq_l %1,8(%4),0,0\n\
|
||||
psq_l %2,16(%4),0,0\n\
|
||||
psq_l %3,24(%4),0,0\n\
|
||||
@@ -105,151 +106,152 @@ static inline void WriteMtxPS4x2(register f32 mt[3][4], register void* wgpipe)
|
||||
psq_st %1,0(%5),0,0\n\
|
||||
psq_st %2,0(%5),0,0\n\
|
||||
psq_st %3,0(%5),0,0"
|
||||
: "=&f"(tmp0),"=&f"(tmp1),"=&f"(tmp2),"=&f"(tmp3)
|
||||
: "b"(mt), "b"(wgpipe)
|
||||
: "memory"
|
||||
);
|
||||
: "=&f"(tmp0), "=&f"(tmp1), "=&f"(tmp2), "=&f"(tmp3)
|
||||
: "b"(mt), "b"(wgpipe)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
void CGX_LoadPosMatrixDirect(f32 mt[3][4], u32 index)
|
||||
{
|
||||
// Untested
|
||||
/* CGX_BEGIN_LOAD_XF_REGS((index<<2)&0xFF, 12);
|
||||
WriteMtxPS4x2(mt, (void*)wgPipe);*/
|
||||
GX_LoadPosMtxImm(mt, index);
|
||||
// Untested
|
||||
/* CGX_BEGIN_LOAD_XF_REGS((index<<2)&0xFF, 12);
|
||||
WriteMtxPS4x2(mt, (void*)wgPipe);*/
|
||||
GX_LoadPosMtxImm(mt, index);
|
||||
}
|
||||
|
||||
void CGX_LoadProjectionMatrixPerspective(float mtx[4][4])
|
||||
{
|
||||
// Untested
|
||||
/* CGX_BEGIN_LOAD_XF_REGS(0x1020, 7);
|
||||
wgPipe->F32 = mtx[0][0];
|
||||
wgPipe->F32 = mtx[0][2];
|
||||
wgPipe->F32 = mtx[1][1];
|
||||
wgPipe->F32 = mtx[1][2];
|
||||
wgPipe->F32 = mtx[2][2];
|
||||
wgPipe->F32 = mtx[2][3];
|
||||
wgPipe->U32 = 0;*/
|
||||
GX_LoadProjectionMtx(mtx, 0);
|
||||
// Untested
|
||||
/* CGX_BEGIN_LOAD_XF_REGS(0x1020, 7);
|
||||
wgPipe->F32 = mtx[0][0];
|
||||
wgPipe->F32 = mtx[0][2];
|
||||
wgPipe->F32 = mtx[1][1];
|
||||
wgPipe->F32 = mtx[1][2];
|
||||
wgPipe->F32 = mtx[2][2];
|
||||
wgPipe->F32 = mtx[2][3];
|
||||
wgPipe->U32 = 0;*/
|
||||
GX_LoadProjectionMtx(mtx, 0);
|
||||
}
|
||||
|
||||
void CGX_LoadProjectionMatrixOrthographic(float mtx[4][4])
|
||||
{
|
||||
// Untested
|
||||
/* CGX_BEGIN_LOAD_XF_REGS(0x1020, 7);
|
||||
wgPipe->F32 = mtx[0][0];
|
||||
wgPipe->F32 = mtx[0][3];
|
||||
wgPipe->F32 = mtx[1][1];
|
||||
wgPipe->F32 = mtx[1][3];
|
||||
wgPipe->F32 = mtx[2][2];
|
||||
wgPipe->F32 = mtx[2][3];
|
||||
wgPipe->U32 = 1;*/
|
||||
GX_LoadProjectionMtx(mtx, 1);
|
||||
// Untested
|
||||
/* CGX_BEGIN_LOAD_XF_REGS(0x1020, 7);
|
||||
wgPipe->F32 = mtx[0][0];
|
||||
wgPipe->F32 = mtx[0][3];
|
||||
wgPipe->F32 = mtx[1][1];
|
||||
wgPipe->F32 = mtx[1][3];
|
||||
wgPipe->F32 = mtx[2][2];
|
||||
wgPipe->F32 = mtx[2][3];
|
||||
wgPipe->U32 = 1;*/
|
||||
GX_LoadProjectionMtx(mtx, 1);
|
||||
}
|
||||
|
||||
void CGX_DoEfbCopyTex(u16 left, u16 top, u16 width, u16 height, u8 dest_format, bool copy_to_intensity, void* dest, bool scale_down, bool clear)
|
||||
void CGX_DoEfbCopyTex(u16 left, u16 top, u16 width, u16 height, u8 dest_format,
|
||||
bool copy_to_intensity, void* dest, bool scale_down, bool clear)
|
||||
{
|
||||
assert(left <= 1023);
|
||||
assert(top <= 1023);
|
||||
assert(width <= 1023);
|
||||
assert(height <= 1023);
|
||||
assert(left <= 1023);
|
||||
assert(top <= 1023);
|
||||
assert(width <= 1023);
|
||||
assert(height <= 1023);
|
||||
|
||||
// TODO: GX_TF_Z16 seems to have special treatment in libogc? oO
|
||||
// TODO: GX_TF_Z16 seems to have special treatment in libogc? oO
|
||||
|
||||
X10Y10 coords;
|
||||
coords.hex = BPMEM_EFB_TL << 24;
|
||||
coords.x = left;
|
||||
coords.y = top;
|
||||
CGX_LOAD_BP_REG(coords.hex);
|
||||
X10Y10 coords;
|
||||
coords.hex = BPMEM_EFB_TL << 24;
|
||||
coords.x = left;
|
||||
coords.y = top;
|
||||
CGX_LOAD_BP_REG(coords.hex);
|
||||
|
||||
coords.hex = BPMEM_EFB_BR << 24;
|
||||
coords.x = width - 1;
|
||||
coords.y = height - 1;
|
||||
CGX_LOAD_BP_REG(coords.hex);
|
||||
coords.hex = BPMEM_EFB_BR << 24;
|
||||
coords.x = width - 1;
|
||||
coords.y = height - 1;
|
||||
CGX_LOAD_BP_REG(coords.hex);
|
||||
|
||||
// TODO: this one is hardcoded against dest_format=RGBA8...
|
||||
CGX_LOAD_BP_REG((BPMEM_MIPMAP_STRIDE << 24) | (((width+3)>>2) * 2));
|
||||
// TODO: this one is hardcoded against dest_format=RGBA8...
|
||||
CGX_LOAD_BP_REG((BPMEM_MIPMAP_STRIDE << 24) | (((width + 3) >> 2) * 2));
|
||||
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_ADDR<<24) | (MEM_VIRTUAL_TO_PHYSICAL(dest)>>5));
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_ADDR << 24) | (MEM_VIRTUAL_TO_PHYSICAL(dest) >> 5));
|
||||
|
||||
UPE_Copy reg;
|
||||
reg.Hex = BPMEM_TRIGGER_EFB_COPY<<24;
|
||||
reg.target_pixel_format = ((dest_format << 1) & 0xE) | (dest_format >> 3);
|
||||
reg.half_scale = scale_down;
|
||||
reg.clear = clear;
|
||||
reg.intensity_fmt = copy_to_intensity;
|
||||
reg.clamp0 = 1;
|
||||
reg.clamp1 = 1;
|
||||
CGX_LOAD_BP_REG(reg.Hex);
|
||||
UPE_Copy reg;
|
||||
reg.Hex = BPMEM_TRIGGER_EFB_COPY << 24;
|
||||
reg.target_pixel_format = ((dest_format << 1) & 0xE) | (dest_format >> 3);
|
||||
reg.half_scale = scale_down;
|
||||
reg.clear = clear;
|
||||
reg.intensity_fmt = copy_to_intensity;
|
||||
reg.clamp0 = 1;
|
||||
reg.clamp1 = 1;
|
||||
CGX_LOAD_BP_REG(reg.Hex);
|
||||
|
||||
DCFlushRange(dest, GX_GetTexBufferSize(width,height,GX_TF_RGBA8,GX_FALSE,1));
|
||||
DCFlushRange(dest, GX_GetTexBufferSize(width, height, GX_TF_RGBA8, GX_FALSE, 1));
|
||||
}
|
||||
|
||||
void CGX_DoEfbCopyXfb(u16 left, u16 top, u16 width, u16 src_height, u16 dst_height, void* dest, bool clear)
|
||||
void CGX_DoEfbCopyXfb(u16 left, u16 top, u16 width, u16 src_height, u16 dst_height, void* dest,
|
||||
bool clear)
|
||||
{
|
||||
assert(left <= 1023);
|
||||
assert(top <= 1023);
|
||||
assert(width <= 1023);
|
||||
assert(src_height <= 1023);
|
||||
assert(left <= 1023);
|
||||
assert(top <= 1023);
|
||||
assert(width <= 1023);
|
||||
assert(src_height <= 1023);
|
||||
|
||||
/* UPE_Copy reg;
|
||||
reg.Hex = BPMEM_TRIGGER_EFB_COPY<<24;
|
||||
reg.clear = clear;
|
||||
reg.copy_to_xfb = 1;
|
||||
/* UPE_Copy reg;
|
||||
reg.Hex = BPMEM_TRIGGER_EFB_COPY<<24;
|
||||
reg.clear = clear;
|
||||
reg.copy_to_xfb = 1;
|
||||
|
||||
X10Y10 coords;
|
||||
coords.hex = 0;
|
||||
coords.x = left;
|
||||
coords.y = top;
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_TL << 24) | coords.hex);
|
||||
coords.x = width - 1;
|
||||
coords.y = height - 1;
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_BR << 24) | coords.hex);
|
||||
X10Y10 coords;
|
||||
coords.hex = 0;
|
||||
coords.x = left;
|
||||
coords.y = top;
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_TL << 24) | coords.hex);
|
||||
coords.x = width - 1;
|
||||
coords.y = height - 1;
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_BR << 24) | coords.hex);
|
||||
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_ADDR<<24) | (MEM_VIRTUAL_TO_PHYSICAL(dest)>>5));
|
||||
CGX_LOAD_BP_REG((BPMEM_EFB_ADDR<<24) | (MEM_VIRTUAL_TO_PHYSICAL(dest)>>5));
|
||||
|
||||
CGX_LOAD_BP_REG((BPMEM_MIPMAP_STRIDE<<24) | (width >> 4));
|
||||
CGX_LOAD_BP_REG(reg.Hex);*/
|
||||
CGX_LOAD_BP_REG((BPMEM_MIPMAP_STRIDE<<24) | (width >> 4));
|
||||
CGX_LOAD_BP_REG(reg.Hex);*/
|
||||
|
||||
GX_SetDispCopySrc(left, top, width, src_height);
|
||||
GX_SetDispCopyDst(width, dst_height);
|
||||
// SetCopyFilter, SetFieldMode, SetDispCopyGamma
|
||||
GX_CopyDisp(dest, clear);
|
||||
GX_SetDispCopySrc(left, top, width, src_height);
|
||||
GX_SetDispCopyDst(width, dst_height);
|
||||
// SetCopyFilter, SetFieldMode, SetDispCopyGamma
|
||||
GX_CopyDisp(dest, clear);
|
||||
}
|
||||
|
||||
void CGX_ForcePipelineFlush()
|
||||
{
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
wgPipe->U32 = 0;
|
||||
}
|
||||
|
||||
static void __CGXFinishInterruptHandler(u32 irq,void *ctx)
|
||||
static void __CGXFinishInterruptHandler(u32 irq, void* ctx)
|
||||
{
|
||||
_peReg[5] = (_peReg[5]&~0x08)|0x08;
|
||||
_cgxfinished = 1;
|
||||
_peReg[5] = (_peReg[5] & ~0x08) | 0x08;
|
||||
_cgxfinished = 1;
|
||||
|
||||
LWP_ThreadBroadcast(_cgxwaitfinish);
|
||||
LWP_ThreadBroadcast(_cgxwaitfinish);
|
||||
}
|
||||
|
||||
void CGX_WaitForGpuToFinish()
|
||||
{
|
||||
u32 level;
|
||||
u32 level;
|
||||
|
||||
_CPU_ISR_Disable(level);
|
||||
CGX_LOAD_BP_REG(0x45000002); // draw done
|
||||
CGX_ForcePipelineFlush();
|
||||
_CPU_ISR_Disable(level);
|
||||
CGX_LOAD_BP_REG(0x45000002); // draw done
|
||||
CGX_ForcePipelineFlush();
|
||||
|
||||
_cgxfinished = 0;
|
||||
_CPU_ISR_Flash(level);
|
||||
_cgxfinished = 0;
|
||||
_CPU_ISR_Flash(level);
|
||||
|
||||
while(!_cgxfinished)
|
||||
LWP_ThreadSleep(_cgxwaitfinish);
|
||||
while (!_cgxfinished)
|
||||
LWP_ThreadSleep(_cgxwaitfinish);
|
||||
|
||||
_CPU_ISR_Restore(level);
|
||||
_CPU_ISR_Restore(level);
|
||||
}
|
||||
|
||||
59
gxtest/cgx.h
59
gxtest/cgx.h
@@ -21,49 +21,56 @@
|
||||
|
||||
typedef union
|
||||
{
|
||||
volatile u8 U8;
|
||||
volatile s8 S8;
|
||||
volatile u16 U16;
|
||||
volatile s16 S16;
|
||||
volatile u32 U32;
|
||||
volatile s32 S32;
|
||||
volatile f32 F32;
|
||||
volatile u8 U8;
|
||||
volatile s8 S8;
|
||||
volatile u16 U16;
|
||||
volatile s16 S16;
|
||||
volatile u32 U32;
|
||||
volatile s32 S32;
|
||||
volatile f32 F32;
|
||||
} CWGPipe;
|
||||
|
||||
static CWGPipe* const wgPipe = (CWGPipe*)0xCC008000;
|
||||
*/
|
||||
|
||||
#define CGX_LOAD_BP_REG(x) \
|
||||
do { \
|
||||
wgPipe->U8 = 0x61; \
|
||||
wgPipe->U32 = (u32)(x); \
|
||||
} while(0)
|
||||
#define CGX_LOAD_BP_REG(x) \
|
||||
do \
|
||||
{ \
|
||||
wgPipe->U8 = 0x61; \
|
||||
wgPipe->U32 = (u32)(x); \
|
||||
} while (0)
|
||||
|
||||
#define CGX_LOAD_CP_REG(x, y) \
|
||||
do { \
|
||||
wgPipe->U8 = 0x08; \
|
||||
wgPipe->U8 = (u8)(x); \
|
||||
wgPipe->U32 = (u32)(y); \
|
||||
} while(0)
|
||||
#define CGX_LOAD_CP_REG(x, y) \
|
||||
do \
|
||||
{ \
|
||||
wgPipe->U8 = 0x08; \
|
||||
wgPipe->U8 = (u8)(x); \
|
||||
wgPipe->U32 = (u32)(y); \
|
||||
} while (0)
|
||||
|
||||
#define CGX_BEGIN_LOAD_XF_REGS(x, n) \
|
||||
do { \
|
||||
wgPipe->U8 = 0x10; \
|
||||
wgPipe->U32 = (u32)(((((n)&0xffff)-1)<<16)|((x)&0xffff)); \
|
||||
} while(0)
|
||||
#define CGX_BEGIN_LOAD_XF_REGS(x, n) \
|
||||
do \
|
||||
{ \
|
||||
wgPipe->U8 = 0x10; \
|
||||
wgPipe->U32 = (u32)(((((n)&0xffff) - 1) << 16) | ((x)&0xffff)); \
|
||||
} while (0)
|
||||
|
||||
void CGX_Init();
|
||||
|
||||
void CGX_SetViewport(float origin_x, float origin_y, float width, float height, float near, f32 far);
|
||||
void CGX_SetViewport(float origin_x, float origin_y, float width, float height, float near,
|
||||
f32 far);
|
||||
|
||||
void CGX_LoadPosMatrixDirect(f32 mt[3][4], u32 index);
|
||||
void CGX_LoadProjectionMatrixPerspective(float mtx[4][4]);
|
||||
void CGX_LoadProjectionMatrixOrthographic(float mtx[4][4]);
|
||||
|
||||
void CGX_DoEfbCopyTex(u16 left, u16 top, u16 width, u16 height, u8 dest_format, bool copy_to_intensity, void* dest, bool scale_down=false, bool clear=false);
|
||||
void CGX_DoEfbCopyTex(u16 left, u16 top, u16 width, u16 height, u8 dest_format,
|
||||
bool copy_to_intensity, void* dest, bool scale_down = false,
|
||||
bool clear = false);
|
||||
|
||||
// TODO: Add support for other parameters...
|
||||
void CGX_DoEfbCopyXfb(u16 left, u16 top, u16 width, u16 src_height, u16 dst_height, void* dest, bool clear=false);
|
||||
void CGX_DoEfbCopyXfb(u16 left, u16 top, u16 width, u16 src_height, u16 dst_height, void* dest,
|
||||
bool clear = false);
|
||||
|
||||
void CGX_ForcePipelineFlush();
|
||||
|
||||
|
||||
@@ -8,95 +8,94 @@
|
||||
#include "gxtest/CPMemory.h"
|
||||
#include "gxtest/XFMemory.h"
|
||||
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static T CGXDefault();
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static T CGXDefault(int);
|
||||
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static T CGXDefault(int, bool);
|
||||
|
||||
template<>
|
||||
template <>
|
||||
GenMode CGXDefault<GenMode>()
|
||||
{
|
||||
GenMode genmode;
|
||||
genmode.hex = BPMEM_GENMODE<<24;
|
||||
genmode.numtexgens = 0;
|
||||
genmode.numcolchans = 1;
|
||||
genmode.numtevstages = 0; // One stage
|
||||
genmode.cullmode = 0; // No culling
|
||||
genmode.numindstages = 0;
|
||||
genmode.zfreeze = 0;
|
||||
return genmode;
|
||||
GenMode genmode;
|
||||
genmode.hex = BPMEM_GENMODE << 24;
|
||||
genmode.numtexgens = 0;
|
||||
genmode.numcolchans = 1;
|
||||
genmode.numtevstages = 0; // One stage
|
||||
genmode.cullmode = 0; // No culling
|
||||
genmode.numindstages = 0;
|
||||
genmode.zfreeze = 0;
|
||||
return genmode;
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
ZMode CGXDefault<ZMode>()
|
||||
{
|
||||
ZMode zmode;
|
||||
zmode.hex = BPMEM_ZMODE << 24;
|
||||
zmode.testenable = 0;
|
||||
zmode.func = COMPARE_ALWAYS;
|
||||
zmode.updateenable = 0;
|
||||
return zmode;
|
||||
ZMode zmode;
|
||||
zmode.hex = BPMEM_ZMODE << 24;
|
||||
zmode.testenable = 0;
|
||||
zmode.func = COMPARE_ALWAYS;
|
||||
zmode.updateenable = 0;
|
||||
return zmode;
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
TevStageCombiner::ColorCombiner CGXDefault<TevStageCombiner::ColorCombiner>(int stage)
|
||||
{
|
||||
TevStageCombiner::ColorCombiner cc;
|
||||
cc.hex = (BPMEM_TEV_COLOR_ENV+2*stage)<<24;
|
||||
cc.a = TEVCOLORARG_ZERO;
|
||||
cc.b = TEVCOLORARG_ZERO;
|
||||
cc.c = TEVCOLORARG_ZERO;
|
||||
cc.d = TEVCOLORARG_ZERO;
|
||||
cc.op = TEVOP_ADD;
|
||||
cc.bias = 0;
|
||||
cc.shift = TEVSCALE_1;
|
||||
cc.clamp = 0;
|
||||
cc.dest = GX_TEVPREV;
|
||||
return cc;
|
||||
TevStageCombiner::ColorCombiner cc;
|
||||
cc.hex = (BPMEM_TEV_COLOR_ENV + 2 * stage) << 24;
|
||||
cc.a = TEVCOLORARG_ZERO;
|
||||
cc.b = TEVCOLORARG_ZERO;
|
||||
cc.c = TEVCOLORARG_ZERO;
|
||||
cc.d = TEVCOLORARG_ZERO;
|
||||
cc.op = TEVOP_ADD;
|
||||
cc.bias = 0;
|
||||
cc.shift = TEVSCALE_1;
|
||||
cc.clamp = 0;
|
||||
cc.dest = GX_TEVPREV;
|
||||
return cc;
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
TevStageCombiner::AlphaCombiner CGXDefault<TevStageCombiner::AlphaCombiner>(int stage)
|
||||
{
|
||||
TevStageCombiner::AlphaCombiner ac;
|
||||
ac.hex = (BPMEM_TEV_ALPHA_ENV+2*stage)<<24;
|
||||
ac.a = TEVALPHAARG_ZERO;
|
||||
ac.b = TEVALPHAARG_ZERO;
|
||||
ac.c = TEVALPHAARG_ZERO;
|
||||
ac.d = TEVALPHAARG_ZERO;
|
||||
ac.op = TEVOP_ADD;
|
||||
ac.bias = 0;
|
||||
ac.shift = TEVSCALE_1;
|
||||
ac.clamp = 0;
|
||||
ac.dest = GX_TEVPREV;
|
||||
return ac;
|
||||
TevStageCombiner::AlphaCombiner ac;
|
||||
ac.hex = (BPMEM_TEV_ALPHA_ENV + 2 * stage) << 24;
|
||||
ac.a = TEVALPHAARG_ZERO;
|
||||
ac.b = TEVALPHAARG_ZERO;
|
||||
ac.c = TEVALPHAARG_ZERO;
|
||||
ac.d = TEVALPHAARG_ZERO;
|
||||
ac.op = TEVOP_ADD;
|
||||
ac.bias = 0;
|
||||
ac.shift = TEVSCALE_1;
|
||||
ac.clamp = 0;
|
||||
ac.dest = GX_TEVPREV;
|
||||
return ac;
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
TwoTevStageOrders CGXDefault<TwoTevStageOrders>(int index)
|
||||
{
|
||||
TwoTevStageOrders orders;
|
||||
orders.hex = (BPMEM_TREF+index)<<24;
|
||||
orders.texmap0 = GX_TEXMAP_NULL;
|
||||
orders.texcoord0 = GX_TEXCOORDNULL;
|
||||
orders.enable0 = 0;
|
||||
orders.colorchan0 = 0; // equivalent to GX_COLOR0A0
|
||||
return orders;
|
||||
TwoTevStageOrders orders;
|
||||
orders.hex = (BPMEM_TREF + index) << 24;
|
||||
orders.texmap0 = GX_TEXMAP_NULL;
|
||||
orders.texcoord0 = GX_TEXCOORDNULL;
|
||||
orders.enable0 = 0;
|
||||
orders.colorchan0 = 0; // equivalent to GX_COLOR0A0
|
||||
return orders;
|
||||
}
|
||||
|
||||
template<>
|
||||
template <>
|
||||
TevReg CGXDefault<TevReg>(int index, bool is_konst_color)
|
||||
{
|
||||
TevReg tevreg;
|
||||
tevreg.hex = 0;
|
||||
tevreg.low = (BPMEM_TEV_REGISTER_L+2*index)<<24;
|
||||
tevreg.high = (BPMEM_TEV_REGISTER_H+2*index)<<24;
|
||||
tevreg.type_ra = is_konst_color;
|
||||
tevreg.type_bg = is_konst_color;
|
||||
return tevreg;
|
||||
TevReg tevreg;
|
||||
tevreg.hex = 0;
|
||||
tevreg.low = (BPMEM_TEV_REGISTER_L + 2 * index) << 24;
|
||||
tevreg.high = (BPMEM_TEV_REGISTER_H + 2 * index) << 24;
|
||||
tevreg.type_ra = is_konst_color;
|
||||
tevreg.type_bg = is_konst_color;
|
||||
return tevreg;
|
||||
}
|
||||
|
||||
@@ -3,239 +3,246 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <initializer_list>
|
||||
#include "common/hwtests.h"
|
||||
#include <math.h>
|
||||
#include <ogcsys.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include "common/hwtests.h"
|
||||
#include "gxtest/cgx.h"
|
||||
#include "gxtest/cgx_defaults.h"
|
||||
#include "gxtest/util.h"
|
||||
#include <ogcsys.h>
|
||||
|
||||
void ClipTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 1; // from vertex
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 1; // from vertex
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
|
||||
CGX_LOAD_BP_REG(CGXDefault<TevStageCombiner::AlphaCombiner>(0).hex);
|
||||
CGX_LOAD_BP_REG(CGXDefault<TevStageCombiner::AlphaCombiner>(0).hex);
|
||||
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE<<24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
|
||||
for (int step = 0; step < 16; ++step)
|
||||
{
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
for (int step = 0; step < 16; ++step)
|
||||
{
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
|
||||
// First off, clear previous screen contents
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f, 1.0f); // stuff which really should not be filled
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0,0,0,0xff).Draw();
|
||||
// First off, clear previous screen contents
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f,
|
||||
1.0f); // stuff which really should not be filled
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0, 0, 0, 0xff).Draw();
|
||||
|
||||
CGX_SetViewport(75.0f, 0.0f, 100.0f, 50.0f, 0.0f, 1.0f); // guardband
|
||||
cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0,0x7f,0,0xff).Draw();
|
||||
CGX_SetViewport(75.0f, 0.0f, 100.0f, 50.0f, 0.0f, 1.0f); // guardband
|
||||
cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0, 0x7f, 0, 0xff).Draw();
|
||||
|
||||
CGX_SetViewport(100.0f, 0.0f, 50.0f, 50.0f, 0.0f, 1.0f); // viewport
|
||||
cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0,0xff,0,0xff).Draw();
|
||||
CGX_SetViewport(100.0f, 0.0f, 50.0f, 50.0f, 0.0f, 1.0f); // viewport
|
||||
cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0, 0xff, 0, 0xff).Draw();
|
||||
|
||||
// Now, enable testing viewport and draw the (red) testing quad
|
||||
CGX_SetViewport(100.0f, 0.0f, 50.0f, 50.0f, 0.0f, 1.0f);
|
||||
// Now, enable testing viewport and draw the (red) testing quad
|
||||
CGX_SetViewport(100.0f, 0.0f, 50.0f, 50.0f, 0.0f, 1.0f);
|
||||
|
||||
cc.d = TEVCOLORARG_C0;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
cc.d = TEVCOLORARG_C0;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
|
||||
auto tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = 0xff;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
auto tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = 0xff;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 0; // 0 = enable clipping, 1 = disable clipping
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 0; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
bool expect_quad_to_be_drawn = true;
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
GXTest::Quad test_quad;
|
||||
test_quad.ColorRGBA(0xff,0xff,0xff,0xff);
|
||||
bool expect_quad_to_be_drawn = true;
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
GXTest::Quad test_quad;
|
||||
test_quad.ColorRGBA(0xff, 0xff, 0xff, 0xff);
|
||||
|
||||
switch (step)
|
||||
{
|
||||
// Rendering outside the viewport when scissor rect is bigger than viewport
|
||||
// TODO: What about partially covered primitives?
|
||||
switch (step)
|
||||
{
|
||||
// Rendering outside the viewport when scissor rect is bigger than viewport
|
||||
// TODO: What about partially covered primitives?
|
||||
|
||||
case 0: // all vertices within viewport
|
||||
// Nothing to do
|
||||
break;
|
||||
case 0: // all vertices within viewport
|
||||
// Nothing to do
|
||||
break;
|
||||
|
||||
case 1: // two vertices outside viewport, but within guardband
|
||||
test_quad.VertexTopLeft(-1.8f, 1.0f, 1.0f).VertexBottomLeft(-1.8f, -1.0f, 1.0f);
|
||||
test_x = 75; // TODO: Move closer to actual viewport, but debug readback issues first
|
||||
break;
|
||||
|
||||
case 1: // two vertices outside viewport, but within guardband
|
||||
test_quad.VertexTopLeft(-1.8f, 1.0f, 1.0f).VertexBottomLeft(-1.8f, -1.0f, 1.0f);
|
||||
test_x = 75; // TODO: Move closer to actual viewport, but debug readback issues first
|
||||
break;
|
||||
case 2: // two vertices outside viewport and guardband
|
||||
test_quad.VertexTopLeft(-2.5f, 1.0f, 1.0f).VertexBottomLeft(-2.5f, -1.0f, 1.0f);
|
||||
test_x = 51; // TODO: This is actually outside the guardband
|
||||
// TODO: Check x=50, should be green
|
||||
break;
|
||||
|
||||
case 2: // two vertices outside viewport and guardband
|
||||
test_quad.VertexTopLeft(-2.5f, 1.0f, 1.0f).VertexBottomLeft(-2.5f, -1.0f, 1.0f);
|
||||
test_x = 51; // TODO: This is actually outside the guardband
|
||||
// TODO: Check x=50, should be green
|
||||
break;
|
||||
case 3: // all vertices outside viewport, but within guardband and NOT on the same side of the
|
||||
// viewport
|
||||
test_quad.VertexTopLeft(-1.5f, 1.0f, 1.0f).VertexBottomLeft(-1.5f, -1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(1.5f, 1.0f, 1.0f).VertexBottomRight(1.5f, 1.0f, 1.0f);
|
||||
test_x = 80; // TODO: Move closer to actual viewport
|
||||
break;
|
||||
|
||||
case 3: // all vertices outside viewport, but within guardband and NOT on the same side of the viewport
|
||||
test_quad.VertexTopLeft(-1.5f, 1.0f, 1.0f).VertexBottomLeft(-1.5f, -1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(1.5f, 1.0f, 1.0f).VertexBottomRight(1.5f, 1.0f, 1.0f);
|
||||
test_x = 80; // TODO: Move closer to actual viewport
|
||||
break;
|
||||
case 4: // all vertices outside viewport and guardband, but NOT on the same side of the
|
||||
// viewport
|
||||
test_quad.VertexTopLeft(-2.5f, 1.0f, 1.0f).VertexBottomLeft(-2.5f, -1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(2.5f, 1.0f, 1.0f).VertexBottomRight(2.5f, 1.0f, 1.0f);
|
||||
test_x = 51; // TODO: This is actually outside the guardband
|
||||
// TODO: Check x=50,x=200?,x=201?, 50 and 201 should be green, 200 should be red
|
||||
break;
|
||||
|
||||
case 4: // all vertices outside viewport and guardband, but NOT on the same side of the viewport
|
||||
test_quad.VertexTopLeft(-2.5f, 1.0f, 1.0f).VertexBottomLeft(-2.5f, -1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(2.5f, 1.0f, 1.0f).VertexBottomRight(2.5f, 1.0f, 1.0f);
|
||||
test_x = 51; // TODO: This is actually outside the guardband
|
||||
// TODO: Check x=50,x=200?,x=201?, 50 and 201 should be green, 200 should be red
|
||||
break;
|
||||
case 5: // all vertices outside viewport, but within guardband and on the same side of the
|
||||
// viewport
|
||||
test_quad.VertexTopLeft(-1.8f, 1.0f, 1.0f).VertexBottomLeft(-1.8f, -1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(-1.2f, 1.0f, 1.0f).VertexBottomRight(-1.2f, 1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(1.5f, 1.0f, 1.0f);
|
||||
expect_quad_to_be_drawn = false;
|
||||
break;
|
||||
|
||||
case 5: // all vertices outside viewport, but within guardband and on the same side of the viewport
|
||||
test_quad.VertexTopLeft(-1.8f, 1.0f, 1.0f).VertexBottomLeft(-1.8f, -1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(-1.2f, 1.0f, 1.0f).VertexBottomRight(-1.2f, 1.0f, 1.0f);
|
||||
test_quad.VertexTopRight(1.5f, 1.0f, 1.0f);
|
||||
expect_quad_to_be_drawn = false;
|
||||
break;
|
||||
case 6: // guardband-clipping test
|
||||
// TODO: Currently broken
|
||||
// Exceeds the guard-band clipping plane by the viewport width,
|
||||
// so the primitive will get clipped such that one edge touches
|
||||
// the clipping plane.exactly at the vertical viewport center.
|
||||
// ASCII picture of clipped primitive (within guard-band region):
|
||||
// |----- pixel row 0
|
||||
// | pixel row 1
|
||||
// | pixel row 2
|
||||
// | pixel row 3
|
||||
// | pixel row 4
|
||||
// \ pixel row 5 <-- vertical viewport center
|
||||
// \ pixel row 6
|
||||
// \ pixel row 7
|
||||
// \ pixel row 8
|
||||
// \ pixel row 9
|
||||
// \ pixel row 10
|
||||
test_quad.VertexTopLeft(-4.0f, 1.0f, 1.0f);
|
||||
test_x = 51; // TODO: This is actually outside the guardband
|
||||
test_y = 1;
|
||||
// TODO: Test y roughly equals 60 (there's no good way to test this without relying on
|
||||
// pixel-perfect clipping), here should NOT be a quad!
|
||||
break;
|
||||
|
||||
case 6: // guardband-clipping test
|
||||
// TODO: Currently broken
|
||||
// Exceeds the guard-band clipping plane by the viewport width,
|
||||
// so the primitive will get clipped such that one edge touches
|
||||
// the clipping plane.exactly at the vertical viewport center.
|
||||
// ASCII picture of clipped primitive (within guard-band region):
|
||||
// |----- pixel row 0
|
||||
// | pixel row 1
|
||||
// | pixel row 2
|
||||
// | pixel row 3
|
||||
// | pixel row 4
|
||||
// \ pixel row 5 <-- vertical viewport center
|
||||
// \ pixel row 6
|
||||
// \ pixel row 7
|
||||
// \ pixel row 8
|
||||
// \ pixel row 9
|
||||
// \ pixel row 10
|
||||
test_quad.VertexTopLeft(-4.0f, 1.0f, 1.0f);
|
||||
test_x = 51; // TODO: This is actually outside the guardband
|
||||
test_y = 1;
|
||||
// TODO: Test y roughly equals 60 (there's no good way to test this without relying on pixel-perfect clipping), here should NOT be a quad!
|
||||
break;
|
||||
// Depth clipping tests
|
||||
case 7: // Everything behind z=w plane, depth clipping enabled
|
||||
case 8: // Everything behind z=w plane, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 7; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
// Depth clipping tests
|
||||
case 7: // Everything behind z=w plane, depth clipping enabled
|
||||
case 8: // Everything behind z=w plane, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 7; // 0 = enable clipping, 1 = disable clipping
|
||||
test_quad.AtDepth(1.1);
|
||||
expect_quad_to_be_drawn = false;
|
||||
break;
|
||||
|
||||
test_quad.AtDepth(1.1);
|
||||
expect_quad_to_be_drawn = false;
|
||||
break;
|
||||
case 9: // Everything in front of z=0 plane, depth clipping enabled
|
||||
case 10: // Everything in front of z=0 plane, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 9; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
case 9: // Everything in front of z=0 plane, depth clipping enabled
|
||||
case 10: // Everything in front of z=0 plane, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 9; // 0 = enable clipping, 1 = disable clipping
|
||||
test_quad.AtDepth(-0.00001);
|
||||
expect_quad_to_be_drawn = false;
|
||||
break;
|
||||
|
||||
test_quad.AtDepth(-0.00001);
|
||||
expect_quad_to_be_drawn = false;
|
||||
break;
|
||||
case 11: // Very slightly behind z=w plane, depth clipping enabled
|
||||
case 12: // Very slightly behind z=w plane, depth clipping disabled
|
||||
// TODO: For whatever reason, this doesn't actually work, yet
|
||||
// The GC/Wii GPU doesn't implement IEEE floats strictly, hence
|
||||
// the sum of the projected position's z and w is a very small
|
||||
// number, which by IEEE would be non-zero but which in fact is
|
||||
// treated as zero.
|
||||
// In particular, the value by IEEE is -0.00000011920928955078125.
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 11; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
case 11: // Very slightly behind z=w plane, depth clipping enabled
|
||||
case 12: // Very slightly behind z=w plane, depth clipping disabled
|
||||
// TODO: For whatever reason, this doesn't actually work, yet
|
||||
// The GC/Wii GPU doesn't implement IEEE floats strictly, hence
|
||||
// the sum of the projected position's z and w is a very small
|
||||
// number, which by IEEE would be non-zero but which in fact is
|
||||
// treated as zero.
|
||||
// In particular, the value by IEEE is -0.00000011920928955078125.
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 11; // 0 = enable clipping, 1 = disable clipping
|
||||
test_quad.AtDepth(1.0000001);
|
||||
break;
|
||||
|
||||
test_quad.AtDepth(1.0000001);
|
||||
break;
|
||||
case 13: // One vertex behind z=w plane, depth clipping enabled
|
||||
case 14: // One vertex behind z=w plane, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 13; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
case 13: // One vertex behind z=w plane, depth clipping enabled
|
||||
case 14: // One vertex behind z=w plane, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = step - 13; // 0 = enable clipping, 1 = disable clipping
|
||||
test_quad.VertexTopLeft(-1.0f, 1.0f, 1.5f);
|
||||
|
||||
test_quad.VertexTopLeft(-1.0f, 1.0f, 1.5f);
|
||||
// whole primitive gets clipped away if depth clipping is enabled.
|
||||
// Otherwise the whole primitive is drawn.
|
||||
expect_quad_to_be_drawn = step - 13;
|
||||
break;
|
||||
|
||||
// whole primitive gets clipped away if depth clipping is enabled.
|
||||
// Otherwise the whole primitive is drawn.
|
||||
expect_quad_to_be_drawn = step - 13;
|
||||
break;
|
||||
case 15: // Three vertices with a very large value for z, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 1; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
case 15: // Three vertices with a very large value for z, depth clipping disabled
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 1; // 0 = enable clipping, 1 = disable clipping
|
||||
test_quad.VertexTopLeft(-1.0f, 1.0f, 65537.f);
|
||||
test_quad.VertexTopRight(1.0f, 1.0f, 65537.f);
|
||||
test_quad.VertexBottomLeft(-1.0f, -1.0f, 65537.f);
|
||||
break;
|
||||
|
||||
test_quad.VertexTopLeft(-1.0f, 1.0f, 65537.f);
|
||||
test_quad.VertexTopRight(1.0f, 1.0f, 65537.f);
|
||||
test_quad.VertexBottomLeft(-1.0f, -1.0f, 65537.f);
|
||||
break;
|
||||
// TODO: One vertex with z < 0, depth clipping enabled, primitive gets properly (!) clipped
|
||||
// TODO: One vertex with z < 0, depth clipping disabled, whole primitive gets drawn
|
||||
}
|
||||
|
||||
// TODO: One vertex with z < 0, depth clipping enabled, primitive gets properly (!) clipped
|
||||
// TODO: One vertex with z < 0, depth clipping disabled, whole primitive gets drawn
|
||||
test_quad.Draw();
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
|
||||
}
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
if (expect_quad_to_be_drawn)
|
||||
DO_TEST(result.r == 0xff, "Clipping test failed at step %d (expected quad to be shown at "
|
||||
"pixel (%d, %d), but it was not)",
|
||||
step, test_x, test_y);
|
||||
else
|
||||
DO_TEST(result.r == 0x00, "Clipping test failed at step %d (expected quad to be hidden at "
|
||||
"pixel (%d, %d), but it was not)",
|
||||
step, test_x, test_y);
|
||||
|
||||
test_quad.Draw();
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
}
|
||||
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
if (expect_quad_to_be_drawn)
|
||||
DO_TEST(result.r == 0xff, "Clipping test failed at step %d (expected quad to be shown at pixel (%d, %d), but it was not)", step, test_x, test_y);
|
||||
else
|
||||
DO_TEST(result.r == 0x00, "Clipping test failed at step %d (expected quad to be hidden at pixel (%d, %d), but it was not)", step, test_x, test_y);
|
||||
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
}
|
||||
|
||||
END_TEST();
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
GXTest::Init();
|
||||
GXTest::Init();
|
||||
|
||||
ClipTest();
|
||||
ClipTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,108 +3,110 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <initializer_list>
|
||||
#include "common/hwtests.h"
|
||||
#include <math.h>
|
||||
#include <ogcsys.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include "common/hwtests.h"
|
||||
#include "gxtest/cgx.h"
|
||||
#include "gxtest/cgx_defaults.h"
|
||||
#include "gxtest/util.h"
|
||||
#include <ogcsys.h>
|
||||
|
||||
void LightingTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 0; // from register
|
||||
chan.ambsource = 0; // from register
|
||||
chan.enablelighting = true;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 0; // from register
|
||||
chan.ambsource = 0; // from register
|
||||
chan.enablelighting = true;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
|
||||
CGX_LOAD_BP_REG(CGXDefault<TevStageCombiner::AlphaCombiner>(0).hex);
|
||||
CGX_LOAD_BP_REG(CGXDefault<TevStageCombiner::AlphaCombiner>(0).hex);
|
||||
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
|
||||
// Test to check how the hardware rounds the final computation of the
|
||||
// lit color of a vertex. The formula is basically just
|
||||
// (material color * lighting color), but the rounding isn't obvious
|
||||
// because the hardware uses fixed-point math and takes some shortcuts.
|
||||
for (int step = 0; step < 256*256; ++step)
|
||||
{
|
||||
int matcolor = step & 255;
|
||||
int ambcolor = step >> 8;
|
||||
// Test to check how the hardware rounds the final computation of the
|
||||
// lit color of a vertex. The formula is basically just
|
||||
// (material color * lighting color), but the rounding isn't obvious
|
||||
// because the hardware uses fixed-point math and takes some shortcuts.
|
||||
for (int step = 0; step < 256 * 256; ++step)
|
||||
{
|
||||
int matcolor = step & 255;
|
||||
int ambcolor = step >> 8;
|
||||
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
|
||||
auto tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = 0xff;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
auto tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = 0xff;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 0; // 0 = enable clipping, 1 = disable clipping
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 0; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100a, 1);
|
||||
wgPipe->U32 = (ambcolor << 24) | 255;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100a, 1);
|
||||
wgPipe->U32 = (ambcolor << 24) | 255;
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100c, 1);
|
||||
wgPipe->U32 = (matcolor << 24) | 255;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100c, 1);
|
||||
wgPipe->U32 = (matcolor << 24) | 255;
|
||||
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f, 1.0f);
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0, 0, 0, 0xff).Draw();
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f, 1.0f);
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
GXTest::Quad().ColorRGBA(0, 0, 0, 0xff).Draw();
|
||||
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
int expected = (matcolor * (ambcolor + (ambcolor >> 7))) >> 8;
|
||||
DO_TEST(result.r == expected, "lighting test failed at amb %d mat %d actual %d", ambcolor, matcolor, result.r);
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
int expected = (matcolor * (ambcolor + (ambcolor >> 7))) >> 8;
|
||||
DO_TEST(result.r == expected, "lighting test failed at amb %d mat %d actual %d", ambcolor,
|
||||
matcolor, result.r);
|
||||
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
WPAD_ScanPads();
|
||||
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME) break;
|
||||
}
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
WPAD_ScanPads();
|
||||
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
|
||||
break;
|
||||
}
|
||||
|
||||
END_TEST();
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
GXTest::Init();
|
||||
GXTest::Init();
|
||||
|
||||
LightingTest();
|
||||
LightingTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,134 +3,175 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <initializer_list>
|
||||
#include "common/hwtests.h"
|
||||
#include <math.h>
|
||||
#include <ogcsys.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include "common/hwtests.h"
|
||||
#include "gxtest/cgx.h"
|
||||
#include "gxtest/cgx_defaults.h"
|
||||
#include "gxtest/util.h"
|
||||
#include <ogcsys.h>
|
||||
|
||||
void CoordinatePrecisionTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 1; // from vertex
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 1; // from vertex
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
|
||||
auto ac = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac.d = TEVALPHAARG_RASA;
|
||||
CGX_LOAD_BP_REG(ac.hex);
|
||||
auto ac = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac.d = TEVALPHAARG_RASA;
|
||||
CGX_LOAD_BP_REG(ac.hex);
|
||||
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_RASC;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
|
||||
// Test at which coordinates a pixel is considered to be within a primitive.
|
||||
// TODO: Not sure how to interpret the results, yet.
|
||||
for (float xpos = 0.583328247070f; xpos <= 0.583328306675f; xpos = nextafterf(xpos,+1.0f))
|
||||
{
|
||||
CGX_SetViewport(xpos, 0.0f, 100.0f, 100.0f, 0.0f, 1.0f);
|
||||
// Test at which coordinates a pixel is considered to be within a primitive.
|
||||
// TODO: Not sure how to interpret the results, yet.
|
||||
for (float xpos = 0.583328247070f; xpos <= 0.583328306675f; xpos = nextafterf(xpos, +1.0f))
|
||||
{
|
||||
CGX_SetViewport(xpos, 0.0f, 100.0f, 100.0f, 0.0f, 1.0f);
|
||||
|
||||
// first off, clear the full area.
|
||||
GXTest::Quad().VertexTopLeft(-2.0, 2.0, 1.0).VertexBottomLeft(-2.0, -2.0, 1.0).VertexTopRight(2.0, 2.0, 1.0).VertexBottomRight(2.0, -2.0, 1.0).ColorRGBA(0,0,0,255).Draw();
|
||||
GXTest::Quad().ColorRGBA(0,255,0,255).Draw();
|
||||
// first off, clear the full area.
|
||||
GXTest::Quad()
|
||||
.VertexTopLeft(-2.0, 2.0, 1.0)
|
||||
.VertexBottomLeft(-2.0, -2.0, 1.0)
|
||||
.VertexTopRight(2.0, 2.0, 1.0)
|
||||
.VertexBottomRight(2.0, -2.0, 1.0)
|
||||
.ColorRGBA(0, 0, 0, 255)
|
||||
.Draw();
|
||||
GXTest::Quad().ColorRGBA(0, 255, 0, 255).Draw();
|
||||
|
||||
// now, draw the actual testing quad.
|
||||
GXTest::Quad().VertexTopLeft(0, 1.0, 1.0).VertexBottomLeft(0, -1.0, 1.0).ColorRGBA(255,0,255,255).Draw();
|
||||
GXTest::CopyToTestBuffer(50, 0, 127, 127);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
// now, draw the actual testing quad.
|
||||
GXTest::Quad()
|
||||
.VertexTopLeft(0, 1.0, 1.0)
|
||||
.VertexBottomLeft(0, -1.0, 1.0)
|
||||
.ColorRGBA(255, 0, 255, 255)
|
||||
.Draw();
|
||||
GXTest::CopyToTestBuffer(50, 0, 127, 127);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(0, 0, 128);
|
||||
u8 expectation = (xpos <= 0.583328247070f) ? 255 : 0;
|
||||
int subsample_index = (int)(xpos * 12.0f) % 12;
|
||||
DO_TEST(result.r == expectation, "Incorrect rasterization (result=%d,expected=%d,screencoord=%.6f,subsample_index=%d)", result.r, expectation, xpos, subsample_index);
|
||||
}
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(0, 0, 128);
|
||||
u8 expectation = (xpos <= 0.583328247070f) ? 255 : 0;
|
||||
int subsample_index = (int)(xpos * 12.0f) % 12;
|
||||
DO_TEST(result.r == expectation,
|
||||
"Incorrect rasterization (result=%d,expected=%d,screencoord=%.6f,subsample_index=%d)",
|
||||
result.r, expectation, xpos, subsample_index);
|
||||
}
|
||||
|
||||
// Test for the default pixel subsample location by creating tiny viewports (smaller than the pixel width)
|
||||
// By drawing a quad over the whole viewport, we can check if the current viewport spans the subsample location.
|
||||
// The results seem to indicate that the default subsample is located close to (but somewhat off) screen position 7/12.
|
||||
// I (neobrain) am not sure if the sample indeed is not at that location or if it's just due to floating point rounding errors.
|
||||
for (float xpos = 0.583297669888f; xpos <= 0.583328306675; xpos = nextafterf(xpos,+1.0f))
|
||||
{
|
||||
CGX_SetViewport(0.0, 0.0f, 100.0f, 100.0f, 0.0f, 1.0f);
|
||||
// Test for the default pixel subsample location by creating tiny viewports (smaller than the
|
||||
// pixel width)
|
||||
// By drawing a quad over the whole viewport, we can check if the current viewport spans the
|
||||
// subsample location.
|
||||
// The results seem to indicate that the default subsample is located close to (but somewhat off)
|
||||
// screen position 7/12.
|
||||
// I (neobrain) am not sure if the sample indeed is not at that location or if it's just due to
|
||||
// floating point rounding errors.
|
||||
for (float xpos = 0.583297669888f; xpos <= 0.583328306675; xpos = nextafterf(xpos, +1.0f))
|
||||
{
|
||||
CGX_SetViewport(0.0, 0.0f, 100.0f, 100.0f, 0.0f, 1.0f);
|
||||
|
||||
// first off, clear the full area.
|
||||
GXTest::Quad().VertexTopLeft(-2.0, 2.0, 1.0).VertexBottomLeft(-2.0, -2.0, 1.0).VertexTopRight(2.0, 2.0, 1.0).VertexBottomRight(2.0, -2.0, 1.0).ColorRGBA(0,0,0,255).Draw();
|
||||
GXTest::Quad().ColorRGBA(0,255,0,255).Draw();
|
||||
// first off, clear the full area.
|
||||
GXTest::Quad()
|
||||
.VertexTopLeft(-2.0, 2.0, 1.0)
|
||||
.VertexBottomLeft(-2.0, -2.0, 1.0)
|
||||
.VertexTopRight(2.0, 2.0, 1.0)
|
||||
.VertexBottomRight(2.0, -2.0, 1.0)
|
||||
.ColorRGBA(0, 0, 0, 255)
|
||||
.Draw();
|
||||
GXTest::Quad().ColorRGBA(0, 255, 0, 255).Draw();
|
||||
|
||||
// manual viewport setting to make sure we aren't limited (too much) by floating point precision
|
||||
// 2.0e-5 seems to be the smallest possible viewport width which behaves sane.
|
||||
// For this size, values of xpos from 0.583297729492 to 0.583328247070 will yield a covered pixel
|
||||
float vp_width = 2.0e-5f;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x101a,6);
|
||||
wgPipe->F32 = vp_width;
|
||||
wgPipe->F32 = -50.0f;
|
||||
wgPipe->F32 = 16777215.0f;
|
||||
wgPipe->F32 = 342.0f+xpos+vp_width;
|
||||
wgPipe->F32 = 392.0f;
|
||||
wgPipe->F32 = 16777215.0f;
|
||||
// manual viewport setting to make sure we aren't limited (too much) by floating point precision
|
||||
// 2.0e-5 seems to be the smallest possible viewport width which behaves sane.
|
||||
// For this size, values of xpos from 0.583297729492 to 0.583328247070 will yield a covered
|
||||
// pixel
|
||||
float vp_width = 2.0e-5f;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x101a, 6);
|
||||
wgPipe->F32 = vp_width;
|
||||
wgPipe->F32 = -50.0f;
|
||||
wgPipe->F32 = 16777215.0f;
|
||||
wgPipe->F32 = 342.0f + xpos + vp_width;
|
||||
wgPipe->F32 = 392.0f;
|
||||
wgPipe->F32 = 16777215.0f;
|
||||
|
||||
// now, draw the actual testing quad.
|
||||
GXTest::Quad().ColorRGBA(255,0,255,255).Draw();
|
||||
GXTest::CopyToTestBuffer(0, 0, 127, 127);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
// now, draw the actual testing quad.
|
||||
GXTest::Quad().ColorRGBA(255, 0, 255, 255).Draw();
|
||||
GXTest::CopyToTestBuffer(0, 0, 127, 127);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(0, 0, 128);
|
||||
u8 expectation = (xpos == 0.583297669888f || xpos == 0.583328306675f) ? 0 : 255;
|
||||
int subsample_index = (int)(xpos * 12.0f) % 12;
|
||||
DO_TEST(result.r == expectation, "Incorrect rasterization (result=%d,expected=%d,screencoord=%.12f,subsample_index=%d)", result.r, expectation, xpos, subsample_index);
|
||||
}
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(0, 0, 128);
|
||||
u8 expectation = (xpos == 0.583297669888f || xpos == 0.583328306675f) ? 0 : 255;
|
||||
int subsample_index = (int)(xpos * 12.0f) % 12;
|
||||
DO_TEST(result.r == expectation,
|
||||
"Incorrect rasterization (result=%d,expected=%d,screencoord=%.12f,subsample_index=%d)",
|
||||
result.r, expectation, xpos, subsample_index);
|
||||
}
|
||||
|
||||
// Guardband clipping indeed uses floating point math!
|
||||
// Hence, the smallest floating point value smaller than -2.0 will yield a clipped primitive.
|
||||
CGX_SetViewport(100.0f, 100.0f, 100.0f, 100.0f, 0.0f, 1.0f);
|
||||
for (float xpos : {-2.0000000f, nextafterf(-2.0f, -1.0f)})
|
||||
{
|
||||
// first off, clear the full area, including the guardband
|
||||
GXTest::Quad().VertexTopLeft(-2.0, 2.0, 1.0).VertexBottomLeft(-2.0, -2.0, 1.0).VertexTopRight(2.0, 2.0, 1.0).VertexBottomRight(2.0, -2.0, 1.0).ColorRGBA(0,0,0,255).Draw();
|
||||
// Guardband clipping indeed uses floating point math!
|
||||
// Hence, the smallest floating point value smaller than -2.0 will yield a clipped primitive.
|
||||
CGX_SetViewport(100.0f, 100.0f, 100.0f, 100.0f, 0.0f, 1.0f);
|
||||
for (float xpos : {-2.0000000f, nextafterf(-2.0f, -1.0f)})
|
||||
{
|
||||
// first off, clear the full area, including the guardband
|
||||
GXTest::Quad()
|
||||
.VertexTopLeft(-2.0, 2.0, 1.0)
|
||||
.VertexBottomLeft(-2.0, -2.0, 1.0)
|
||||
.VertexTopRight(2.0, 2.0, 1.0)
|
||||
.VertexBottomRight(2.0, -2.0, 1.0)
|
||||
.ColorRGBA(0, 0, 0, 255)
|
||||
.Draw();
|
||||
|
||||
// now, draw the actual testing quad such that all vertices are outside the viewport (and on the same side of the viewport)
|
||||
// The two left vertices are at the border of the guardband; if they are outside the guardband, the primitive gets clipped away.
|
||||
GXTest::Quad().VertexTopLeft(xpos, 1.0, 1.0).VertexBottomLeft(xpos, -1.0, 1.0).VertexTopRight(xpos+1.0, 1.0, 1.0).VertexBottomRight(xpos+1.0, -1.0, 1.0).ColorRGBA(255,0,255,255).Draw();
|
||||
GXTest::CopyToTestBuffer(50, 100, 127, 127);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
// now, draw the actual testing quad such that all vertices are outside the viewport (and on the
|
||||
// same side of the viewport)
|
||||
// The two left vertices are at the border of the guardband; if they are outside the guardband,
|
||||
// the primitive gets clipped away.
|
||||
GXTest::Quad()
|
||||
.VertexTopLeft(xpos, 1.0, 1.0)
|
||||
.VertexBottomLeft(xpos, -1.0, 1.0)
|
||||
.VertexTopRight(xpos + 1.0, 1.0, 1.0)
|
||||
.VertexBottomRight(xpos + 1.0, -1.0, 1.0)
|
||||
.ColorRGBA(255, 0, 255, 255)
|
||||
.Draw();
|
||||
GXTest::CopyToTestBuffer(50, 100, 127, 127);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(10, 10, 128);
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(10, 10, 128);
|
||||
|
||||
int expectation = (xpos >= -2.0) ? 255 : 0;
|
||||
DO_TEST(result.r == expectation, "Incorrect guardband clipping (result=%d,expected=%d,xpos=%.10f)", result.r, expectation, xpos);
|
||||
};
|
||||
int expectation = (xpos >= -2.0) ? 255 : 0;
|
||||
DO_TEST(result.r == expectation,
|
||||
"Incorrect guardband clipping (result=%d,expected=%d,xpos=%.10f)", result.r,
|
||||
expectation, xpos);
|
||||
};
|
||||
|
||||
END_TEST();
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
GXTest::Init();
|
||||
GXTest::Init();
|
||||
|
||||
CoordinatePrecisionTest();
|
||||
CoordinatePrecisionTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
617
gxtest/tev.cpp
617
gxtest/tev.cpp
@@ -3,397 +3,398 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <initializer_list>
|
||||
#include "common/hwtests.h"
|
||||
#include <math.h>
|
||||
#include <ogcsys.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <wiiuse/wpad.h>
|
||||
#include "common/hwtests.h"
|
||||
#include "gxtest/cgx.h"
|
||||
#include "gxtest/cgx_defaults.h"
|
||||
#include "gxtest/util.h"
|
||||
#include <ogcsys.h>
|
||||
|
||||
int TevCombinerExpectation(int a, int b, int c, int d, int shift, int bias, int op, int clamp)
|
||||
{
|
||||
a &= 255;
|
||||
b &= 255;
|
||||
c &= 255;
|
||||
a &= 255;
|
||||
b &= 255;
|
||||
c &= 255;
|
||||
|
||||
// TODO: Does not handle compare mode, yet
|
||||
c = c+(c>>7);
|
||||
u16 lshift = (shift == 1) ? 1 : (shift == 2) ? 2 : 0;
|
||||
u16 rshift = (shift == 3) ? 1 : 0;
|
||||
int round_bias = (shift==3) ? 0 : ((op==1) ? 127 : 128);
|
||||
int expected = (((a*(256-c) + b*c) << lshift)+round_bias)>>8; // lerp
|
||||
expected = (d << lshift) + expected * ((op == 1) ? (-1) : 1);
|
||||
expected += ((bias == 2) ? -128 : (bias == 1) ? 128 : 0) << lshift;
|
||||
expected >>= rshift;
|
||||
if (clamp)
|
||||
expected = (expected < 0) ? 0 : (expected > 255) ? 255 : expected;
|
||||
else
|
||||
expected = (expected < -1024) ? -1024 : (expected > 1023) ? 1023 : expected;
|
||||
return expected;
|
||||
// TODO: Does not handle compare mode, yet
|
||||
c = c + (c >> 7);
|
||||
u16 lshift = (shift == 1) ? 1 : (shift == 2) ? 2 : 0;
|
||||
u16 rshift = (shift == 3) ? 1 : 0;
|
||||
int round_bias = (shift == 3) ? 0 : ((op == 1) ? 127 : 128);
|
||||
int expected = (((a * (256 - c) + b * c) << lshift) + round_bias) >> 8; // lerp
|
||||
expected = (d << lshift) + expected * ((op == 1) ? (-1) : 1);
|
||||
expected += ((bias == 2) ? -128 : (bias == 1) ? 128 : 0) << lshift;
|
||||
expected >>= rshift;
|
||||
if (clamp)
|
||||
expected = (expected < 0) ? 0 : (expected > 255) ? 255 : expected;
|
||||
else
|
||||
expected = (expected < -1024) ? -1024 : (expected > 1023) ? 1023 : expected;
|
||||
return expected;
|
||||
}
|
||||
|
||||
void TevCombinerTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 1; // from vertex
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 1; // from vertex
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
|
||||
auto ac = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
CGX_LOAD_BP_REG(ac.hex);
|
||||
auto ac = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
CGX_LOAD_BP_REG(ac.hex);
|
||||
|
||||
// Test if we can reliably extract all bits of the tev combiner output...
|
||||
auto tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (tevreg.red = -1024; tevreg.red != 1023; tevreg.red = tevreg.red+1)
|
||||
{
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
// Test if we can reliably extract all bits of the tev combiner output...
|
||||
auto tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
for (int i = 0; i < 2; ++i)
|
||||
for (tevreg.red = -1024; tevreg.red != 1023; tevreg.red = tevreg.red + 1)
|
||||
{
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_C0;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.d = TEVCOLORARG_C0;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE<<24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
if (i == 0)
|
||||
{
|
||||
// 8 bits per channel: No worries about GetTevOutput making
|
||||
// mistakes when writing to framebuffer or when performing
|
||||
// an EFB copy.
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
if (i == 0)
|
||||
{
|
||||
// 8 bits per channel: No worries about GetTevOutput making
|
||||
// mistakes when writing to framebuffer or when performing
|
||||
// an EFB copy.
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
|
||||
int result = GXTest::GetTevOutput(genmode, cc, ac).r;
|
||||
int result = GXTest::GetTevOutput(genmode, cc, ac).r;
|
||||
|
||||
DO_TEST(result == tevreg.red, "Got %d, expected %d", result, (s32)tevreg.red);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: This doesn't quite work, yet.
|
||||
break;
|
||||
DO_TEST(result == tevreg.red, "Got %d, expected %d", result, (s32)tevreg.red);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: This doesn't quite work, yet.
|
||||
break;
|
||||
|
||||
// 6 bits per channel: Implement GetTevOutput functionality
|
||||
// manually, to verify how tev output is truncated to 6 bit
|
||||
// and how EFB copies upscale that to 8 bit again.
|
||||
ctrl.pixel_format = PIXELFMT_RGBA6_Z24;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
// 6 bits per channel: Implement GetTevOutput functionality
|
||||
// manually, to verify how tev output is truncated to 6 bit
|
||||
// and how EFB copies upscale that to 8 bit again.
|
||||
ctrl.pixel_format = PIXELFMT_RGBA6_Z24;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
|
||||
GXTest::Quad().AtDepth(1.0).ColorRGBA(255,255,255,255).Draw();
|
||||
GXTest::CopyToTestBuffer(0, 0, 99, 9);
|
||||
CGX_ForcePipelineFlush();
|
||||
CGX_WaitForGpuToFinish();
|
||||
u16 result = GXTest::ReadTestBuffer(5, 5, 100).r;
|
||||
GXTest::Quad().AtDepth(1.0).ColorRGBA(255, 255, 255, 255).Draw();
|
||||
GXTest::CopyToTestBuffer(0, 0, 99, 9);
|
||||
CGX_ForcePipelineFlush();
|
||||
CGX_WaitForGpuToFinish();
|
||||
u16 result = GXTest::ReadTestBuffer(5, 5, 100).r;
|
||||
|
||||
int expected = (((tevreg.red+1)>>2)&0xFF) << 2;
|
||||
expected = expected | (expected>>6);
|
||||
DO_TEST(result == expected, "Run %d: Got %d, expected %d", (int)tevreg.red, result, expected);
|
||||
}
|
||||
}
|
||||
int expected = (((tevreg.red + 1) >> 2) & 0xFF) << 2;
|
||||
expected = expected | (expected >> 6);
|
||||
DO_TEST(result == expected, "Run %d: Got %d, expected %d", (int)tevreg.red, result,
|
||||
expected);
|
||||
}
|
||||
}
|
||||
|
||||
// Now: Randomized testing of tev combiners.
|
||||
for (int i = 0x000000; i < 0x000F000; ++i)
|
||||
{
|
||||
if ((i & 0xFF00) == i)
|
||||
network_printf("progress: %x\n", i);
|
||||
// Now: Randomized testing of tev combiners.
|
||||
for (int i = 0x000000; i < 0x000F000; ++i)
|
||||
{
|
||||
if ((i & 0xFF00) == i)
|
||||
network_printf("progress: %x\n", i);
|
||||
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
|
||||
// Randomly configured TEV stage, output in PREV.
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.a = TEVCOLORARG_C0;
|
||||
cc.b = TEVCOLORARG_C1;
|
||||
cc.c = TEVCOLORARG_C2;
|
||||
cc.d = TEVCOLORARG_ZERO; // TEVCOLORARG_CPREV; // NOTE: TEVCOLORARG_CPREV doesn't actually seem to fetch its data from PREV when used in the first stage?
|
||||
cc.shift = rand() % 4;
|
||||
cc.bias = rand() % 3;
|
||||
cc.op = rand()%2;
|
||||
cc.clamp = rand() % 2;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
// Randomly configured TEV stage, output in PREV.
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.a = TEVCOLORARG_C0;
|
||||
cc.b = TEVCOLORARG_C1;
|
||||
cc.c = TEVCOLORARG_C2;
|
||||
cc.d = TEVCOLORARG_ZERO; // TEVCOLORARG_CPREV; // NOTE: TEVCOLORARG_CPREV doesn't actually seem
|
||||
// to fetch its data from PREV when used in the first stage?
|
||||
cc.shift = rand() % 4;
|
||||
cc.bias = rand() % 3;
|
||||
cc.op = rand() % 2;
|
||||
cc.clamp = rand() % 2;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
|
||||
int a = -1024 + (rand() % 2048);
|
||||
int b = -1024 + (rand() % 2048);
|
||||
int c = -1024 + (rand() % 2048);
|
||||
int d = 0; //-1024 + (rand() % 2048);
|
||||
tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = a;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(2, false); // c1
|
||||
tevreg.red = b;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(3, false); // c2
|
||||
tevreg.red = c;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(0, false); // prev
|
||||
tevreg.red = d;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
int a = -1024 + (rand() % 2048);
|
||||
int b = -1024 + (rand() % 2048);
|
||||
int c = -1024 + (rand() % 2048);
|
||||
int d = 0; //-1024 + (rand() % 2048);
|
||||
tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = a;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(2, false); // c1
|
||||
tevreg.red = b;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(3, false); // c2
|
||||
tevreg.red = c;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(0, false); // prev
|
||||
tevreg.red = d;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE<<24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
|
||||
int result = GXTest::GetTevOutput(genmode, cc, ac).r;
|
||||
int result = GXTest::GetTevOutput(genmode, cc, ac).r;
|
||||
|
||||
int expected = TevCombinerExpectation(a, b, c, d, cc.shift, cc.bias, cc.op, cc.clamp);
|
||||
DO_TEST(result == expected, "Mismatch on a=%d, b=%d, c=%d, d=%d, shift=%d, bias=%d, op=%d, clamp=%d: expected %d, got %d", a, b, c, d, (u32)cc.shift, (u32)cc.bias, (u32)cc.op, (u32)cc.clamp, expected, result);
|
||||
int expected = TevCombinerExpectation(a, b, c, d, cc.shift, cc.bias, cc.op, cc.clamp);
|
||||
DO_TEST(result == expected, "Mismatch on a=%d, b=%d, c=%d, d=%d, shift=%d, bias=%d, op=%d, "
|
||||
"clamp=%d: expected %d, got %d",
|
||||
a, b, c, d, (u32)cc.shift, (u32)cc.bias, (u32)cc.op, (u32)cc.clamp, expected, result);
|
||||
|
||||
WPAD_ScanPads();
|
||||
WPAD_ScanPads();
|
||||
|
||||
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
|
||||
break;
|
||||
}
|
||||
if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)
|
||||
break;
|
||||
}
|
||||
|
||||
// Testing compare mode: (a.r > b.r) ? c.a : 0
|
||||
// One of the following will be the case for the alpha combiner:
|
||||
// (1) a.r will be assigned the value of c2.r (color combiner setting)
|
||||
// (2) a.r will be assigned the value of c0.r (alpha combiner setting)
|
||||
// If (1) is the case, the first run of this test will return black and
|
||||
// the second one will return red. If (2) is the case, the test will
|
||||
// always return black.
|
||||
// Indeed, this test shows that the alpha combiner reads the a and b
|
||||
// inputs from the color combiner setting, i.e. scenario (1) is
|
||||
// accurate to hardware behavior.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
// Testing compare mode: (a.r > b.r) ? c.a : 0
|
||||
// One of the following will be the case for the alpha combiner:
|
||||
// (1) a.r will be assigned the value of c2.r (color combiner setting)
|
||||
// (2) a.r will be assigned the value of c0.r (alpha combiner setting)
|
||||
// If (1) is the case, the first run of this test will return black and
|
||||
// the second one will return red. If (2) is the case, the test will
|
||||
// always return black.
|
||||
// Indeed, this test shows that the alpha combiner reads the a and b
|
||||
// inputs from the color combiner setting, i.e. scenario (1) is
|
||||
// accurate to hardware behavior.
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.a = TEVCOLORARG_C2;
|
||||
cc.b = TEVCOLORARG_C1;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
auto cc = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc.a = TEVCOLORARG_C2;
|
||||
cc.b = TEVCOLORARG_C1;
|
||||
CGX_LOAD_BP_REG(cc.hex);
|
||||
|
||||
auto ac = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac.bias = TevBias_COMPARE;
|
||||
ac.a = TEVALPHAARG_A0; // different from color combiner
|
||||
ac.b = TEVALPHAARG_A1; // same as color combiner
|
||||
ac.c = TEVALPHAARG_A2;
|
||||
CGX_LOAD_BP_REG(ac.hex);
|
||||
auto ac = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac.bias = TevBias_COMPARE;
|
||||
ac.a = TEVALPHAARG_A0; // different from color combiner
|
||||
ac.b = TEVALPHAARG_A1; // same as color combiner
|
||||
ac.c = TEVALPHAARG_A2;
|
||||
CGX_LOAD_BP_REG(ac.hex);
|
||||
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE<<24;
|
||||
ctrl.pixel_format = PIXELFMT_RGBA6_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGBA6_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
|
||||
tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = 127; // 127 is always NOT less than 127.
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(1, false); // c0
|
||||
tevreg.red = 127; // 127 is always NOT less than 127.
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
|
||||
tevreg = CGXDefault<TevReg>(2, false); // c1
|
||||
tevreg.red = 127;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(2, false); // c1
|
||||
tevreg.red = 127;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
|
||||
tevreg = CGXDefault<TevReg>(3, false); // c2
|
||||
tevreg.red = 127+i; // 127+i is less than 127 iff i>0.
|
||||
tevreg.alpha = 255;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
tevreg = CGXDefault<TevReg>(3, false); // c2
|
||||
tevreg.red = 127 + i; // 127+i is less than 127 iff i>0.
|
||||
tevreg.alpha = 255;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
|
||||
int result = GXTest::GetTevOutput(genmode, cc, ac).a;
|
||||
int expected = (i == 1) ? 255 : 0;
|
||||
DO_TEST(result == expected, "Mismatch on run %d: expected %d, got %d", i, expected, result);
|
||||
}
|
||||
int result = GXTest::GetTevOutput(genmode, cc, ac).a;
|
||||
int expected = (i == 1) ? 255 : 0;
|
||||
DO_TEST(result == expected, "Mismatch on run %d: expected %d, got %d", i, expected, result);
|
||||
}
|
||||
|
||||
END_TEST();
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
void KonstTest()
|
||||
{
|
||||
START_TEST();
|
||||
START_TEST();
|
||||
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
CGX_LOAD_BP_REG(CGXDefault<TwoTevStageOrders>(0).hex);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1009, 1);
|
||||
wgPipe->U32 = 1; // 1 color channel
|
||||
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 0; // from register
|
||||
chan.ambsource = 0; // from register
|
||||
chan.enablelighting = false;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
LitChannel chan;
|
||||
chan.hex = 0;
|
||||
chan.matsource = 0; // from register
|
||||
chan.ambsource = 0; // from register
|
||||
chan.enablelighting = false;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x100e, 1); // color channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1010, 1); // alpha channel 1
|
||||
wgPipe->U32 = chan.hex;
|
||||
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 1; // Two stages
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 1; // Two stages
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGB8_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 0; // 0 = enable clipping, 1 = disable clipping
|
||||
CGX_BEGIN_LOAD_XF_REGS(0x1005, 1);
|
||||
wgPipe->U32 = 0; // 0 = enable clipping, 1 = disable clipping
|
||||
|
||||
// Set up "konst" colors with recognizable values.
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
auto tevreg = CGXDefault<TevReg>(i, true);
|
||||
tevreg.red = 10 + 50 * i;
|
||||
tevreg.green = 20 + 50 * i;
|
||||
tevreg.blue = 30 + 50 * i;
|
||||
tevreg.alpha = 40 + 50 * i;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
}
|
||||
// Set up "konst" colors with recognizable values.
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
auto tevreg = CGXDefault<TevReg>(i, true);
|
||||
tevreg.red = 10 + 50 * i;
|
||||
tevreg.green = 20 + 50 * i;
|
||||
tevreg.blue = 30 + 50 * i;
|
||||
tevreg.alpha = 40 + 50 * i;
|
||||
CGX_LOAD_BP_REG(tevreg.low);
|
||||
CGX_LOAD_BP_REG(tevreg.high);
|
||||
}
|
||||
|
||||
// Make sure blending is set appropriately (no blending).
|
||||
BlendMode bm;
|
||||
bm.hex = (BPMEM_BLENDMODE << 24);
|
||||
bm.blendenable = 0;
|
||||
bm.logicopenable = 0;
|
||||
bm.dither = 1;
|
||||
bm.colorupdate = 1;
|
||||
bm.alphaupdate = 1;
|
||||
bm.dstfactor = GX_BL_INVSRCALPHA;
|
||||
bm.srcfactor = GX_BL_SRCALPHA;
|
||||
bm.subtract = 0;
|
||||
bm.logicmode = 0;
|
||||
CGX_LOAD_BP_REG(bm.hex);
|
||||
// Make sure blending is set appropriately (no blending).
|
||||
BlendMode bm;
|
||||
bm.hex = (BPMEM_BLENDMODE << 24);
|
||||
bm.blendenable = 0;
|
||||
bm.logicopenable = 0;
|
||||
bm.dither = 1;
|
||||
bm.colorupdate = 1;
|
||||
bm.alphaupdate = 1;
|
||||
bm.dstfactor = GX_BL_INVSRCALPHA;
|
||||
bm.srcfactor = GX_BL_SRCALPHA;
|
||||
bm.subtract = 0;
|
||||
bm.logicmode = 0;
|
||||
CGX_LOAD_BP_REG(bm.hex);
|
||||
|
||||
// Test for values returned for "konst" TEV inputs. Goes through
|
||||
// all the possible values for kasel and kcsel.
|
||||
for (int step = 0; step < 64; ++step)
|
||||
{
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
// Test for values returned for "konst" TEV inputs. Goes through
|
||||
// all the possible values for kasel and kcsel.
|
||||
for (int step = 0; step < 64; ++step)
|
||||
{
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
|
||||
// First stage pulls in konst values.
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f, 1.0f);
|
||||
auto cc0 = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc0.d = TEVCOLORARG_KONST;
|
||||
CGX_LOAD_BP_REG(cc0.hex);
|
||||
auto ac0 = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac0.d = TEVALPHAARG_KONST;
|
||||
CGX_LOAD_BP_REG(ac0.hex);
|
||||
// First stage pulls in konst values.
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f, 1.0f);
|
||||
auto cc0 = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc0.d = TEVCOLORARG_KONST;
|
||||
CGX_LOAD_BP_REG(cc0.hex);
|
||||
auto ac0 = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac0.d = TEVALPHAARG_KONST;
|
||||
CGX_LOAD_BP_REG(ac0.hex);
|
||||
|
||||
// Second stage makes sure the output is always in the red channel.
|
||||
auto cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(1);
|
||||
cc1.d = step < 32 ? TEVCOLORARG_CPREV : TEVCOLORARG_APREV;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
auto ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(1);
|
||||
ac1.d = TEVALPHAARG_ZERO;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
// Second stage makes sure the output is always in the red channel.
|
||||
auto cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(1);
|
||||
cc1.d = step < 32 ? TEVCOLORARG_CPREV : TEVCOLORARG_APREV;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
auto ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(1);
|
||||
ac1.d = TEVALPHAARG_ZERO;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
|
||||
TevKSel sel;
|
||||
sel.hex = BPMEM_TEV_KSEL << 24;
|
||||
sel.swap1 = 0;
|
||||
sel.swap2 = 0;
|
||||
sel.kcsel0 = step < 32 ? step : 0;
|
||||
sel.kcsel1 = 0;
|
||||
sel.kasel0 = step >= 32 ? step : 0;
|
||||
sel.kasel1 = 0;
|
||||
CGX_LOAD_BP_REG(sel.hex);
|
||||
TevKSel sel;
|
||||
sel.hex = BPMEM_TEV_KSEL << 24;
|
||||
sel.swap1 = 0;
|
||||
sel.swap2 = 0;
|
||||
sel.kcsel0 = step < 32 ? step : 0;
|
||||
sel.kcsel1 = 0;
|
||||
sel.kasel0 = step >= 32 ? step : 0;
|
||||
sel.kasel1 = 0;
|
||||
CGX_LOAD_BP_REG(sel.hex);
|
||||
|
||||
GXTest::Quad().ColorRGBA(0, 0, 0, 0xff).Draw();
|
||||
GXTest::Quad().ColorRGBA(0, 0, 0, 0xff).Draw();
|
||||
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
int expected[] = {
|
||||
255, 223, 191, 159, 128, 96, 64, 32,
|
||||
0, 0, 0, 0, 10, 60, 110, 160,
|
||||
10, 60, 110, 160, 20, 70, 120, 170,
|
||||
30, 80, 130, 180, 40, 90, 140, 190,
|
||||
255, 223, 191, 159, 128, 96, 64, 32,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
10, 60, 110, 160, 20, 70, 120, 170,
|
||||
30, 80, 130, 180, 40, 90, 140, 190,
|
||||
};
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
int expected[] = {
|
||||
255, 223, 191, 159, 128, 96, 64, 32, 0, 0, 0, 0, 10, 60, 110, 160,
|
||||
10, 60, 110, 160, 20, 70, 120, 170, 30, 80, 130, 180, 40, 90, 140, 190,
|
||||
255, 223, 191, 159, 128, 96, 64, 32, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
10, 60, 110, 160, 20, 70, 120, 170, 30, 80, 130, 180, 40, 90, 140, 190,
|
||||
};
|
||||
|
||||
DO_TEST(expected[step] == result.r, "konst test failed; actual %d, expected %d", result.r, expected[step]);
|
||||
DO_TEST(expected[step] == result.r, "konst test failed; actual %d, expected %d", result.r,
|
||||
expected[step]);
|
||||
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
}
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
}
|
||||
|
||||
// Test the behavior of TEVCOLORARG_HALF.
|
||||
{
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
// Test the behavior of TEVCOLORARG_HALF.
|
||||
{
|
||||
auto genmode = CGXDefault<GenMode>();
|
||||
genmode.numtevstages = 0; // One stage
|
||||
CGX_LOAD_BP_REG(genmode.hex);
|
||||
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
auto zmode = CGXDefault<ZMode>();
|
||||
CGX_LOAD_BP_REG(zmode.hex);
|
||||
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
int test_x = 125, test_y = 25; // Somewhere within the viewport
|
||||
|
||||
// First stage pulls in konst values.
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f, 1.0f);
|
||||
auto cc0 = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc0.d = TEVCOLORARG_HALF;
|
||||
CGX_LOAD_BP_REG(cc0.hex);
|
||||
auto ac0 = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac0.d = TEVALPHAARG_ZERO;
|
||||
CGX_LOAD_BP_REG(ac0.hex);
|
||||
// First stage pulls in konst values.
|
||||
CGX_SetViewport(0.0f, 0.0f, 201.0f, 50.0f, 0.0f, 1.0f);
|
||||
auto cc0 = CGXDefault<TevStageCombiner::ColorCombiner>(0);
|
||||
cc0.d = TEVCOLORARG_HALF;
|
||||
CGX_LOAD_BP_REG(cc0.hex);
|
||||
auto ac0 = CGXDefault<TevStageCombiner::AlphaCombiner>(0);
|
||||
ac0.d = TEVALPHAARG_ZERO;
|
||||
CGX_LOAD_BP_REG(ac0.hex);
|
||||
|
||||
GXTest::Quad().ColorRGBA(0, 0, 0, 0xff).Draw();
|
||||
GXTest::Quad().ColorRGBA(0, 0, 0, 0xff).Draw();
|
||||
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
GXTest::CopyToTestBuffer(0, 0, 199, 49);
|
||||
CGX_WaitForGpuToFinish();
|
||||
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
GXTest::Vec4<u8> result = GXTest::ReadTestBuffer(test_x, test_y, 200);
|
||||
|
||||
DO_TEST(result.r == 128, "TEVCOLORARG_HALF test failed; actual %d", result.r);
|
||||
DO_TEST(result.r == 128, "TEVCOLORARG_HALF test failed; actual %d", result.r);
|
||||
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
}
|
||||
GXTest::DebugDisplayEfbContents();
|
||||
}
|
||||
|
||||
END_TEST();
|
||||
END_TEST();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
network_init();
|
||||
WPAD_Init();
|
||||
|
||||
GXTest::Init();
|
||||
GXTest::Init();
|
||||
|
||||
TevCombinerTest();
|
||||
KonstTest();
|
||||
TevCombinerTest();
|
||||
KonstTest();
|
||||
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
network_printf("Shutting down...\n");
|
||||
network_shutdown();
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
564
gxtest/util.cpp
564
gxtest/util.cpp
@@ -3,10 +3,10 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <gccore.h>
|
||||
#include <malloc.h>
|
||||
#include <ogc/video.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gxtest/cgx.h"
|
||||
#include "gxtest/cgx_defaults.h"
|
||||
@@ -16,405 +16,403 @@
|
||||
|
||||
namespace GXTest
|
||||
{
|
||||
#define TEST_BUFFER_SIZE (640*528*4)
|
||||
#define TEST_BUFFER_SIZE (640 * 528 * 4)
|
||||
static u32* test_buffer;
|
||||
|
||||
#ifdef ENABLE_DEBUG_DISPLAY
|
||||
static u32 fb = 0;
|
||||
static void *frameBuffer[2] = { NULL, NULL};
|
||||
static GXRModeObj *rmode;
|
||||
static void* frameBuffer[2] = {NULL, NULL};
|
||||
static GXRModeObj* rmode;
|
||||
|
||||
float yscale;
|
||||
u32 xfbHeight;
|
||||
#endif
|
||||
|
||||
|
||||
void Init()
|
||||
{
|
||||
GXColor background = {0, 0x27, 0, 0xff};
|
||||
GXColor background = {0, 0x27, 0, 0xff};
|
||||
|
||||
#if defined(ENABLE_DEBUG_DISPLAY)
|
||||
VIDEO_Init();
|
||||
VIDEO_Init();
|
||||
|
||||
rmode = VIDEO_GetPreferredMode(NULL);
|
||||
rmode = VIDEO_GetPreferredMode(NULL);
|
||||
|
||||
frameBuffer[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
|
||||
frameBuffer[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
|
||||
frameBuffer[0] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
|
||||
frameBuffer[1] = MEM_K0_TO_K1(SYS_AllocateFramebuffer(rmode));
|
||||
|
||||
VIDEO_Configure(rmode);
|
||||
VIDEO_SetNextFramebuffer(frameBuffer[fb]);
|
||||
VIDEO_SetBlack(FALSE);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
if(rmode->viTVMode&VI_NON_INTERLACE) VIDEO_WaitVSync();
|
||||
VIDEO_Configure(rmode);
|
||||
VIDEO_SetNextFramebuffer(frameBuffer[fb]);
|
||||
VIDEO_SetBlack(FALSE);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
if (rmode->viTVMode & VI_NON_INTERLACE)
|
||||
VIDEO_WaitVSync();
|
||||
|
||||
CGX_Init();
|
||||
CGX_Init();
|
||||
|
||||
GX_SetCopyClear(background, 0x00ffffff);
|
||||
GX_SetViewport(0,0,rmode->fbWidth,rmode->efbHeight,0,1);
|
||||
yscale = GX_GetYScaleFactor(rmode->efbHeight, rmode->xfbHeight);
|
||||
xfbHeight = GX_SetDispCopyYScale(yscale);
|
||||
GX_SetScissor(0,0,rmode->fbWidth,rmode->efbHeight);
|
||||
GX_SetDispCopySrc(0,0,rmode->fbWidth,rmode->efbHeight);
|
||||
GX_SetDispCopyDst(rmode->fbWidth,xfbHeight);
|
||||
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, 1, rmode->vfilter);
|
||||
GX_SetFieldMode(rmode->field_rendering, ((rmode->viHeight==2*rmode->xfbHeight)?1:0));
|
||||
GX_SetDispCopyGamma(GX_GM_1_0);
|
||||
GX_SetCopyClear(background, 0x00ffffff);
|
||||
GX_SetViewport(0, 0, rmode->fbWidth, rmode->efbHeight, 0, 1);
|
||||
yscale = GX_GetYScaleFactor(rmode->efbHeight, rmode->xfbHeight);
|
||||
xfbHeight = GX_SetDispCopyYScale(yscale);
|
||||
GX_SetScissor(0, 0, rmode->fbWidth, rmode->efbHeight);
|
||||
GX_SetDispCopySrc(0, 0, rmode->fbWidth, rmode->efbHeight);
|
||||
GX_SetDispCopyDst(rmode->fbWidth, xfbHeight);
|
||||
GX_SetCopyFilter(rmode->aa, rmode->sample_pattern, 1, rmode->vfilter);
|
||||
GX_SetFieldMode(rmode->field_rendering, ((rmode->viHeight == 2 * rmode->xfbHeight) ? 1 : 0));
|
||||
GX_SetDispCopyGamma(GX_GM_1_0);
|
||||
#else
|
||||
CGX_Init();
|
||||
CGX_Init();
|
||||
|
||||
GX_SetCopyClear(background, 0x00ffffff);
|
||||
GX_SetViewport(0,0,640,528,0,1);
|
||||
GX_SetScissor(0,0,640,528);
|
||||
GX_SetCopyClear(background, 0x00ffffff);
|
||||
GX_SetViewport(0, 0, 640, 528, 0, 1);
|
||||
GX_SetScissor(0, 0, 640, 528);
|
||||
#endif
|
||||
|
||||
test_buffer = (u32*)memalign(32, 640*528*4);
|
||||
test_buffer = (u32*)memalign(32, 640 * 528 * 4);
|
||||
|
||||
GX_SetTexCopySrc(0, 0, 100, 100);
|
||||
GX_SetTexCopyDst(100, 100, GX_TF_RGBA8, false);
|
||||
GX_SetTexCopySrc(0, 0, 100, 100);
|
||||
GX_SetTexCopyDst(100, 100, GX_TF_RGBA8, false);
|
||||
|
||||
// We draw a dummy quad here to apply cached GX state...
|
||||
// TODO: Implement proper GPU initialization in GX so that we don't need
|
||||
// to do this anymore
|
||||
GX_ClearVtxDesc();
|
||||
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
||||
// We draw a dummy quad here to apply cached GX state...
|
||||
// TODO: Implement proper GPU initialization in GX so that we don't need
|
||||
// to do this anymore
|
||||
GX_ClearVtxDesc();
|
||||
GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
||||
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
GX_SetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
|
||||
Mtx model;
|
||||
guMtxIdentity(model);
|
||||
GX_LoadPosMtxImm(model, GX_PNMTX0);
|
||||
Mtx model;
|
||||
guMtxIdentity(model);
|
||||
GX_LoadPosMtxImm(model, GX_PNMTX0);
|
||||
|
||||
float mtx[4][4];
|
||||
memset(mtx, 0, sizeof(mtx));
|
||||
mtx[0][0] = 1;
|
||||
mtx[1][1] = 1;
|
||||
mtx[2][2] = -1;
|
||||
CGX_LoadProjectionMatrixOrthographic(mtx);
|
||||
float mtx[4][4];
|
||||
memset(mtx, 0, sizeof(mtx));
|
||||
mtx[0][0] = 1;
|
||||
mtx[1][1] = 1;
|
||||
mtx[2][2] = -1;
|
||||
CGX_LoadProjectionMatrixOrthographic(mtx);
|
||||
|
||||
GX_SetNumChans(1); // damnit dirty state...
|
||||
GX_SetNumTexGens(0);
|
||||
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0);
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||
GX_SetNumChans(1); // damnit dirty state...
|
||||
GX_SetNumTexGens(0);
|
||||
GX_SetTevOrder(GX_TEVSTAGE0, GX_TEXCOORDNULL, GX_TEXMAP_NULL, GX_COLOR0A0);
|
||||
GX_SetTevOp(GX_TEVSTAGE0, GX_PASSCLR);
|
||||
|
||||
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
// Bottom right
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
// Bottom right
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
|
||||
// Top right
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
// Top right
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
|
||||
// Top left
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
// Top left
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
|
||||
// Bottom left
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
// Bottom left
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = -1.0;
|
||||
wgPipe->F32 = 1.0;
|
||||
wgPipe->U32 = 0xFFFFFFFF;
|
||||
|
||||
GX_End();
|
||||
GX_Flush();
|
||||
GX_End();
|
||||
GX_Flush();
|
||||
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE<<24;
|
||||
ctrl.pixel_format = PIXELFMT_RGBA6_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
PE_CONTROL ctrl;
|
||||
ctrl.hex = BPMEM_ZCOMPARE << 24;
|
||||
ctrl.pixel_format = PIXELFMT_RGBA6_Z24;
|
||||
ctrl.zformat = ZC_LINEAR;
|
||||
ctrl.early_ztest = 0;
|
||||
CGX_LOAD_BP_REG(ctrl.hex);
|
||||
}
|
||||
|
||||
void DebugDisplayEfbContents()
|
||||
{
|
||||
#ifdef ENABLE_DEBUG_DISPLAY
|
||||
CGX_DoEfbCopyXfb(0, 0, rmode->fbWidth, rmode->efbHeight, xfbHeight, frameBuffer[fb]);
|
||||
CGX_WaitForGpuToFinish();
|
||||
CGX_DoEfbCopyXfb(0, 0, rmode->fbWidth, rmode->efbHeight, xfbHeight, frameBuffer[fb]);
|
||||
CGX_WaitForGpuToFinish();
|
||||
|
||||
VIDEO_SetNextFramebuffer(frameBuffer[fb]);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
fb ^= 1;
|
||||
VIDEO_SetNextFramebuffer(frameBuffer[fb]);
|
||||
VIDEO_Flush();
|
||||
VIDEO_WaitVSync();
|
||||
fb ^= 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
Vec4<u8> ReadTestBuffer(int s, int t, int width)
|
||||
{
|
||||
u16 sBlk = s >> 2;
|
||||
u16 tBlk = t >> 2;
|
||||
u16 widthBlks = (width >> 2) + 1;
|
||||
u32 base = (tBlk * widthBlks + sBlk) << 5;
|
||||
u16 blkS = s & 3;
|
||||
u16 blkT = t & 3;
|
||||
u32 blkOff = (blkT << 2) + blkS;
|
||||
u16 sBlk = s >> 2;
|
||||
u16 tBlk = t >> 2;
|
||||
u16 widthBlks = (width >> 2) + 1;
|
||||
u32 base = (tBlk * widthBlks + sBlk) << 5;
|
||||
u16 blkS = s & 3;
|
||||
u16 blkT = t & 3;
|
||||
u32 blkOff = (blkT << 2) + blkS;
|
||||
|
||||
u32 offset = (base + blkOff) << 1 ;
|
||||
const u8* valAddr = ((u8*)test_buffer) + offset;
|
||||
u32 offset = (base + blkOff) << 1;
|
||||
const u8* valAddr = ((u8*)test_buffer) + offset;
|
||||
|
||||
Vec4<u8> ret;
|
||||
ret.r = valAddr[1];
|
||||
ret.g = valAddr[32];
|
||||
ret.b = valAddr[33];
|
||||
ret.a = valAddr[0];
|
||||
return ret;
|
||||
Vec4<u8> ret;
|
||||
ret.r = valAddr[1];
|
||||
ret.g = valAddr[32];
|
||||
ret.b = valAddr[33];
|
||||
ret.a = valAddr[0];
|
||||
return ret;
|
||||
}
|
||||
|
||||
Quad::Quad()
|
||||
{
|
||||
// top left
|
||||
x[0] = -1.0;
|
||||
y[0] = 1.0;
|
||||
z[0] = 1.0;
|
||||
// top left
|
||||
x[0] = -1.0;
|
||||
y[0] = 1.0;
|
||||
z[0] = 1.0;
|
||||
|
||||
// top right
|
||||
x[1] = 1.0;
|
||||
y[1] = 1.0;
|
||||
z[1] = 1.0;
|
||||
// top right
|
||||
x[1] = 1.0;
|
||||
y[1] = 1.0;
|
||||
z[1] = 1.0;
|
||||
|
||||
// bottom right
|
||||
x[2] = 1.0;
|
||||
y[2] = -1.0;
|
||||
z[2] = 1.0;
|
||||
// bottom right
|
||||
x[2] = 1.0;
|
||||
y[2] = -1.0;
|
||||
z[2] = 1.0;
|
||||
|
||||
// bottom left
|
||||
x[3] = -1.0;
|
||||
y[3] = -1.0;
|
||||
z[3] = 1.0;
|
||||
// bottom left
|
||||
x[3] = -1.0;
|
||||
y[3] = -1.0;
|
||||
z[3] = 1.0;
|
||||
|
||||
has_color = false;
|
||||
has_color = false;
|
||||
}
|
||||
|
||||
Quad& Quad::VertexTopLeft(f32 x, f32 y, f32 z)
|
||||
{
|
||||
this->x[0] = x;
|
||||
this->y[0] = y;
|
||||
this->z[0] = z;
|
||||
return *this;
|
||||
this->x[0] = x;
|
||||
this->y[0] = y;
|
||||
this->z[0] = z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Quad& Quad::VertexTopRight(f32 x, f32 y, f32 z)
|
||||
{
|
||||
this->x[1] = x;
|
||||
this->y[1] = y;
|
||||
this->z[1] = z;
|
||||
return *this;
|
||||
this->x[1] = x;
|
||||
this->y[1] = y;
|
||||
this->z[1] = z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Quad& Quad::VertexBottomRight(f32 x, f32 y, f32 z)
|
||||
{
|
||||
this->x[2] = x;
|
||||
this->y[2] = y;
|
||||
this->z[2] = z;
|
||||
return *this;
|
||||
this->x[2] = x;
|
||||
this->y[2] = y;
|
||||
this->z[2] = z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Quad& Quad::VertexBottomLeft(f32 x, f32 y, f32 z)
|
||||
{
|
||||
this->x[3] = x;
|
||||
this->y[3] = y;
|
||||
this->z[3] = z;
|
||||
return *this;
|
||||
this->x[3] = x;
|
||||
this->y[3] = y;
|
||||
this->z[3] = z;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Quad& Quad::AtDepth(f32 depth)
|
||||
{
|
||||
z[0] = z[1] = z[2] = z[3] = depth;
|
||||
z[0] = z[1] = z[2] = z[3] = depth;
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Quad& Quad::ColorRGBA(u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
color = ((u32)r << 24) | ((u32)g << 16) | ((u32)b << 8) | (u32)a;
|
||||
has_color = true;
|
||||
color = ((u32)r << 24) | ((u32)g << 16) | ((u32)b << 8) | (u32)a;
|
||||
has_color = true;
|
||||
|
||||
return *this;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Quad::Draw()
|
||||
{
|
||||
VAT vtxattr;
|
||||
vtxattr.g0.Hex = 0;
|
||||
vtxattr.g1.Hex = 0;
|
||||
vtxattr.g2.Hex = 0;
|
||||
VAT vtxattr;
|
||||
vtxattr.g0.Hex = 0;
|
||||
vtxattr.g1.Hex = 0;
|
||||
vtxattr.g2.Hex = 0;
|
||||
|
||||
vtxattr.g0.PosElements = VA_TYPE_POS_XYZ;
|
||||
vtxattr.g0.PosFormat = VA_FMT_F32;
|
||||
vtxattr.g0.PosElements = VA_TYPE_POS_XYZ;
|
||||
vtxattr.g0.PosFormat = VA_FMT_F32;
|
||||
|
||||
if (has_color)
|
||||
{
|
||||
vtxattr.g0.Color0Elements = VA_TYPE_CLR_RGBA;
|
||||
vtxattr.g0.Color0Comp = VA_FMT_RGBA8;
|
||||
}
|
||||
if (has_color)
|
||||
{
|
||||
vtxattr.g0.Color0Elements = VA_TYPE_CLR_RGBA;
|
||||
vtxattr.g0.Color0Comp = VA_FMT_RGBA8;
|
||||
}
|
||||
|
||||
// TODO: Figure out what this does and why it needs to be 1 for Dolphin not to error out
|
||||
vtxattr.g0.ByteDequant = 1;
|
||||
// TODO: Figure out what this does and why it needs to be 1 for Dolphin not to error out
|
||||
vtxattr.g0.ByteDequant = 1;
|
||||
|
||||
TVtxDesc vtxdesc;
|
||||
vtxdesc.Hex = 0;
|
||||
vtxdesc.Position = VTXATTR_DIRECT;
|
||||
TVtxDesc vtxdesc;
|
||||
vtxdesc.Hex = 0;
|
||||
vtxdesc.Position = VTXATTR_DIRECT;
|
||||
|
||||
if (has_color)
|
||||
vtxdesc.Color0 = VTXATTR_DIRECT;
|
||||
if (has_color)
|
||||
vtxdesc.Color0 = VTXATTR_DIRECT;
|
||||
|
||||
// TODO: Not sure if the order of these two is correct
|
||||
CGX_LOAD_CP_REG(0x50, vtxdesc.Hex0);
|
||||
CGX_LOAD_CP_REG(0x60, vtxdesc.Hex1);
|
||||
// TODO: Not sure if the order of these two is correct
|
||||
CGX_LOAD_CP_REG(0x50, vtxdesc.Hex0);
|
||||
CGX_LOAD_CP_REG(0x60, vtxdesc.Hex1);
|
||||
|
||||
CGX_LOAD_CP_REG(0x70, vtxattr.g0.Hex);
|
||||
CGX_LOAD_CP_REG(0x80, vtxattr.g1.Hex);
|
||||
CGX_LOAD_CP_REG(0x90, vtxattr.g2.Hex);
|
||||
CGX_LOAD_CP_REG(0x70, vtxattr.g0.Hex);
|
||||
CGX_LOAD_CP_REG(0x80, vtxattr.g1.Hex);
|
||||
CGX_LOAD_CP_REG(0x90, vtxattr.g2.Hex);
|
||||
|
||||
/* TODO: Should reset this matrix..
|
||||
float mtx[3][4];
|
||||
memset(&mtx, 0, sizeof(mtx));
|
||||
mtx[0][0] = 1.0;
|
||||
mtx[1][1] = 1.0;
|
||||
mtx[2][2] = 1.0;
|
||||
CGX_LoadPosMatrixDirect(mtx, 0);*/
|
||||
/* TODO: Should reset this matrix..
|
||||
float mtx[3][4];
|
||||
memset(&mtx, 0, sizeof(mtx));
|
||||
mtx[0][0] = 1.0;
|
||||
mtx[1][1] = 1.0;
|
||||
mtx[2][2] = 1.0;
|
||||
CGX_LoadPosMatrixDirect(mtx, 0);*/
|
||||
|
||||
float mtx[4][4];
|
||||
memset(mtx, 0, sizeof(mtx));
|
||||
mtx[0][0] = 1;
|
||||
mtx[1][1] = 1;
|
||||
mtx[2][2] = -1;
|
||||
CGX_LoadProjectionMatrixOrthographic(mtx);
|
||||
float mtx[4][4];
|
||||
memset(mtx, 0, sizeof(mtx));
|
||||
mtx[0][0] = 1;
|
||||
mtx[1][1] = 1;
|
||||
mtx[2][2] = -1;
|
||||
CGX_LoadProjectionMatrixOrthographic(mtx);
|
||||
|
||||
wgPipe->U8 = 0x80; // draw quads
|
||||
wgPipe->U16 = 4; // 4 vertices
|
||||
wgPipe->U8 = 0x80; // draw quads
|
||||
wgPipe->U16 = 4; // 4 vertices
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
wgPipe->F32 = x[i];
|
||||
wgPipe->F32 = y[i];
|
||||
wgPipe->F32 = z[i];
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
wgPipe->F32 = x[i];
|
||||
wgPipe->F32 = y[i];
|
||||
wgPipe->F32 = z[i];
|
||||
|
||||
if (has_color)
|
||||
wgPipe->U32 = color;
|
||||
}
|
||||
if (has_color)
|
||||
wgPipe->U32 = color;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyToTestBuffer(int left_most_pixel, int top_most_pixel, int right_most_pixel, int bottom_most_pixel)
|
||||
void CopyToTestBuffer(int left_most_pixel, int top_most_pixel, int right_most_pixel,
|
||||
int bottom_most_pixel)
|
||||
{
|
||||
// TODO: Do we need to impose additional constraints on the parameters?
|
||||
memset(test_buffer, 0, TEST_BUFFER_SIZE);
|
||||
CGX_DoEfbCopyTex(left_most_pixel, top_most_pixel,
|
||||
right_most_pixel - left_most_pixel + 1,
|
||||
bottom_most_pixel - top_most_pixel + 1, 0x6 /*RGBA8*/,
|
||||
false, test_buffer);
|
||||
// TODO: Do we need to impose additional constraints on the parameters?
|
||||
memset(test_buffer, 0, TEST_BUFFER_SIZE);
|
||||
CGX_DoEfbCopyTex(left_most_pixel, top_most_pixel, right_most_pixel - left_most_pixel + 1,
|
||||
bottom_most_pixel - top_most_pixel + 1, 0x6 /*RGBA8*/, false, test_buffer);
|
||||
}
|
||||
|
||||
|
||||
Vec4<int> GetTevOutput(const GenMode& genmode, const TevStageCombiner::ColorCombiner& last_cc, const TevStageCombiner::AlphaCombiner& last_ac)
|
||||
Vec4<int> GetTevOutput(const GenMode& genmode, const TevStageCombiner::ColorCombiner& last_cc,
|
||||
const TevStageCombiner::AlphaCombiner& last_ac)
|
||||
{
|
||||
int previous_stage = ((last_cc.hex >> 24)-BPMEM_TEV_COLOR_ENV)>>1;
|
||||
assert(previous_stage < 13);
|
||||
assert(previous_stage == (((last_ac.hex >> 24)-BPMEM_TEV_ALPHA_ENV)>>1));
|
||||
int previous_stage = ((last_cc.hex >> 24) - BPMEM_TEV_COLOR_ENV) >> 1;
|
||||
assert(previous_stage < 13);
|
||||
assert(previous_stage == (((last_ac.hex >> 24) - BPMEM_TEV_ALPHA_ENV) >> 1));
|
||||
|
||||
// The TEV output gets truncated to 8 bits when writing to the EFB.
|
||||
// Hence, we cannot retrieve all 11 TEV output bits directly.
|
||||
// Instead, we're performing two render passes, one of which retrieves
|
||||
// the lower 6 output bits, the other one of which retrieves the upper
|
||||
// 5 bits.
|
||||
// The TEV output gets truncated to 8 bits when writing to the EFB.
|
||||
// Hence, we cannot retrieve all 11 TEV output bits directly.
|
||||
// Instead, we're performing two render passes, one of which retrieves
|
||||
// the lower 6 output bits, the other one of which retrieves the upper
|
||||
// 5 bits.
|
||||
|
||||
// FIRST RENDER PASS:
|
||||
// As set up by the caller, with one additional tev stage multiplying the result by 4.
|
||||
// This will retrieve the lower 6 bits of the TEV output.
|
||||
// FIRST RENDER PASS:
|
||||
// As set up by the caller, with one additional tev stage multiplying the result by 4.
|
||||
// This will retrieve the lower 6 bits of the TEV output.
|
||||
|
||||
auto gm = genmode;
|
||||
gm.numtevstages = previous_stage + 1; // one additional stage
|
||||
CGX_LOAD_BP_REG(gm.hex);
|
||||
auto gm = genmode;
|
||||
gm.numtevstages = previous_stage + 1; // one additional stage
|
||||
CGX_LOAD_BP_REG(gm.hex);
|
||||
|
||||
// Enable new TEV stage. Note that we are using the "a" input here to make
|
||||
// sure the input doesn't get erroneously clamped to 11 bit range.
|
||||
auto cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage+1);
|
||||
cc1.a = last_cc.dest * 2;
|
||||
cc1.shift = TEVSCALE_4;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
// Enable new TEV stage. Note that we are using the "a" input here to make
|
||||
// sure the input doesn't get erroneously clamped to 11 bit range.
|
||||
auto cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage + 1);
|
||||
cc1.a = last_cc.dest * 2;
|
||||
cc1.shift = TEVSCALE_4;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
|
||||
auto ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage+1);
|
||||
ac1.a = last_ac.dest * 2;
|
||||
ac1.shift = TEVSCALE_4;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
auto ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage + 1);
|
||||
ac1.a = last_ac.dest * 2;
|
||||
ac1.shift = TEVSCALE_4;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
|
||||
memset(test_buffer, 0, TEST_BUFFER_SIZE); // Just for debugging
|
||||
Quad().AtDepth(1.0).ColorRGBA(255,255,255,255).Draw();
|
||||
CGX_DoEfbCopyTex(0, 0, 100, 100, 0x6 /*RGBA8*/, false, test_buffer);
|
||||
CGX_ForcePipelineFlush();
|
||||
CGX_WaitForGpuToFinish();
|
||||
u16 result1r = ReadTestBuffer(5, 5, 100).r >> 2;
|
||||
u16 result1g = ReadTestBuffer(5, 5, 100).g >> 2;
|
||||
u16 result1b = ReadTestBuffer(5, 5, 100).b >> 2;
|
||||
u16 result1a = ReadTestBuffer(5, 5, 100).a >> 2;
|
||||
memset(test_buffer, 0, TEST_BUFFER_SIZE); // Just for debugging
|
||||
Quad().AtDepth(1.0).ColorRGBA(255, 255, 255, 255).Draw();
|
||||
CGX_DoEfbCopyTex(0, 0, 100, 100, 0x6 /*RGBA8*/, false, test_buffer);
|
||||
CGX_ForcePipelineFlush();
|
||||
CGX_WaitForGpuToFinish();
|
||||
u16 result1r = ReadTestBuffer(5, 5, 100).r >> 2;
|
||||
u16 result1g = ReadTestBuffer(5, 5, 100).g >> 2;
|
||||
u16 result1b = ReadTestBuffer(5, 5, 100).b >> 2;
|
||||
u16 result1a = ReadTestBuffer(5, 5, 100).a >> 2;
|
||||
|
||||
// SECOND RENDER PASS
|
||||
// Uses three additional TEV stages which shift the previous result
|
||||
// three bits to the right. This is necessary to read off the 5 upper bits,
|
||||
// 3 of which got masked off when writing to the EFB in the first pass.
|
||||
gm = genmode;
|
||||
gm.numtevstages = previous_stage + 3; // three additional stages
|
||||
CGX_LOAD_BP_REG(gm.hex);
|
||||
// SECOND RENDER PASS
|
||||
// Uses three additional TEV stages which shift the previous result
|
||||
// three bits to the right. This is necessary to read off the 5 upper bits,
|
||||
// 3 of which got masked off when writing to the EFB in the first pass.
|
||||
gm = genmode;
|
||||
gm.numtevstages = previous_stage + 3; // three additional stages
|
||||
CGX_LOAD_BP_REG(gm.hex);
|
||||
|
||||
// The following tev stages are exclusively used to rightshift the
|
||||
// upper bits such that they get written to the render target.
|
||||
cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage+1);
|
||||
cc1.d = last_cc.dest * 2;
|
||||
cc1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
// The following tev stages are exclusively used to rightshift the
|
||||
// upper bits such that they get written to the render target.
|
||||
cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage + 1);
|
||||
cc1.d = last_cc.dest * 2;
|
||||
cc1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
|
||||
ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage+1);
|
||||
ac1.d = last_ac.dest * 2;
|
||||
ac1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage + 1);
|
||||
ac1.d = last_ac.dest * 2;
|
||||
ac1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
|
||||
cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage+2);
|
||||
cc1.d = last_cc.dest * 2;
|
||||
cc1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage + 2);
|
||||
cc1.d = last_cc.dest * 2;
|
||||
cc1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
|
||||
ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage+2);
|
||||
ac1.d = last_ac.dest * 2;
|
||||
ac1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage + 2);
|
||||
ac1.d = last_ac.dest * 2;
|
||||
ac1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
|
||||
cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage+3);
|
||||
cc1.d = last_cc.dest * 2;
|
||||
cc1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
cc1 = CGXDefault<TevStageCombiner::ColorCombiner>(previous_stage + 3);
|
||||
cc1.d = last_cc.dest * 2;
|
||||
cc1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(cc1.hex);
|
||||
|
||||
ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage+3);
|
||||
ac1.d = last_ac.dest * 2;
|
||||
ac1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
ac1 = CGXDefault<TevStageCombiner::AlphaCombiner>(previous_stage + 3);
|
||||
ac1.d = last_ac.dest * 2;
|
||||
ac1.shift = TEVDIVIDE_2;
|
||||
CGX_LOAD_BP_REG(ac1.hex);
|
||||
|
||||
memset(test_buffer, 0, TEST_BUFFER_SIZE);
|
||||
Quad().AtDepth(1.0).ColorRGBA(255,255,255,255).Draw();
|
||||
CGX_DoEfbCopyTex(0, 0, 100, 100, 0x6 /*RGBA8*/, false, test_buffer);
|
||||
CGX_ForcePipelineFlush();
|
||||
CGX_WaitForGpuToFinish();
|
||||
memset(test_buffer, 0, TEST_BUFFER_SIZE);
|
||||
Quad().AtDepth(1.0).ColorRGBA(255, 255, 255, 255).Draw();
|
||||
CGX_DoEfbCopyTex(0, 0, 100, 100, 0x6 /*RGBA8*/, false, test_buffer);
|
||||
CGX_ForcePipelineFlush();
|
||||
CGX_WaitForGpuToFinish();
|
||||
|
||||
u16 result2r = ReadTestBuffer(5, 5, 100).r >> 3;
|
||||
u16 result2g = ReadTestBuffer(5, 5, 100).g >> 3;
|
||||
u16 result2b = ReadTestBuffer(5, 5, 100).b >> 3;
|
||||
u16 result2a = ReadTestBuffer(5, 5, 100).a >> 3;
|
||||
u16 result2r = ReadTestBuffer(5, 5, 100).r >> 3;
|
||||
u16 result2g = ReadTestBuffer(5, 5, 100).g >> 3;
|
||||
u16 result2b = ReadTestBuffer(5, 5, 100).b >> 3;
|
||||
u16 result2a = ReadTestBuffer(5, 5, 100).a >> 3;
|
||||
|
||||
// uh.. let's just say this works, but I guess it could be simplified.
|
||||
Vec4<int> result;
|
||||
result.r = result1r + ((result2r & 0x10) ? (-0x400+((result2r&0xF)<<6)) : (result2r<<6));
|
||||
result.g = result1g + ((result2g & 0x10) ? (-0x400+((result2g&0xF)<<6)) : (result2g<<6));
|
||||
result.b = result1b + ((result2b & 0x10) ? (-0x400+((result2b&0xF)<<6)) : (result2b<<6));
|
||||
result.a = result1a + ((result2a & 0x10) ? (-0x400+((result2a&0xF)<<6)) : (result2a<<6));
|
||||
return result;
|
||||
// uh.. let's just say this works, but I guess it could be simplified.
|
||||
Vec4<int> result;
|
||||
result.r = result1r + ((result2r & 0x10) ? (-0x400 + ((result2r & 0xF) << 6)) : (result2r << 6));
|
||||
result.g = result1g + ((result2g & 0x10) ? (-0x400 + ((result2g & 0xF) << 6)) : (result2g << 6));
|
||||
result.b = result1b + ((result2b & 0x10) ? (-0x400 + ((result2b & 0xF) << 6)) : (result2b << 6));
|
||||
result.a = result1a + ((result2a & 0x10) ? (-0x400 + ((result2a & 0xF) << 6)) : (result2a << 6));
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,43 +6,42 @@
|
||||
|
||||
namespace GXTest
|
||||
{
|
||||
|
||||
// Four component vector with arbitrary base type
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
union Vec4
|
||||
{
|
||||
struct
|
||||
{
|
||||
T r, g, b, a;
|
||||
};
|
||||
struct
|
||||
{
|
||||
T x, y, z, w;
|
||||
};
|
||||
struct
|
||||
{
|
||||
T r, g, b, a;
|
||||
};
|
||||
struct
|
||||
{
|
||||
T x, y, z, w;
|
||||
};
|
||||
};
|
||||
|
||||
// Utility class to draw quads
|
||||
class Quad
|
||||
{
|
||||
public:
|
||||
Quad();
|
||||
Quad();
|
||||
|
||||
Quad& VertexTopLeft(f32 x, f32 y, f32 z);
|
||||
Quad& VertexTopRight(f32 x, f32 y, f32 z);
|
||||
Quad& VertexBottomRight(f32 x, f32 y, f32 z);
|
||||
Quad& VertexBottomLeft(f32 x, f32 y, f32 z);
|
||||
Quad& VertexTopLeft(f32 x, f32 y, f32 z);
|
||||
Quad& VertexTopRight(f32 x, f32 y, f32 z);
|
||||
Quad& VertexBottomRight(f32 x, f32 y, f32 z);
|
||||
Quad& VertexBottomLeft(f32 x, f32 y, f32 z);
|
||||
|
||||
Quad& AtDepth(f32 depth);
|
||||
Quad& AtDepth(f32 depth);
|
||||
|
||||
Quad& ColorRGBA(u8 r, u8 g, u8 b, u8 a);
|
||||
Quad& ColorRGBA(u8 r, u8 g, u8 b, u8 a);
|
||||
|
||||
void Draw();
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
f32 x[4], y[4], z[4];
|
||||
f32 x[4], y[4], z[4];
|
||||
|
||||
bool has_color;
|
||||
u32 color;
|
||||
bool has_color;
|
||||
u32 color;
|
||||
};
|
||||
|
||||
// Initialize CGX and GXTest
|
||||
@@ -53,7 +52,8 @@ void Init();
|
||||
void DrawFullScreenQuad();
|
||||
|
||||
// Perform an RGBA8 EFB copy to the internal testing buffer
|
||||
void CopyToTestBuffer(int left_most_pixel, int top_most_pixel, int right_most_pixel, int bottom_most_pixel);
|
||||
void CopyToTestBuffer(int left_most_pixel, int top_most_pixel, int right_most_pixel,
|
||||
int bottom_most_pixel);
|
||||
|
||||
// Read back result from test buffer
|
||||
// CopyToTestBuffer needs to be called before using this.
|
||||
@@ -65,9 +65,9 @@ Vec4<u8> ReadTestBuffer(int x, int y, int previous_copy_width);
|
||||
// calling this function. The function logic adds 3 additional tev stages,
|
||||
// so care must be taken not to enable more than 13 tev stages before usage.
|
||||
// NOTE: This will only work correctly if the EFB format is set to RGB8
|
||||
Vec4<int> GetTevOutput(const GenMode& genmode, const TevStageCombiner::ColorCombiner& last_cc, const TevStageCombiner::AlphaCombiner& last_ac);
|
||||
Vec4<int> GetTevOutput(const GenMode& genmode, const TevStageCombiner::ColorCombiner& last_cc,
|
||||
const TevStageCombiner::AlphaCombiner& last_ac);
|
||||
|
||||
void DebugDisplayEfbContents();
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user