Route app thread orchestration through app core

This commit is contained in:
2026-06-05 07:01:51 +02:00
parent 32c95b224f
commit c50ea14a2a
12 changed files with 749 additions and 64 deletions

View File

@@ -9,6 +9,7 @@
#include "app_core/app_shutdown.h"
#include "app_core/app_status.h"
#include "app_core/app_startup.h"
#include "app_core/app_thread.h"
#include "app_core/canvas_tool_ui.h"
#include "app_core/document_recording.h"
#include "app_core/document_route.h"
@@ -475,8 +476,11 @@ void App::async_start()
void App::async_redraw()
{
redraw = true;
ui_cv.notify_all();
const auto plan = pp::app::plan_app_async_redraw();
if (plan.set_redraw)
redraw = true;
if (plan.notify_ui)
ui_cv.notify_all();
}
void App::async_end()
@@ -802,19 +806,21 @@ void App::render_thread_tick()
{
static uint32_t count = 0;
render_thread_id = std::this_thread::get_id();
render_running = true;
std::deque<AppTask> working_list;
pp::app::AppQueueDrainPlan drain_plan;
// move the task list locally to free the queue for other threads
{
std::unique_lock<std::mutex> lock(render_task_mutex);
if (render_tasklist.empty())
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);
}
// execute the tasks
if (!working_list.empty())
if (drain_plan.wrap_in_render_context)
{
async_start();
while (!working_list.empty())
@@ -835,20 +841,22 @@ void App::render_thread_main()
uint32_t count = 0;
render_thread_id = std::this_thread::get_id();
render_running = true;
render_running = pp::app::plan_app_thread_start().mark_running;
while (render_running)
{
std::deque<AppTask> working_list;
pp::app::AppQueueDrainPlan drain_plan;
// move the task list locally to free the queue for other threads
{
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);
}
// execute the tasks
if (!working_list.empty())
if (drain_plan.wrap_in_render_context)
{
async_start();
while (!working_list.empty())
@@ -867,18 +875,20 @@ void App::render_thread_main()
void App::ui_thread_tick()
{
ui_thread_id = std::this_thread::get_id();
ui_running = true;
std::deque<AppTask> working_list;
pp::app::AppUiTickPlan tick_plan;
// move the task list locally to free the queue for other threads
{
std::unique_lock<std::mutex> lock(ui_task_mutex);
tick_plan = pp::app::plan_app_ui_thread_tick(ui_tasklist.size(), redraw);
ui_running = tick_plan.mark_running;
working_list = std::move(ui_tasklist);
}
// execute the tasks
if (!working_list.empty())
if (tick_plan.execute_tasks)
{
while (!working_list.empty())
{
@@ -888,11 +898,14 @@ void App::ui_thread_tick()
}
}
tick(0);
if (tick_plan.tick_app)
tick(0);
if (redraw)
const auto redraw_plan = pp::app::plan_app_ui_loop_redraw(redraw, 0);
if (redraw_plan.enqueue_render_frame)
{
update(0);
if (redraw_plan.update_before_render)
update(0);
render_task([this]
{
bind_default_render_target();
@@ -909,7 +922,7 @@ void App::ui_thread_main()
uint32_t count = 0;
ui_thread_id = std::this_thread::get_id();
ui_running = true;
ui_running = pp::app::plan_app_thread_start().mark_running;
attach_ui_thread();
@@ -949,25 +962,25 @@ void App::ui_thread_main()
float dt = std::chrono::duration<float>(t_now - t_start).count();
t_start = t_now;
update_platform_frame(dt);
const auto timer_plan = pp::app::plan_app_ui_loop_timers(
dt,
t_frame,
t_fps_counter,
t_reloader,
rendered_frames,
platform_enables_live_asset_reloading());
if (timer_plan) {
if (timer_plan.value().update_platform_frame)
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;
// increment timers
t_frame += dt;
t_fps_counter += dt;
if (timer_plan.value().report_rendered_frames)
report_rendered_frames(timer_plan.value().reported_frame_count);
if (t_fps_counter > 1.f)
{
report_rendered_frames(rendered_frames);
t_fps_counter = 0;
rendered_frames = 0;
}
if (platform_enables_live_asset_reloading())
{
t_reloader += dt;
if (t_reloader > 1.0)
{
t_reloader = 0;
if (timer_plan.value().check_live_asset_reload) {
if (ShaderManager::reload())
{
stroke->update_controls();
@@ -980,11 +993,14 @@ void App::ui_thread_main()
}
}
tick(dt);
const auto redraw_plan = pp::app::plan_app_ui_loop_redraw(redraw, rendered_frames);
if (redraw_plan.tick_app)
tick(dt);
if (redraw)
if (redraw_plan.enqueue_render_frame)
{
update(t_frame);
if (redraw_plan.update_before_render)
update(t_frame);
render_task([this, t_frame]
{
bind_default_render_target();
@@ -992,8 +1008,9 @@ void App::ui_thread_main()
draw(t_frame);
async_swap();
});
t_frame = 0;
rendered_frames++;
if (redraw_plan.reset_frame_accumulator)
t_frame = 0;
rendered_frames = redraw_plan.rendered_frames;
}
}
detach_ui_thread();
@@ -1001,28 +1018,38 @@ void App::ui_thread_main()
void App::render_thread_start()
{
render_thread = std::thread(&App::render_thread_main, this);
render_running = true;
const auto plan = pp::app::plan_app_thread_start();
if (plan.start_thread)
render_thread = std::thread(&App::render_thread_main, this);
render_running = plan.mark_running;
}
void App::render_thread_stop()
{
render_running = false;
render_cv.notify_all();
if (render_thread.joinable())
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 App::ui_thread_start()
{
ui_thread = std::thread(&App::ui_thread_main, this);
ui_running = true;
const auto plan = pp::app::plan_app_thread_start();
if (plan.start_thread)
ui_thread = std::thread(&App::ui_thread_main, this);
ui_running = plan.mark_running;
}
void App::ui_thread_stop()
{
ui_running = false;
ui_cv.notify_all();
if (ui_thread.joinable())
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();
}