Files
Renderive/Core/flow/explicit/Explicit_Renderable_Runtime.cpp
T
2026-08-04 16:24:41 +08:00

244 lines
8.6 KiB
C++

#include "Explicit_Renderable_Runtime.h"
#include "../../architecture/Renderable.h"
#include "../../base/Memory.h"
#include <mutex>
#include <system_error>
#include <utility>
namespace renderive {
namespace {
struct Explicit_Input_Slot {
Input_Data* data{};
std::uint64_t version = 0;
bool pending = false;
std::shared_ptr<Update_State> completion_state;
};
} // namespace
struct Explicit_Renderable_Runtime_Data {
Renderable* owner{};
mutable std::mutex state_mutex;
mutable std::mutex input_mutex;
Render_Object_Owner state_owner;
Render_State* state{};
Render_Object_Owner input_owner;
Explicit_Input_Slot input;
std::uint64_t input_version = 0;
std::pmr::vector<std::shared_ptr<Update_State>> committed_update_states{memory_resource(Memory_Domain::Update_Completion)};
void initialize(Renderable& renderable) {
clear();
state_owner = renderable.create_render_state();
state = state_owner.get<Render_State>();
if (state)
state->version = 1;
input_owner = renderable.create_input_data();
input.data = input_owner.get<Input_Data>();
input.version = 0;
input.pending = false;
input.completion_state.reset();
}
void cancel_pending_completions() {
std::lock_guard<std::mutex> lock(input_mutex);
if (input.completion_state) {
input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
input.completion_state.reset();
}
cancel_update_states(committed_update_states);
}
void clear() {
{
std::lock_guard<std::mutex> input_lock(input_mutex);
if (input.completion_state) {
input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
input.completion_state.reset();
}
input.data = nullptr;
input.version = 0;
input.pending = false;
input_owner.reset();
input_version = 0;
}
{
std::lock_guard<std::mutex> state_lock(state_mutex);
state = nullptr;
state_owner.reset();
}
}
};
namespace {
struct Explicit_State_Read_Handle final : Render_State_Read_Handle {
explicit Explicit_State_Read_Handle(std::unique_lock<std::mutex> lock)
: lock(std::move(lock)) {}
std::unique_lock<std::mutex> lock;
};
struct Explicit_Input_Frame_Handle final : Render_Input_Frame_Handle {
Explicit_Input_Frame_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock<std::mutex> lock)
: runtime(runtime), lock(std::move(lock)) {}
void consume_input(Input_Data* input) override {
if (consumed || !runtime)
return;
consumed = true;
if (runtime->input.completion_state) {
runtime->input.completion_state->complete_until(Update_Stage::Committed);
runtime->committed_update_states.push_back(std::move(runtime->input.completion_state));
}
if (input)
input->consume();
runtime->input.pending = false;
}
Explicit_Renderable_Runtime_Data* runtime{};
std::unique_lock<std::mutex> lock;
bool consumed = false;
};
struct Explicit_State_Write_Handle final : Render_State_Write_Handle {
Explicit_State_Write_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock<std::mutex> lock)
: runtime(runtime), lock(std::move(lock)) {}
~Explicit_State_Write_Handle() override {
if (!runtime || !runtime->state)
return;
++runtime->state->version;
lock.unlock();
if (runtime->owner)
runtime->owner->mark_render_dirty(Dirty_Reason::Config);
}
Explicit_Renderable_Runtime_Data* runtime{};
std::unique_lock<std::mutex> lock;
};
struct Explicit_Input_Write_Handle final : Render_Input_Write_Handle {
Explicit_Input_Write_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock<std::mutex> lock, bool notify_render)
: runtime(runtime), lock(std::move(lock)), notify_render(notify_render) {}
~Explicit_Input_Write_Handle() override {
if (!runtime)
return;
runtime->input.version = ++runtime->input_version;
runtime->input.pending = true;
lock.unlock();
if (notify_render && runtime->owner)
runtime->owner->mark_render_dirty();
}
void set_completion(std::shared_ptr<Update_State> state) override {
if (!runtime)
return;
if (runtime->input.completion_state && runtime->input.completion_state != state)
runtime->input.completion_state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled);
runtime->input.completion_state = std::move(state);
}
Explicit_Renderable_Runtime_Data* runtime{};
std::unique_lock<std::mutex> lock;
bool notify_render{};
};
} // namespace
Explicit_Renderable_Runtime::Explicit_Renderable_Runtime(Renderable& owner)
: d(std::make_unique<Explicit_Renderable_Runtime_Data>()) {
d->owner = &owner;
d->initialize(owner);
}
Explicit_Renderable_Runtime::~Explicit_Renderable_Runtime() {
d->clear();
}
void Explicit_Renderable_Runtime::set_render_state_copier(Copy_Render_State_Function) {}
void Explicit_Renderable_Runtime::cancel_pending_completions() {
d->cancel_pending_completions();
}
void Explicit_Renderable_Runtime::drain_committed_update_states(std::pmr::vector<std::shared_ptr<Update_State>>& output) {
for (auto& state : d->committed_update_states)
output.push_back(std::move(state));
d->committed_update_states.clear();
}
Render_State_Read_Guard Explicit_Renderable_Runtime::acquire_state_read(Renderable_State_Role) {
return acquire_render_state_read();
}
Render_State_Read_Guard Explicit_Renderable_Runtime::acquire_render_state_read() {
std::unique_lock<std::mutex> lock(d->state_mutex);
if (!d->state)
return {};
return Render_State_Read_Guard(d->state, std::make_unique<Explicit_State_Read_Handle>(std::move(lock)));
}
Render_State_Read_Guard Explicit_Renderable_Runtime::acquire_edit_state_read() {
return acquire_render_state_read();
}
Render_State_Write_Guard Explicit_Renderable_Runtime::acquire_edit_state() {
std::unique_lock<std::mutex> lock(d->state_mutex);
if (!d->state)
return {};
return Render_State_Write_Guard(d->state, std::make_unique<Explicit_State_Write_Handle>(d.get(), std::move(lock)));
}
Render_Input_Write_Guard Explicit_Renderable_Runtime::acquire_edit_input(bool notify_render) {
std::unique_lock<std::mutex> lock(d->input_mutex);
if (!d->input.data)
return {};
return Render_Input_Write_Guard(d->input.data, std::make_unique<Explicit_Input_Write_Handle>(d.get(), std::move(lock), notify_render));
}
Render_Input_Frame_Guard Explicit_Renderable_Runtime::acquire_input_read(Renderable_Input_Role) {
std::unique_lock<std::mutex> lock(d->input_mutex, std::try_to_lock);
if (!lock || !d->input.data)
return {};
return Render_Input_Frame_Guard(d->input.data, std::make_unique<Explicit_Input_Frame_Handle>(d.get(), std::move(lock)));
}
Renderable_Frame_View Explicit_Renderable_Runtime::capture_frame_view() {
std::unique_lock<std::mutex> state_lock(d->state_mutex);
if (!d->state)
return {};
auto state_guard = Render_State_Read_Guard(
d->state,
std::make_unique<Explicit_State_Read_Handle>(std::move(state_lock)));
Render_Input_Frame_Guard input_guard;
std::unique_lock<std::mutex> input_lock(d->input_mutex);
if (d->input.data) {
input_guard = Render_Input_Frame_Guard(
d->input.data,
std::make_unique<Explicit_Input_Frame_Handle>(d.get(), std::move(input_lock)));
}
return Renderable_Frame_View(std::move(state_guard), std::move(input_guard));
}
Render_State* Explicit_Renderable_Runtime::state(Renderable_State_Role) {
return d->state;
}
Input_Data* Explicit_Renderable_Runtime::input_data(Renderable_Input_Role) {
return d->input.data;
}
void Explicit_Renderable_Runtime::clear_render_input() {
std::lock_guard<std::mutex> lock(d->input_mutex);
if (d->input.completion_state) {
d->input.completion_state->complete_until(Update_Stage::Committed);
d->committed_update_states.push_back(std::move(d->input.completion_state));
}
if (d->input.data)
d->input.data->clear();
d->input.pending = false;
}
std::unique_ptr<Renderable_Runtime> make_explicit_renderable_runtime(Renderable& owner) {
return std::make_unique<Explicit_Renderable_Runtime>(owner);
}
} // namespace renderive