Files

108 lines
3.4 KiB
C++
Raw Permalink Normal View History

#include "../lib/gfx/render_worker.hpp"
#include <atomic>
#include <chrono>
#include <future>
#include <thread>
#include <vector>
#include <gtest/gtest.h>
namespace {
using namespace std::chrono_literals;
using aurora::gfx::render_worker::BoundedQueue;
using aurora::gfx::render_worker::FrameSlotPool;
using aurora::gfx::render_worker::ItemType;
using aurora::gfx::render_worker::QueueItem;
class RenderWorkerTest : public testing::Test {
protected:
void TearDown() override { aurora::gfx::render_worker::shutdown(); }
};
TEST(RenderWorkerQueue, PreservesOrdering) {
BoundedQueue queue{4};
ASSERT_TRUE(queue.push(QueueItem{.type = ItemType::BeginFrame, .frameId = 1}));
ASSERT_TRUE(queue.push(QueueItem{.type = ItemType::EncodePass, .frameId = 1, .passIndex = 7}));
ASSERT_TRUE(queue.push(QueueItem{.type = ItemType::EndFrame, .frameId = 1}));
bool closed = false;
auto first = queue.pop_for(0ms, closed);
auto second = queue.pop_for(0ms, closed);
auto third = queue.pop_for(0ms, closed);
ASSERT_TRUE(first.has_value());
ASSERT_TRUE(second.has_value());
ASSERT_TRUE(third.has_value());
EXPECT_EQ(first->type, ItemType::BeginFrame);
EXPECT_EQ(second->type, ItemType::EncodePass);
EXPECT_EQ(second->passIndex, 7u);
EXPECT_EQ(third->type, ItemType::EndFrame);
EXPECT_FALSE(closed);
}
TEST(RenderWorkerQueue, PushBlocksWhenFull) {
BoundedQueue queue{1};
ASSERT_TRUE(queue.push(QueueItem{.type = ItemType::BeginFrame}));
std::atomic_bool pushed = false;
auto future = std::async(std::launch::async, [&] {
const bool result = queue.push(QueueItem{.type = ItemType::EncodePass});
pushed.store(result, std::memory_order_release);
});
std::this_thread::sleep_for(20ms);
EXPECT_FALSE(pushed.load(std::memory_order_acquire));
bool closed = false;
ASSERT_TRUE(queue.pop_for(0ms, closed).has_value());
future.wait();
EXPECT_TRUE(pushed.load(std::memory_order_acquire));
}
TEST_F(RenderWorkerTest, SyncWaitsForPriorWork) {
std::vector<int> order;
aurora::gfx::render_worker::initialize();
aurora::gfx::render_worker::enqueue_begin_frame(1, [&] { order.push_back(1); });
aurora::gfx::render_worker::enqueue_encode_pass(1, 0, [&] { order.push_back(2); });
aurora::gfx::render_worker::synchronize();
ASSERT_EQ(order.size(), 2u);
EXPECT_EQ(order[0], 1);
EXPECT_EQ(order[1], 2);
EXPECT_TRUE(aurora::gfx::render_worker::is_idle());
}
TEST_F(RenderWorkerTest, ShutdownCompletesQueuedWork) {
std::atomic_int count = 0;
aurora::gfx::render_worker::initialize();
aurora::gfx::render_worker::enqueue_begin_frame(1, [&] { count.fetch_add(1, std::memory_order_acq_rel); });
aurora::gfx::render_worker::shutdown();
EXPECT_EQ(count.load(std::memory_order_acquire), 1);
EXPECT_TRUE(aurora::gfx::render_worker::is_idle());
}
TEST(RenderWorkerFrameSlots, RecyclesReleasedSlots) {
FrameSlotPool slots{2};
const size_t first = slots.acquire();
const size_t second = slots.acquire();
EXPECT_NE(first, second);
EXPECT_EQ(slots.free_count(), 0u);
std::atomic_bool acquired = false;
auto future = std::async(std::launch::async, [&] {
const size_t recycled = slots.acquire();
EXPECT_EQ(recycled, first);
acquired.store(true, std::memory_order_release);
});
std::this_thread::sleep_for(20ms);
EXPECT_FALSE(acquired.load(std::memory_order_acquire));
slots.release(first);
future.wait();
slots.release(second);
EXPECT_EQ(slots.free_count(), 1u);
}
} // namespace