Reformat all the things. Have fun with merge conflicts.

This commit is contained in:
Pierre Bourdon
2016-06-24 10:43:46 +02:00
parent 2115e8a4a6
commit 3570c7f03a
1116 changed files with 187405 additions and 180344 deletions

View File

@ -7,164 +7,159 @@
#include "Common/BitField.h"
#include "Common/CommonTypes.h"
union TestUnion
{
u64 hex;
union TestUnion {
u64 hex;
BitField< 0,64,u64> full_u64; // spans whole storage
BitField< 0,64,s64> full_s64; // spans whole storage
BitField<0, 64, u64> full_u64; // spans whole storage
BitField<0, 64, s64> full_s64; // spans whole storage
BitField< 9, 3,u64> regular_field_unsigned; // a plain bitfield
BitField< 9, 3,u64> regular_field_unsigned2; // Just the very same bitfield again
BitField< 9, 3,s64> regular_field_signed; // Same bitfield, but different sign
BitField<9, 3, u64> regular_field_unsigned; // a plain bitfield
BitField<9, 3, u64> regular_field_unsigned2; // Just the very same bitfield again
BitField<9, 3, s64> regular_field_signed; // Same bitfield, but different sign
BitField<30, 4,s64> at_dword_boundary; // goes over the boundary of two u32 values
BitField<30, 4, s64> at_dword_boundary; // goes over the boundary of two u32 values
BitField<15, 1,s64> signed_1bit; // allowed values: -1 and 0
BitField<15, 1, s64> signed_1bit; // allowed values: -1 and 0
};
// table of raw numbers to test with
static u64 table[] =
{
0x0000000000000000ull, // all zero
0xffffffffffffffffull, // all one
0x7fffffffffffffffull, // all one apart from the sign bit
0x8000000000000000ull, // all zero apart from the sign bit
0x8000000000000048ull, // regular_field = 0b1001
static u64 table[] = {
0x0000000000000000ull, // all zero
0xffffffffffffffffull, // all one
0x7fffffffffffffffull, // all one apart from the sign bit
0x8000000000000000ull, // all zero apart from the sign bit
0x8000000000000048ull, // regular_field = 0b1001
// "random" numbers
0x0F7B8B1ABD9B8D3Full,
0xA8B86F73FDAADD2Dull,
0x1B17A557BFEB351Dull,
0xE3354268B0C2395Bull,
// "random" numbers
0x0F7B8B1ABD9B8D3Full, 0xA8B86F73FDAADD2Dull, 0x1B17A557BFEB351Dull, 0xE3354268B0C2395Bull,
};
// Verify that bitfields in a union have the same underlying data
TEST(BitField, Storage)
{
TestUnion object;
TestUnion object;
EXPECT_EQ((void*)&object.hex, (void*)&object.regular_field_unsigned);
EXPECT_EQ(sizeof(TestUnion), sizeof(object.hex));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_u64));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_s64));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_unsigned));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_signed));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit));
EXPECT_EQ((void*)&object.hex, (void*)&object.regular_field_unsigned);
EXPECT_EQ(sizeof(TestUnion), sizeof(object.hex));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_u64));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.full_s64));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_unsigned));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.regular_field_signed));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.at_dword_boundary));
EXPECT_EQ(sizeof(TestUnion), sizeof(object.signed_1bit));
// Now write some values to one field and check if this reflects properly
// in the others.
for (u64 val : table)
{
object.hex = val;
EXPECT_EQ(object.hex, object.full_u64);
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
// Now write some values to one field and check if this reflects properly
// in the others.
for (u64 val : table)
{
object.hex = val;
EXPECT_EQ(object.hex, object.full_u64);
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
object.regular_field_unsigned = val & 0x3;
EXPECT_EQ(object.hex, object.full_u64);
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
}
object.regular_field_unsigned = val & 0x3;
EXPECT_EQ(object.hex, object.full_u64);
EXPECT_EQ(object.regular_field_unsigned, object.regular_field_unsigned2);
}
}
TEST(BitField, Read)
{
TestUnion object;
TestUnion object;
for (u64 val : table)
{
object.hex = val;
for (u64 val : table)
{
object.hex = val;
// Make sure reading/casting does not behave completely idiotic
EXPECT_EQ(object.full_u64, (u64)object.full_u64);
EXPECT_EQ(object.full_s64, (s64)object.full_s64);
EXPECT_EQ(object.regular_field_unsigned, (u64)object.regular_field_unsigned);
EXPECT_EQ(object.regular_field_unsigned2, (u64)object.regular_field_unsigned2);
EXPECT_EQ(object.regular_field_signed, (s64)object.regular_field_signed);
EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary);
EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit);
// Make sure reading/casting does not behave completely idiotic
EXPECT_EQ(object.full_u64, (u64)object.full_u64);
EXPECT_EQ(object.full_s64, (s64)object.full_s64);
EXPECT_EQ(object.regular_field_unsigned, (u64)object.regular_field_unsigned);
EXPECT_EQ(object.regular_field_unsigned2, (u64)object.regular_field_unsigned2);
EXPECT_EQ(object.regular_field_signed, (s64)object.regular_field_signed);
EXPECT_EQ(object.at_dword_boundary, (s64)object.at_dword_boundary);
EXPECT_EQ(object.signed_1bit, (s64)object.signed_1bit);
// Now make sure the value is indeed correct
EXPECT_EQ(val, object.full_u64);
EXPECT_EQ(*(s64*)&val, object.full_s64);
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned);
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned2);
EXPECT_EQ(((s64)(object.hex << 52)) >> 61, object.regular_field_signed);
EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary);
EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit);
}
// Now make sure the value is indeed correct
EXPECT_EQ(val, object.full_u64);
EXPECT_EQ(*(s64*)&val, object.full_s64);
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned);
EXPECT_EQ((val >> 9) & 0x7, object.regular_field_unsigned2);
EXPECT_EQ(((s64)(object.hex << 52)) >> 61, object.regular_field_signed);
EXPECT_EQ(((s64)(object.hex << 30)) >> 60, object.at_dword_boundary);
EXPECT_EQ(((object.hex >> 15) & 1) ? -1 : 0, object.signed_1bit);
}
}
TEST(BitField, Assignment)
{
TestUnion object;
TestUnion object;
for (u64 val : table)
{
// Assignments with fixed values
object.full_u64 = val;
EXPECT_EQ(val, object.full_u64);
for (u64 val : table)
{
// Assignments with fixed values
object.full_u64 = val;
EXPECT_EQ(val, object.full_u64);
object.full_s64 = (s64)val;
EXPECT_EQ(val, object.full_u64);
object.full_s64 = (s64)val;
EXPECT_EQ(val, object.full_u64);
object.regular_field_unsigned = val;
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
object.regular_field_unsigned = val;
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
object.at_dword_boundary = val;
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
object.at_dword_boundary = val;
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
object.signed_1bit = val;
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
object.signed_1bit = val;
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
object.regular_field_signed = val;
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
object.regular_field_signed = val;
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
// Assignment from other BitField
object.at_dword_boundary = object.regular_field_signed;
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
}
// Assignment from other BitField
object.at_dword_boundary = object.regular_field_signed;
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
}
}
// Test class behavior on oddly aligned structures.
TEST(BitField, Alignment)
{
#pragma pack(1)
struct OddlyAlignedTestStruct
{
u8 padding;
TestUnion obj;
};
#pragma pack()
#pragma pack(1)
struct OddlyAlignedTestStruct
{
u8 padding;
TestUnion obj;
};
#pragma pack()
alignas(16) OddlyAlignedTestStruct test_struct;
TestUnion& object = test_struct.obj;
static_assert(alignof(decltype(test_struct.obj.signed_1bit)) == 1,
"Incorrect variable alignment");
alignas(16) OddlyAlignedTestStruct test_struct;
TestUnion& object = test_struct.obj;
static_assert(alignof(decltype(test_struct.obj.signed_1bit)) == 1,
"Incorrect variable alignment");
for (u64 val : table)
{
// Assignments with fixed values
object.full_u64 = val;
EXPECT_EQ(val, object.full_u64);
for (u64 val : table)
{
// Assignments with fixed values
object.full_u64 = val;
EXPECT_EQ(val, object.full_u64);
object.full_s64 = (s64)val;
EXPECT_EQ(val, object.full_u64);
object.full_s64 = (s64)val;
EXPECT_EQ(val, object.full_u64);
object.regular_field_unsigned = val;
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
object.regular_field_unsigned = val;
EXPECT_EQ(val & 0x7, object.regular_field_unsigned);
object.at_dword_boundary = val;
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
object.at_dword_boundary = val;
EXPECT_EQ(((s64)(val << 60)) >> 60, object.at_dword_boundary);
object.signed_1bit = val;
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
object.signed_1bit = val;
EXPECT_EQ((val & 1) ? -1 : 0, object.signed_1bit);
object.regular_field_signed = val;
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
object.regular_field_signed = val;
EXPECT_EQ(((s64)(object.hex << 61)) >> 61, object.regular_field_signed);
// Assignment from other BitField
object.at_dword_boundary = object.regular_field_signed;
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
}
// Assignment from other BitField
object.at_dword_boundary = object.regular_field_signed;
EXPECT_EQ(object.regular_field_signed, object.at_dword_boundary);
}
}

View File

