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

169
src/app.h
View File

@@ -25,6 +25,7 @@
#include "layout.h"
#include "app_core/document_session.h"
#include "app_core/app_thread.h"
#include "app_runtime.h"
namespace pp::platform {
class PlatformServices;
@@ -76,21 +77,6 @@ struct VRController
virtual float get_trigger_value() const { return 1.f; }
};
struct AppTask : public std::packaged_task<void()>
{
size_t task_id;
#ifdef _DEBUG
std::string name;
#endif
template<typename F> AppTask(F f) : std::packaged_task<void()>(f)
{
task_id = typeid(f).hash_code();
#ifdef _DEBUG
name = typeid(f).name();
#endif
}
};
class App
{
public:
@@ -345,16 +331,13 @@ public:
void cmd_convert(std::string pano_path, std::string out_path);
AppRuntime& runtime() noexcept { return runtime_; }
const AppRuntime& runtime() const noexcept { return runtime_; }
//////////////////////////////////////////////////////////////////////////
// RENDER THREAD
//////////////////////////////////////////////////////////////////////////
static std::deque<AppTask> render_tasklist;
static std::mutex render_task_mutex;
static std::condition_variable render_cv;
static std::thread render_thread;
static std::thread::id render_thread_id;
static bool render_running;
void render_thread_tick();
void render_thread_main();
void render_thread_start();
@@ -362,94 +345,30 @@ public:
bool is_render_thread()
{
return std::this_thread::get_id() == render_thread_id;
return runtime_.is_render_thread();
}
// don't capture a reference to this ptr as the object may be destroyed
// by the time the task is executed
template<typename T>
std::future<void> render_task_async(T task, bool unique = false)
{
AppTask pt(task);
auto f = pt.get_future();
const auto dispatch = pp::app::plan_app_task_dispatch(
is_render_thread(),
unique,
0U,
render_running,
false,
false);
if (dispatch.execute_immediately)
{
pt();
}
else if (dispatch.queue_task)
{
{
std::lock_guard<std::mutex> lock(render_task_mutex);
const auto queue_dispatch = pp::app::plan_app_task_dispatch(
false,
unique,
render_tasklist.size(),
render_running,
false,
false);
// remove any previously queued task from the same lambda
if (queue_dispatch.remove_matching_unique_task)
render_tasklist.erase(std::remove_if(render_tasklist.begin(), render_tasklist.end(),
[id = pt.task_id](AppTask const& t){ return t.task_id == id; }), render_tasklist.end());
render_tasklist.push_back(std::move(pt));
}
if (dispatch.notify_worker)
render_cv.notify_all();
}
return f;
return runtime_.render_task_async(std::move(task), unique);
}
template<typename T>
void render_task(T task)
{
AppTask pt(task);
auto f = pt.get_future();
const auto dispatch = pp::app::plan_app_task_dispatch(
is_render_thread(),
false,
0U,
render_running,
true,
false);
if (dispatch.execute_immediately)
{
pt();
}
else if (dispatch.queue_task)
{
{
std::lock_guard<std::mutex> lock(render_task_mutex);
render_tasklist.push_back(std::move(pt));
}
if (dispatch.notify_worker)
render_cv.notify_all();
}
if (dispatch.wait_for_completion)
f.get();
runtime_.render_task(std::move(task));
}
void render_sync()
{
render_task([] {});
runtime_.render_sync();
}
//////////////////////////////////////////////////////////////////////////
// UI THREAD
//////////////////////////////////////////////////////////////////////////
static std::deque<AppTask> ui_tasklist;
static std::mutex ui_task_mutex;
static std::condition_variable ui_cv;
static std::thread ui_thread;
static std::thread::id ui_thread_id;
static bool ui_running;
void ui_thread_tick();
void ui_thread_main();
void ui_thread_start();
@@ -457,83 +376,29 @@ public:
bool is_ui_thread()
{
return std::this_thread::get_id() == ui_thread_id;
return runtime_.is_ui_thread();
}
// don't capture a reference to this ptr as the object may be destroyed
// by the time the task is executed
template<typename T>
std::future<void> ui_task_async(T task, bool unique = false)
{
AppTask pt(task);
auto f = pt.get_future();
const auto dispatch = pp::app::plan_app_task_dispatch(
is_ui_thread(),
unique,
0U,
ui_running,
false,
false);
if (dispatch.execute_immediately)
{
pt();
}
else if (dispatch.queue_task)
{
{
std::lock_guard<std::mutex> lock(ui_task_mutex);
const auto queue_dispatch = pp::app::plan_app_task_dispatch(
false,
unique,
ui_tasklist.size(),
ui_running,
false,
false);
// remove any previously queued task from the same lambda
if (queue_dispatch.remove_matching_unique_task)
ui_tasklist.erase(std::remove_if(ui_tasklist.begin(), ui_tasklist.end(),
[id = pt.task_id](AppTask const& t){ return t.task_id == id; }), ui_tasklist.end());
ui_tasklist.push_back(std::move(pt));
}
if (dispatch.notify_worker)
ui_cv.notify_all();
}
return f;
return runtime_.ui_task_async(std::move(task), unique);
}
template<typename T>
void ui_task(T task)
{
AppTask pt(task);
auto f = pt.get_future();
const auto dispatch = pp::app::plan_app_task_dispatch(
is_ui_thread(),
false,
0U,
ui_running,
true,
true);
if (dispatch.execute_immediately)
{
pt();
}
else if (dispatch.queue_task)
{
{
std::lock_guard<std::mutex> lock(ui_task_mutex);
ui_tasklist.push_back(std::move(pt));
}
if (dispatch.notify_worker)
ui_cv.notify_all();
}
if (dispatch.wait_for_completion)
f.get();
if (dispatch.request_redraw)
runtime_.ui_task(std::move(task));
if (runtime_.request_redraw())
redraw = true;
runtime_.clear_request_redraw();
}
void ui_sync()
{
ui_task([] {});
runtime_.ui_sync();
}
private:
AppRuntime runtime_;
};