mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 22:29:39 -06:00
Reformat all the things. Have fun with merge conflicts.
This commit is contained in:
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user