@ -8,77 +8,75 @@
TEST(BitSet, Basics)
{
BitSet32 bs;
BitSet64 bs2(1);
BitSet64 bs3(2);
EXPECT_EQ(true, !!bs2);
EXPECT_EQ(false, !!bs);
EXPECT_EQ(bs2, bs2);
EXPECT_NE(bs2, bs3);
EXPECT_EQ(BitSet32(0xfff), BitSet32::AllTrue(12));
EXPECT_EQ(BitSet64(0xffffffffffffffff), BitSet64::AllTrue(64));
BitSet32 bs;
BitSet64 bs2(1);
BitSet64 bs3(2);
EXPECT_EQ(true, !!bs2);
EXPECT_EQ(false, !!bs);
EXPECT_EQ(bs2, bs2);
EXPECT_NE(bs2, bs3);
EXPECT_EQ(BitSet32(0xfff), BitSet32::AllTrue(12));
EXPECT_EQ(BitSet64(0xffffffffffffffff), BitSet64::AllTrue(64));
}
TEST(BitSet, BitGetSet)
{
BitSet32 bs;
bs[3] = bs[8] = bs[11] = true;
EXPECT_EQ(true, bs[3]);
EXPECT_EQ(false, bs[4]);
EXPECT_EQ((u32)((1 << 3) | (1 << 8) | (1 << 11)), bs.m_val);
BitSet32 bs;
bs[3] = bs[8] = bs[11] = true;
EXPECT_EQ(true, bs[3]);
EXPECT_EQ(false, bs[4]);
EXPECT_EQ((u32)((1 << 3) | (1 << 8) | (1 << 11)), bs.m_val);
}
TEST(BitSet, Count)
{
u32 random_numbers[] = {
0x2cb0b5f3, 0x81ab32a6, 0xd9030dc5, 0x325ffe26, 0xb2fcaee3,
0x4ccf188a, 0xf8be36dc, 0xb2fcecd5, 0xb750c2e5, 0x31d19074,
0xf267644a, 0xac00a719, 0x6d45f19b, 0xf7e91c5b, 0xf687e694,
0x9057c24e, 0x5eb65c39, 0x85d3038b, 0x101f4e66, 0xc202d136
};
u32 counts[] = {
17, 14, 14, 19, 20, 14, 20, 20, 16, 13, 16, 12, 18, 20, 18, 14, 18, 14, 14, 12
};
for (size_t i = 0; i < 20; i++)
{
EXPECT_EQ(counts[i], BitSet32(random_numbers[i]).Count());
}
u32 random_numbers[] = {0x2cb0b5f3, 0x81ab32a6, 0xd9030dc5, 0x325ffe26, 0xb2fcaee3,
0x4ccf188a, 0xf8be36dc, 0xb2fcecd5, 0xb750c2e5, 0x31d19074,
0xf267644a, 0xac00a719, 0x6d45f19b, 0xf7e91c5b, 0xf687e694,
0x9057c24e, 0x5eb65c39, 0x85d3038b, 0x101f4e66, 0xc202d136};
u32 counts[] = {17, 14, 14, 19, 20, 14, 20, 20, 16, 13, 16, 12, 18, 20, 18, 14, 18, 14, 14, 12};
for (size_t i = 0; i < 20; i++)
{
EXPECT_EQ(counts[i], BitSet32(random_numbers[i]).Count());
}
u64 random_numbers_64[] = {
0xf86cd6f6ef09d7d4ULL, 0x6f2d8533255ead3cULL, 0x9da7941e0e52b345ULL,
0x06e4189be67d2b17ULL, 0x3eb0681f65cb6d25ULL, 0xccab8a7c74a51203ULL,
0x09d470516694c64bULL, 0x38cd077e075c778fULL, 0xd69ebfa6355ebfdeULL
};
u32 counts_64[] = {
39, 34, 31, 32, 33, 29, 27, 35, 43
};
for (size_t i = 0; i < 9; i++)
{
EXPECT_EQ(counts_64[i], BitSet64(random_numbers_64[i]).Count());
}
u64 random_numbers_64[] = {0xf86cd6f6ef09d7d4ULL, 0x6f2d8533255ead3cULL, 0x9da7941e0e52b345ULL,
0x06e4189be67d2b17ULL, 0x3eb0681f65cb6d25ULL, 0xccab8a7c74a51203ULL,
0x09d470516694c64bULL, 0x38cd077e075c778fULL, 0xd69ebfa6355ebfdeULL};
u32 counts_64[] = {39, 34, 31, 32, 33, 29, 27, 35, 43};
for (size_t i = 0; i < 9; i++)
{
EXPECT_EQ(counts_64[i], BitSet64(random_numbers_64[i]).Count());
}
}
TEST(BitSet, BitOps)
{
BitSet32 a(3), b(5), c;
EXPECT_EQ(BitSet32(7), a | b);
EXPECT_EQ(BitSet32(6), a ^ b);
EXPECT_EQ(BitSet32(1), a & b);
EXPECT_EQ(BitSet32(0xfffffffc), ~a);
c = a; c |= b; EXPECT_EQ(BitSet32(7), c);
c = a; c ^= b; EXPECT_EQ(BitSet32(6), c);
c = a; c &= b; EXPECT_EQ(BitSet32(1), c);
BitSet32 a(3), b(5), c;
EXPECT_EQ(BitSet32(7), a | b);
EXPECT_EQ(BitSet32(6), a ^ b);
EXPECT_EQ(BitSet32(1), a & b);
EXPECT_EQ(BitSet32(0xfffffffc), ~a);
c = a;
c |= b;
EXPECT_EQ(BitSet32(7), c);
c = a;
c ^= b;
EXPECT_EQ(BitSet32(6), c);
c = a;
c &= b;
EXPECT_EQ(BitSet32(1), c);
}
TEST(BitSet, InitializerListsAndIteration)
{
std::vector<int> bits { 1, 10, 15, 17, 20, 30 };
BitSet32 bs { 1, 10, 15, 17, 20, 30 };
auto vit = bits.begin();
for (auto i : bs)
{
EXPECT_NE(vit, bits.end());
EXPECT_EQ(i, *vit++);
}
EXPECT_EQ(vit, bits.end());
std::vector<int> bits{1, 10, 15, 17, 20, 30};
BitSet32 bs{1, 10, 15, 17, 20, 30};
auto vit = bits.begin();
for (auto i : bs)
{
EXPECT_NE(vit, bits.end());
EXPECT_EQ(i, *vit++);
}
EXPECT_EQ(vit, bits.end());
}

View File

@ -11,74 +11,70 @@
TEST(BlockingLoop, MultiThreaded)
{
Common::BlockingLoop loop;
std::atomic<int> signaled_a(0);
std::atomic<int> received_a(0);
std::atomic<int> signaled_b(0);
std::atomic<int> received_b(0);
for (int i = 0; i < 100; i++)
{
// Invalidate the current state.
received_a.store(signaled_a.load() + 1);
received_b.store(signaled_b.load() + 123);
Common::BlockingLoop loop;
std::atomic<int> signaled_a(0);
std::atomic<int> received_a(0);
std::atomic<int> signaled_b(0);
std::atomic<int> received_b(0);
for (int i = 0; i < 100; i++)
{
// Invalidate the current state.
received_a.store(signaled_a.load() + 1);
received_b.store(signaled_b.load() + 123);
// Must not block as the loop is stopped.
loop.Wait();
// Must not block as the loop is stopped.
loop.Wait();
std::thread loop_thread(
[&]() {
loop.Run(
[&]() {
received_a.store(signaled_a.load());
received_b.store(signaled_b.load());
});
});
std::thread loop_thread([&]() {
loop.Run([&]() {
received_a.store(signaled_a.load());
received_b.store(signaled_b.load());
});
});
// Now Wait must block.
loop.Prepare();
// Now Wait must block.
loop.Prepare();
// The payload must run at least once on startup.
loop.Wait();
EXPECT_EQ(signaled_a.load(), received_a.load());
EXPECT_EQ(signaled_b.load(), received_b.load());
// The payload must run at least once on startup.
loop.Wait();
EXPECT_EQ(signaled_a.load(), received_a.load());
EXPECT_EQ(signaled_b.load(), received_b.load());
std::thread run_a_thread(
[&]() {
for (int j = 0; j < 100; j++)
{
for (int k = 0; k < 100; k++)
{
signaled_a++;
loop.Wakeup();
}
std::thread run_a_thread([&]() {
for (int j = 0; j < 100; j++)
{
for (int k = 0; k < 100; k++)
{
signaled_a++;
loop.Wakeup();
}
loop.Wait();
EXPECT_EQ(signaled_a.load(), received_a.load());
}
});
std::thread run_b_thread(
[&]() {
for (int j = 0; j < 100; j++)
{
for (int k = 0; k < 100; k++)
{
signaled_b++;
loop.Wakeup();
}
loop.Wait();
EXPECT_EQ(signaled_a.load(), received_a.load());
}
});
std::thread run_b_thread([&]() {
for (int j = 0; j < 100; j++)
{
for (int k = 0; k < 100; k++)
{
signaled_b++;
loop.Wakeup();
}
loop.Wait();
EXPECT_EQ(signaled_b.load(), received_b.load());
}
});
loop.Wait();
EXPECT_EQ(signaled_b.load(), received_b.load());
}
});
run_a_thread.join();
run_b_thread.join();
run_a_thread.join();
run_b_thread.join();
loop.Stop();
loop.Stop();
// Must not block
loop.Wait();
// Must not block
loop.Wait();
loop_thread.join();
}
loop_thread.join();
}
}

View File

