Files
Renderive/Kernel/tests/renderive/scene/Scene_State_Observer_Test.cpp
T
2026-08-15 00:23:52 +08:00

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);
}