OverviewFilesCommitsIssuesDocsReleasesPeers

blender-bridge / test / test_tile_requests.cpp

244 lines · cpp ref:
#include "../src/tile_request_queue.h"

#include <cassert>
#include <cstdio>
#include <cstring>

static int tests_passed = 0;

#define TEST(name)                             \
	do {                                       \
		printf("  %-40s", #name "...");        \
	} while (0)
#define PASS()                                 \
	do {                                       \
		printf("PASS\n");                      \
		tests_passed++;                        \
	} while (0)

void test_pack_unpack() {
	TEST(pack_unpack);
	uint32_t packed = pack_feedback(42, 100, 200, 7);
	int tex_id, tile_x, tile_y, mip;
	unpack_feedback(packed, tex_id, tile_x, tile_y, mip);
	assert(tex_id == 42);
	assert(tile_x == 100);
	assert(tile_y == 200);
	assert(mip == 7);

	// Edge cases
	packed = pack_feedback(4095, 255, 255, 15);
	unpack_feedback(packed, tex_id, tile_x, tile_y, mip);
	assert(tex_id == 4095);
	assert(tile_x == 255);
	assert(tile_y == 255);
	assert(mip == 15);

	// Zero = no request (all fields zero packs to 0)
	assert(pack_feedback(0, 0, 0, 0) == 0);
	PASS();
}

void test_add_from_feedback() {
	TEST(add_from_feedback);
	TileRequestQueue queue;

	uint32_t feedback[] = {
		pack_feedback(1, 10, 20, 0),
		pack_feedback(1, 10, 20, 0), // duplicate
		pack_feedback(1, 11, 20, 0), // different tile
		0, // skip empty
		pack_feedback(2, 5, 5, 1),
	};

	queue.add_from_feedback(feedback, 5);

	// Should have 3 unique requests (deduped the duplicate)
	assert(queue.pending_count() == 3);
	PASS();
}

void test_dedup_coverage() {
	TEST(dedup_coverage);
	TileRequestQueue queue;
	queue.set_coverage_threshold(3);

	// Same tile appears 5 times → high coverage
	uint32_t feedback[5];
	for (int i = 0; i < 5; i++) {
		feedback[i] = pack_feedback(1, 10, 20, 0);
	}
	queue.add_from_feedback(feedback, 5);

	auto batch = queue.get_next_batch(10);
	assert(batch.size() == 1);
	assert(batch[0].pixel_coverage == 5);
	assert(batch[0].priority == PRIORITY_HIGH_COVERAGE);
	PASS();
}

void test_invalidated_priority() {
	TEST(invalidated_priority);
	TileRequestQueue queue;

	// Add feedback requests
	uint32_t feedback[] = {
		pack_feedback(1, 10, 20, 0),
		pack_feedback(1, 10, 20, 0),
		pack_feedback(1, 10, 20, 0),
		pack_feedback(1, 10, 20, 0),
		pack_feedback(1, 10, 20, 0),
		pack_feedback(1, 11, 20, 0),
	};
	queue.add_from_feedback(feedback, 6);

	// Invalidate a different tile
	queue.add_invalidated(2, 0, 0, 0);

	auto batch = queue.get_next_batch(10);
	assert(batch.size() == 3);

	// Invalidated should be first
	assert(batch[0].priority == PRIORITY_INVALIDATED);
	assert(batch[0].tile.texture_id == 2);
	PASS();
}

void test_priority_sort_order() {
	TEST(priority_sort_order);
	TileRequestQueue queue;
	queue.set_coverage_threshold(3);

	// Tile A: 1 pixel (low coverage)
	uint32_t fb_a[] = { pack_feedback(1, 0, 0, 0) };
	queue.add_from_feedback(fb_a, 1);

	// Tile B: 10 pixels (high coverage)
	uint32_t fb_b[10];
	for (int i = 0; i < 10; i++)
		fb_b[i] = pack_feedback(1, 1, 0, 0);
	queue.add_from_feedback(fb_b, 10);

	// Tile C: invalidated
	queue.add_invalidated(1, 2, 0, 0);

	auto batch = queue.get_next_batch(10);
	assert(batch.size() == 3);

	// Order: invalidated (C) > high coverage (B) > low coverage (A)
	assert(batch[0].tile.tile_x == 2); // C - invalidated
	assert(batch[1].tile.tile_x == 1); // B - high coverage (10 pixels)
	assert(batch[2].tile.tile_x == 0); // A - low coverage (1 pixel)
	PASS();
}

void test_budget_throttle() {
	TEST(budget_throttle);
	TileRequestQueue queue;

	// Add 20 requests (tex_id=1 to avoid zero-packed being skipped)
	for (int i = 0; i < 20; i++) {
		uint32_t fb[] = { pack_feedback(1, i, 0, 0) };
		queue.add_from_feedback(fb, 1);
	}
	assert(queue.pending_count() == 20);

	// Budget of 5 — should only return 5
	auto batch = queue.get_next_batch(5);
	assert((int)batch.size() == 5);

	// Queue should be cleared after get_next_batch
	assert(queue.pending_count() == 0);
	PASS();
}

void test_invalidated_upgrades_existing() {
	TEST(invalidated_upgrades_existing);
	TileRequestQueue queue;

	// Add from feedback first
	uint32_t fb[] = { pack_feedback(1, 10, 20, 0) };
	queue.add_from_feedback(fb, 1);

	// Now invalidate the same tile — should upgrade priority
	queue.add_invalidated(1, 10, 20, 0);

	auto batch = queue.get_next_batch(10);
	assert(batch.size() == 1);
	assert(batch[0].priority == PRIORITY_INVALIDATED);
	assert(batch[0].pixel_coverage == 1); // coverage preserved
	PASS();
}

void test_empty_feedback() {
	TEST(empty_feedback);
	TileRequestQueue queue;

	// All zeros — nothing added
	uint32_t fb[10] = {};
	queue.add_from_feedback(fb, 10);
	assert(queue.pending_count() == 0);

	auto batch = queue.get_next_batch(10);
	assert(batch.empty());
	PASS();
}

void test_clear() {
	TEST(clear);
	TileRequestQueue queue;

	uint32_t fb[] = { pack_feedback(1, 0, 0, 0), pack_feedback(2, 0, 0, 0) };
	queue.add_from_feedback(fb, 2);
	assert(queue.pending_count() == 2);

	queue.clear();
	assert(queue.pending_count() == 0);
	PASS();
}

void test_high_coverage_sorts_within_priority() {
	TEST(high_coverage_within_priority);
	TileRequestQueue queue;
	queue.set_coverage_threshold(2);

	// Tile A: 5 pixels (tex_id=1 to avoid zero packing)
	for (int i = 0; i < 5; i++) {
		uint32_t fb[] = { pack_feedback(1, 0, 0, 0) };
		queue.add_from_feedback(fb, 1);
	}

	// Tile B: 10 pixels
	for (int i = 0; i < 10; i++) {
		uint32_t fb[] = { pack_feedback(1, 1, 0, 0) };
		queue.add_from_feedback(fb, 1);
	}

	auto batch = queue.get_next_batch(10);
	assert(batch.size() == 2);
	// Both are HIGH priority, but B has more coverage → B first
	assert(batch[0].tile.tile_x == 1);
	assert(batch[0].pixel_coverage == 10);
	assert(batch[1].tile.tile_x == 0);
	assert(batch[1].pixel_coverage == 5);
	PASS();
}

int main() {
	printf("=== Tile Request Queue Tests ===\n");

	test_pack_unpack();
	test_add_from_feedback();
	test_dedup_coverage();
	test_invalidated_priority();
	test_priority_sort_order();
	test_budget_throttle();
	test_invalidated_upgrades_existing();
	test_empty_feedback();
	test_clear();
	test_high_coverage_sorts_within_priority();

	printf("\nAll %d tests passed.\n", tests_passed);
	return 0;
}