@ -12,40 +12,34 @@
TEST(BusyLoopTest, MultiThreaded)
{
Common::BlockingLoop loop;
Common::Event e;
for (int i = 0; i < 100; i++)
{
loop.Prepare();
std::thread loop_thread(
[&]() {
loop.Run(
[&]() {
e.Set();
});
});
Common::BlockingLoop loop;
Common::Event e;
for (int i = 0; i < 100; i++)
{
loop.Prepare();
std::thread loop_thread([&]() { loop.Run([&]() { e.Set(); }); });
// Ping - Pong
for (int j = 0; j < 10; j++)
{
loop.Wakeup();
e.Wait();
// Ping - Pong
for (int j = 0; j < 10; j++)
{
loop.Wakeup();
e.Wait();
// Just waste some time. So the main loop did fall back to the sleep state much more likely.
Common::SleepCurrentThread(1);
}
// Just waste some time. So the main loop did fall back to the sleep state much more likely.
Common::SleepCurrentThread(1);
}
for (int j = 0; j < 100; j++)
{
// We normally have to call Wakeup to assure the Event is triggered.
// But this check is for an internal feature of the BlockingLoop.
// It's implemented to fall back to a busy loop regulary.
// If we're in the busy loop, the payload (and so the Event) is called all the time.
//loop.Wakeup();
e.Wait();
}
for (int j = 0; j < 100; j++)
{
// We normally have to call Wakeup to assure the Event is triggered.
// But this check is for an internal feature of the BlockingLoop.
// It's implemented to fall back to a busy loop regulary.
// If we're in the busy loop, the payload (and so the Event) is called all the time.
// loop.Wakeup();
e.Wait();
}
loop.Stop();
loop_thread.join();
}
loop.Stop();
loop_thread.join();
}
}

View File

@ -8,33 +8,33 @@
TEST(CommonFuncs, ArraySizeFunction)
{
char test[4];
u32 test2[42];
char test[4];
u32 test2[42];
EXPECT_EQ(4u, ArraySize(test));
EXPECT_EQ(42u, ArraySize(test2));
EXPECT_EQ(4u, ArraySize(test));
EXPECT_EQ(42u, ArraySize(test2));
(void)test;
(void)test2;
(void)test;
(void)test2;
}
TEST(CommonFuncs, RoundUpPow2Macro)
{
EXPECT_EQ(4, ROUND_UP_POW2(3));
EXPECT_EQ(4, ROUND_UP_POW2(4));
EXPECT_EQ(8, ROUND_UP_POW2(6));
EXPECT_EQ(0x40000000, ROUND_UP_POW2(0x23456789));
EXPECT_EQ(4, ROUND_UP_POW2(3));
EXPECT_EQ(4, ROUND_UP_POW2(4));
EXPECT_EQ(8, ROUND_UP_POW2(6));
EXPECT_EQ(0x40000000, ROUND_UP_POW2(0x23456789));
}
TEST(CommonFuncs, CrashMacro)
{
EXPECT_DEATH({ Crash(); }, "");
EXPECT_DEATH({ Crash(); }, "");
}
TEST(CommonFuncs, Swap)
{
EXPECT_EQ(0xf0, Common::swap8(0xf0));
EXPECT_EQ(0x1234, Common::swap16(0x3412));
EXPECT_EQ(0x12345678u, Common::swap32(0x78563412));
EXPECT_EQ(0x123456789abcdef0ull, Common::swap64(0xf0debc9a78563412ull));
EXPECT_EQ(0xf0, Common::swap8(0xf0));
EXPECT_EQ(0x1234, Common::swap16(0x3412));
EXPECT_EQ(0x12345678u, Common::swap32(0x78563412));
EXPECT_EQ(0x123456789abcdef0ull, Common::swap64(0xf0debc9a78563412ull));
}

View File

@ -2,8 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <thread>
#include <gtest/gtest.h>
#include <thread>
#include "Common/Event.h"
@ -11,32 +11,33 @@ using Common::Event;
TEST(Event, MultiThreaded)
{
Event has_sent, can_send;
int shared_obj;
const int ITERATIONS_COUNT = 100000;
Event has_sent, can_send;
int shared_obj;
const int ITERATIONS_COUNT = 100000;
auto sender = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
can_send.Wait();
shared_obj = i;
has_sent.Set();
}
};
auto sender = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
can_send.Wait();
shared_obj = i;
has_sent.Set();
}
};
auto receiver = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i) {
has_sent.Wait();
EXPECT_EQ(i, shared_obj);
can_send.Set();
}
};
auto receiver = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
has_sent.Wait();
EXPECT_EQ(i, shared_obj);
can_send.Set();
}
};
std::thread sender_thread(sender);
std::thread receiver_thread(receiver);
std::thread sender_thread(sender);
std::thread receiver_thread(receiver);
can_send.Set();
can_send.Set();
sender_thread.join();
receiver_thread.join();
sender_thread.join();
receiver_thread.join();
}

View File

@ -2,66 +2,70 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <thread>
#include <gtest/gtest.h>
#include <thread>
#include "Common/FifoQueue.h"
TEST(FifoQueue, Simple)
{
Common::FifoQueue<u32> q;
Common::FifoQueue<u32> q;
EXPECT_EQ(0u, q.Size());
EXPECT_TRUE(q.Empty());
EXPECT_EQ(0u, q.Size());
EXPECT_TRUE(q.Empty());
q.Push(1);
EXPECT_EQ(1u, q.Size());
EXPECT_FALSE(q.Empty());
q.Push(1);
EXPECT_EQ(1u, q.Size());
EXPECT_FALSE(q.Empty());
u32 v; q.Pop(v);
EXPECT_EQ(1u, v);
EXPECT_EQ(0u, q.Size());
EXPECT_TRUE(q.Empty());
u32 v;
q.Pop(v);
EXPECT_EQ(1u, v);
EXPECT_EQ(0u, q.Size());
EXPECT_TRUE(q.Empty());
// Test the FIFO order.
for (u32 i = 0; i < 1000; ++i)
q.Push(i);
EXPECT_EQ(1000u, q.Size());
for (u32 i = 0; i < 1000; ++i)
{
u32 v2; q.Pop(v2);
EXPECT_EQ(i, v2);
}
EXPECT_TRUE(q.Empty());
// Test the FIFO order.
for (u32 i = 0; i < 1000; ++i)
q.Push(i);
EXPECT_EQ(1000u, q.Size());
for (u32 i = 0; i < 1000; ++i)
{
u32 v2;
q.Pop(v2);
EXPECT_EQ(i, v2);
}
EXPECT_TRUE(q.Empty());
for (u32 i = 0; i < 1000; ++i)
q.Push(i);
EXPECT_FALSE(q.Empty());
q.Clear();
EXPECT_TRUE(q.Empty());
for (u32 i = 0; i < 1000; ++i)
q.Push(i);
EXPECT_FALSE(q.Empty());
q.Clear();
EXPECT_TRUE(q.Empty());
}
TEST(FifoQueue, MultiThreaded)
{
Common::FifoQueue<u32> q;
Common::FifoQueue<u32> q;
auto inserter = [&q]() {
for (u32 i = 0; i < 100000; ++i)
q.Push(i);
};
auto inserter = [&q]() {
for (u32 i = 0; i < 100000; ++i)
q.Push(i);
};
auto popper = [&q]() {
for (u32 i = 0; i < 100000; ++i)
{
while (q.Empty());
u32 v; q.Pop(v);
EXPECT_EQ(i, v);
}
};
auto popper = [&q]() {
for (u32 i = 0; i < 100000; ++i)
{
while (q.Empty())
;
u32 v;
q.Pop(v);
EXPECT_EQ(i, v);
}
};
std::thread popper_thread(popper);
std::thread inserter_thread(inserter);
std::thread popper_thread(popper);
std::thread inserter_thread(inserter);
popper_thread.join();
inserter_thread.join();
popper_thread.join();
inserter_thread.join();
}

View File

@ -8,26 +8,26 @@
TEST(FixedSizeQueue, Simple)
{
FixedSizeQueue<int, 5> q;
FixedSizeQueue<int, 5> q;
EXPECT_EQ(0u, q.size());
EXPECT_EQ(0u, q.size());
q.push(0);
q.push(1);
q.push(2);
q.push(3);
q.push(4);
for (int i = 0; i < 1000; ++i)
{
EXPECT_EQ(i, q.front());
EXPECT_EQ(i, q.pop_front());
q.push(i + 5);
}
EXPECT_EQ(1000, q.pop_front());
EXPECT_EQ(1001, q.pop_front());
EXPECT_EQ(1002, q.pop_front());
EXPECT_EQ(1003, q.pop_front());
EXPECT_EQ(1004, q.pop_front());
q.push(0);
q.push(1);
q.push(2);
q.push(3);
q.push(4);
for (int i = 0; i < 1000; ++i)
{
EXPECT_EQ(i, q.front());
EXPECT_EQ(i, q.pop_front());
q.push(i + 5);
}
EXPECT_EQ(1000, q.pop_front());
EXPECT_EQ(1001, q.pop_front());
EXPECT_EQ(1002, q.pop_front());
EXPECT_EQ(1003, q.pop_front());
EXPECT_EQ(1004, q.pop_front());
EXPECT_EQ(0u, q.size());
EXPECT_EQ(0u, q.size());
}

View File

