#include "Explicit_Frame_Flow.h" #include "Explicit_Renderable_Runtime.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 const_cast(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; } std::unique_ptr Explicit_Frame_Flow::create_renderable_runtime(Renderable& owner) const { return make_explicit_renderable_runtime(owner); } 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), false, 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 = present_surface; } if (output) cancel_update_states(const_cast(output.get())->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(); output->render_complete.store(false, std::memory_order_release); 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->render_complete.load(std::memory_order_acquire) || !handle->output->metadata || !handle->output->metadata->render_end_ns || handle->output->image.empty()) { if (handle->output->metadata) handle->output->metadata->outcome = Frame_Outcome::Publish_Dropped; result.dropped_frame_record = handle->output->metadata; supersede_update_states(handle->output->presented_update_states); 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; Render_Output* mutable_output = const_cast(output.get()); if (mutable_output->metadata) { mutable_output->metadata->update_request_id = ++next_present_request_id; mutable_output->metadata->update_request_time_ns = now_ns; result.update_request_id = mutable_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) 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); Render_Output* mutable_output = const_cast(output.get()); if (is_new && mutable_output->metadata) { mutable_output->metadata->transition_23_ns = now_ns; mutable_output->metadata->present_queue_wait_ns = now_ns > mutable_output->metadata->transition_12_ns ? now_ns - mutable_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); 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(Dirty_Reason, 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); 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