From cb6744be440f22c3bc9673f03a4b06493f3dbd69 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Tue, 9 Jul 2019 01:07:13 +0200 Subject: [PATCH] move render thread to App class and add ui thread with ui tasks queue --- src/app.cpp | 120 ++++++++++++++++++++++++ src/app.h | 97 +++++++++++++++++--- src/app_vr.cpp | 10 -- src/canvas.cpp | 4 - src/canvas_actions.cpp | 1 - src/main.cpp | 201 +++++++---------------------------------- 6 files changed, 239 insertions(+), 194 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 9817818..fa5e55d 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1019,3 +1019,123 @@ void App::rec_loop() } } } + +void App::render_thread_main() +{ + uint32_t count = 0; + render_thread_id = std::this_thread::get_id(); + render_running = true; + while (render_running) + { + std::deque> working_list; + + // move the task list locally to free the queue for other threads + { + std::unique_lock lock(render_task_mutex); + render_cv.wait(lock, [this] { return render_tasklist.empty() && render_running ? false : true; }); + working_list = std::move(render_tasklist); + } + + // execute the tasks + if (!working_list.empty()) + { + async_lock(); + while (!working_list.empty()) + { + //LOG("render task %d", count); + count++; + working_list.front()(); + working_list.pop_front(); + } + async_unlock(); + } + } +} + +void App::ui_thread_main() +{ + uint32_t count = 0; + ui_thread_id = std::this_thread::get_id(); + ui_running = true; + auto t_start = std::chrono::high_resolution_clock::now(); + float t_frame = 0; + float t_fps_counter = 0; + int rendered_frames = 0; + while (ui_running) + { + std::deque> working_list; + + // move the task list locally to free the queue for other threads + { + std::unique_lock lock(ui_task_mutex); + ui_cv.wait(lock, [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(t_now - t_start).count(); + + // increment timers + t_frame += dt; + t_fps_counter += dt; + + if (t_fps_counter > 1.f) + { + + } + + tick(dt); + + if (redraw) + { + update(t_frame); + render_task([this, t_frame] + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + clear(); + draw(t_frame); + async_swap(); + }); + t_frame = 0; + rendered_frames++; + } + } +} + +void App::render_thread_start() +{ + render_thread = std::thread(&App::render_thread_main, this); +} + +void App::render_thread_stop() +{ + render_running = false; + render_cv.notify_all(); + if (render_thread.joinable()) + render_thread.join(); +} + +void App::ui_thread_start() +{ + ui_thread = std::thread(&App::ui_thread_main, this); +} + +void App::ui_thread_stop() +{ + ui_running = false; + ui_cv.notify_all(); + if (ui_thread.joinable()) + ui_thread.join(); +} diff --git a/src/app.h b/src/app.h index 1816f69..cc77dc2 100644 --- a/src/app.h +++ b/src/app.h @@ -73,7 +73,7 @@ public: std::mutex rec_mutex; std::condition_variable rec_cv; std::deque> rec_frames; - + RTT uirtt; Sampler sampler; Sampler sampler_stencil; @@ -251,11 +251,23 @@ public: void cmd_convert(std::string pano_path, std::string out_path); + ////////////////////////////////////////////////////////////////////////// + // RENDER THREAD + ////////////////////////////////////////////////////////////////////////// + + std::deque> render_tasklist; + std::mutex render_task_mutex; + std::condition_variable render_cv; + std::thread render_thread; + std::thread::id render_thread_id; + bool render_running = false; + void render_thread_main(); + void render_thread_start(); + void render_thread_stop(); + bool is_render_thread() { - extern std::thread::id render_thread_id; - extern std::thread::id gl_thread; - return std::this_thread::get_id() == render_thread_id || std::this_thread::get_id() == gl_thread; + return std::this_thread::get_id() == render_thread_id; } // don't capture a reference to this ptr as the object may be destroyed @@ -264,9 +276,6 @@ public: std::future render_task_async(T task) { #ifdef _WIN32 - extern std::deque> render_tasklist; - extern std::mutex render_task_mutex; - extern std::condition_variable render_cv; std::packaged_task pt(task); std::future f = pt.get_future(); if (is_render_thread()) @@ -289,9 +298,6 @@ public: R render_task(T task) { #ifdef _WIN32 - extern std::deque> render_tasklist; - extern std::mutex render_task_mutex; - extern std::condition_variable render_cv; std::packaged_task pt(task); std::future f = pt.get_future(); if (is_render_thread()) @@ -306,7 +312,7 @@ public: } render_cv.notify_all(); } - return f.get(); + return render_running ? f.get() : R(); #endif // _WIN32 } @@ -315,4 +321,73 @@ public: render_task([] {}); } + ////////////////////////////////////////////////////////////////////////// + // UI THREAD + ////////////////////////////////////////////////////////////////////////// + + std::deque> ui_tasklist; + std::mutex ui_task_mutex; + std::condition_variable ui_cv; + std::thread ui_thread; + std::thread::id ui_thread_id; + bool ui_running = false; + void ui_thread_main(); + void ui_thread_start(); + void ui_thread_stop(); + + bool is_ui_thread() + { + return std::this_thread::get_id() == ui_thread_id; + } + + // don't capture a reference to this ptr as the object may be destroyed + // by the time the task is executed + template::type> + std::future ui_task_async(T task) + { +#ifdef _WIN32 + std::packaged_task pt(task); + std::future f = pt.get_future(); + if (is_ui_thread()) + { + pt(); + } + else + { + { + std::lock_guard lock(ui_task_mutex); + ui_tasklist.push_back(std::move(pt)); + } + ui_cv.notify_all(); + } + return f; +#endif // _WIN32 + } + + template::type> + R ui_task(T task) + { +#ifdef _WIN32 + std::packaged_task pt(task); + std::future f = pt.get_future(); + if (is_ui_thread()) + { + pt(); + } + else + { + { + std::lock_guard lock(ui_task_mutex); + ui_tasklist.push_back(std::move(pt)); + } + ui_cv.notify_all(); + } + return ui_running ? f.get() : R(); +#endif // _WIN32 + } + + void ui_sync() + { + ui_task([] {}); + } }; diff --git a/src/app_vr.cpp b/src/app_vr.cpp index 767c5dc..22d25b0 100644 --- a/src/app_vr.cpp +++ b/src/app_vr.cpp @@ -6,7 +6,6 @@ #ifdef _WIN32 bool win32_vr_start(); void win32_vr_stop(); -void win32_render_thread_notify(); #endif bool trigger_down = false; @@ -86,9 +85,6 @@ void App::vr_update(float dt) mouse_move(controller_cursor.x, controller_cursor.y, 1.f, kEventSource::Mouse, false); async_end(); ui_inside = true; -#ifdef _WIN32 - win32_render_thread_notify(); -#endif } } } @@ -122,17 +118,11 @@ void App::vr_analog(const VRController& c, VRController::kButton b, VRController { mouse_down(0, controller_cursor.x, controller_cursor.y, 1.f, kEventSource::Mouse, false); ui_capture = true; -#ifdef _WIN32 - win32_render_thread_notify(); -#endif } else { mouse_up(0, controller_cursor.x, controller_cursor.y, kEventSource::Mouse, false); ui_capture = false; -#ifdef _WIN32 - win32_render_thread_notify(); -#endif } async_end(); } diff --git a/src/canvas.cpp b/src/canvas.cpp index a28ae70..0b5a5ae 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -2845,8 +2845,6 @@ void Canvas::draw_objects_direct(std::functiondraw_merge(); } size_t ActionStroke::memory() diff --git a/src/main.cpp b/src/main.cpp index 34a721a..4c0d711 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -33,23 +33,11 @@ std::thread::id gl_thread; std::map vkey_map; std::thread hmd_renderer; -std::thread ui_renderer; int vr_frames = 0; int running = -1; int vr_running = 0; -std::mutex ui_render_mutex; -std::condition_variable ui_render_cv; - -std::deque> render_tasklist; -std::mutex render_task_mutex; -std::condition_variable render_cv; -std::thread render_thread; -std::thread::id render_thread_id; -bool render_running = false; int gl_count = 0; -std::deque> tasklist; -std::mutex task_mutex; std::deque> main_tasklist; std::mutex main_task_mutex; float timer_stylus = 0; @@ -119,63 +107,6 @@ void destroy_window() }); } -bool is_render_thread() -{ - extern std::thread::id render_thread_id; - extern std::thread::id gl_thread; - return std::this_thread::get_id() == render_thread_id || std::this_thread::get_id() == gl_thread; -} - -template::type> -std::future render_task_async(T task) -{ -#ifdef _WIN32 - extern std::deque> render_tasklist; - extern std::mutex render_task_mutex; - extern std::condition_variable render_cv; - std::packaged_task pt(task); - std::future f = pt.get_future(); - if (is_render_thread()) - { - pt(); - } - else - { - { - std::lock_guard lock(render_task_mutex); - render_tasklist.push_back(std::move(pt)); - } - render_cv.notify_all(); - } - return f; -#endif // _WIN32 -} - -template::type> -R render_task(T task) -{ -#ifdef _WIN32 - extern std::deque> render_tasklist; - extern std::mutex render_task_mutex; - extern std::condition_variable render_cv; - std::packaged_task pt(task); - std::future f = pt.get_future(); - if (is_render_thread()) - { - pt(); - } - else - { - { - std::lock_guard lock(render_task_mutex); - render_tasklist.push_back(std::move(pt)); - } - render_cv.notify_all(); - } - return f.get(); -#endif // _WIN32 -} - void async_lock() { //std::lock_guard _lock(async_mutex); @@ -228,11 +159,6 @@ void async_unlock() } } -void win32_render_thread_notify() -{ - ui_render_cv.notify_all(); -} - void win32_show_cursor(bool visible) { std::lock_guard lock(main_task_mutex); @@ -781,46 +707,6 @@ BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle return fRc; } -void render_thread_main() -{ - uint32_t count = 0; - render_thread_id = std::this_thread::get_id(); - render_running = true; - while (render_running == 1) - { - std::deque> working_list; - - // move the task list locally to free the queue for other threads - { - std::unique_lock lock(render_task_mutex); - render_cv.wait(lock, [] { return render_tasklist.empty() && render_running ? false : true; }); - working_list = std::move(render_tasklist); - } - - //{ - // std::lock_guard lock(task_mutex); - // working_list.insert(working_list.end(), - // std::make_move_iterator(tasklist.begin()), - // std::make_move_iterator(tasklist.end())); - // tasklist.clear(); - //} - - // execute the tasks - if (!working_list.empty()) - { - async_lock(); - while (!working_list.empty()) - { - LOG("render task %d", count); - count++; - working_list.front()(); - working_list.pop_front(); - } - async_unlock(); - } - } -} - int main(int argc, char** argv) { WNDCLASS wc; @@ -1015,7 +901,8 @@ int main(int argc, char** argv) wglMakeCurrent(NULL, NULL); running = 1; - render_thread = std::thread(render_thread_main); + App::I.render_thread_start(); + App::I.ui_thread_start(); LOG("init app"); App::I.init(); @@ -1034,6 +921,17 @@ int main(int argc, char** argv) SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1))); + { + WINDOWPLACEMENT wp; + GetWindowPlacement(hWnd, &wp); + wp.showCmd = show_cmd; + SetWindowPlacement(hWnd, &wp); + //GetClientRect(hWnd, &clientRect); + //App::I.width = clientRect.right - clientRect.left; + //App::I.height = clientRect.bottom - clientRect.top; + } + + /* ui_renderer = std::thread([&] { BT_SetTerminate(); LOG("start render thread"); @@ -1041,7 +939,6 @@ int main(int argc, char** argv) const float target_tick_rate = 10; unsigned long t0 = GetTickCount64(); unsigned long t1; - bool first_frame = true; int frames = 0; float one_sec = 0; float render_timer = 0; @@ -1094,18 +991,6 @@ int main(int argc, char** argv) } } - if (first_frame) - { - first_frame = false; - WINDOWPLACEMENT wp; - GetWindowPlacement(hWnd, &wp); - wp.showCmd = show_cmd; - SetWindowPlacement(hWnd, &wp); -// GetClientRect(hWnd, &clientRect); -// App::I.width = clientRect.right - clientRect.left; -// App::I.height = clientRect.bottom - clientRect.top; - } - App::I.tick(dt); std::unique_lock lock(ui_render_mutex); @@ -1134,7 +1019,7 @@ int main(int argc, char** argv) if (App::I.redraw) { App::I.update(frame_timer); - render_task([frame_timer] + App::I.render_task([frame_timer] { glBindFramebuffer(GL_FRAMEBUFFER, 0); App::I.clear(); @@ -1151,9 +1036,8 @@ int main(int argc, char** argv) //std::this_thread::sleep_for(std::chrono::milliseconds(30)); t0 = t1; } - LOG("renderer terminated"); }); - + */ SetTimer(hWnd, 1, 500, NULL); if (start_in_vr) @@ -1202,12 +1086,11 @@ int main(int argc, char** argv) } } - if (!tasklist.empty()) - ui_render_cv.notify_all(); +// if (!tasklist.empty()) +// ui_render_cv.notify_all(); } // Clean up WacomTablet::I.terminate(); - render_cv.notify_all(); UnregisterClass(className, hInst); LogRemote::I.stop(); @@ -1227,16 +1110,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { case WM_USER_CLOSE: running = 0; - ui_render_cv.notify_all(); - if (ui_renderer.joinable()) - ui_renderer.join(); if (hmd_renderer.joinable()) hmd_renderer.join(); + App::I.ui_thread_stop(); + App::I.render_thread_stop(); App::I.terminate(); PostQuitMessage(0); - render_running = false; - if (render_thread.joinable()) - render_thread.join(); return 0; case WM_PAINT: App::I.redraw = true; @@ -1246,8 +1125,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) break; case WM_CLOSE: { - std::lock_guard lock(task_mutex); - tasklist.emplace_back([=] { + App::I.ui_task_async([] { if (App::I.request_close()) { destroy_window(); @@ -1262,8 +1140,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) auto h = (float)HIWORD(lp); if (h != 0 && running == 1) { - std::lock_guard lock(task_mutex); - tasklist.emplace_back([=] + App::I.ui_task_async([=] { App::I.resize(w, h); App::I.redraw = true; @@ -1273,8 +1150,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) } case WM_ACTIVATE: { - std::lock_guard lock(task_mutex); - tasklist.emplace_back([=] { + App::I.ui_task_async([=] { int active = GET_WM_ACTIVATE_STATE(wp, lp); WacomTablet::I.set_focus(active); static BYTE keys[256]; @@ -1298,8 +1174,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) } // case WM_TOUCH: // { -// std::lock_guard lock(task_mutex); -// tasklist.emplace_back([=] { +// App::I.ui_task_async([=] { // //LOG("touch"); // }); // break; @@ -1308,8 +1183,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { App::I.set_stylus(); timer_stylus = 0; - std::lock_guard lock(task_mutex); - tasklist.emplace_back([=] { + App::I.ui_task_async([=] { WacomTablet::I.handle_message(hWnd, msg, wp, lp); }); break; @@ -1319,8 +1193,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) if ((lp >> 30 & 1) == 0 && // ignore repeated !(wp == VK_TAB && App::I.keys[(int)kKey::KeyAlt])) // ignore alt+tab { - std::lock_guard lock(task_mutex); - tasklist.emplace_back([wp] { + App::I.ui_task_async([wp] { App::I.key_down(convert_key((int)wp)); }); } @@ -1329,16 +1202,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) case WM_KEYUP: if (!(wp == VK_TAB && App::I.keys[(int)kKey::KeyAlt])) // ignore alt+tab { - std::lock_guard lock(task_mutex); - tasklist.emplace_back([wp] { + App::I.ui_task_async([wp] { App::I.key_up(convert_key((int)wp)); }); } break; case WM_CHAR: { - std::lock_guard lock(task_mutex); - tasklist.emplace_back([wp]{ + App::I.ui_task_async([wp]{ App::I.key_char((int)wp); }); } @@ -1362,8 +1233,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) lastPoint = { GET_X_LPARAM(lp), GET_Y_LPARAM(lp) }; auto pt = lastPoint; - std::lock_guard lock(task_mutex); - tasklist.emplace_back([pt, extra, p = WacomTablet::I.get_pressure()]{ + App::I.ui_task_async([pt, extra, p = WacomTablet::I.get_pressure()]{ kEventSource pointer_source; if (WacomTablet::I.m_ink_pen || WacomTablet::I.m_ink_touch) { @@ -1382,9 +1252,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) case WM_LBUTTONDOWN: { SetCapture(hWnd); - std::lock_guard lock(task_mutex); auto pt = lastPoint; - tasklist.emplace_back([pt, extra, hWnd, p = WacomTablet::I.get_pressure()]{ + App::I.ui_task_async([pt, extra, hWnd, p = WacomTablet::I.get_pressure()]{ kEventSource pointer_source; if (WacomTablet::I.m_ink_pen || WacomTablet::I.m_ink_touch) { @@ -1403,9 +1272,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) case WM_LBUTTONUP: { ReleaseCapture(); - std::lock_guard lock(task_mutex); auto pt = lastPoint; - tasklist.emplace_back([pt, extra] { + App::I.ui_task_async([pt, extra] { WacomTablet::I.reset_pressure(); kEventSource pointer_source; if (WacomTablet::I.m_ink_pen || WacomTablet::I.m_ink_touch) @@ -1425,9 +1293,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) case WM_RBUTTONDOWN: { SetCapture(hWnd); - std::lock_guard lock(task_mutex); auto pt = lastPoint; - tasklist.emplace_back([pt, extra, hWnd] { + App::I.ui_task_async([pt, extra, hWnd] { kEventSource pointer_source; if (WacomTablet::I.m_ink_pen || WacomTablet::I.m_ink_touch) { @@ -1446,9 +1313,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) case WM_RBUTTONUP: { ReleaseCapture(); - std::lock_guard lock(task_mutex); auto pt = lastPoint; - tasklist.emplace_back([pt, extra] { + App::I.ui_task_async([pt, extra] { kEventSource pointer_source; if (WacomTablet::I.m_ink_pen || WacomTablet::I.m_ink_touch) { @@ -1471,8 +1337,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) pt.y = GET_Y_LPARAM(lp); ScreenToClient(hWnd, &pt); { - std::lock_guard lock(task_mutex); - tasklist.emplace_back([pt, wp] { + App::I.ui_task_async([pt, wp] { App::I.mouse_scroll((float)pt.x, (float)pt.y, (float)GET_WHEEL_DELTA_WPARAM(wp) / (float)WHEEL_DELTA); });