@ -3,8 +3,8 @@
// Refer to the license.txt file included.
#include <array>
#include <thread>
#include <gtest/gtest.h>
#include <thread>
#include "Common/Flag.h"
@ -12,80 +12,83 @@ using Common::Flag;
TEST(Flag, Simple)
{
Flag f;
EXPECT_FALSE(f.IsSet());
Flag f;
EXPECT_FALSE(f.IsSet());
f.Set();
EXPECT_TRUE(f.IsSet());
f.Set();
EXPECT_TRUE(f.IsSet());
f.Clear();
EXPECT_FALSE(f.IsSet());
f.Clear();
EXPECT_FALSE(f.IsSet());
f.Set(false);
EXPECT_FALSE(f.IsSet());
f.Set(false);
EXPECT_FALSE(f.IsSet());
EXPECT_TRUE(f.TestAndSet());
EXPECT_TRUE(f.TestAndClear());
EXPECT_TRUE(f.TestAndSet());
EXPECT_TRUE(f.TestAndClear());
Flag f2(true);
EXPECT_TRUE(f2.IsSet());
Flag f2(true);
EXPECT_TRUE(f2.IsSet());
}
TEST(Flag, MultiThreaded)
{
Flag f;
int count = 0;
const int ITERATIONS_COUNT = 100000;
Flag f;
int count = 0;
const int ITERATIONS_COUNT = 100000;
auto setter = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
while (f.IsSet());
f.Set();
}
};
auto setter = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
while (f.IsSet())
;
f.Set();
}
};
auto clearer = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
while (!f.IsSet());
count++;
f.Clear();
}
};
auto clearer = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
while (!f.IsSet())
;
count++;
f.Clear();
}
};
std::thread setter_thread(setter);
std::thread clearer_thread(clearer);
std::thread setter_thread(setter);
std::thread clearer_thread(clearer);
setter_thread.join();
clearer_thread.join();
setter_thread.join();
clearer_thread.join();
EXPECT_EQ(ITERATIONS_COUNT, count);
EXPECT_EQ(ITERATIONS_COUNT, count);
}
TEST(Flag, SpinLock)
{
// Uses a flag to implement basic spinlocking using TestAndSet.
Flag f;
int count = 0;
const int ITERATIONS_COUNT = 5000;
const int THREADS_COUNT = 50;
// Uses a flag to implement basic spinlocking using TestAndSet.
Flag f;
int count = 0;
const int ITERATIONS_COUNT = 5000;
const int THREADS_COUNT = 50;
auto adder_func = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
// Acquire the spinlock.
while (!f.TestAndSet());
count++;
f.Clear();
}
};
auto adder_func = [&]() {
for (int i = 0; i < ITERATIONS_COUNT; ++i)
{
// Acquire the spinlock.
while (!f.TestAndSet())
;
count++;
f.Clear();
}
};
std::array<std::thread, THREADS_COUNT> threads;
for (auto& th : threads)
th = std::thread(adder_func);
for (auto& th : threads)
th.join();
std::array<std::thread, THREADS_COUNT> threads;
for (auto& th : threads)
th = std::thread(adder_func);
for (auto& th : threads)
th.join();
EXPECT_EQ(ITERATIONS_COUNT * THREADS_COUNT, count);
EXPECT_EQ(ITERATIONS_COUNT * THREADS_COUNT, count);
}

View File

