94 lines
4.8 KiB
C++
94 lines
4.8 KiB
C++
#include <gtest/gtest.h>
|
|
#include <atomic>
|
|
#include <cstdint>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <vector>
|
|
#include "renderive/scene/Scene.hpp"
|
|
#include "../state/State_Test_Types.hpp"
|
|
struct Scene_State_Observer_Test_State : Scene2D_State {
|
|
int value{};
|
|
};
|
|
struct Scene_State_Observer_Test_Time_Source {
|
|
std::uint64_t now_ns() const noexcept {
|
|
return 100;
|
|
}
|
|
};
|
|
struct Scene_State_Observer_Test_Data {
|
|
std::vector<Scene_Base::Observation_Event> events;
|
|
std::atomic<int> complete_snapshot_count{};
|
|
};
|
|
struct Scene_State_Observer_Test_Recorder {
|
|
static constexpr bool enabled = true;
|
|
std::shared_ptr<Scene_State_Observer_Test_Data> data{std::make_shared<Scene_State_Observer_Test_Data>()};
|
|
void observe(const Scene_Base::Observation& observation) noexcept {
|
|
data->events.push_back(observation.event);
|
|
if (observation.topology && observation.frame_snapshot &&
|
|
observation.render_plan)
|
|
data->complete_snapshot_count.fetch_add(1,
|
|
std::memory_order_relaxed);
|
|
}
|
|
};
|
|
using Scene_State_Observer_Test_Scene_Observer = Observer_State<Scene_State_Observer_Test_Recorder, Scene_State_Observer_Test_Time_Source>;
|
|
using Scene_State_Observer_Test_State_Observer = Observer_State<>;
|
|
TEST(scene_state_observer_test, scene_uses_double_state_and_observes_lifecycle) {
|
|
State_Render_State_Reader render;
|
|
Scene_State_Observer_Test_Recorder recorder;
|
|
using Scene = Scene2D_Context<Low_Latency_Strategy<Scene2D_Frame_Data>, Recording_Color_Cache, Scene_State_Observer_Test_State, Scene_State_Observer_Test_State_Observer, Scene_State_Observer_Test_Scene_Observer>;
|
|
Scene scene(With_Observer(Scene_State_Observer_Test_State_Observer{}), With_Observer(Scene_State_Observer_Test_Scene_Observer(recorder, Scene_State_Observer_Test_Time_Source{})));
|
|
scene.Scene_State_Strategy::set<&Scene_State_Observer_Test_State::value>(9);
|
|
scene.Scene_State_Strategy::publish();
|
|
scene.render();
|
|
scene.wait_for_render();
|
|
EXPECT_EQ(render.read(static_cast<const Scene::Scene_State_Strategy&>(scene)).value, 9);
|
|
EXPECT_EQ(recorder.data->events, (std::vector<Scene_Base::Observation_Event>{Scene_Base::Observation_Event::render_submitted, Scene_Base::Observation_Event::render_started, Scene_Base::Observation_Event::render_completed}));
|
|
EXPECT_EQ(recorder.data->complete_snapshot_count.load(), 3);
|
|
}
|
|
struct Scene_Reentrant_Observer_Data {
|
|
std::function<void(Scene_Base::Observation_Event)> callback;
|
|
};
|
|
struct Scene_Reentrant_Observer {
|
|
static constexpr bool enabled = true;
|
|
std::shared_ptr<Scene_Reentrant_Observer_Data> data{std::make_shared<Scene_Reentrant_Observer_Data>()};
|
|
void observe(const Scene_Base::Observation& observation) noexcept {
|
|
if (data->callback) {
|
|
data->callback(observation.event);
|
|
}
|
|
}
|
|
};
|
|
using Scene_Reentrant_Observer_State = Observer_State<Scene_Reentrant_Observer, Scene_State_Observer_Test_Time_Source>;
|
|
TEST(scene_state_observer_test, render_worker_observer_can_wait_for_current_render_without_deadlock) {
|
|
Scene_Reentrant_Observer recorder;
|
|
auto data = recorder.data;
|
|
using Scene = Scene2D_Context<Low_Latency_Strategy<Scene2D_Frame_Data>, Recording_Color_Cache, Scene_State_Observer_Test_State, Scene_State_Observer_Test_State_Observer, Scene_Reentrant_Observer_State>;
|
|
Scene scene(With_Observer(Scene_State_Observer_Test_State_Observer{}), With_Observer(Scene_Reentrant_Observer_State(recorder, Scene_State_Observer_Test_Time_Source{})));
|
|
std::atomic<bool> reentered{};
|
|
data->callback = [&](Scene_Base::Observation_Event event) {
|
|
if (event == Scene_Base::Observation_Event::render_started) {
|
|
scene.wait_for_render();
|
|
reentered.store(true, std::memory_order_release);
|
|
}
|
|
};
|
|
scene.render();
|
|
scene.wait_for_render();
|
|
EXPECT_TRUE(reentered.load(std::memory_order_acquire));
|
|
}
|
|
TEST(scene_state_observer_test, render_submitted_observer_can_submit_next_render_without_deadlock) {
|
|
Scene_Reentrant_Observer recorder;
|
|
auto data = recorder.data;
|
|
using Scene = Scene2D_Context<Low_Latency_Strategy<Scene2D_Frame_Data>, Recording_Color_Cache, Scene_State_Observer_Test_State, Scene_State_Observer_Test_State_Observer, Scene_Reentrant_Observer_State>;
|
|
Scene scene(With_Observer(Scene_State_Observer_Test_State_Observer{}), With_Observer(Scene_Reentrant_Observer_State(recorder, Scene_State_Observer_Test_Time_Source{})));
|
|
std::atomic<int> submitted{};
|
|
data->callback = [&](Scene_Base::Observation_Event event) {
|
|
if (event != Scene_Base::Observation_Event::render_submitted) {
|
|
return;
|
|
}
|
|
if (submitted.fetch_add(1, std::memory_order_acq_rel) == 0) {
|
|
scene.render();
|
|
}
|
|
};
|
|
scene.render();
|
|
scene.wait_for_render();
|
|
EXPECT_EQ(submitted.load(std::memory_order_acquire), 2);
|
|
}
|