Files
Renderive/Core/flow/explicit/Explicit_Frame_Flow.cpp
T
2026-08-02 14:57:24 +08:00

276 lines
10 KiB
C++

#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<Render_Output> output) : output(std::move(output)) {}
std::shared_ptr<Render_Output> output;
};
struct Explicit_Present_Surface_Handle final {
explicit Explicit_Present_Surface_Handle(std::shared_ptr<Render_Output> output) : output_value(std::move(output)) {}
[[nodiscard]] Render_Output* output() const {
return output_value.get();
}
std::shared_ptr<Render_Output> output_value;
};
Explicit_Render_Surface_Handle* explicit_handle(Render_Frame_Surface& surface) {
return static_cast<Explicit_Render_Surface_Handle*>(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<std::mutex> 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<std::mutex> 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<Render_Output> output;
{
std::lock_guard<std::mutex> 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<Render_Output>();
auto handle = std::make_unique<Explicit_Render_Surface_Handle>(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<Render_Output> output = std::move(handle->output);
Size size = output ? output->image.size() : Size{};
{
std::lock_guard<std::mutex> 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<Render_Output> output;
{
std::lock_guard<std::mutex> 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<Frame_Lifecycle_Record>& returned_frame_record) {
returned_frame_record.reset();
std::shared_ptr<Render_Output> output;
{
std::lock_guard<std::mutex> 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<Explicit_Present_Surface_Handle>(
is_new,
pending,
std::move(output));
}
std::shared_ptr<Frame_Lifecycle_Record> Explicit_Frame_Flow::end_present(Present_Surface_Lease&& surface, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns) {
std::shared_ptr<Frame_Lifecycle_Record> 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<std::shared_ptr<Update_State>>& output) {
std::lock_guard<std::mutex> 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<std::mutex> lock(request_mutex);
return Explicit_Diagnostics{
view_active_state.load(std::memory_order_acquire),
static_cast<std::uint64_t>(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