@ -2,87 +2,91 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <gtest/gtest.h>
#include <limits>
#include <random>
#include <gtest/gtest.h>
#include "Common/MathUtil.h"
TEST(MathUtil, Clamp)
{
EXPECT_EQ(1, MathUtil::Clamp(1, 0, 2));
EXPECT_EQ(1.0, MathUtil::Clamp(1.0, 0.0, 2.0));
EXPECT_EQ(1, MathUtil::Clamp(1, 0, 2));
EXPECT_EQ(1.0, MathUtil::Clamp(1.0, 0.0, 2.0));
EXPECT_EQ(2, MathUtil::Clamp(4, 0, 2));
EXPECT_EQ(2.0, MathUtil::Clamp(4.0, 0.0, 2.0));
EXPECT_EQ(2, MathUtil::Clamp(4, 0, 2));
EXPECT_EQ(2.0, MathUtil::Clamp(4.0, 0.0, 2.0));
EXPECT_EQ(0, MathUtil::Clamp(-1, 0, 2));
EXPECT_EQ(0.0, MathUtil::Clamp(-1.0, 0.0, 2.0));
EXPECT_EQ(0, MathUtil::Clamp(-1, 0, 2));
EXPECT_EQ(0.0, MathUtil::Clamp(-1.0, 0.0, 2.0));
}
TEST(MathUtil, IsQNAN)
{
EXPECT_TRUE(MathUtil::IsQNAN(std::numeric_limits<double>::quiet_NaN()));
EXPECT_FALSE(MathUtil::IsQNAN(MathUtil::SNANConstant<double>()));
EXPECT_TRUE(MathUtil::IsQNAN(std::numeric_limits<double>::quiet_NaN()));
EXPECT_FALSE(MathUtil::IsQNAN(MathUtil::SNANConstant<double>()));
}
TEST(MathUtil, IsSNAN)
{
EXPECT_FALSE(MathUtil::IsSNAN(std::numeric_limits<double>::quiet_NaN()));
EXPECT_TRUE(MathUtil::IsSNAN(MathUtil::SNANConstant<double>()));
EXPECT_FALSE(MathUtil::IsSNAN(std::numeric_limits<double>::quiet_NaN()));
EXPECT_TRUE(MathUtil::IsSNAN(MathUtil::SNANConstant<double>()));
}
TEST(MathUtil, IntLog2)
{
EXPECT_EQ(0, IntLog2(1));
EXPECT_EQ(1, IntLog2(2));
EXPECT_EQ(2, IntLog2(4));
EXPECT_EQ(3, IntLog2(8));
EXPECT_EQ(63, IntLog2(0x8000000000000000ull));
EXPECT_EQ(0, IntLog2(1));
EXPECT_EQ(1, IntLog2(2));
EXPECT_EQ(2, IntLog2(4));
EXPECT_EQ(3, IntLog2(8));
EXPECT_EQ(63, IntLog2(0x8000000000000000ull));
// Rounding behavior.
EXPECT_EQ(3, IntLog2(15));
EXPECT_EQ(63, IntLog2(0xFFFFFFFFFFFFFFFFull));
// Rounding behavior.
EXPECT_EQ(3, IntLog2(15));
EXPECT_EQ(63, IntLog2(0xFFFFFFFFFFFFFFFFull));
}
TEST(MathUtil, FlushToZero)
{
// To test the software implementation we need to make sure FTZ and DAZ are disabled.
// Using volatile here to ensure the compiler doesn't constant-fold it,
// we want the multiplication to occur at test runtime.
volatile float s = std::numeric_limits<float>::denorm_min();
volatile double d = std::numeric_limits<double>::denorm_min();
// Casting away the volatile attribute is required in order for msvc to resolve this to the
// correct instance of the comparison function.
EXPECT_LT(0.f, (float)(s * 2));
EXPECT_LT(0.0, (double)(d * 2));
// To test the software implementation we need to make sure FTZ and DAZ are disabled.
// Using volatile here to ensure the compiler doesn't constant-fold it,
// we want the multiplication to occur at test runtime.
volatile float s = std::numeric_limits<float>::denorm_min();
volatile double d = std::numeric_limits<double>::denorm_min();
// Casting away the volatile attribute is required in order for msvc to resolve this to the
// correct instance of the comparison function.
EXPECT_LT(0.f, (float)(s * 2));
EXPECT_LT(0.0, (double)(d * 2));
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::denorm_min()));
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::denorm_min()));
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::min() / 2));
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::min() / 2));
EXPECT_EQ(std::numeric_limits<double>::min(), MathUtil::FlushToZero(std::numeric_limits<double>::min()));
EXPECT_EQ(std::numeric_limits<double>::max(), MathUtil::FlushToZero(std::numeric_limits<double>::max()));
EXPECT_EQ(+std::numeric_limits<double>::infinity(), MathUtil::FlushToZero(+std::numeric_limits<double>::infinity()));
EXPECT_EQ(-std::numeric_limits<double>::infinity(), MathUtil::FlushToZero(-std::numeric_limits<double>::infinity()));
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::denorm_min()));
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::denorm_min()));
EXPECT_EQ(+0.0, MathUtil::FlushToZero(+std::numeric_limits<double>::min() / 2));
EXPECT_EQ(-0.0, MathUtil::FlushToZero(-std::numeric_limits<double>::min() / 2));
EXPECT_EQ(std::numeric_limits<double>::min(),
MathUtil::FlushToZero(std::numeric_limits<double>::min()));
EXPECT_EQ(std::numeric_limits<double>::max(),
MathUtil::FlushToZero(std::numeric_limits<double>::max()));
EXPECT_EQ(+std::numeric_limits<double>::infinity(),
MathUtil::FlushToZero(+std::numeric_limits<double>::infinity()));
EXPECT_EQ(-std::numeric_limits<double>::infinity(),
MathUtil::FlushToZero(-std::numeric_limits<double>::infinity()));
// Test all subnormals as well as an equally large set of random normal floats.
std::default_random_engine engine(0);
std::uniform_int_distribution<u32> dist(0x00800000u, 0x7fffffffu);
for (u32 i = 0; i <= 0x007fffffu; ++i)
{
MathUtil::IntFloat x(i);
EXPECT_EQ(+0.f, MathUtil::FlushToZero(x.f));
// Test all subnormals as well as an equally large set of random normal floats.
std::default_random_engine engine(0);
std::uniform_int_distribution<u32> dist(0x00800000u, 0x7fffffffu);
for (u32 i = 0; i <= 0x007fffffu; ++i)
{
MathUtil::IntFloat x(i);
EXPECT_EQ(+0.f, MathUtil::FlushToZero(x.f));
x.i = i | 0x80000000u;
EXPECT_EQ(-0.f, MathUtil::FlushToZero(x.f));
x.i = i | 0x80000000u;
EXPECT_EQ(-0.f, MathUtil::FlushToZero(x.f));
x.i = dist(engine);
MathUtil::IntFloat y(MathUtil::FlushToZero(x.f));
EXPECT_EQ(x.i, y.i);
x.i = dist(engine);
MathUtil::IntFloat y(MathUtil::FlushToZero(x.f));
EXPECT_EQ(x.i, y.i);
x.i |= 0x80000000u;
y.f = MathUtil::FlushToZero(x.f);
EXPECT_EQ(x.i, y.i);
}
x.i |= 0x80000000u;
y.f = MathUtil::FlushToZero(x.f);
EXPECT_EQ(x.i, y.i);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,8 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <unordered_set>
#include <gtest/gtest.h>
#include <unordered_set>
#include "Common/CommonTypes.h"
#include "Core/HW/MMIO.h"
@ -12,120 +12,120 @@
// number: that is, it is unique in the address ranges we care about.
TEST(UniqueID, UniqueEnough)
{
std::unordered_set<u32> ids;
for (u32 i = 0x0C000000; i < 0x0C010000; ++i)
{
u32 unique_id = MMIO::UniqueID(i);
EXPECT_EQ(ids.end(), ids.find(unique_id));
ids.insert(unique_id);
}
for (u32 i = 0x0D000000; i < 0x0D010000; ++i)
{
u32 unique_id = MMIO::UniqueID(i);
EXPECT_EQ(ids.end(), ids.find(unique_id));
ids.insert(unique_id);
}
std::unordered_set<u32> ids;
for (u32 i = 0x0C000000; i < 0x0C010000; ++i)
{
u32 unique_id = MMIO::UniqueID(i);
EXPECT_EQ(ids.end(), ids.find(unique_id));
ids.insert(unique_id);
}
for (u32 i = 0x0D000000; i < 0x0D010000; ++i)
{
u32 unique_id = MMIO::UniqueID(i);
EXPECT_EQ(ids.end(), ids.find(unique_id));
ids.insert(unique_id);
}
}
TEST(IsMMIOAddress, SpecialAddresses)
{
SConfig::Init();
SConfig::GetInstance().bWii = true;
SConfig::Init();
SConfig::GetInstance().bWii = true;
// WG Pipe address, should not be handled by MMIO.
EXPECT_FALSE(MMIO::IsMMIOAddress(0x0C008000));
// WG Pipe address, should not be handled by MMIO.
EXPECT_FALSE(MMIO::IsMMIOAddress(0x0C008000));
// Locked L1 cache allocation.
EXPECT_FALSE(MMIO::IsMMIOAddress(0xE0000000));
// Locked L1 cache allocation.
EXPECT_FALSE(MMIO::IsMMIOAddress(0xE0000000));
// Uncached mirror of MEM1, shouldn't be handled by MMIO
EXPECT_FALSE(MMIO::IsMMIOAddress(0xC0000000));
// Uncached mirror of MEM1, shouldn't be handled by MMIO
EXPECT_FALSE(MMIO::IsMMIOAddress(0xC0000000));
// Effective address of an MMIO register; MMIO only deals with physical
// addresses.
EXPECT_FALSE(MMIO::IsMMIOAddress(0xCC0000E0));
// Effective address of an MMIO register; MMIO only deals with physical
// addresses.
EXPECT_FALSE(MMIO::IsMMIOAddress(0xCC0000E0));
// And lets check some valid addresses too
EXPECT_TRUE(MMIO::IsMMIOAddress(0x0C0000E0)); // Gamecube MMIOs
EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D00008C)); // Wii MMIOs
EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D800F10)); // Mirror of Wii MMIOs
// And lets check some valid addresses too
EXPECT_TRUE(MMIO::IsMMIOAddress(0x0C0000E0)); // Gamecube MMIOs
EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D00008C)); // Wii MMIOs
EXPECT_TRUE(MMIO::IsMMIOAddress(0x0D800F10)); // Mirror of Wii MMIOs
SConfig::Shutdown();
SConfig::Shutdown();
}
class MappingTest : public testing::Test
{
protected:
virtual void SetUp() override
{
m_mapping = new MMIO::Mapping();
}
virtual void TearDown() override
{
delete m_mapping;
}
MMIO::Mapping* m_mapping;
virtual void SetUp() override { m_mapping = new MMIO::Mapping(); }
virtual void TearDown() override { delete m_mapping; }
MMIO::Mapping* m_mapping;
};
TEST_F(MappingTest, ReadConstant)
{
m_mapping->Register(0x0C001234, MMIO::Constant<u8>(0x42), MMIO::Nop<u8>());
m_mapping->Register(0x0C001234, MMIO::Constant<u16>(0x1234), MMIO::Nop<u16>());
m_mapping->Register(0x0C001234, MMIO::Constant<u32>(0xdeadbeef), MMIO::Nop<u32>());
m_mapping->Register(0x0C001234, MMIO::Constant<u8>(0x42), MMIO::Nop<u8>());
m_mapping->Register(0x0C001234, MMIO::Constant<u16>(0x1234), MMIO::Nop<u16>());
m_mapping->Register(0x0C001234, MMIO::Constant<u32>(0xdeadbeef), MMIO::Nop<u32>());
u8 val8 = m_mapping->Read<u8>(0x0C001234);
u16 val16 = m_mapping->Read<u16>(0x0C001234);
u32 val32 = m_mapping->Read<u32>(0x0C001234);
u8 val8 = m_mapping->Read<u8>(0x0C001234);
u16 val16 = m_mapping->Read<u16>(0x0C001234);
u32 val32 = m_mapping->Read<u32>(0x0C001234);
EXPECT_EQ(0x42, val8);
EXPECT_EQ(0x1234, val16);
EXPECT_EQ(0xdeadbeef, val32);
EXPECT_EQ(0x42, val8);
EXPECT_EQ(0x1234, val16);
EXPECT_EQ(0xdeadbeef, val32);
}
TEST_F(MappingTest, ReadWriteDirect)
{
u8 target_8 = 0;
u16 target_16 = 0;
u32 target_32 = 0;
u8 target_8 = 0;
u16 target_16 = 0;
u32 target_32 = 0;
m_mapping->Register(0x0C001234, MMIO::DirectRead<u8>(&target_8), MMIO::DirectWrite<u8>(&target_8));
m_mapping->Register(0x0C001234, MMIO::DirectRead<u16>(&target_16), MMIO::DirectWrite<u16>(&target_16));
m_mapping->Register(0x0C001234, MMIO::DirectRead<u32>(&target_32), MMIO::DirectWrite<u32>(&target_32));
m_mapping->Register(0x0C001234, MMIO::DirectRead<u8>(&target_8),
MMIO::DirectWrite<u8>(&target_8));
m_mapping->Register(0x0C001234, MMIO::DirectRead<u16>(&target_16),
MMIO::DirectWrite<u16>(&target_16));
m_mapping->Register(0x0C001234, MMIO::DirectRead<u32>(&target_32),
MMIO::DirectWrite<u32>(&target_32));
for (u32 i = 0; i < 100; ++i)
{
u8 val8 = m_mapping->Read<u8>(0x0C001234); EXPECT_EQ(i, val8);
u16 val16 = m_mapping->Read<u16>(0x0C001234); EXPECT_EQ(i, val16);
u32 val32 = m_mapping->Read<u32>(0x0C001234); EXPECT_EQ(i, val32);
for (u32 i = 0; i < 100; ++i)
{
u8 val8 = m_mapping->Read<u8>(0x0C001234);
EXPECT_EQ(i, val8);
u16 val16 = m_mapping->Read<u16>(0x0C001234);
EXPECT_EQ(i, val16);
u32 val32 = m_mapping->Read<u32>(0x0C001234);
EXPECT_EQ(i, val32);
val8 += 1; m_mapping->Write(0x0C001234, val8);
val16 += 1; m_mapping->Write(0x0C001234, val16);
val32 += 1; m_mapping->Write(0x0C001234, val32);
}
val8 += 1;
m_mapping->Write(0x0C001234, val8);
val16 += 1;
m_mapping->Write(0x0C001234, val16);
val32 += 1;
m_mapping->Write(0x0C001234, val32);
}
}
TEST_F(MappingTest, ReadWriteComplex)
{
bool read_called = false, write_called = false;
bool read_called = false, write_called = false;
m_mapping->Register(0x0C001234,
MMIO::ComplexRead<u8>([&read_called](u32 addr) {
EXPECT_EQ(0x0C001234u, addr);
read_called = true;
return 0x12;
}),
MMIO::ComplexWrite<u8>([&write_called](u32 addr, u8 val) {
EXPECT_EQ(0x0C001234u, addr);
EXPECT_EQ(0x34, val);
write_called = true;
})
);
m_mapping->Register(0x0C001234, MMIO::ComplexRead<u8>([&read_called](u32 addr) {
EXPECT_EQ(0x0C001234u, addr);
read_called = true;
return 0x12;
}),
MMIO::ComplexWrite<u8>([&write_called](u32 addr, u8 val) {
EXPECT_EQ(0x0C001234u, addr);
EXPECT_EQ(0x34, val);
write_called = true;
}));
u8 val = m_mapping->Read<u8>(0x0C001234); EXPECT_EQ(0x12, val);
m_mapping->Write(0x0C001234, (u8)0x34);
u8 val = m_mapping->Read<u8>(0x0C001234);
EXPECT_EQ(0x12, val);
m_mapping->Write(0x0C001234, (u8)0x34);
EXPECT_TRUE(read_called);
EXPECT_TRUE(write_called);
EXPECT_TRUE(read_called);
EXPECT_TRUE(write_called);
}

View File

