Advance app runtime ownership and modernization docs

This commit is contained in:
2026-06-16 06:35:59 +02:00
parent c3d757f4a4
commit a76560e3df
24 changed files with 6675 additions and 9009 deletions

258
src/app_runtime.cpp Normal file
View File

@@ -0,0 +1,258 @@
#include "pch.h"
#include "app_runtime.h"
#include "app.h"
bool AppRuntime::is_render_thread() const noexcept
{
return std::this_thread::get_id() == render_thread_id_;
}
bool AppRuntime::is_ui_thread() const noexcept
{
return std::this_thread::get_id() == ui_thread_id_;
}
void AppRuntime::notify_render_worker() noexcept
{
render_cv_.notify_all();
}
void AppRuntime::notify_ui_worker() noexcept
{
ui_cv_.notify_all();
}
void AppRuntime::render_thread_tick(App& app)
{
static uint32_t count = 0;
render_thread_id_ = std::this_thread::get_id();
std::deque<AppTask> working_list;
pp::app::AppQueueDrainPlan drain_plan;
{
std::unique_lock<std::mutex> lock(render_task_mutex_);
drain_plan = pp::app::plan_app_render_queue_drain(render_tasklist_.size());
render_running_ = drain_plan.mark_running;
if (!drain_plan.drain_tasks)
return;
working_list = std::move(render_tasklist_);
}
if (drain_plan.wrap_in_render_context)
{
app.async_start();
while (!working_list.empty())
{
count++;
working_list.front()();
working_list.pop_front();
}
app.async_end();
}
}
void AppRuntime::render_thread_main(App& app)
{
BT_SetTerminate();
render_thread_id_ = std::this_thread::get_id();
render_running_ = pp::app::plan_app_thread_start().mark_running;
while (render_running_)
{
std::deque<AppTask> working_list;
pp::app::AppQueueDrainPlan drain_plan;
{
std::unique_lock<std::mutex> lock(render_task_mutex_);
render_cv_.wait(lock, [this] { return render_tasklist_.empty() && render_running_ ? false : true; });
drain_plan = pp::app::plan_app_render_queue_drain(render_tasklist_.size());
working_list = std::move(render_tasklist_);
}
if (drain_plan.wrap_in_render_context)
{
app.async_start();
while (!working_list.empty())
{
working_list.front()();
working_list.pop_front();
}
app.async_end();
}
}
}
void AppRuntime::ui_thread_tick(App& app)
{
ui_thread_id_ = std::this_thread::get_id();
std::deque<AppTask> working_list;
pp::app::AppUiTickPlan tick_plan;
{
std::unique_lock<std::mutex> lock(ui_task_mutex_);
tick_plan = pp::app::plan_app_ui_thread_tick(ui_tasklist_.size(), app.redraw);
ui_running_ = tick_plan.mark_running;
working_list = std::move(ui_tasklist_);
}
if (tick_plan.execute_tasks)
{
while (!working_list.empty())
{
working_list.front()();
working_list.pop_front();
}
}
if (tick_plan.tick_app)
app.tick(0);
const auto redraw_plan = pp::app::plan_app_ui_loop_redraw(app.redraw, 0);
if (redraw_plan.enqueue_render_frame)
{
if (redraw_plan.update_before_render)
app.update(0);
app.render_task([&app]
{
app.bind_default_render_target();
app.clear();
app.draw(0);
app.async_swap();
});
}
}
void AppRuntime::ui_thread_main(App& app)
{
BT_SetTerminate();
ui_thread_id_ = std::this_thread::get_id();
ui_running_ = pp::app::plan_app_thread_start().mark_running;
app.attach_ui_thread();
LOG("ui thread init()");
app.init();
auto t_start = std::chrono::high_resolution_clock::now();
float t_frame = 0;
float t_fps_counter = 0;
float t_reloader = 0;
int rendered_frames = 0;
while (ui_running_)
{
std::deque<AppTask> working_list;
{
std::unique_lock<std::mutex> lock(ui_task_mutex_);
ui_cv_.wait_for(lock, std::chrono::milliseconds(app.idle_ms),
[this] { return ui_tasklist_.empty() && ui_running_ ? false : true; });
working_list = std::move(ui_tasklist_);
}
if (!working_list.empty())
{
while (!working_list.empty())
{
working_list.front()();
working_list.pop_front();
}
}
auto t_now = std::chrono::high_resolution_clock::now();
float dt = std::chrono::duration<float>(t_now - t_start).count();
t_start = t_now;
const auto timer_plan = pp::app::plan_app_ui_loop_timers(
dt,
t_frame,
t_fps_counter,
t_reloader,
rendered_frames,
app.platform_enables_live_asset_reloading());
if (timer_plan) {
if (timer_plan.value().update_platform_frame)
app.update_platform_frame(dt);
t_frame = timer_plan.value().frame_accumulator;
t_fps_counter = timer_plan.value().fps_accumulator;
t_reloader = timer_plan.value().reload_accumulator;
rendered_frames = timer_plan.value().rendered_frames_after_report;
if (timer_plan.value().report_rendered_frames)
app.report_rendered_frames(timer_plan.value().reported_frame_count);
if (timer_plan.value().check_live_asset_reload) {
if (ShaderManager::reload())
{
app.stroke->update_controls();
app.redraw = true;
}
if (app.layout.reload())
app.redraw = true;
if (app.layout_designer.reload())
app.redraw = true;
}
}
const auto redraw_plan = pp::app::plan_app_ui_loop_redraw(app.redraw, rendered_frames);
if (redraw_plan.tick_app)
app.tick(dt);
if (redraw_plan.enqueue_render_frame)
{
if (redraw_plan.update_before_render)
app.update(t_frame);
app.render_task([&app, t_frame]
{
app.bind_default_render_target();
app.clear();
app.draw(t_frame);
app.async_swap();
});
if (redraw_plan.reset_frame_accumulator)
t_frame = 0;
rendered_frames = redraw_plan.rendered_frames;
}
}
app.detach_ui_thread();
}
void AppRuntime::render_thread_start(App& app)
{
const auto plan = pp::app::plan_app_thread_start();
if (plan.start_thread)
render_thread_ = std::thread(&AppRuntime::render_thread_main, this, std::ref(app));
render_running_ = plan.mark_running;
}
void AppRuntime::render_thread_stop()
{
const auto plan = pp::app::plan_app_thread_stop(render_thread_.joinable());
if (plan.mark_not_running)
render_running_ = false;
if (plan.notify_worker)
render_cv_.notify_all();
if (plan.join_thread)
render_thread_.join();
}
void AppRuntime::ui_thread_start(App& app)
{
const auto plan = pp::app::plan_app_thread_start();
if (plan.start_thread)
ui_thread_ = std::thread(&AppRuntime::ui_thread_main, this, std::ref(app));
ui_running_ = plan.mark_running;
}
void AppRuntime::ui_thread_stop()
{
const auto plan = pp::app::plan_app_thread_stop(ui_thread_.joinable());
if (plan.mark_not_running)
ui_running_ = false;
if (plan.notify_worker)
ui_cv_.notify_all();
if (plan.join_thread)
ui_thread_.join();
}