Advance app runtime ownership and modernization docs
This commit is contained in:
245
src/app.cpp
245
src/app.cpp
@@ -32,10 +32,6 @@
|
||||
|
||||
App* App::I = nullptr; // singleton
|
||||
|
||||
std::deque<AppTask> App::render_tasklist;
|
||||
std::mutex App::render_task_mutex;
|
||||
std::condition_variable App::render_cv;
|
||||
|
||||
namespace {
|
||||
|
||||
pp::app::CanvasToolMode canvas_tool_mode_from_canvas_mode(kCanvasMode mode) noexcept
|
||||
@@ -130,17 +126,6 @@ void apply_app_scissor_test(bool enabled)
|
||||
}
|
||||
|
||||
}
|
||||
std::thread App::render_thread;
|
||||
std::thread::id App::render_thread_id;
|
||||
bool App::render_running = false;
|
||||
|
||||
std::deque<AppTask> App::ui_tasklist;
|
||||
std::mutex App::ui_task_mutex;
|
||||
std::condition_variable App::ui_cv;
|
||||
std::thread App::ui_thread;
|
||||
std::thread::id App::ui_thread_id;
|
||||
bool App::ui_running = false;
|
||||
|
||||
void App::create()
|
||||
{
|
||||
const auto initial_surface = pp::app::plan_app_initial_surface();
|
||||
@@ -353,7 +338,7 @@ void App::async_redraw()
|
||||
if (plan.set_redraw)
|
||||
redraw = true;
|
||||
if (plan.notify_ui)
|
||||
ui_cv.notify_all();
|
||||
runtime_.notify_ui_worker();
|
||||
}
|
||||
|
||||
void App::async_end()
|
||||
@@ -699,252 +684,40 @@ void App::rec_loop()
|
||||
|
||||
void App::render_thread_tick()
|
||||
{
|
||||
static uint32_t count = 0;
|
||||
render_thread_id = std::this_thread::get_id();
|
||||
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);
|
||||
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 (drain_plan.wrap_in_render_context)
|
||||
{
|
||||
async_start();
|
||||
while (!working_list.empty())
|
||||
{
|
||||
//LOG("render task %d", count);
|
||||
//LOG("task %s", working_list.front().name.c_str());
|
||||
count++;
|
||||
working_list.front()();
|
||||
working_list.pop_front();
|
||||
}
|
||||
async_end();
|
||||
}
|
||||
runtime_.render_thread_tick(*this);
|
||||
}
|
||||
|
||||
void App::render_thread_main()
|
||||
{
|
||||
BT_SetTerminate();
|
||||
|
||||
uint32_t count = 0;
|
||||
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;
|
||||
|
||||
// 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 (drain_plan.wrap_in_render_context)
|
||||
{
|
||||
async_start();
|
||||
while (!working_list.empty())
|
||||
{
|
||||
//LOG("render task %d", count);
|
||||
//LOG("task %s", working_list.front().name.c_str());
|
||||
count++;
|
||||
working_list.front()();
|
||||
working_list.pop_front();
|
||||
}
|
||||
async_end();
|
||||
}
|
||||
}
|
||||
runtime_.render_thread_main(*this);
|
||||
}
|
||||
|
||||
void App::ui_thread_tick()
|
||||
{
|
||||
ui_thread_id = std::this_thread::get_id();
|
||||
|
||||
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 (tick_plan.execute_tasks)
|
||||
{
|
||||
while (!working_list.empty())
|
||||
{
|
||||
//LOG("ui task %d", count);
|
||||
working_list.front()();
|
||||
working_list.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
if (tick_plan.tick_app)
|
||||
tick(0);
|
||||
|
||||
const auto redraw_plan = pp::app::plan_app_ui_loop_redraw(redraw, 0);
|
||||
if (redraw_plan.enqueue_render_frame)
|
||||
{
|
||||
if (redraw_plan.update_before_render)
|
||||
update(0);
|
||||
render_task([this]
|
||||
{
|
||||
bind_default_render_target();
|
||||
clear();
|
||||
draw(0);
|
||||
async_swap();
|
||||
});
|
||||
}
|
||||
runtime_.ui_thread_tick(*this);
|
||||
}
|
||||
|
||||
void App::ui_thread_main()
|
||||
{
|
||||
BT_SetTerminate();
|
||||
|
||||
uint32_t count = 0;
|
||||
ui_thread_id = std::this_thread::get_id();
|
||||
ui_running = pp::app::plan_app_thread_start().mark_running;
|
||||
|
||||
attach_ui_thread();
|
||||
|
||||
LOG("ui thread init()");
|
||||
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;
|
||||
|
||||
// move the task list locally to free the queue for other threads
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(ui_task_mutex);
|
||||
ui_cv.wait_for(lock, std::chrono::milliseconds(idle_ms),
|
||||
[this] { return ui_tasklist.empty() && ui_running ? false : true; });
|
||||
working_list = std::move(ui_tasklist);
|
||||
}
|
||||
|
||||
// execute the tasks
|
||||
if (!working_list.empty())
|
||||
{
|
||||
while (!working_list.empty())
|
||||
{
|
||||
//LOG("ui task %d", count);
|
||||
count++;
|
||||
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,
|
||||
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;
|
||||
|
||||
if (timer_plan.value().report_rendered_frames)
|
||||
report_rendered_frames(timer_plan.value().reported_frame_count);
|
||||
|
||||
if (timer_plan.value().check_live_asset_reload) {
|
||||
if (ShaderManager::reload())
|
||||
{
|
||||
stroke->update_controls();
|
||||
redraw = true;
|
||||
}
|
||||
if (layout.reload())
|
||||
redraw = true;
|
||||
if (layout_designer.reload())
|
||||
redraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
const auto redraw_plan = pp::app::plan_app_ui_loop_redraw(redraw, rendered_frames);
|
||||
if (redraw_plan.tick_app)
|
||||
tick(dt);
|
||||
|
||||
if (redraw_plan.enqueue_render_frame)
|
||||
{
|
||||
if (redraw_plan.update_before_render)
|
||||
update(t_frame);
|
||||
render_task([this, t_frame]
|
||||
{
|
||||
bind_default_render_target();
|
||||
clear();
|
||||
draw(t_frame);
|
||||
async_swap();
|
||||
});
|
||||
if (redraw_plan.reset_frame_accumulator)
|
||||
t_frame = 0;
|
||||
rendered_frames = redraw_plan.rendered_frames;
|
||||
}
|
||||
}
|
||||
detach_ui_thread();
|
||||
runtime_.ui_thread_main(*this);
|
||||
}
|
||||
|
||||
void App::render_thread_start()
|
||||
{
|
||||
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;
|
||||
runtime_.render_thread_start(*this);
|
||||
}
|
||||
|
||||
void App::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();
|
||||
runtime_.render_thread_stop();
|
||||
}
|
||||
|
||||
void App::ui_thread_start()
|
||||
{
|
||||
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;
|
||||
runtime_.ui_thread_start(*this);
|
||||
}
|
||||
|
||||
void App::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();
|
||||
runtime_.ui_thread_stop();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user