@ -10,70 +10,69 @@
#include "Core/PowerPC/JitCommon/JitBase.h"
// include order is important
#include <gtest/gtest.h> // NOLINT
#include <gtest/gtest.h> // NOLINT
enum
{
#ifdef _WIN32
PAGE_GRAN = 0x10000
PAGE_GRAN = 0x10000
#else
PAGE_GRAN = 0x1000
PAGE_GRAN = 0x1000
#endif
};
class PageFaultFakeJit : public JitBase
{
public:
// CPUCoreBase methods
void Init() override {}
void Shutdown() override {}
void ClearCache() override {}
void Run() override {}
void SingleStep() override {}
const char *GetName() override { return nullptr; }
// CPUCoreBase methods
void Init() override {}
void Shutdown() override {}
void ClearCache() override {}
void Run() override {}
void SingleStep() override {}
const char* GetName() override { return nullptr; }
// JitBase methods
JitBaseBlockCache* GetBlockCache() override { return nullptr; }
void Jit(u32 em_address) override {}
const CommonAsmRoutinesBase* GetAsmRoutines() override { return nullptr; }
virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override
{
m_pre_unprotect_time = std::chrono::high_resolution_clock::now();
UnWriteProtectMemory(m_data, PAGE_GRAN, /*allowExecute*/ false);
m_post_unprotect_time = std::chrono::high_resolution_clock::now();
return true;
}
// JitBase methods
JitBaseBlockCache *GetBlockCache() override { return nullptr; }
void Jit(u32 em_address) override {}
const CommonAsmRoutinesBase *GetAsmRoutines() override { return nullptr; }
virtual bool HandleFault(uintptr_t access_address, SContext* ctx) override
{
m_pre_unprotect_time = std::chrono::high_resolution_clock::now();
UnWriteProtectMemory(m_data, PAGE_GRAN, /*allowExecute*/ false);
m_post_unprotect_time = std::chrono::high_resolution_clock::now();
return true;
}
void* m_data;
std::chrono::time_point<std::chrono::high_resolution_clock>
m_pre_unprotect_time, m_post_unprotect_time;
void* m_data;
std::chrono::time_point<std::chrono::high_resolution_clock> m_pre_unprotect_time,
m_post_unprotect_time;
};
TEST(PageFault, PageFault)
{
EMM::InstallExceptionHandler();
void* data = AllocateMemoryPages(PAGE_GRAN);
EXPECT_NE(data, nullptr);
WriteProtectMemory(data, PAGE_GRAN, false);
EMM::InstallExceptionHandler();
void* data = AllocateMemoryPages(PAGE_GRAN);
EXPECT_NE(data, nullptr);
WriteProtectMemory(data, PAGE_GRAN, false);
PageFaultFakeJit pfjit;
jit = &pfjit;
pfjit.m_data = data;
PageFaultFakeJit pfjit;
jit = &pfjit;
pfjit.m_data = data;
auto start = std::chrono::high_resolution_clock::now();
*(volatile int*) data = 5;
auto end = std::chrono::high_resolution_clock::now();
auto start = std::chrono::high_resolution_clock::now();
*(volatile int*)data = 5;
auto end = std::chrono::high_resolution_clock::now();
#define AS_NS(diff) ((unsigned long long)std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count())
#define AS_NS(diff) \
((unsigned long long)std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count())
EMM::UninstallExceptionHandler();
jit = nullptr;
EMM::UninstallExceptionHandler();
jit = nullptr;
printf("page fault timing:\n");
printf("start->HandleFault %llu ns\n", AS_NS(pfjit.m_pre_unprotect_time - start));
printf("UnWriteProtectMemory %llu ns\n", AS_NS(pfjit.m_post_unprotect_time - pfjit.m_pre_unprotect_time));
printf("HandleFault->end %llu ns\n", AS_NS(end - pfjit.m_post_unprotect_time));
printf("total %llu ns\n", AS_NS(end - start));
printf("page fault timing:\n");
printf("start->HandleFault %llu ns\n", AS_NS(pfjit.m_pre_unprotect_time - start));
printf("UnWriteProtectMemory %llu ns\n",
AS_NS(pfjit.m_post_unprotect_time - pfjit.m_pre_unprotect_time));
printf("HandleFault->end %llu ns\n", AS_NS(end - pfjit.m_post_unprotect_time));
printf("total %llu ns\n", AS_NS(end - start));
}

View File

@ -11,20 +11,59 @@
#include "Common/GL/GLInterfaceBase.h"
#include "Core/Host.h"
void Host_NotifyMapLoaded() {}
void Host_RefreshDSPDebuggerWindow() {}
void Host_Message(int) {}
void* Host_GetRenderHandle() { return nullptr; }
void Host_UpdateTitle(const std::string&) {}
void Host_UpdateDisasmDialog() {}
void Host_UpdateMainFrame() {}
void Host_RequestRenderWindowSize(int, int) {}
void Host_RequestFullscreen(bool) {}
void Host_SetStartupDebuggingParameters() {}
bool Host_UIHasFocus() { return false; }
bool Host_RendererHasFocus() { return false; }
bool Host_RendererIsFullscreen() { return false; }
void Host_ConnectWiimote(int, bool) {}
void Host_SetWiiMoteConnectionState(int) {}
void Host_ShowVideoConfig(void*, const std::string&, const std::string&) {}
std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface() { return nullptr; }
void Host_NotifyMapLoaded()
{
}
void Host_RefreshDSPDebuggerWindow()
{
}
void Host_Message(int)
{
}
void* Host_GetRenderHandle()
{
return nullptr;
}
void Host_UpdateTitle(const std::string&)
{
}
void Host_UpdateDisasmDialog()
{
}
void Host_UpdateMainFrame()
{
}
void Host_RequestRenderWindowSize(int, int)
{
}
void Host_RequestFullscreen(bool)
{
}
void Host_SetStartupDebuggingParameters()
{
}
bool Host_UIHasFocus()
{
return false;
}
bool Host_RendererHasFocus()
{
return false;
}
bool Host_RendererIsFullscreen()
{
return false;
}
void Host_ConnectWiimote(int, bool)
{
}
void Host_SetWiiMoteConnectionState(int)
{
}
void Host_ShowVideoConfig(void*, const std::string&, const std::string&)
{
}
std::unique_ptr<cInterfaceBase> HostGL_CreateGLInterface()
{
return nullptr;
}

View File

