threaded brush preview rendering
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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)));
|
||||
|
||||
@@ -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*> 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::StrokeFrame> 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);
|
||||
|
||||
@@ -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<NodeStrokePreview*> s_queue;
|
||||
static void terminate_renderer();
|
||||
std::shared_ptr<Brush> m_brush;
|
||||
std::shared_ptr<Brush> m_dual_brush;
|
||||
Stroke m_stroke;
|
||||
@@ -43,6 +48,7 @@ public:
|
||||
glm::vec4 stroke_draw_samples(std::array<vertex_t, 4>& P, Texture2D& blend_tex);
|
||||
std::vector<StrokeFrame> 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;
|
||||
|
||||
18
src/util.h
18
src/util.h
@@ -151,18 +151,18 @@ template<typename T> struct cbuffer
|
||||
template<typename T, int Max = 0>
|
||||
class BlockingQueue
|
||||
{
|
||||
public:
|
||||
std::deque<T> 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<std::mutex> 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<T>(pkt));
|
||||
q.push_back(pkt);
|
||||
get_cv.notify_one();
|
||||
}
|
||||
void PostUnique(T pkt)
|
||||
{
|
||||
std::unique_lock<std::mutex> 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()
|
||||
|
||||
Reference in New Issue
Block a user