From f20f935d435a5ce67534fdabac7cf8101b882213 Mon Sep 17 00:00:00 2001 From: omigamedev Date: Thu, 28 Feb 2019 14:47:06 +0100 Subject: [PATCH] threaded brush preview rendering --- src/app.cpp | 1 + src/main.cpp | 4 ++++ src/node_stroke_preview.cpp | 46 ++++++++++++++++++++++++++++++++++++- src/node_stroke_preview.h | 6 +++++ src/util.h | 18 ++++++++++++--- 5 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index c9c8693..4772b01 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -678,6 +678,7 @@ void App::terminate() LOG("App::terminate"); TextureManager::invalidate(); ShaderManager::invalidate(); + NodeStrokePreview::terminate_renderer(); layout.unload(); uirtt.destroy(); m_face_plane.destroy(); diff --git a/src/main.cpp b/src/main.cpp index cd194a7..e2674ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -573,6 +573,8 @@ int main(int argc, char** argv) LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str()); } + async_lock(); + LOG("init app"); App::I.init(); @@ -604,6 +606,8 @@ int main(int argc, char** argv) LOG("SKIP init WinTab"); } + async_unlock(); + LOG("change icon"); SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1))); diff --git a/src/node_stroke_preview.cpp b/src/node_stroke_preview.cpp index b14c41d..9ba92b0 100644 --- a/src/node_stroke_preview.cpp +++ b/src/node_stroke_preview.cpp @@ -7,6 +7,21 @@ #include "canvas.h" #include "app.h" +std::atomic_int NodeStrokePreview::s_instances{ 0 }; +std::atomic_bool NodeStrokePreview::s_running{ false }; +std::thread NodeStrokePreview::s_renderer; +BlockingQueue NodeStrokePreview::s_queue; + +void NodeStrokePreview::terminate_renderer() +{ + if (s_running && s_renderer.joinable()) + { + s_running = false; + s_queue.UnlockGetters(); + s_renderer.join(); + } +} + Node* NodeStrokePreview::clone_instantiate() const { return new NodeStrokePreview(); @@ -224,7 +239,7 @@ std::vector NodeStrokePreview::stroke_draw_compu return ret; } -void NodeStrokePreview::draw_stroke() +void NodeStrokePreview::draw_stroke_immediate() { if (m_size.x == 0 || m_size.y == 0) return; @@ -458,6 +473,35 @@ void NodeStrokePreview::draw_stroke() glClearColor(cc[0], cc[1], cc[2], cc[3]); } +void NodeStrokePreview::draw_stroke() +{ + if (m_size.x == 0 || m_size.y == 0) + return; + s_queue.mutex.lock(); + if (!s_running) + { + s_running = true; + s_renderer = std::thread([] { + while (s_running) + { + auto node = s_queue.Get(); + if (node) + { + node->async_start(); + gl_state gl; + gl.save(); + node->draw_stroke_immediate(); + gl.restore(); + node->async_end(); + std::this_thread::sleep_for(std::chrono::milliseconds(30)); + } + } + }); + } + s_queue.mutex.unlock(); + s_queue.PostUnique(this); +} + void NodeStrokePreview::draw() { //glEnable(GL_BLEND); diff --git a/src/node_stroke_preview.h b/src/node_stroke_preview.h index 32908a2..bfacaf9 100644 --- a/src/node_stroke_preview.h +++ b/src/node_stroke_preview.h @@ -25,6 +25,11 @@ class NodeStrokePreview : public NodeBorder Sampler m_sampler_mipmap; DynamicShape m_brush_shape; public: + static std::atomic_int s_instances; + static std::atomic_bool s_running; + static std::thread s_renderer; + static BlockingQueue s_queue; + static void terminate_renderer(); std::shared_ptr m_brush; std::shared_ptr m_dual_brush; Stroke m_stroke; @@ -43,6 +48,7 @@ public: glm::vec4 stroke_draw_samples(std::array& P, Texture2D& blend_tex); std::vector stroke_draw_compute(Stroke& stroke) const; void draw_stroke(); + void draw_stroke_immediate(); virtual void draw() override; virtual void handle_resize(glm::vec2 old_size, glm::vec2 new_size) override; virtual void destroy_immediate() override; diff --git a/src/util.h b/src/util.h index 3aacc63..9945ab7 100644 --- a/src/util.h +++ b/src/util.h @@ -151,18 +151,18 @@ template struct cbuffer template class BlockingQueue { +public: std::deque q; std::condition_variable post_cv; std::condition_variable get_cv; mutable std::mutex mutex; -public: volatile bool unlocked = false; BlockingQueue() = default; BlockingQueue(const BlockingQueue& other) = delete; BlockingQueue& operator=(const BlockingQueue& other) = delete; BlockingQueue(BlockingQueue&& other) : q(std::move(q)) { } BlockingQueue& operator=(BlockingQueue&& other) { q = std::move(q); return *this; } - void Post(T&& pkt) + void Post(T pkt) { std::unique_lock lock(mutex); if (Max > 0) @@ -170,7 +170,19 @@ public: post_cv.wait(lock, [&]() { return unlocked | (q.size() < Max); }); if (q.size() >= Max) return; } - q.push_back(std::forward(pkt)); + q.push_back(pkt); + get_cv.notify_one(); + } + void PostUnique(T pkt) + { + std::unique_lock lock(mutex); + if (Max > 0) + { + post_cv.wait(lock, [&]() { return unlocked | (q.size() < Max); }); + if (q.size() >= Max) return; + } + if (std::find(q.begin(), q.end(), pkt) == q.end()); + q.push_back(pkt); get_cv.notify_one(); } T Get()