@ -20,23 +20,23 @@
TEST(VertexLoaderUID, UniqueEnough)
{
std::unordered_set<VertexLoaderUID> uids;
std::unordered_set<VertexLoaderUID> uids;
TVtxDesc vtx_desc;
memset(&vtx_desc, 0, sizeof(vtx_desc));
VAT vat;
memset(&vat, 0, sizeof(vat));
uids.insert(VertexLoaderUID(vtx_desc, vat));
TVtxDesc vtx_desc;
memset(&vtx_desc, 0, sizeof(vtx_desc));
VAT vat;
memset(&vat, 0, sizeof(vat));
uids.insert(VertexLoaderUID(vtx_desc, vat));
vtx_desc.Hex = 0xFEDCBA9876543210ull;
EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat)));
uids.insert(VertexLoaderUID(vtx_desc, vat));
vtx_desc.Hex = 0xFEDCBA9876543210ull;
EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat)));
uids.insert(VertexLoaderUID(vtx_desc, vat));
vat.g0.Hex = 0xFFFFFFFF;
vat.g1.Hex = 0xFFFFFFFF;
vat.g2.Hex = 0xFFFFFFFF;
EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat)));
uids.insert(VertexLoaderUID(vtx_desc, vat));
vat.g0.Hex = 0xFFFFFFFF;
vat.g1.Hex = 0xFFFFFFFF;
vat.g2.Hex = 0xFFFFFFFF;
EXPECT_EQ(uids.end(), uids.find(VertexLoaderUID(vtx_desc, vat)));
uids.insert(VertexLoaderUID(vtx_desc, vat));
}
static u8 input_memory[16 * 1024 * 1024];
@ -45,267 +45,311 @@ static u8 output_memory[16 * 1024 * 1024];
class VertexLoaderTest : public testing::Test
{
protected:
void SetUp() override
{
memset(input_memory, 0, sizeof(input_memory));
memset(output_memory, 0xFF, sizeof(input_memory));
void SetUp() override
{
memset(input_memory, 0, sizeof(input_memory));
memset(output_memory, 0xFF, sizeof(input_memory));
memset(&m_vtx_desc, 0, sizeof(m_vtx_desc));
memset(&m_vtx_attr, 0, sizeof(m_vtx_attr));
memset(&m_vtx_desc, 0, sizeof(m_vtx_desc));
memset(&m_vtx_attr, 0, sizeof(m_vtx_attr));
m_loader = nullptr;
m_loader = nullptr;
ResetPointers();
}
ResetPointers();
}
void CreateAndCheckSizes(size_t input_size, size_t output_size)
{
m_loader = VertexLoaderBase::CreateVertexLoader(m_vtx_desc, m_vtx_attr);
ASSERT_EQ((int)input_size, m_loader->m_VertexSize);
ASSERT_EQ((int)output_size, m_loader->m_native_vtx_decl.stride);
}
void CreateAndCheckSizes(size_t input_size, size_t output_size)
{
m_loader = VertexLoaderBase::CreateVertexLoader(m_vtx_desc, m_vtx_attr);
ASSERT_EQ((int)input_size, m_loader->m_VertexSize);
ASSERT_EQ((int)output_size, m_loader->m_native_vtx_decl.stride);
}
template <typename T>
void Input(T val)
{
// Write swapped.
m_src.Write<T, true>(val);
}
template <typename T>
void Input(T val)
{
// Write swapped.
m_src.Write<T, true>(val);
}
void ExpectOut(float val)
{
// Read unswapped.
MathUtil::IntFloat expected(val), actual(m_dst.Read<float, false>());
if (!actual.f || actual.f != actual.f)
EXPECT_EQ(expected.i, actual.i);
else
EXPECT_EQ(expected.f, actual.f);
}
void ExpectOut(float val)
{
// Read unswapped.
MathUtil::IntFloat expected(val), actual(m_dst.Read<float, false>());
if (!actual.f || actual.f != actual.f)
EXPECT_EQ(expected.i, actual.i);
else
EXPECT_EQ(expected.f, actual.f);
}
void RunVertices(int count, int expected_count = -1)
{
if (expected_count == -1)
expected_count = count;
ResetPointers();
int actual_count = m_loader->RunVertices(m_src, m_dst, count);
EXPECT_EQ(actual_count, expected_count);
}
void RunVertices(int count, int expected_count = -1)
{
if (expected_count == -1)
expected_count = count;
ResetPointers();
int actual_count = m_loader->RunVertices(m_src, m_dst, count);
EXPECT_EQ(actual_count, expected_count);
}
void ResetPointers()
{
m_src = DataReader(input_memory, input_memory + sizeof(input_memory));
m_dst = DataReader(output_memory, output_memory + sizeof(output_memory));
}
void ResetPointers()
{
m_src = DataReader(input_memory, input_memory + sizeof(input_memory));
m_dst = DataReader(output_memory, output_memory + sizeof(output_memory));
}
DataReader m_src;
DataReader m_dst;
DataReader m_src;
DataReader m_dst;
TVtxDesc m_vtx_desc;
VAT m_vtx_attr;
std::unique_ptr<VertexLoaderBase> m_loader;
TVtxDesc m_vtx_desc;
VAT m_vtx_attr;
std::unique_ptr<VertexLoaderBase> m_loader;
};
class VertexLoaderParamTest : public VertexLoaderTest, public ::testing::WithParamInterface<std::tuple<int, int, int, int>> {};
class VertexLoaderParamTest : public VertexLoaderTest,
public ::testing::WithParamInterface<std::tuple<int, int, int, int>>
{
};
extern int gtest_AllCombinationsVertexLoaderParamTest_dummy_;
INSTANTIATE_TEST_CASE_P(
AllCombinations, VertexLoaderParamTest,
::testing::Combine(
::testing::Values(DIRECT, INDEX8, INDEX16),
::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, FORMAT_USHORT, FORMAT_SHORT, FORMAT_FLOAT),
::testing::Values(0, 1), // elements
::testing::Values(0, 1, 31) // frac
)
);
INSTANTIATE_TEST_CASE_P(AllCombinations, VertexLoaderParamTest,
::testing::Combine(::testing::Values(DIRECT, INDEX8, INDEX16),
::testing::Values(FORMAT_UBYTE, FORMAT_BYTE,
FORMAT_USHORT, FORMAT_SHORT,
FORMAT_FLOAT),
::testing::Values(0, 1), // elements
::testing::Values(0, 1, 31) // frac
));
TEST_P(VertexLoaderParamTest, PositionAll)
{
int addr, format, elements, frac;
std::tie(addr, format, elements, frac) = GetParam();
this->m_vtx_desc.Position = addr;
this->m_vtx_attr.g0.PosFormat = format;
this->m_vtx_attr.g0.PosElements = elements;
this->m_vtx_attr.g0.PosFrac = frac;
this->m_vtx_attr.g0.ByteDequant = true;
elements += 2;
int addr, format, elements, frac;
std::tie(addr, format, elements, frac) = GetParam();
this->m_vtx_desc.Position = addr;
this->m_vtx_attr.g0.PosFormat = format;
this->m_vtx_attr.g0.PosElements = elements;
this->m_vtx_attr.g0.PosFrac = frac;
this->m_vtx_attr.g0.ByteDequant = true;
elements += 2;
std::vector<float> values = {
std::numeric_limits<float>::lowest(),
std::numeric_limits<float>::denorm_min(),
std::numeric_limits<float>::min(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::quiet_NaN(),
std::numeric_limits<float>::infinity(),
-0x8000, -0x80, -1, -0, 0, 1, 123, 0x7F, 0xFF, 0x7FFF, 0xFFFF, 12345678,
};
ASSERT_EQ(0u, values.size() % 2);
ASSERT_EQ(0u, values.size() % 3);
std::vector<float> values = {
std::numeric_limits<float>::lowest(),
std::numeric_limits<float>::denorm_min(),
std::numeric_limits<float>::min(),
std::numeric_limits<float>::max(),
std::numeric_limits<float>::quiet_NaN(),
std::numeric_limits<float>::infinity(),
-0x8000,
-0x80,
-1,
-0,
0,
1,
123,
0x7F,
0xFF,
0x7FFF,
0xFFFF,
12345678,
};
ASSERT_EQ(0u, values.size() % 2);
ASSERT_EQ(0u, values.size() % 3);
int count = (int)values.size() / elements;
u32 elem_size = 1 << (format / 2);
size_t input_size = elements * elem_size;
if (addr & MASK_INDEXED)
{
input_size = addr - 1;
for (int i = 0; i < count; i++)
if (addr == INDEX8)
Input<u8>(i);
else
Input<u16>(i);
VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer();
g_main_cp_state.array_strides[ARRAY_POSITION] = elements * elem_size;
}
CreateAndCheckSizes(input_size, elements * sizeof(float));
for (float value : values)
{
switch (format)
{
case FORMAT_UBYTE: Input((u8)value); break;
case FORMAT_BYTE: Input((s8)value); break;
case FORMAT_USHORT: Input((u16)value); break;
case FORMAT_SHORT: Input((s16)value); break;
case FORMAT_FLOAT: Input(value); break;
}
}
int count = (int)values.size() / elements;
u32 elem_size = 1 << (format / 2);
size_t input_size = elements * elem_size;
if (addr & MASK_INDEXED)
{
input_size = addr - 1;
for (int i = 0; i < count; i++)
if (addr == INDEX8)
Input<u8>(i);
else
Input<u16>(i);
VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer();
g_main_cp_state.array_strides[ARRAY_POSITION] = elements * elem_size;
}
CreateAndCheckSizes(input_size, elements * sizeof(float));
for (float value : values)
{
switch (format)
{
case FORMAT_UBYTE:
Input((u8)value);
break;
case FORMAT_BYTE:
Input((s8)value);
break;
case FORMAT_USHORT:
Input((u16)value);
break;
case FORMAT_SHORT:
Input((s16)value);
break;
case FORMAT_FLOAT:
Input(value);
break;
}
}
RunVertices(count);
RunVertices(count);
float scale = 1.f / (1u << (format == FORMAT_FLOAT ? 0 : frac));
for (auto iter = values.begin(); iter != values.end();)
{
float f, g;
switch (format)
{
case FORMAT_UBYTE: f = (u8)*iter++; g = (u8)*iter++; break;
case FORMAT_BYTE: f = (s8)*iter++; g = (s8)*iter++; break;
case FORMAT_USHORT: f = (u16)*iter++; g = (u16)*iter++; break;
case FORMAT_SHORT: f = (s16)*iter++; g = (s16)*iter++; break;
case FORMAT_FLOAT: f = *iter++; g = *iter++; break;
}
ExpectOut(f * scale);
ExpectOut(g * scale);
}
float scale = 1.f / (1u << (format == FORMAT_FLOAT ? 0 : frac));
for (auto iter = values.begin(); iter != values.end();)
{
float f, g;
switch (format)
{
case FORMAT_UBYTE:
f = (u8)*iter++;
g = (u8)*iter++;
break;
case FORMAT_BYTE:
f = (s8)*iter++;
g = (s8)*iter++;
break;
case FORMAT_USHORT:
f = (u16)*iter++;
g = (u16)*iter++;
break;
case FORMAT_SHORT:
f = (s16)*iter++;
g = (s16)*iter++;
break;
case FORMAT_FLOAT:
f = *iter++;
g = *iter++;
break;
}
ExpectOut(f * scale);
ExpectOut(g * scale);
}
}
TEST_F(VertexLoaderTest, PositionIndex16FloatXY)
{
m_vtx_desc.Position = INDEX16;
m_vtx_attr.g0.PosFormat = FORMAT_FLOAT;
CreateAndCheckSizes(sizeof(u16), 2 * sizeof(float));
Input<u16>(1); Input<u16>(0);
VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer();
g_main_cp_state.array_strides[ARRAY_POSITION] = sizeof(float); // ;)
Input(1.f); Input(2.f); Input(3.f);
RunVertices(2);
ExpectOut(2); ExpectOut(3);
ExpectOut(1); ExpectOut(2);
m_vtx_desc.Position = INDEX16;
m_vtx_attr.g0.PosFormat = FORMAT_FLOAT;
CreateAndCheckSizes(sizeof(u16), 2 * sizeof(float));
Input<u16>(1);
Input<u16>(0);
VertexLoaderManager::cached_arraybases[ARRAY_POSITION] = m_src.GetPointer();
g_main_cp_state.array_strides[ARRAY_POSITION] = sizeof(float); // ;)
Input(1.f);
Input(2.f);
Input(3.f);
RunVertices(2);
ExpectOut(2);
ExpectOut(3);
ExpectOut(1);
ExpectOut(2);
}
class VertexLoaderSpeedTest : public VertexLoaderTest, public ::testing::WithParamInterface<std::tuple<int, int>> {};
class VertexLoaderSpeedTest : public VertexLoaderTest,
public ::testing::WithParamInterface<std::tuple<int, int>>
{
};
extern int gtest_FormatsAndElementsVertexLoaderSpeedTest_dummy_;
INSTANTIATE_TEST_CASE_P(
FormatsAndElements, VertexLoaderSpeedTest,
::testing::Combine(
::testing::Values(FORMAT_UBYTE, FORMAT_BYTE, FORMAT_USHORT, FORMAT_SHORT, FORMAT_FLOAT),
::testing::Values(0, 1) // elements
)
);
INSTANTIATE_TEST_CASE_P(FormatsAndElements, VertexLoaderSpeedTest,
::testing::Combine(::testing::Values(FORMAT_UBYTE, FORMAT_BYTE,
FORMAT_USHORT, FORMAT_SHORT,
FORMAT_FLOAT),
::testing::Values(0, 1) // elements
));
TEST_P(VertexLoaderSpeedTest, PositionDirectAll)
{
int format, elements;
std::tie(format, elements) = GetParam();
const char* map[] = { "u8", "s8", "u16", "s16", "float" };
printf("format: %s, elements: %d\n", map[format], elements);
m_vtx_desc.Position = DIRECT;
m_vtx_attr.g0.PosFormat = format;
m_vtx_attr.g0.PosElements = elements;
elements += 2;
size_t elem_size = static_cast<size_t>(1) << (format / 2);
CreateAndCheckSizes(elements * elem_size, elements * sizeof(float));
for (int i = 0; i < 1000; ++i)
RunVertices(100000);
int format, elements;
std::tie(format, elements) = GetParam();
const char* map[] = {"u8", "s8", "u16", "s16", "float"};
printf("format: %s, elements: %d\n", map[format], elements);
m_vtx_desc.Position = DIRECT;
m_vtx_attr.g0.PosFormat = format;
m_vtx_attr.g0.PosElements = elements;
elements += 2;
size_t elem_size = static_cast<size_t>(1) << (format / 2);
CreateAndCheckSizes(elements * elem_size, elements * sizeof(float));
for (int i = 0; i < 1000; ++i)
RunVertices(100000);
}
TEST_P(VertexLoaderSpeedTest, TexCoordSingleElement)
{
int format, elements;
std::tie(format, elements) = GetParam();
const char* map[] = { "u8", "s8", "u16", "s16", "float" };
printf("format: %s, elements: %d\n", map[format], elements);
m_vtx_desc.Position = DIRECT;
m_vtx_attr.g0.PosFormat = FORMAT_BYTE;
m_vtx_desc.Tex0Coord = DIRECT;
m_vtx_attr.g0.Tex0CoordFormat = format;
m_vtx_attr.g0.Tex0CoordElements = elements;
elements += 1;
size_t elem_size = static_cast<size_t>(1) << (format / 2);
CreateAndCheckSizes(2 * sizeof(s8) + elements * elem_size,
2 * sizeof(float) + elements * sizeof(float));
for (int i = 0; i < 1000; ++i)
RunVertices(100000);
int format, elements;
std::tie(format, elements) = GetParam();
const char* map[] = {"u8", "s8", "u16", "s16", "float"};
printf("format: %s, elements: %d\n", map[format], elements);
m_vtx_desc.Position = DIRECT;
m_vtx_attr.g0.PosFormat = FORMAT_BYTE;
m_vtx_desc.Tex0Coord = DIRECT;
m_vtx_attr.g0.Tex0CoordFormat = format;
m_vtx_attr.g0.Tex0CoordElements = elements;
elements += 1;
size_t elem_size = static_cast<size_t>(1) << (format / 2);
CreateAndCheckSizes(2 * sizeof(s8) + elements * elem_size,
2 * sizeof(float) + elements * sizeof(float));
for (int i = 0; i < 1000; ++i)
RunVertices(100000);
}
TEST_F(VertexLoaderTest, LargeFloatVertexSpeed)
{
// Enables most attributes in floating point indexed mode to test speed.
m_vtx_desc.PosMatIdx = 1;
m_vtx_desc.Tex0MatIdx = 1;
m_vtx_desc.Tex1MatIdx = 1;
m_vtx_desc.Tex2MatIdx = 1;
m_vtx_desc.Tex3MatIdx = 1;
m_vtx_desc.Tex4MatIdx = 1;
m_vtx_desc.Tex5MatIdx = 1;
m_vtx_desc.Tex6MatIdx = 1;
m_vtx_desc.Tex7MatIdx = 1;
m_vtx_desc.Position = INDEX16;
m_vtx_desc.Normal = INDEX16;
m_vtx_desc.Color0 = INDEX16;
m_vtx_desc.Color1 = INDEX16;
m_vtx_desc.Tex0Coord = INDEX16;
m_vtx_desc.Tex1Coord = INDEX16;
m_vtx_desc.Tex2Coord = INDEX16;
m_vtx_desc.Tex3Coord = INDEX16;
m_vtx_desc.Tex4Coord = INDEX16;
m_vtx_desc.Tex5Coord = INDEX16;
m_vtx_desc.Tex6Coord = INDEX16;
m_vtx_desc.Tex7Coord = INDEX16;
// Enables most attributes in floating point indexed mode to test speed.
m_vtx_desc.PosMatIdx = 1;
m_vtx_desc.Tex0MatIdx = 1;
m_vtx_desc.Tex1MatIdx = 1;
m_vtx_desc.Tex2MatIdx = 1;
m_vtx_desc.Tex3MatIdx = 1;
m_vtx_desc.Tex4MatIdx = 1;
m_vtx_desc.Tex5MatIdx = 1;
m_vtx_desc.Tex6MatIdx = 1;
m_vtx_desc.Tex7MatIdx = 1;
m_vtx_desc.Position = INDEX16;
m_vtx_desc.Normal = INDEX16;
m_vtx_desc.Color0 = INDEX16;
m_vtx_desc.Color1 = INDEX16;
m_vtx_desc.Tex0Coord = INDEX16;
m_vtx_desc.Tex1Coord = INDEX16;
m_vtx_desc.Tex2Coord = INDEX16;
m_vtx_desc.Tex3Coord = INDEX16;
m_vtx_desc.Tex4Coord = INDEX16;
m_vtx_desc.Tex5Coord = INDEX16;
m_vtx_desc.Tex6Coord = INDEX16;
m_vtx_desc.Tex7Coord = INDEX16;
m_vtx_attr.g0.PosElements = 1; // XYZ
m_vtx_attr.g0.PosFormat = FORMAT_FLOAT;
m_vtx_attr.g0.NormalElements = 1; // NBT
m_vtx_attr.g0.NormalFormat = FORMAT_FLOAT;
m_vtx_attr.g0.Color0Elements = 1; // Has Alpha
m_vtx_attr.g0.Color0Comp = FORMAT_32B_8888;
m_vtx_attr.g0.Color1Elements = 1; // Has Alpha
m_vtx_attr.g0.Color1Comp = FORMAT_32B_8888;
m_vtx_attr.g0.Tex0CoordElements = 1; // ST
m_vtx_attr.g0.Tex0CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex1CoordElements = 1; // ST
m_vtx_attr.g1.Tex1CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex2CoordElements = 1; // ST
m_vtx_attr.g1.Tex2CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex3CoordElements = 1; // ST
m_vtx_attr.g1.Tex3CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex4CoordElements = 1; // ST
m_vtx_attr.g1.Tex4CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g2.Tex5CoordElements = 1; // ST
m_vtx_attr.g2.Tex5CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g2.Tex6CoordElements = 1; // ST
m_vtx_attr.g2.Tex6CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g2.Tex7CoordElements = 1; // ST
m_vtx_attr.g2.Tex7CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g0.PosElements = 1; // XYZ
m_vtx_attr.g0.PosFormat = FORMAT_FLOAT;
m_vtx_attr.g0.NormalElements = 1; // NBT
m_vtx_attr.g0.NormalFormat = FORMAT_FLOAT;
m_vtx_attr.g0.Color0Elements = 1; // Has Alpha
m_vtx_attr.g0.Color0Comp = FORMAT_32B_8888;
m_vtx_attr.g0.Color1Elements = 1; // Has Alpha
m_vtx_attr.g0.Color1Comp = FORMAT_32B_8888;
m_vtx_attr.g0.Tex0CoordElements = 1; // ST
m_vtx_attr.g0.Tex0CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex1CoordElements = 1; // ST
m_vtx_attr.g1.Tex1CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex2CoordElements = 1; // ST
m_vtx_attr.g1.Tex2CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex3CoordElements = 1; // ST
m_vtx_attr.g1.Tex3CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g1.Tex4CoordElements = 1; // ST
m_vtx_attr.g1.Tex4CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g2.Tex5CoordElements = 1; // ST
m_vtx_attr.g2.Tex5CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g2.Tex6CoordElements = 1; // ST
m_vtx_attr.g2.Tex6CoordFormat = FORMAT_FLOAT;
m_vtx_attr.g2.Tex7CoordElements = 1; // ST
m_vtx_attr.g2.Tex7CoordFormat = FORMAT_FLOAT;
CreateAndCheckSizes(33, 156);
CreateAndCheckSizes(33, 156);
for (int i = 0; i < 12; i++)
{
VertexLoaderManager::cached_arraybases[i] = m_src.GetPointer();
g_main_cp_state.array_strides[i] = 129;
}
for (int i = 0; i < 12; i++)
{
VertexLoaderManager::cached_arraybases[i] = m_src.GetPointer();
g_main_cp_state.array_strides[i] = 129;
}
// This test is only done 100x in a row since it's ~20x slower using the
// current vertex loader implementation.
for (int i = 0; i < 100; ++i)
RunVertices(100000);
// This test is only done 100x in a row since it's ~20x slower using the
// current vertex loader implementation.
for (int i = 0; i < 100; ++i)
RunVertices(100000);
}