#include "Explicit_Frame_Flow.h" #include "../../architecture/Render_Time.h" #include "../../architecture/Update_Completion.h" namespace renderive { namespace { struct Explicit_Render_Surface_Handle final : Render_Frame_Surface_Handle { explicit Explicit_Render_Surface_Handle(std::shared_ptr output) : output(std::move(output)) {} std::shared_ptr output; }; struct Explicit_Present_Surface_Handle final { explicit Explicit_Present_Surface_Handle(std::shared_ptr output) : output_value(std::move(output)) {} [[nodiscard]] Render_Output* output() const { return output_value.get(); } std::shared_ptr output_value; }; Explicit_Render_Surface_Handle* explicit_handle(Render_Frame_Surface& surface) { return static_cast(surface.handle.get()); } } // namespace Explicit_Frame_Flow::Explicit_Frame_Flow() : pending_requests(memory_resource(Memory_Domain::Update_Completion)) {} Render_Ticket Explicit_Frame_Flow::request_render() { auto state = make_update_state(); { std::lock_guard lock(request_mutex); pending_requests.push_back(state); } manual_request_pending.store(true, std::memory_order_release); return Render_Ticket(std::move(state)); } void Explicit_Frame_Flow::attach(Frame_Flow_Host& host_value) { host = &host_value; } Frame_Flow_Runtime_Snapshot Explicit_Frame_Flow::runtime_snapshot(std::uint64_t now_ns, bool destroying) const { return { destroying, manual_request_pending.load(std::memory_order_acquire), render_job_active.load(std::memory_order_acquire), frame_ready.load(std::memory_order_acquire), present_active.load(std::memory_order_acquire), now_ns }; } void Explicit_Frame_Flow::advance_edit_version() { edit_version.fetch_add(1, std::memory_order_acq_rel); } void Explicit_Frame_Flow::cancel_all_update_states() { { std::lock_guard lock(request_mutex); for (auto& state : pending_requests) { if (state) state->complete_all(std::make_error_code(std::errc::operation_canceled), Update_Outcome::Cancelled); } pending_requests.clear(); } std::shared_ptr output; { std::lock_guard lock(surface_mutex); output = std::move(present_surface); } if (output) cancel_update_states(output->presented_update_states); } Render_Frame_Surface Explicit_Frame_Flow::begin_render_frame() { if (render_job_active.exchange(true, std::memory_order_acq_rel)) return {}; auto output = std::make_shared(); auto handle = std::make_unique(output); auto* output_pointer = output.get(); std::uint64_t input_version = edit_version.load(std::memory_order_acquire); return Render_Frame_Surface(output_pointer, input_version, std::move(handle)); } void Explicit_Frame_Flow::cancel_render_frame(Render_Frame_Surface&& surface) { (void)surface; render_job_active.store(false, std::memory_order_release); } void Explicit_Frame_Flow::discard_render_frame(Render_Frame_Surface&& surface) { (void)surface; render_job_active.store(false, std::memory_order_release); } Render_Surface_Publish_Result Explicit_Frame_Flow::publish_rendered_frame(Render_Frame_Surface&& surface, std::uint64_t now_ns) { Render_Surface_Publish_Result result; auto* handle = explicit_handle(surface); if (!handle || !handle->output) { render_job_active.store(false, std::memory_order_release); return result; } if (handle->output->metadata) { handle->output->metadata->transition_12_ns = now_ns; handle->output->metadata->ready_queue_wait_ns = now_ns > handle->output->metadata->render_end_ns ? now_ns - handle->output->metadata->render_end_ns : 0; handle->output->metadata->update_request_id = ++next_present_request_id; handle->output->metadata->update_request_time_ns = now_ns; result.update_request_id = handle->output->metadata->update_request_id; result.update_request_time = now_ns; } std::shared_ptr output = std::move(handle->output); Size size = output ? output->image.size() : Size{}; { std::lock_guard lock(surface_mutex); present_surface = output; } frame_ready.store(true, std::memory_order_release); paint_request_pending.store(true, std::memory_order_release); render_job_active.store(false, std::memory_order_release); result.dirty_rect = Rect{0, 0, size.width, size.height}; result.request_present = true; return result; } Render_Surface_Publish_Result Explicit_Frame_Flow::request_present(std::uint64_t now_ns) { Render_Surface_Publish_Result result; std::shared_ptr output; { std::lock_guard lock(surface_mutex); output = present_surface; } if (!output) return result; if (output->metadata) { output->metadata->update_request_id = ++next_present_request_id; output->metadata->update_request_time_ns = now_ns; result.update_request_id = output->metadata->update_request_id; result.update_request_time = now_ns; } paint_request_pending.store(true, std::memory_order_release); Size size = output->image.size(); result.dirty_rect = Rect{0, 0, size.width, size.height}; result.request_present = true; return result; } Present_Surface_Lease Explicit_Frame_Flow::begin_present(std::uint64_t now_ns, std::shared_ptr& returned_frame_record) { returned_frame_record.reset(); std::shared_ptr output; { std::lock_guard lock(surface_mutex); output = present_surface; } if (!output || present_active.exchange(true, std::memory_order_acq_rel)) return {}; bool is_new = frame_ready.exchange(false, std::memory_order_acq_rel); bool pending = paint_request_pending.exchange(false, std::memory_order_acq_rel); if (is_new && output->metadata) { output->metadata->transition_23_ns = now_ns; output->metadata->present_queue_wait_ns = now_ns > output->metadata->transition_12_ns ? now_ns - output->metadata->transition_12_ns : 0; } return Present_Surface_Lease_Access::from_handle( is_new, pending, std::move(output)); } std::shared_ptr Explicit_Frame_Flow::end_present(Present_Surface_Lease&& surface, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns) { std::shared_ptr record; Render_Output* output = Present_Surface_Lease_Access::output(surface); if (output && surface.new_frame()) { record = output->metadata; if (record) { record->paint_begin_ns = paint_begin_ns; record->paint_end_ns = paint_end_ns; record->outcome = Frame_Outcome::Presented; } complete_update_states(output->presented_update_states, Update_Stage::Presented); } Present_Surface_Lease_Access::reset(surface); present_active.store(false, std::memory_order_release); return record; } void Explicit_Frame_Flow::activate_view(std::uint64_t now_ns) { view_active_state.store(true, std::memory_order_release); evaluate(now_ns); } void Explicit_Frame_Flow::deactivate_view() { view_active_state.store(false, std::memory_order_release); } bool Explicit_Frame_Flow::view_active() const { return view_active_state.load(std::memory_order_acquire); } void Explicit_Frame_Flow::notify_model_dirty(std::uint64_t now_ns) { evaluate(now_ns); } void Explicit_Frame_Flow::notify_viewport_changed(Size, std::uint64_t now_ns) { evaluate(now_ns); } void Explicit_Frame_Flow::notify_render_finished(Frame_Lifecycle_Record&, std::uint64_t now_ns) { evaluate(now_ns); } void Explicit_Frame_Flow::notify_paint_finished(std::uint64_t now_ns) { evaluate(now_ns); } void Explicit_Frame_Flow::notify_frame_returned(Frame_Lifecycle_Record&, std::uint64_t now_ns) { evaluate(now_ns); } void Explicit_Frame_Flow::notify_timer_fired(std::uint64_t now_ns) { evaluate(now_ns); } void Explicit_Frame_Flow::drain_frame_update_states(std::pmr::vector>& output) { std::lock_guard lock(request_mutex); for (auto& state : pending_requests) output.push_back(std::move(state)); pending_requests.clear(); manual_request_pending.store(false, std::memory_order_release); } Explicit_Diagnostics Explicit_Frame_Flow::explicit_diagnostics() const { std::lock_guard lock(request_mutex); return Explicit_Diagnostics{ view_active_state.load(std::memory_order_acquire), static_cast(pending_requests.size()) }; } Flow_Diagnostics Explicit_Frame_Flow::diagnostics() const { Explicit_Diagnostics typed = explicit_diagnostics(); return Flow_Diagnostics{ Common_Flow_Diagnostics{typed.active}, typed }; } void Explicit_Frame_Flow::shutdown() { host = nullptr; cancel_all_update_states(); view_active_state.store(false, std::memory_order_release); manual_request_pending.store(false, std::memory_order_release); render_job_active.store(false, std::memory_order_release); frame_ready.store(false, std::memory_order_release); present_active.store(false, std::memory_order_release); paint_request_pending.store(false, std::memory_order_release); } void Explicit_Frame_Flow::evaluate(std::uint64_t now_ns) { if (!host) return; Frame_Flow_Runtime_Snapshot runtime = host->runtime_snapshot(now_ns); if (runtime.destroying) return; if (runtime.middle_has_new_frame && !runtime.paint_active) host->request_paint_from_middle(); if (!manual_request_pending.load(std::memory_order_acquire)) return; if (runtime.render_job_active) return; if (host->try_render_once()) manual_request_pending.store(false, std::memory_order_release); } } // namespace renderive