blob: 6b414e7b5947269d3717353c9e1d19806790dd0d [file] [log] [blame]
/*
* Copyright 2024 Rive
*/
#include "../src/intersection_board.hpp"
#include "common/intersection_board_reference_impl.hpp"
#include <catch.hpp>
#include <tuple>
namespace rive::gpu
{
template <GroupingType Type, typename T>
std::tuple<int16_t, int16_t>
find_standalone_max_group_index_and_overlappability(T& impl, int4 ltrb)
{
auto r = impl.template findMaxIntersectingGroupIndex<Type>(ltrb, {});
auto maxIndex = simd::reduce_max(r.maxGroupIndices);
int16_t fullOverlap = 0;
// The individual tiles allow overlappability to be written (as an inner
// loop optimization) when no overlap has occurred, so filter that out for
// testing (the intersection board also handles this)
if (maxIndex != 0)
{
for (int i = 0; i < 8; i++)
{
if (r.maxGroupIndices[i] == maxIndex)
{
fullOverlap |= r.overlapBits[i];
}
}
}
return {maxIndex, fullOverlap};
}
template <GroupingType Type = GroupingType::disjoint, typename T>
int16_t find_standalone_max_group_index(T& impl, int4 ltrb)
{
return std::get<0>(
find_standalone_max_group_index_and_overlappability<Type>(impl, ltrb));
}
template <GroupingType Type, typename T>
uint16_t find_standalone_overlappability(T& impl, int4 ltrb)
{
return std::get<1>(
find_standalone_max_group_index_and_overlappability<Type>(impl, ltrb));
}
void add_tile_rectangle(IntersectionBoardReferenceImpl& ref,
int4 ltrb,
int16_t groupIndex)
{
ref.addRectangle(ltrb, groupIndex);
}
void add_tile_rectangle(IntersectionTile& tile, int4 ltrb, int16_t groupIndex)
{
tile.testingOnly_addRectangleAndValidate<GroupingType::disjoint>(ltrb,
groupIndex,
0);
}
template <typename T>
void check_simple_intersections(T& impl, int top, int left)
{
impl.reset(top, left, 0);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 0);
add_tile_rectangle(impl, int4{-1, -1, 10, 10}, 1);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 1);
impl.reset(top, left, 3);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 3);
add_tile_rectangle(impl, int4{-1, -1, 10, 10}, 4);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 4);
add_tile_rectangle(impl, int4{10, 10, 100, 100}, 5);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 4);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 11, 10}) == 4);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 11}) == 4);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 11, 10}) == 4);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 11, 11}) == 5);
add_tile_rectangle(impl, int4{9, 10, 100, 100}, 6);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 4);
add_tile_rectangle(impl, int4{10, 9, 100, 100}, 7);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 4);
add_tile_rectangle(impl, int4{9, 9, 100, 100}, 8);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 8);
}
template <typename T> void check_maximal_rectangles(T& impl)
{
impl.reset(0, 0, 0);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 0);
add_tile_rectangle(impl, int4{-1, -1, 10, 10}, 3);
CHECK(find_standalone_max_group_index(impl, int4{-1, -1, 10, 10}) == 3);
CHECK(find_standalone_max_group_index(impl,
int4{0,
0,
IntersectionTile::TILE_DIM,
IntersectionTile::TILE_DIM}) ==
3);
add_tile_rectangle(
impl,
int4{0, 0, IntersectionTile::TILE_DIM, IntersectionTile::TILE_DIM},
7);
CHECK(find_standalone_max_group_index(impl, int4{1, 1, 2, 2}) == 7);
CHECK(find_standalone_max_group_index(impl,
int4{0,
0,
IntersectionTile::TILE_DIM,
IntersectionTile::TILE_DIM}) ==
7);
CHECK(find_standalone_max_group_index(impl, int4{-999, -999, 999, 999}) ==
7);
add_tile_rectangle(impl, int4{-999, -999, 999, 999}, 6000);
CHECK(find_standalone_max_group_index(impl, int4{1, 1, 2, 2}) == 6000);
CHECK(find_standalone_max_group_index(impl, int4{-999, -999, 999, 999}) ==
6000);
}
template <typename T> void check_maximal_group_ids(T& impl)
{
impl.reset(0, 0, 32767);
CHECK(find_standalone_max_group_index(impl, int4{59, 131, 205, 181}) ==
32767);
impl.reset(0, 0, 32764);
CHECK(find_standalone_max_group_index(impl, int4{59, 131, 205, 181}) ==
32764);
add_tile_rectangle(impl, int4{59, 131, 205, 181}, 32765);
CHECK(find_standalone_max_group_index(impl, int4{79, -90, 182, 324}) ==
32765);
add_tile_rectangle(impl, int4{79, -90, 182, 324}, 32766);
CHECK(find_standalone_max_group_index(impl, int4{145, 93, 166, 214}) ==
32766);
add_tile_rectangle(impl, int4{145, 93, 166, 214}, 32767);
CHECK(find_standalone_max_group_index(impl, int4{12, -133, 104, 1}) ==
32766);
CHECK(find_standalone_max_group_index(impl, int4{12, -133, 104, 328}) ==
32766);
CHECK(find_standalone_max_group_index(impl, int4{12, -133, 150, 328}) ==
32767);
}
static int rand_range(int min, int max)
{
int mag = max - min + 1;
return (rand() % mag) + min;
}
void check_multiple_rectangles(IntersectionBoardReferenceImpl& ref,
IntersectionTile& fast,
int maxSize,
size_t n)
{
int tileLeft = rand() % 6000 - 3000;
int tileTop = rand() % 6000 - 3000;
uint16_t baseline = rand() % 10;
ref.reset(tileLeft, tileTop, baseline);
fast.reset(tileLeft, tileTop, baseline);
for (size_t i = 0; i < n; ++i)
{
int width = (rand() % maxSize) + 1;
int height = (rand() % maxSize) + 1;
int l =
tileLeft + rand_range(-width + 1, IntersectionTile::TILE_DIM - 1);
int t =
tileTop + rand_range(-height + 1, IntersectionTile::TILE_DIM - 1);
int4 ltrb = {l, t, l + width, t + height};
uint16_t idx = find_standalone_max_group_index(ref, ltrb);
uint16_t fastIdx = find_standalone_max_group_index(fast, ltrb);
CHECK(fastIdx == idx);
ref.addRectangle(ltrb, idx + 1);
fast.testingOnly_addRectangleAndValidate<GroupingType::disjoint>(
ltrb,
fastIdx + 1,
0);
}
}
TEST_CASE("IntersectionTile", "[IntersectionBoard]")
{
IntersectionBoardReferenceImpl ref;
IntersectionTile fast;
check_simple_intersections(ref, 0, 0);
check_simple_intersections(fast, 0, 0);
check_simple_intersections(ref, -100, -65);
check_simple_intersections(fast, -100, -65);
check_simple_intersections(ref, 8, 7);
check_simple_intersections(fast, 8, 7);
check_maximal_rectangles(ref);
check_maximal_rectangles(fast);
check_maximal_group_ids(ref);
check_maximal_group_ids(fast);
srand(0);
check_multiple_rectangles(ref, fast, 32, 1000);
check_multiple_rectangles(ref, fast, 1, 1000);
check_multiple_rectangles(ref, fast, 65, 1000);
check_multiple_rectangles(ref, fast, 200, 1000);
check_multiple_rectangles(ref, fast, 255, 1000);
check_multiple_rectangles(ref,
fast,
500,
1000); // Exercise maximal rectangles.
check_multiple_rectangles(ref,
fast,
1000,
1000); // Exercise maximal rectangles.
}
template <typename T> void check_intersection_board_corner_cases(T& impl)
{
impl.resizeAndReset(1000, 1000);
CHECK(impl.addRectangle(int4{1, 1, 800, 600}) == 1);
CHECK(impl.addRectangle(int4{799, 599, 999, 999}) == 2);
const int32_t kMax32i = std::numeric_limits<int32_t>::max();
const int32_t kMin32i = std::numeric_limits<int32_t>::min();
CHECK(impl.addRectangle(int4{kMin32i, kMin32i, kMax32i, kMax32i}) == 3);
// Check tile boundaries.
impl.resizeAndReset(800, 600);
CHECK(impl.addRectangle(int4{254, 254, 256, 256}) == 1);
CHECK(impl.addRectangle(int4{254, 254, 255, 255}) == 2);
CHECK(impl.addRectangle(int4{255, 0, 510, 255}) == 2);
CHECK(impl.addRectangle(int4{255, 255, 256, 510}) == 2);
CHECK(impl.addRectangle(int4{0, 255, 255, 256}) == 2);
CHECK(impl.addRectangle(int4{0, 0, 800, 600}) == 3);
// Check tiles that stretch offscreen.
impl.resizeAndReset(1600, 1200);
CHECK(impl.addRectangle(int4{-10000, 500, 10000, 501}) == 1);
CHECK(impl.addRectangle(int4{8, -10000, 9, 10000}) == 2);
CHECK(impl.addRectangle(int4{-10000, 0, 10000, 1}) == 3);
CHECK(impl.addRectangle(
int4{-999999999, -999999999, 999999999, 999999999}) == 4);
CHECK(impl.addRectangle(int4{1, 2, 3, 4}) == 5);
}
void check_intersection_board_random_rectangles(int maxSize, size_t n)
{
IntersectionBoardReferenceImpl ref;
IntersectionBoard fast{GroupingType::disjoint};
ref.resizeAndReset(3840, 2160);
fast.resizeAndReset(3840, 2160);
for (size_t i = 0; i < n; ++i)
{
int width = (rand() % maxSize) + 1;
int height = (rand() % maxSize) + 1;
int l = rand_range(-width + 1, 3840 - 1);
int t = rand_range(-height + 1, 2160 - 1);
int4 ltrb = {l, t, l + width, t + height};
int16_t layerCount = rand() % 5 + 1;
int16_t refIdx = ref.addRectangle(ltrb);
for (int16_t j = 1; j < layerCount; ++j)
{
ref.addRectangle(ltrb);
}
CHECK(refIdx == fast.addRectangle(ltrb, layerCount));
}
}
void check_intersection_board_random_rectangles2(size_t n)
{
IntersectionBoardReferenceImpl ref;
IntersectionBoard fast{GroupingType::disjoint};
ref.resizeAndReset(3840, 2160);
fast.resizeAndReset(3840, 2160);
for (size_t i = 0; i < n; ++i)
{
int4 box =
int4{rand(), rand(), rand(), rand()} % int4{3840, 2160, 3840, 2160};
int4 ltrb;
ltrb.xy = simd::min(box.xy, box.zw);
ltrb.zw = simd::max(box.xy, box.zw);
ltrb.zw += 1;
CHECK(ref.addRectangle(ltrb) == fast.addRectangle(ltrb));
}
}
TEST_CASE("IntersectionBoard", "[IntersectionBoard]")
{
IntersectionBoardReferenceImpl ref;
IntersectionBoard fast{GroupingType::disjoint};
check_intersection_board_corner_cases(ref);
check_intersection_board_corner_cases(fast);
// Offscreen and empty rectangles get discarded
fast.resizeAndReset(1000, 1000);
CHECK(fast.addRectangle(int4{0, 0, 0, 1}) == 0);
CHECK(fast.addRectangle(int4{0, 0, 1, 0}) == 0);
CHECK(fast.addRectangle(int4{1000, 999, 1001, 1001}) == 0);
CHECK(fast.addRectangle(int4{999, 1000, 1001, 1001}) == 0);
CHECK(fast.addRectangle(int4{8, 8, 8, 9}) == 0);
CHECK(fast.addRectangle(int4{8, 8, 9, 8}) == 0);
srand(0);
check_intersection_board_random_rectangles(100, 1000);
check_intersection_board_random_rectangles(500, 1000);
check_intersection_board_random_rectangles(1000, 1000);
check_intersection_board_random_rectangles(10000, 1000);
check_intersection_board_random_rectangles2(1000);
}
// Check inserting rectangles that have more than one layer.
TEST_CASE("layerCount", "[IntersectionBoard]")
{
IntersectionBoard board{GroupingType::disjoint};
board.resizeAndReset(800, 600);
CHECK(board.addRectangle(int4{254, 254, 256, 256}, 7) == 1);
// Since the previous rect had 7 layers, the next group index is 8.
CHECK(board.addRectangle(int4{254, 254, 255, 255}, 1) == 8);
CHECK(board.addRectangle(int4{255, 0, 510, 255}, 2) == 8);
CHECK(board.addRectangle(int4{255, 255, 256, 510}, 3) == 8);
CHECK(board.addRectangle(int4{0, 255, 255, 256}, 4) == 8);
CHECK(board.addRectangle(int4{0, 254, 800, 255}) == 10);
CHECK(board.addRectangle(int4{0, 255, 800, 256}) == 12);
CHECK(board.addRectangle(int4{0, 0, 800, 600}) == 13);
}
TEST_CASE("BasicTileOverlap", "[IntersectionBoard]")
{
IntersectionTile tile;
tile.reset(0, 0, 0);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{0, 0, 20, 20},
1,
0x0001);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{40, 40, 60, 60},
1,
0x0002);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{60, 60, 80, 80},
1,
0x0004);
// Add a bunch of rectangles to push the higher group element into the next
// chunk
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{80, 80, 100, 100},
1,
0x7fff);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{80, 80, 100, 100},
1,
0x7fff);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{80, 80, 100, 100},
1,
0x7fff);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{80, 80, 100, 100},
1,
0x7fff);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{80, 80, 100, 100},
1,
0x7fff);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{80, 80, 100, 100},
1,
0x7fff);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{80, 80, 100, 100},
2,
0x0008);
// Ensure that we get no overlappability bits if we didn't overlap any
// rectangles
auto [index, overlap] = find_standalone_max_group_index_and_overlappability<
GroupingType::overlapAllowed>(tile, int4{100, 100, 120, 120});
CHECK(index == 0);
CHECK(overlap == 0x0000);
std::tie(index, overlap) =
find_standalone_max_group_index_and_overlappability<
GroupingType::overlapAllowed>(tile, int4{0, 0, 40, 40});
CHECK(index == 1);
CHECK(overlap == 0x0001);
std::tie(index, overlap) =
find_standalone_max_group_index_and_overlappability<
GroupingType::overlapAllowed>(tile, int4{0, 0, 41, 41});
CHECK(index == 1);
CHECK(overlap == 0x0003);
std::tie(index, overlap) =
find_standalone_max_group_index_and_overlappability<
GroupingType::overlapAllowed>(tile, int4{0, 0, 61, 61});
CHECK(index == 1);
CHECK(overlap == 0x0007);
std::tie(index, overlap) =
find_standalone_max_group_index_and_overlappability<
GroupingType::overlapAllowed>(tile, int4{0, 0, 81, 81});
CHECK(index == 2);
CHECK(overlap == 0x0008);
}
void check_intersection_board_random_rectangles_overlappability(int maxSize,
size_t n)
{
IntersectionBoardReferenceImpl ref;
IntersectionBoard fast{GroupingType::overlapAllowed};
ref.resizeAndReset(3840, 2160);
fast.resizeAndReset(3840, 2160);
for (size_t i = 0; i < n; ++i)
{
int width = (rand() % maxSize) + 1;
int height = (rand() % maxSize) + 1;
int l = rand_range(-width + 1, 3840 - 1);
int t = rand_range(-height + 1, 2160 - 1);
int4 ltrb = {l, t, l + width, t + height};
auto destOverlap =
uint16_t((1 << (rand() % 16)) | (1 << (rand() % 16)));
auto overlappabilityMask =
uint16_t((1 << (rand() % 16)) | (1 << (rand() % 16)));
int16_t refIdx = ref.addRectangle(ltrb,
GroupingType::overlapAllowed,
destOverlap,
overlappabilityMask);
int16_t testIdx =
fast.addRectangle(ltrb, destOverlap, overlappabilityMask, 1);
CHECK(refIdx == testIdx);
}
}
TEST_CASE("Basic IntersectionBoard overlappability", "[IntersectionBoard]")
{
IntersectionBoard board{GroupingType::overlapAllowed};
board.resizeAndReset(100, 100);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 1, 0, 1) == 1);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 2, 0, 1) == 1);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 4, 0, 1) == 1);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 8, 0, 1) == 1);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 16, 1, 1) == 2);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 8, 1, 1) == 2);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 4, 1, 1) == 2);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 2, 1, 1) == 2);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 1, 1, 1) == 2);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 8, 1, 1) == 3);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 8, 1, 1) == 3);
CHECK(board.addRectangle(int4{0, 0, 100, 100}, 8, 9, 1) == 4);
}
TEST_CASE("IntersectionBoard overlap baseline", "[IntersectionBoard]")
{
// Full-sized tile, greater max group (no rectangles remaining)
IntersectionTile tile;
tile.reset(0, 0, 0, 0);
constexpr auto TILE_DIM = IntersectionTile::TILE_DIM;
auto fullTile = int4{0, 0, TILE_DIM, TILE_DIM};
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
fullTile,
1,
0x1001);
CHECK(tile.testingOnly_rectangleCount() == 0);
CHECK(tile.testingOnly_baselineGroupIndex() == 1);
CHECK(tile.testingOnly_maxGroupIndex() == 1);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x1001);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0x1001);
CHECK(find_standalone_max_group_index<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 1);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 0x1001);
// Adding a new rectangle to the baseline group that has only bits in the
// baseline group should do nothing.
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{0, 0, 20, 20},
1,
0x0000);
CHECK(tile.testingOnly_rectangleCount() == 0);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{0, 0, 20, 20},
1,
0x0001);
CHECK(tile.testingOnly_rectangleCount() == 0);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{0, 0, 20, 20},
1,
0x1000);
CHECK(tile.testingOnly_rectangleCount() == 0);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{0, 0, 20, 20},
1,
0x1001);
CHECK(tile.testingOnly_rectangleCount() == 0);
CHECK(find_standalone_max_group_index<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 1);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 0x1001);
CHECK(tile.testingOnly_baselineGroupIndex() == 1);
CHECK(tile.testingOnly_maxGroupIndex() == 1);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x1001);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0x1001);
// New rectangles in the baseline should be added correctly, though.
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{0, 0, 20, 20},
1,
0x0010);
CHECK(tile.testingOnly_rectangleCount() == 1);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{20, 20, 40, 40},
1,
0x1040);
CHECK(tile.testingOnly_rectangleCount() == 2);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{40, 40, 60, 60},
1,
0x0021);
CHECK(tile.testingOnly_rectangleCount() == 3);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{60, 60, 80, 80},
1,
0x2181);
CHECK(tile.testingOnly_rectangleCount() == 4);
CHECK(tile.testingOnly_baselineGroupIndex() == 1);
CHECK(tile.testingOnly_maxGroupIndex() == 1);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x1001);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0x31F1);
// Test that detection in various spots gives the correct overlappability
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 0x1051);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{50, 50, 70, 70}) == 0x31A1);
// Adding a new baseline rectangle that touches *none* of the existing bits
// should leave all of the existing rectangles in that group.
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
fullTile,
1,
0x8002);
CHECK(tile.testingOnly_rectangleCount() == 4);
CHECK(tile.testingOnly_baselineGroupIndex() == 1);
CHECK(tile.testingOnly_maxGroupIndex() == 1);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x9003);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0xB1F3);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 0x9053);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{50, 50, 70, 70}) == 0xB1A3);
// Simiarly, test adding a new rectangle the doesn't change the baseline in
// any way.
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
fullTile,
1,
0x9003);
CHECK(tile.testingOnly_rectangleCount() == 4);
CHECK(tile.testingOnly_baselineGroupIndex() == 1);
CHECK(tile.testingOnly_maxGroupIndex() == 1);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x9003);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0xB1F3);
// Adding a new baseline rectangle that touches *some* of the existing bits
// should remove those rectangles, even if it doesn't add all the new bits
// directly
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
fullTile,
1,
0x0030);
// two rectangles (first and third) are now "under" these bits and should
// have been removed
CHECK(tile.testingOnly_rectangleCount() == 2);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x9033);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0xB1F3);
// Adding a new baseline rectangle that causes the baseline to cover every
// bit of them should result in 0 rectangles.
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
fullTile,
1,
0x21C0);
CHECK(tile.testingOnly_rectangleCount() == 0);
CHECK(tile.testingOnly_baselineGroupIndex() == 1);
CHECK(tile.testingOnly_maxGroupIndex() == 1);
CHECK(tile.testingOnly_baselineOverlapBits() == 0xB1F3);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0xB1F3);
// A new full-tile rectangle in the next group up should replace the
// baseline and max group overlappability bits.
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
fullTile,
2,
0x000C);
CHECK(tile.testingOnly_rectangleCount() == 0);
CHECK(tile.testingOnly_baselineGroupIndex() == 2);
CHECK(tile.testingOnly_maxGroupIndex() == 2);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x000C);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0x000C);
tile.testingOnly_addRectangleAndValidate<GroupingType::overlapAllowed>(
int4{70, 70, 90, 90},
4,
0x000F);
CHECK(tile.testingOnly_baselineGroupIndex() == 2);
CHECK(tile.testingOnly_maxGroupIndex() == 4);
CHECK(tile.testingOnly_baselineOverlapBits() == 0x000C);
CHECK(tile.testingOnly_overlapBitsForMaxGroup() == 0x000F);
CHECK(find_standalone_max_group_index<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 2);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{10, 10, 30, 30}) == 0x000C);
CHECK(find_standalone_max_group_index<GroupingType::overlapAllowed>(
tile,
int4{50, 50, 70, 70}) == 2);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{50, 50, 70, 70}) == 0x000C);
CHECK(find_standalone_max_group_index<GroupingType::overlapAllowed>(
tile,
int4{60, 60, 80, 80}) == 4);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{60, 60, 80, 80}) == 0x000F);
CHECK(find_standalone_max_group_index<GroupingType::overlapAllowed>(
tile,
int4{80, 80, 100, 100}) == 4);
CHECK(find_standalone_overlappability<GroupingType::overlapAllowed>(
tile,
int4{80, 80, 100, 100}) == 0x000F);
}
TEST_CASE("IntersectionBoard overlappability", "[IntersectionBoard]")
{
IntersectionBoardReferenceImpl ref;
IntersectionBoard fast{GroupingType::overlapAllowed};
srand(0);
check_intersection_board_random_rectangles_overlappability(100, 1000);
check_intersection_board_random_rectangles_overlappability(500, 1000);
check_intersection_board_random_rectangles_overlappability(1000, 1000);
check_intersection_board_random_rectangles_overlappability(10000, 1000);
}
} // namespace rive::gpu