#include "Explicit_Renderable_Runtime.h" #include "../../architecture/Renderable.h" #include "../../base/Memory.h" #include #include #include namespace renderive { namespace { struct Explicit_Input_Slot { Input_Data* data{}; std::uint64_t version = 0; bool pending = false; std::shared_ptr 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> committed_update_states{memory_resource(Memory_Domain::Update_Completion)}; void initialize(Renderable& renderable) { clear(); state_owner = renderable.create_render_state(); state = state_owner.get(); if (state) state->version = 1; input_owner = renderable.create_input_data(); input.data = input_owner.get(); input.version = 0; input.pending = false; input.completion_state.reset(); } void cancel_pending_completions() { std::lock_guard 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 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 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 lock) : lock(std::move(lock)) {} std::unique_lock lock; }; struct Explicit_Input_Frame_Handle final : Render_Input_Frame_Handle { Explicit_Input_Frame_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock 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 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 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 lock; }; struct Explicit_Input_Write_Handle final : Render_Input_Write_Handle { Explicit_Input_Write_Handle(Explicit_Renderable_Runtime_Data* runtime, std::unique_lock 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 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 lock; bool notify_render{}; }; } // namespace Explicit_Renderable_Runtime::Explicit_Renderable_Runtime(Renderable& owner) : d(std::make_unique()) { 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>& 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 lock(d->state_mutex); if (!d->state) return {}; return Render_State_Read_Guard(d->state, std::make_unique(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 lock(d->state_mutex); if (!d->state) return {}; return Render_State_Write_Guard(d->state, std::make_unique(d.get(), std::move(lock))); } Render_Input_Write_Guard Explicit_Renderable_Runtime::acquire_edit_input(bool notify_render) { std::unique_lock lock(d->input_mutex); if (!d->input.data) return {}; return Render_Input_Write_Guard(d->input.data, std::make_unique(d.get(), std::move(lock), notify_render)); } Render_Input_Frame_Guard Explicit_Renderable_Runtime::acquire_input_read(Renderable_Input_Role) { std::unique_lock 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(d.get(), std::move(lock))); } Renderable_Frame_View Explicit_Renderable_Runtime::capture_frame_view() { std::unique_lock state_lock(d->state_mutex); if (!d->state) return {}; auto state_guard = Render_State_Read_Guard( d->state, std::make_unique(std::move(state_lock))); Render_Input_Frame_Guard input_guard; std::unique_lock input_lock(d->input_mutex); if (d->input.data) { input_guard = Render_Input_Frame_Guard( d->input.data, std::make_unique(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 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 make_explicit_renderable_runtime(Renderable& owner) { return std::make_unique(owner); } } // namespace renderive