render implement thread, wrap GL commands into tasks

This commit is contained in:
2019-07-06 22:25:07 +02:00
parent db27334ce5
commit 0012e2ce9b
18 changed files with 1252 additions and 904 deletions

View File

@@ -53,14 +53,12 @@ void App::open_document(std::string path)
// on complete // on complete
if (success) if (success)
{ {
async_start();
title_update(); title_update();
for (int layer_index = 0; layer_index < canvas->m_canvas->m_layers.size(); layer_index++) for (int layer_index = 0; layer_index < canvas->m_canvas->m_layers.size(); layer_index++)
{ {
auto l = layers->add_layer(canvas->m_canvas->m_layers[layer_index]->m_name.c_str(), false); auto l = layers->add_layer(canvas->m_canvas->m_layers[layer_index]->m_name.c_str(), false);
l->m_visibility->set_value(canvas->m_canvas->m_layers[layer_index]->m_visible); l->m_visibility->set_value(canvas->m_canvas->m_layers[layer_index]->m_visible);
} }
async_end();
} }
else else
{ {
@@ -80,7 +78,6 @@ bool App::request_close()
return true; return true;
if (!dialog_already_opened) if (!dialog_already_opened)
{ {
async_start();
auto* m = layout[main_id]->add_child<NodeMessageBox>(); auto* m = layout[main_id]->add_child<NodeMessageBox>();
m->m_title->set_text("Unsaved document"); m->m_title->set_text("Unsaved document");
m->m_message->set_text("Do you want to close without saving?"); m->m_message->set_text("Do you want to close without saving?");
@@ -100,8 +97,6 @@ bool App::request_close()
m->destroy(); m->destroy();
dialog_already_opened = false; dialog_already_opened = false;
}; };
async_redraw();
async_end();
dialog_already_opened = true; dialog_already_opened = true;
} }
return false; return false;
@@ -109,6 +104,7 @@ bool App::request_close()
void App::clear() void App::clear()
{ {
assert(is_render_thread());
glClearColor(.1f, .1f, .1f, 1.f); glClearColor(.1f, .1f, .1f, 1.f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
} }
@@ -384,17 +380,11 @@ void App::upload(std::string filename, std::string name, std::function<void(floa
} }
} }
void App::init()
{
#ifdef _WIN32 #ifdef _WIN32
if (glDebugMessageCallback) static CONSOLE_SCREEN_BUFFER_INFO info;
{ void handle_gl_callback(GLenum source, GLenum type, GLuint id,
static CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
// colors: http://stackoverflow.com/questions/4053837/colorizing-text-in-the-console-with-c
glDebugMessageCallback([](GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length, const GLchar* message, const void* userParam) GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{ {
static std::map<GLenum, int> colors = { static std::map<GLenum, int> colors = {
{ GL_DEBUG_SEVERITY_NOTIFICATION, 8 }, { GL_DEBUG_SEVERITY_NOTIFICATION, 8 },
{ GL_DEBUG_SEVERITY_LOW, 8 }, { GL_DEBUG_SEVERITY_LOW, 8 },
@@ -407,17 +397,35 @@ void App::init()
LOG("OPENGL: %.*s", length, message); LOG("OPENGL: %.*s", length, message);
FlushConsoleInputBuffer(GetStdHandle(STD_OUTPUT_HANDLE)); FlushConsoleInputBuffer(GetStdHandle(STD_OUTPUT_HANDLE));
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), info.wAttributes); SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), info.wAttributes);
#ifdef _WIN32 && _DEBUG #ifdef _DEBUG
if (severity == GL_DEBUG_SEVERITY_HIGH) if (severity == GL_DEBUG_SEVERITY_HIGH)
__debugbreak(); __debugbreak();
#endif #endif
} }
}, nullptr); }
#endif
void App::init()
{
#ifdef _WIN32
if (glDebugMessageCallback)
{
// colors: http://stackoverflow.com/questions/4053837/colorizing-text-in-the-console-with-c
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
render_task([]
{
glDebugMessageCallback(handle_gl_callback, nullptr);
glEnable(GL_DEBUG_OUTPUT); glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
});
} }
#endif #endif
LOG("Screen Resolution: %dx%d", (int)width, (int)height);
render_task([]
{
LOG("GL version: %s", glGetString(GL_VERSION)); LOG("GL version: %s", glGetString(GL_VERSION));
LOG("GL vendor: %s", glGetString(GL_VENDOR)); LOG("GL vendor: %s", glGetString(GL_VENDOR));
LOG("GL renderer: %s", glGetString(GL_RENDERER)); LOG("GL renderer: %s", glGetString(GL_RENDERER));
@@ -433,18 +441,14 @@ void App::init()
// } // }
//} //}
LOG("Screen Resolution: %dx%d", (int)width, (int)height);
//zoom = ceilf(width / 2000.f);
//zoom = 2;
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
#if defined(_WIN32) || defined(__OSX__) #if defined(_WIN32) || defined(__OSX__)
glEnable(GL_PROGRAM_POINT_SIZE); glEnable(GL_PROGRAM_POINT_SIZE);
glEnable(GL_LINE_SMOOTH); glEnable(GL_LINE_SMOOTH);
#endif #endif
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX); glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
});
int run_counter = Settings::value<Serializer::Integer>("run_counter") + 1; int run_counter = Settings::value<Serializer::Integer>("run_counter") + 1;
Settings::set("run_counter", Serializer::Integer(run_counter)); Settings::set("run_counter", Serializer::Integer(run_counter));
@@ -462,15 +466,6 @@ void App::init()
{ {
message_box("License", "Could not validate this license, running in demo mode."); message_box("License", "Could not validate this license, running in demo mode.");
} }
//GLfloat width_range[2];
//glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, width_range);
//LOG("GL line range: %f - %f", width_range[0], width_range[1]);
LOG("Screen Size: %f %f", width, height);
GLint fb0;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &fb0);
LOG("Default Framebuffer %d", fb0);
} }
void App::async_start() void App::async_start()
@@ -700,7 +695,6 @@ void App::terminate()
NodeStrokePreview::terminate_renderer(); NodeStrokePreview::terminate_renderer();
rec_stop(); rec_stop();
async_start();
TextureManager::invalidate(); TextureManager::invalidate();
ShaderManager::invalidate(); ShaderManager::invalidate();
layout.unload(); layout.unload();
@@ -716,7 +710,6 @@ void App::terminate()
floating_layers.reset(); floating_layers.reset();
floating_picker.reset(); floating_picker.reset();
quick_mode_state.clear(); quick_mode_state.clear();
async_end();
} }
void App::update_memory_usage(size_t bytes) void App::update_memory_usage(size_t bytes)

View File

@@ -249,4 +249,69 @@ public:
bool get_ui_rtl() const; bool get_ui_rtl() const;
void cmd_convert(std::string pano_path, std::string out_path); void cmd_convert(std::string pano_path, std::string out_path);
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;
}
// don't capture a reference to this ptr as the object may be destroyed
// by the time the task is executed
template<typename T, typename R = std::result_of<T()>::type>
std::future<R> render_task_async(T task)
{
#ifdef _WIN32
extern std::deque<std::packaged_task<R()>> render_tasklist;
extern std::mutex render_task_mutex;
extern std::condition_variable render_cv;
std::packaged_task<R()> pt(task);
std::future<R> f = pt.get_future();
if (is_render_thread())
{
pt();
}
else
{
{
std::lock_guard<std::mutex> lock(render_task_mutex);
render_tasklist.push_back(std::move(pt));
}
render_cv.notify_all();
}
return f;
#endif // _WIN32
}
template<typename T, typename R = std::result_of<T()>::type>
R render_task(T task)
{
#ifdef _WIN32
extern std::deque<std::packaged_task<R()>> render_tasklist;
extern std::mutex render_task_mutex;
extern std::condition_variable render_cv;
std::packaged_task<R()> pt(task);
std::future<R> f = pt.get_future();
if (is_render_thread())
{
pt();
}
else
{
{
std::lock_guard<std::mutex> lock(render_task_mutex);
render_tasklist.push_back(std::move(pt));
}
render_cv.notify_all();
}
return f.get();
#endif // _WIN32
}
void render_sync()
{
render_task([] {});
}
}; };

View File

@@ -28,7 +28,6 @@ std::shared_ptr<NodeProgressBar> App::show_progress(const std::string& title)
NodeMessageBox* App::message_box(const std::string &title, const std::string& text, bool cancel_button) NodeMessageBox* App::message_box(const std::string &title, const std::string& text, bool cancel_button)
{ {
async_start();
auto* m = layout[main_id]->add_child<NodeMessageBox>(); auto* m = layout[main_id]->add_child<NodeMessageBox>();
m->m_title->set_text(title.c_str()); m->m_title->set_text(title.c_str());
m->m_message->set_text(text.c_str()); m->m_message->set_text(text.c_str());
@@ -36,8 +35,6 @@ NodeMessageBox* App::message_box(const std::string &title, const std::string& te
if (!cancel_button) if (!cancel_button)
m->btn_cancel->destroy(); m->btn_cancel->destroy();
layout[main_id]->update(); layout[main_id]->update();
async_redraw();
async_end();
return m; return m;
} }
@@ -80,7 +77,6 @@ void App::dialog_about()
void App::dialog_newdoc() void App::dialog_newdoc()
{ {
auto show_dialog = [this] { auto show_dialog = [this] {
async_start();
auto dialog = std::make_shared<NodeDialogNewDoc>(); auto dialog = std::make_shared<NodeDialogNewDoc>();
dialog->m_manager = &layout; dialog->m_manager = &layout;
dialog->init(); dialog->init();
@@ -153,7 +149,6 @@ void App::dialog_newdoc()
dialog->destroy(); dialog->destroy();
App::I.hideKeyboard(); App::I.hideKeyboard();
}; };
async_end();
}; };
if (canvas) if (canvas)
@@ -190,7 +185,6 @@ void App::dialog_newdoc()
void App::dialog_open() void App::dialog_open()
{ {
auto show_dialog = [this] { auto show_dialog = [this] {
async_start();
// load thumbnail test // load thumbnail test
auto dialog = std::make_shared<NodeDialogOpen>(); auto dialog = std::make_shared<NodeDialogOpen>();
dialog->m_manager = &layout; dialog->m_manager = &layout;
@@ -217,7 +211,6 @@ void App::dialog_open()
// dialog->destroy(); // dialog->destroy();
// ActionManager::clear(); // ActionManager::clear();
}; };
async_end();
}; };
if (canvas) if (canvas)
@@ -253,7 +246,6 @@ void App::dialog_open()
void App::dialog_browse() void App::dialog_browse()
{ {
auto show_dialog = [this] { auto show_dialog = [this] {
async_start();
// load thumbnail test // load thumbnail test
auto dialog = std::make_shared<NodeDialogBrowse>(); auto dialog = std::make_shared<NodeDialogBrowse>();
dialog->m_manager = &layout; dialog->m_manager = &layout;
@@ -277,7 +269,6 @@ void App::dialog_browse()
dialog->destroy(); dialog->destroy();
} }
}; };
async_end();
}; };
if (canvas) if (canvas)

View File

@@ -9,6 +9,7 @@ void App::initShaders()
std::logic_error("check_uniform_uniqueness() failed"); std::logic_error("check_uniform_uniqueness() failed");
#endif // _DEBUG #endif // _DEBUG
render_task([] {
GLint n_exts; GLint n_exts;
glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts); glGetIntegerv(GL_NUM_EXTENSIONS, &n_exts);
for (int i = 0; i < n_exts; i++) for (int i = 0; i < n_exts; i++)
@@ -19,6 +20,7 @@ void App::initShaders()
ShaderManager::ext_framebuffer_fetch = true; ShaderManager::ext_framebuffer_fetch = true;
} }
} }
});
LOG("Shader Extension shader_framebuffer_fetch: %s", ShaderManager::ext_framebuffer_fetch ? "enabled" : "disabled"); LOG("Shader Extension shader_framebuffer_fetch: %s", ShaderManager::ext_framebuffer_fetch ? "enabled" : "disabled");

View File

@@ -6,6 +6,7 @@
void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4& proj) void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4& proj)
{ {
assert(App::I.is_render_thread());
std::vector<instance_t> attributes; std::vector<instance_t> attributes;
attributes.reserve(samples.size()); attributes.reserve(samples.size());
for (const auto& s : samples) for (const auto& s : samples)
@@ -69,6 +70,9 @@ void BrushMesh::draw(const std::vector<StrokeSample>& samples, const glm::mat4&
} }
bool BrushMesh::create() bool BrushMesh::create()
{ {
bool ret = true;
App::I.render_task([&]
{
static GLushort idx[6]{ 0, 1, 2, 0, 2, 3 }; static GLushort idx[6]{ 0, 1, 2, 0, 2, 3 };
static vertex_t vertices[4]{ static vertex_t vertices[4]{
{ { -.5f, -.5f, 0, 1 }, { 0, 0 } }, // A B----C { { -.5f, -.5f, 0, 1 }, { 0, 0 } }, // A B----C
@@ -78,7 +82,10 @@ bool BrushMesh::create()
}; };
glGenBuffers(3, buffers); glGenBuffers(3, buffers);
if (!(buffers[0] && buffers[1] && buffers[2])) if (!(buffers[0] && buffers[1] && buffers[2]))
return false; {
ret = false;
return;
}
static instance_t inst{ glm::mat4(1), .1f }; static instance_t inst{ glm::mat4(1), .1f };
glBindBuffer(GL_ARRAY_BUFFER, buffers[2]); glBindBuffer(GL_ARRAY_BUFFER, buffers[2]);
@@ -99,7 +106,10 @@ bool BrushMesh::create()
#if USE_VBO #if USE_VBO
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
if (!vao) if (!vao)
return false; {
ret = false;
return;
}
glBindVertexArray(vao); glBindVertexArray(vao);
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
@@ -125,8 +135,9 @@ bool BrushMesh::create()
glVertexAttribDivisor(loc_flow, 1); glVertexAttribDivisor(loc_flow, 1);
glBindVertexArray(0); glBindVertexArray(0);
#endif #endif
});
return true; return ret;
} }
StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, float dir_angle) StrokeSample Stroke::randomize_sample(const glm::vec3& pos, float pressure, float dir_angle)
{ {

View File

@@ -1474,10 +1474,13 @@ void Canvas::FloodData::apply()
if (!dirty[plane]) if (!dirty[plane])
continue; continue;
auto& rtt = layer->m_rtt[plane]; auto& rtt = layer->m_rtt[plane];
App::I.render_task([&]
{
rtt.bindTexture(); rtt.bindTexture();
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rtt.getWidth(), rtt.getHeight(), glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, rtt.getWidth(), rtt.getHeight(),
GL_RGBA, GL_UNSIGNED_BYTE, rgb[plane].get()); GL_RGBA, GL_UNSIGNED_BYTE, rgb[plane].get());
rtt.unbindTexture(); rtt.unbindTexture();
});
layer->m_dirty_face[plane] = true; layer->m_dirty_face[plane] = true;
} }
} }
@@ -2766,6 +2769,11 @@ bool Canvas::project_open_thread(std::string file_path)
Image Canvas::thumbnail_generate(int w, int h) Image Canvas::thumbnail_generate(int w, int h)
{ {
Image image;
image.create(w, h);
App::I.render_task([this, w, h, &image]
{
// save viewport and clear color states // save viewport and clear color states
GLint vp[4]; GLint vp[4];
GLfloat cc[4]; GLfloat cc[4];
@@ -2859,8 +2867,6 @@ Image Canvas::thumbnail_generate(int w, int h)
fb.unbindFramebuffer(); fb.unbindFramebuffer();
// read the rendered image // read the rendered image
Image image;
image.create(w, h);
fb.readTextureData((uint8_t*)image.data()); fb.readTextureData((uint8_t*)image.data());
fb.destroy(); fb.destroy();
@@ -2871,6 +2877,7 @@ Image Canvas::thumbnail_generate(int w, int h)
glViewport(vp[0], vp[1], vp[2], vp[3]); glViewport(vp[0], vp[1], vp[2], vp[3]);
glClearColor(cc[0], cc[1], cc[2], cc[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
});
return image; return image;
} }
@@ -2904,6 +2911,8 @@ Image Canvas::thumbnail_read(std::string file_path)
void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer) void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer)
{ {
App::I.render_task([&]
{
// save viewport and clear color states // save viewport and clear color states
GLint vp[4]; GLint vp[4];
GLfloat cc[4]; GLfloat cc[4];
@@ -2946,10 +2955,13 @@ void Canvas::draw_objects_direct(std::function<void(const glm::mat4& camera, con
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
draw_merge(); draw_merge();
});
} }
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer) void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer, Layer& layer)
{ {
App::I.render_task([&]
{
// save viewport and clear color states // save viewport and clear color states
GLint vp[4]; GLint vp[4];
GLfloat cc[4]; GLfloat cc[4];
@@ -3038,6 +3050,7 @@ void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm:
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
draw_merge(); draw_merge();
});
} }
void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer) void Canvas::draw_objects(std::function<void(const glm::mat4& camera, const glm::mat4& proj, int i)> observer)
@@ -3153,7 +3166,6 @@ void Layer::destroy()
void Layer::optimize() void Layer::optimize()
{ {
int saved_bytes = 0; int saved_bytes = 0;
glBindTexture(GL_TEXTURE_2D, 0);
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
if (!m_dirty_face[i]) if (!m_dirty_face[i])
@@ -3209,6 +3221,8 @@ void Layer::restore(const Snapshot& snap)
// it's just a quick fix DON'T SHIP!! // it's just a quick fix DON'T SHIP!!
//m_rtt[i].recreate(); //m_rtt[i].recreate();
App::I.render_task_async([this,i,&snap]
{
m_rtt[i].bindTexture(); m_rtt[i].bindTexture();
glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]); glm::vec2 box_sz = zw(m_dirty_box[i]) - xy(m_dirty_box[i]);
glTexSubImage2D(GL_TEXTURE_2D, 0, glTexSubImage2D(GL_TEXTURE_2D, 0,
@@ -3218,15 +3232,14 @@ void Layer::restore(const Snapshot& snap)
m_rtt[i].unbindTexture(); m_rtt[i].unbindTexture();
LOG("restore face %d - %d bytes (%dx%d)", i, LOG("restore face %d - %d bytes (%dx%d)", i,
(int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y); (int)box_sz.x * (int)box_sz.y * 4, (int)box_sz.x, (int)box_sz.y);
});
} }
App::I.render_sync();
} }
Layer::Snapshot Layer::snapshot(std::array<glm::vec4, 6> * dirty_box /*= nullptr*/, std::array<bool, 6> * dirty_face /*= nullptr*/) Layer::Snapshot Layer::snapshot(std::array<glm::vec4, 6> * dirty_box /*= nullptr*/, std::array<bool, 6> * dirty_face /*= nullptr*/)
{ {
Snapshot snap; Snapshot snap;
static int counter = 0;
glBindTexture(GL_TEXTURE_2D, 0);
//glBindFramebuffer(GL_FRAMEBUFFER, 0);
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : m_dirty_box[i]; snap.m_dirty_box[i] = dirty_box ? dirty_box->at(i) : m_dirty_box[i];
@@ -3238,18 +3251,23 @@ Layer::Snapshot Layer::snapshot(std::array<glm::vec4, 6> * dirty_box /*= nullptr
snap.image[i] = std::make_unique<uint8_t[]>(m_rtt[i].bytes()); snap.image[i] = std::make_unique<uint8_t[]>(m_rtt[i].bytes());
//glReadBuffer(GL_BACK); //glReadBuffer(GL_BACK);
App::I.render_task_async([this,i,&snap]
{
m_rtt[i].bindFramebuffer(); m_rtt[i].bindFramebuffer();
glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]); glm::vec2 box_sz = zw(snap.m_dirty_box[i]) - xy(snap.m_dirty_box[i]);
glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get()); glReadPixels(snap.m_dirty_box[i].x, snap.m_dirty_box[i].y, box_sz.x, box_sz.y, GL_RGBA, GL_UNSIGNED_BYTE, snap.image[i].get());
m_rtt[i].unbindFramebuffer(); m_rtt[i].unbindFramebuffer();
});
//glReadBuffer(GL_NONE); //glReadBuffer(GL_NONE);
} }
counter++; App::I.render_sync();
return snap; return snap;
} }
void Layer::clear(const glm::vec4& c) void Layer::clear(const glm::vec4& c)
{ {
App::I.render_task([&]
{
// push clear color state // push clear color state
GLfloat cc[4]; GLfloat cc[4];
glGetFloatv(GL_COLOR_CLEAR_VALUE, cc); glGetFloatv(GL_COLOR_CLEAR_VALUE, cc);
@@ -3277,6 +3295,7 @@ void Layer::clear(const glm::vec4& c)
// restore clear color state // restore clear color state
glClearColor(cc[0], cc[1], cc[2], cc[3]); glClearColor(cc[0], cc[1], cc[2], cc[3]);
});
} }
bool Layer::create(int width, int height, std::string name) bool Layer::create(int width, int height, std::string name)
@@ -3284,6 +3303,8 @@ bool Layer::create(int width, int height, std::string name)
m_name = name; m_name = name;
w = width; w = width;
h = height; h = height;
App::I.render_task([&]
{
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
m_rtt[i].create(width, height); m_rtt[i].create(width, height);
@@ -3293,6 +3314,7 @@ bool Layer::create(int width, int height, std::string name)
m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box m_dirty_box[i] = glm::vec4(w, h, 0, 0); // reset bounding box
m_dirty_face[i] = false; m_dirty_face[i] = false;
} }
});
return true; return true;
} }

View File

@@ -213,6 +213,7 @@ void CanvasModePen::on_MouseEvent(MouseEvent* me, glm::vec2& loc)
void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera) void CanvasModePen::on_Draw(const glm::mat4& ortho, const glm::mat4& proj, const glm::mat4& camera)
{ {
assert(App::I.is_render_thread());
if (m_draw_tip) if (m_draw_tip)
{ {
const auto& brush = Canvas::I->m_current_brush; const auto& brush = Canvas::I->m_current_brush;

View File

@@ -3,6 +3,8 @@
#include "font.h" #include "font.h"
#include "shader.h" #include "shader.h"
#include "asset.h" #include "asset.h"
#include "util.h"
#include "app.h"
std::map<kFont, Font> FontManager::m_fonts; std::map<kFont, Font> FontManager::m_fonts;
Sampler FontManager::m_sampler; Sampler FontManager::m_sampler;
@@ -58,6 +60,8 @@ const Font& FontManager::get(kFont id)
bool TextMesh::create() bool TextMesh::create()
{ {
App::I.render_task([this]
{
glGenBuffers(2, font_buffers); glGenBuffers(2, font_buffers);
#if USE_VBO #if USE_VBO
glGenVertexArrays(1, &font_array); glGenVertexArrays(1, &font_array);
@@ -67,9 +71,10 @@ bool TextMesh::create()
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]); glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)(sizeof(float)*2)); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (GLvoid*)(sizeof(float) * 2));
glBindVertexArray(0); glBindVertexArray(0);
#endif // USE_VBO #endif // USE_VBO
});
return true; return true;
} }
@@ -120,17 +125,21 @@ void TextMesh::update(kFont id, const char* text)
vi -= glm::vec4(bbmin, 0, 0); vi -= glm::vec4(bbmin, 0, 0);
bb = bbmax - bbmin; bb = bbmax - bbmin;
font_array_count = (int)idx.size(); font_array_count = (int)idx.size();
App::I.render_task([&]
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, font_buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx.size() * sizeof(GLushort), idx.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]); glBindBuffer(GL_ARRAY_BUFFER, font_buffers[0]);
glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(glm::vec4), v.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, v.size() * sizeof(glm::vec4), v.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
});
} }
} }
void TextMesh::draw() void TextMesh::draw()
{ {
assert(App::I.is_render_thread());
auto& f = FontManager::get(font_id); auto& f = FontManager::get(font_id);
if (f.font_tex.ready()) if (f.font_tex.ready())
{ {

View File

@@ -33,12 +33,19 @@ std::thread::id gl_thread;
std::map<kKey, int> vkey_map; std::map<kKey, int> vkey_map;
std::thread hmd_renderer; std::thread hmd_renderer;
std::thread renderer; std::thread ui_renderer;
int vr_frames = 0; int vr_frames = 0;
int running = -1; int running = -1;
int vr_running = 0; int vr_running = 0;
std::mutex render_mutex; std::mutex ui_render_mutex;
std::condition_variable ui_render_cv;
std::deque<std::packaged_task<void()>> render_tasklist;
std::mutex render_task_mutex;
std::condition_variable render_cv; std::condition_variable render_cv;
std::thread render_thread;
std::thread::id render_thread_id;
bool render_running = false;
int gl_count = 0; int gl_count = 0;
std::deque<std::packaged_task<void()>> tasklist; std::deque<std::packaged_task<void()>> tasklist;
@@ -112,6 +119,63 @@ 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<typename T, typename R = std::result_of<T()>::type>
std::future<R> render_task_async(T task)
{
#ifdef _WIN32
extern std::deque<std::packaged_task<R()>> render_tasklist;
extern std::mutex render_task_mutex;
extern std::condition_variable render_cv;
std::packaged_task<R()> pt(task);
std::future<R> f = pt.get_future();
if (is_render_thread())
{
pt();
}
else
{
{
std::lock_guard<std::mutex> lock(render_task_mutex);
render_tasklist.push_back(std::move(pt));
}
render_cv.notify_all();
}
return f;
#endif // _WIN32
}
template<typename T, typename R = std::result_of<T()>::type>
R render_task(T task)
{
#ifdef _WIN32
extern std::deque<std::packaged_task<R()>> render_tasklist;
extern std::mutex render_task_mutex;
extern std::condition_variable render_cv;
std::packaged_task<R()> pt(task);
std::future<R> f = pt.get_future();
if (is_render_thread())
{
pt();
}
else
{
{
std::lock_guard<std::mutex> lock(render_task_mutex);
render_tasklist.push_back(std::move(pt));
}
render_cv.notify_all();
}
return f.get();
#endif // _WIN32
}
void async_lock() void async_lock()
{ {
//std::lock_guard<std::mutex> _lock(async_mutex); //std::lock_guard<std::mutex> _lock(async_mutex);
@@ -166,7 +230,7 @@ void async_unlock()
void win32_render_thread_notify() void win32_render_thread_notify()
{ {
render_cv.notify_all(); ui_render_cv.notify_all();
} }
void win32_show_cursor(bool visible) void win32_show_cursor(bool visible)
@@ -257,12 +321,6 @@ std::string win32_open_dir()
return Buffer; return Buffer;
} }
struct async_locker
{
async_locker() { async_lock(); }
~async_locker() { async_unlock(); }
};
int read_WMI_info() int read_WMI_info()
{ {
// see: http://win32easy.blogspot.co.uk/2011/03/wmi-in-c-query-everyting-from-your-os.html // see: http://win32easy.blogspot.co.uk/2011/03/wmi-in-c-query-everyting-from-your-os.html
@@ -539,16 +597,13 @@ bool win32_vr_start()
vive = new Vive; vive = new Vive;
vive->on_draw = [](const glm::mat4& proj, const glm::mat4& view, const glm::mat4& pose) { App::I.vr_draw(proj, view, pose); }; vive->on_draw = [](const glm::mat4& proj, const glm::mat4& view, const glm::mat4& pose) { App::I.vr_draw(proj, view, pose); };
async_lock();
if (!vive->Initialize()) if (!vive->Initialize())
{ {
delete vive; delete vive;
vive = nullptr; vive = nullptr;
LOG("VR: failed to initialize vive"); LOG("VR: failed to initialize vive");
async_unlock();
return false; return false;
} }
async_unlock();
hmd_renderer = std::thread([&] { hmd_renderer = std::thread([&] {
if (!vive) if (!vive)
@@ -726,6 +781,46 @@ BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle
return fRc; 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<std::packaged_task<void()>> working_list;
// 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, [] { return render_tasklist.empty() && render_running ? false : true; });
working_list = std::move(render_tasklist);
}
//{
// std::lock_guard<std::mutex> 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) int main(int argc, char** argv)
{ {
WNDCLASS wc; WNDCLASS wc;
@@ -917,7 +1012,10 @@ int main(int argc, char** argv)
LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str()); LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str());
} }
async_lock(); wglMakeCurrent(NULL, NULL);
running = 1;
render_thread = std::thread(render_thread_main);
LOG("init app"); LOG("init app");
App::I.init(); App::I.init();
@@ -932,15 +1030,11 @@ int main(int argc, char** argv)
LOG("SKIP init WinTab"); LOG("SKIP init WinTab");
} }
async_unlock();
LOG("change icon"); LOG("change icon");
SendMessage(hWnd, WM_SETICON, ICON_SMALL, SendMessage(hWnd, WM_SETICON, ICON_SMALL,
(LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1))); (LPARAM)LoadIcon(GetModuleHandle(0), MAKEINTRESOURCE(IDI_ICON1)));
running = 1; ui_renderer = std::thread([&] {
renderer = std::thread([&] {
BT_SetTerminate(); BT_SetTerminate();
LOG("start render thread"); LOG("start render thread");
const float target_fps = 10; const float target_fps = 10;
@@ -989,13 +1083,11 @@ int main(int argc, char** argv)
if (!working_list.empty()) if (!working_list.empty())
{ {
async_lock();
while (!working_list.empty()) while (!working_list.empty())
{ {
working_list.front()(); working_list.front()();
working_list.pop_front(); working_list.pop_front();
} }
async_unlock();
//LOG("clear"); //LOG("clear");
//WacomTablet::I.m_stylus = false; //WacomTablet::I.m_stylus = false;
//WacomTablet::I.m_eraser = false; //WacomTablet::I.m_eraser = false;
@@ -1016,7 +1108,7 @@ int main(int argc, char** argv)
App::I.tick(dt); App::I.tick(dt);
std::unique_lock<std::mutex> lock(render_mutex); std::unique_lock<std::mutex> lock(ui_render_mutex);
if (render_timer > 1.0f / target_fps) if (render_timer > 1.0f / target_fps)
{ {
App::I.redraw = true; App::I.redraw = true;
@@ -1041,19 +1133,20 @@ int main(int argc, char** argv)
if (App::I.redraw) if (App::I.redraw)
{ {
async_lock(); render_task([frame_timer]
{
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
App::I.clear(); App::I.clear();
App::I.update(frame_timer); App::I.update(frame_timer);
SwapBuffers(hDC); SwapBuffers(hDC);
async_unlock(); });
frame_timer = 0; frame_timer = 0;
frames++; frames++;
} }
const int framerate = (1.f / target_tick_rate) * 1000; const int framerate = (1.f / target_tick_rate) * 1000;
const int diff = framerate - (t1 - t0); const int diff = framerate - (t1 - t0);
render_cv.wait_for(lock, std::chrono::milliseconds(diff)); //render_cv.wait_for(lock, std::chrono::milliseconds(diff));
//std::this_thread::sleep_for(std::chrono::milliseconds(30)); //std::this_thread::sleep_for(std::chrono::milliseconds(30));
t0 = t1; t0 = t1;
} }
@@ -1109,10 +1202,11 @@ int main(int argc, char** argv)
} }
if (!tasklist.empty()) if (!tasklist.empty())
render_cv.notify_all(); ui_render_cv.notify_all();
} }
// Clean up // Clean up
WacomTablet::I.terminate(); WacomTablet::I.terminate();
render_cv.notify_all();
UnregisterClass(className, hInst); UnregisterClass(className, hInst);
LogRemote::I.stop(); LogRemote::I.stop();
@@ -1132,13 +1226,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{ {
case WM_USER_CLOSE: case WM_USER_CLOSE:
running = 0; running = 0;
render_cv.notify_all(); ui_render_cv.notify_all();
if (renderer.joinable()) if (ui_renderer.joinable())
renderer.join(); ui_renderer.join();
if (hmd_renderer.joinable()) if (hmd_renderer.joinable())
hmd_renderer.join(); hmd_renderer.join();
App::I.terminate(); App::I.terminate();
PostQuitMessage(0); PostQuitMessage(0);
render_running = false;
if (render_thread.joinable())
render_thread.join();
return 0; return 0;
case WM_PAINT: case WM_PAINT:
App::I.redraw = true; App::I.redraw = true;
@@ -1150,13 +1247,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
if (App::I.request_close()) if (App::I.request_close())
{ {
running = 0; running = 0;
render_cv.notify_all(); ui_render_cv.notify_all();
if (renderer.joinable()) if (ui_renderer.joinable())
renderer.join(); ui_renderer.join();
if (hmd_renderer.joinable()) if (hmd_renderer.joinable())
hmd_renderer.join(); hmd_renderer.join();
App::I.terminate(); App::I.terminate();
PostQuitMessage(0); PostQuitMessage(0);
render_running = false;
if (render_thread.joinable())
render_thread.join();
return 0; return 0;
} }
else else
@@ -1170,12 +1270,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
auto h = (float)HIWORD(lp); auto h = (float)HIWORD(lp);
if (h != 0 && running == 1) if (h != 0 && running == 1)
{ {
async_locker lock; App::I.render_task([=]
{
App::I.resize(w, h); App::I.resize(w, h);
App::I.clear(); App::I.clear();
App::I.redraw = true; App::I.redraw = true;
App::I.update(0.f); App::I.update(0.f);
SwapBuffers(hDC); SwapBuffers(hDC);
});
} }
break; break;
} }
@@ -1374,7 +1476,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
break; break;
case WM_MOUSEWHEEL: case WM_MOUSEWHEEL:
{ {
async_locker lock;
POINT pt; POINT pt;
pt.x = GET_X_LPARAM(lp); pt.x = GET_X_LPARAM(lp);
pt.y = GET_Y_LPARAM(lp); pt.y = GET_Y_LPARAM(lp);

View File

@@ -2,6 +2,7 @@
#include "node_colorwheel.h" #include "node_colorwheel.h"
#include "shader.h" #include "shader.h"
#include "log.h" #include "log.h"
#include "app.h"
Node* NodeColorWheel::clone_instantiate() const Node* NodeColorWheel::clone_instantiate() const
{ {
@@ -42,9 +43,11 @@ void NodeColorWheel::loaded()
vertices.push_back({{glm::cos(2.f/3.f*glm::pi<float>())*l,glm::sin(2.f/3.f*glm::pi<float>())*l,0,1},{0,0},{0,0,0,1}}); vertices.push_back({{glm::cos(2.f/3.f*glm::pi<float>())*l,glm::sin(2.f/3.f*glm::pi<float>())*l,0,1},{0,0},{0,0,0,1}});
vertices.push_back({{l,0,0,1},{1,1},{1,0,0,1}}); vertices.push_back({{l,0,0,1},{1,1},{1,0,0,1}});
App::I.render_task([&]
{
glGenBuffers(1, &buffers); glGenBuffers(1, &buffers);
glBindBuffer(GL_ARRAY_BUFFER, buffers); glBindBuffer(GL_ARRAY_BUFFER, buffers);
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vertex_t), vertices.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(vertex_t), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenVertexArrays(1, &arrays); glGenVertexArrays(1, &arrays);
@@ -57,6 +60,7 @@ void NodeColorWheel::loaded()
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs)); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, uvs));
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, col)); glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (GLvoid*)offsetof(vertex_t, col));
glBindVertexArray(0); glBindVertexArray(0);
});
} }
void NodeColorWheel::draw() void NodeColorWheel::draw()

View File

@@ -151,11 +151,14 @@ void NodePanelGrid::init_controls()
m_texture.create_mipmaps(); m_texture.create_mipmaps();
#else #else
// get the texture data and resize it // get the texture data and resize it
m_texture.bind();
Image img; Image img;
img.create(m_texture.size().x, m_texture.size().y); img.create(m_texture.size().x, m_texture.size().y);
App::I.render_task([&]
{
m_texture.bind();
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.m_data.get()); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.m_data.get());
m_texture.unbind(); m_texture.unbind();
});
Image resized = img.resize(texres, texres); Image resized = img.resize(texres, texres);
m_texture.create(resized); m_texture.create(resized);
m_texture.create_mipmaps(); m_texture.create_mipmaps();
@@ -169,9 +172,6 @@ void NodePanelGrid::init_controls()
m_plane.create<1>(1, 1); m_plane.create<1>(1, 1);
TextureManager::load("data/sun.png"); TextureManager::load("data/sun.png");
//glGetFloatv(GL_SMOOTH_LINE_WIDTH_RANGE, m_line_range);
//glGetFloatv(GL_ALIASED_LINE_WIDTH_GRANULARITY, &m_line_granularity);
} }
int NodePanelGrid::get_samples() const int NodePanelGrid::get_samples() const

View File

@@ -514,13 +514,11 @@ void NodeStrokePreview::draw_stroke()
// Good luck, future Omar // Good luck, future Omar
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
#endif #endif
App::I.async_start();
m_sampler_linear.create(); m_sampler_linear.create();
m_sampler_linear_repeat.create(GL_LINEAR, GL_REPEAT); m_sampler_linear_repeat.create(GL_LINEAR, GL_REPEAT);
m_sampler_mipmap.create(); m_sampler_mipmap.create();
m_sampler_mipmap.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR); m_sampler_mipmap.set_filter(GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR);
m_brush_shape.create(); m_brush_shape.create();
App::I.async_end();
while (s_running) while (s_running)
{ {
auto node = s_queue.Get(); auto node = s_queue.Get();
@@ -530,8 +528,8 @@ void NodeStrokePreview::draw_stroke()
bool to_unload = (node->m_brush->m_tip_texture == nullptr); bool to_unload = (node->m_brush->m_tip_texture == nullptr);
node->m_brush->preload(); node->m_brush->preload();
node->async_start(); App::I.render_task([node, to_unload]
{
gl_state gl; gl_state gl;
gl.save(); gl.save();
@@ -553,20 +551,18 @@ void NodeStrokePreview::draw_stroke()
node->m_brush->unload(); node->m_brush->unload();
gl.restore(); gl.restore();
node->app_redraw(); });
node->async_end();
//std::this_thread::sleep_for(std::chrono::milliseconds(30)); //std::this_thread::sleep_for(std::chrono::milliseconds(30));
std::this_thread::yield(); std::this_thread::yield();
} }
} }
App::I.async_start();
m_rtt.destroy(); m_rtt.destroy();
m_rtt_mixer.destroy(); m_rtt_mixer.destroy();
m_tex.destroy(); m_tex.destroy();
m_tex_dual.destroy(); m_tex_dual.destroy();
m_tex_background.destroy(); m_tex_background.destroy();
m_brush_shape.destroy(); m_brush_shape.destroy();
App::I.async_end();
}); });
} }
s_queue.mutex.unlock(); s_queue.mutex.unlock();

View File

@@ -2,6 +2,7 @@
#include "log.h" #include "log.h"
#include "rtt.h" #include "rtt.h"
#include "util.h" #include "util.h"
#include "app.h"
RTT::RTT() RTT::RTT()
{ {
@@ -38,6 +39,8 @@ void RTT::resize(int width, int height)
{ {
RTT new_rtt; RTT new_rtt;
App::I.render_task([&]
{
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID); glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
@@ -51,6 +54,7 @@ void RTT::resize(int width, int height)
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID); glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
destroy(); destroy();
});
oldRFboID = 0; oldRFboID = 0;
oldDFboID = 0; oldDFboID = 0;
@@ -64,22 +68,25 @@ void RTT::resize(int width, int height)
void RTT::destroy() void RTT::destroy()
{ {
App::I.render_task_async([rboID=rboID, texID=texID, fboID=fboID]
{
if (rboID) if (rboID)
{ {
glDeleteRenderbuffers(1, &rboID); glDeleteRenderbuffers(1, &rboID);
} }
if (texID) if (texID)
{ {
unbindTexture(); //unbindTexture();
glDeleteTextures(1, &texID); glDeleteTextures(1, &texID);
//LOG("TEX rtt destroy %d", texID) //LOG("TEX rtt destroy %d", texID)
} }
if (fboID) if (fboID)
{ {
unbindFramebuffer(); //unbindFramebuffer();
glDeleteFramebuffers(1, &fboID); glDeleteFramebuffers(1, &fboID);
//LOG("RTT DESTROY %d", fboID); //LOG("RTT DESTROY %d", fboID);
} }
});
texID = 0; texID = 0;
fboID = 0; fboID = 0;
rboID = 0; rboID = 0;
@@ -89,6 +96,8 @@ void RTT::destroy()
void RTT::copy(const RTT & source) void RTT::copy(const RTT & source)
{ {
App::I.render_task([&]
{
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID); glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
@@ -98,10 +107,14 @@ void RTT::copy(const RTT & source)
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID); glBindFramebuffer(GL_READ_FRAMEBUFFER, oldRFboID);
});
} }
bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/) bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format, bool depth_buffer /*= false*/)
{ {
GLenum status = 0;
App::I.render_task([&]
{
// Destroy any previously created object // Destroy any previously created object
destroy(); destroy();
@@ -170,7 +183,7 @@ bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format,
}; };
// Check FBO status // Check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) if (status != GL_FRAMEBUFFER_COMPLETE)
LOG("RTT::create failed because: %s", err2str(status)); LOG("RTT::create failed because: %s", err2str(status));
@@ -178,12 +191,14 @@ bool RTT::create(int width, int height, int tex/* = -1*/, GLint internal_format,
glBindFramebuffer(GL_FRAMEBUFFER, oldFboID); glBindFramebuffer(GL_FRAMEBUFFER, oldFboID);
oldRFboID = 0; oldRFboID = 0;
oldDFboID = 0; oldDFboID = 0;
});
return status == GL_FRAMEBUFFER_COMPLETE; return status == GL_FRAMEBUFFER_COMPLETE;
} }
void RTT::bindFramebuffer() void RTT::bindFramebuffer()
{ {
assert(App::I.is_render_thread());
#ifdef _DEBUG #ifdef _DEBUG
if (bound) if (bound)
{ {
@@ -193,15 +208,16 @@ void RTT::bindFramebuffer()
#endif #endif
} }
#endif // _DEBUG #endif // _DEBUG
bound = true;
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID); glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &oldDFboID);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID); glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &oldRFboID);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fboID);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID); glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
bound = true;
} }
void RTT::unbindFramebuffer() void RTT::unbindFramebuffer()
{ {
assert(App::I.is_render_thread());
if (!bound) if (!bound)
return; return;
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, oldDFboID);
@@ -213,6 +229,7 @@ void RTT::unbindFramebuffer()
void RTT::clear(glm::vec4 color) void RTT::clear(glm::vec4 color)
{ {
assert(App::I.is_render_thread());
glClearColor(color.r, color.g, color.b, color.a); glClearColor(color.r, color.g, color.b, color.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
} }
@@ -240,11 +257,14 @@ uint8_t* RTT::readTextureData(uint8_t* buffer)
{ {
if (!buffer) if (!buffer)
buffer = createBuffer(); buffer = createBuffer();
App::I.render_task([&]
{
GLint old; GLint old;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old); glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID); glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer); glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER, old); glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
});
return buffer; return buffer;
} }
@@ -252,11 +272,14 @@ float* RTT::readTextureDataFloat(float* buffer)
{ {
if (!buffer) if (!buffer)
buffer = createBufferFloat(); buffer = createBufferFloat();
App::I.render_task([&]
{
GLint old; GLint old;
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old); glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID); glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID);
glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer); glReadPixels(0, 0, w, h, GL_RGBA, GL_FLOAT, buffer);
glBindFramebuffer(GL_READ_FRAMEBUFFER, old); glBindFramebuffer(GL_READ_FRAMEBUFFER, old);
});
return buffer; return buffer;
} }
@@ -272,11 +295,13 @@ float * RTT::createBufferFloat()
void RTT::bindTexture() void RTT::bindTexture()
{ {
assert(App::I.is_render_thread());
glBindTexture(GL_TEXTURE_2D, texID); glBindTexture(GL_TEXTURE_2D, texID);
} }
void RTT::unbindTexture() void RTT::unbindTexture()
{ {
assert(App::I.is_render_thread());
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }

View File

@@ -2,6 +2,7 @@
#include "log.h" #include "log.h"
#include "shader.h" #include "shader.h"
#include "asset.h" #include "asset.h"
#include "app.h"
std::map<kShader, Shader> ShaderManager::m_shaders; std::map<kShader, Shader> ShaderManager::m_shaders;
Shader* ShaderManager::m_current; Shader* ShaderManager::m_current;
@@ -153,6 +154,9 @@ bool Shader::reload()
bool Shader::create(const char* vertex, const char* fragment) bool Shader::create(const char* vertex, const char* fragment)
{ {
bool ret = true;
App::I.render_task([&]
{
GLint status; GLint status;
static char infolog[4096]; static char infolog[4096];
int infolen; int infolen;
@@ -161,7 +165,8 @@ bool Shader::create(const char* vertex, const char* fragment)
auto vs = glCreateShader(GL_VERTEX_SHADER); auto vs = glCreateShader(GL_VERTEX_SHADER);
if (!vs) if (!vs)
{ {
return false; ret = false;
return;
} }
source = vertex; source = vertex;
glShaderSource(vs, 1, &source, nullptr); glShaderSource(vs, 1, &source, nullptr);
@@ -176,14 +181,16 @@ bool Shader::create(const char* vertex, const char* fragment)
if (status == 0) if (status == 0)
{ {
glDeleteShader(vs); glDeleteShader(vs);
return false; ret = false;
return;
} }
auto fs = glCreateShader(GL_FRAGMENT_SHADER); auto fs = glCreateShader(GL_FRAGMENT_SHADER);
if (!fs) if (!fs)
{ {
glDeleteShader(vs); glDeleteShader(vs);
return false; ret = false;
return;
} }
source = fragment; source = fragment;
glShaderSource(fs, 1, &source, nullptr); glShaderSource(fs, 1, &source, nullptr);
@@ -199,7 +206,8 @@ bool Shader::create(const char* vertex, const char* fragment)
{ {
glDeleteShader(vs); glDeleteShader(vs);
glDeleteShader(fs); glDeleteShader(fs);
return false; ret = false;
return;
} }
auto ps = glCreateProgram(); auto ps = glCreateProgram();
@@ -207,7 +215,8 @@ bool Shader::create(const char* vertex, const char* fragment)
{ {
glDeleteShader(vs); glDeleteShader(vs);
glDeleteShader(fs); glDeleteShader(fs);
return false; ret = false;
return;
} }
glAttachShader(ps, vs); glAttachShader(ps, vs);
glAttachShader(ps, fs); glAttachShader(ps, fs);
@@ -238,7 +247,8 @@ bool Shader::create(const char* vertex, const char* fragment)
if (status == 0) if (status == 0)
{ {
glDeleteProgram(ps); glDeleteProgram(ps);
return false; ret = false;
return;
} }
// Parse shader uniforms // Parse shader uniforms
@@ -259,16 +269,20 @@ bool Shader::create(const char* vertex, const char* fragment)
} }
prog = ps; prog = ps;
});
return true; return ret;
} }
void Shader::destroy() void Shader::destroy()
{ {
if (prog) if (prog)
{
App::I.render_task_async([prog=prog]
{ {
glUseProgram(0); glUseProgram(0);
glDeleteProgram(prog); glDeleteProgram(prog);
});
prog = 0; prog = 0;
} }
m_umap.clear(); m_umap.clear();
@@ -276,16 +290,19 @@ void Shader::destroy()
void Shader::use() void Shader::use()
{ {
assert(App::I.is_render_thread());
glUseProgram(prog); glUseProgram(prog);
} }
void Shader::u_vec4(kShaderUniform id, const glm::vec4& v) void Shader::u_vec4(kShaderUniform id, const glm::vec4& v)
{ {
assert(App::I.is_render_thread());
if (m_umap.count(id) == 0) if (m_umap.count(id) == 0)
LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name) LOG("UNIFORM vec4 %d NOT FOUND in shader %d", (int)id, (int)name)
else glUniform4fv(m_umap[id], 1, glm::value_ptr(v)); else glUniform4fv(m_umap[id], 1, glm::value_ptr(v));
} }
void Shader::u_vec3(kShaderUniform id, const glm::vec3& v) void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
{ {
assert(App::I.is_render_thread());
if (m_umap.count(id) == 0) if (m_umap.count(id) == 0)
LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name) LOG("UNIFORM vec3 %d NOT FOUND in shader %d", (int)id, (int)name)
else glUniform3fv(m_umap[id], 1, glm::value_ptr(v)); else glUniform3fv(m_umap[id], 1, glm::value_ptr(v));
@@ -293,6 +310,7 @@ void Shader::u_vec3(kShaderUniform id, const glm::vec3& v)
void Shader::u_vec2(kShaderUniform id, const glm::vec2& v) void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
{ {
assert(App::I.is_render_thread());
if (m_umap.count(id) == 0) if (m_umap.count(id) == 0)
LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name) LOG("UNIFORM vec2 %d NOT FOUND in shader %d", (int)id, (int)name)
else glUniform2fv(m_umap[id], 1, glm::value_ptr(v)); else glUniform2fv(m_umap[id], 1, glm::value_ptr(v));
@@ -300,12 +318,14 @@ void Shader::u_vec2(kShaderUniform id, const glm::vec2& v)
void Shader::u_mat4(kShaderUniform id, const glm::mat4& m) void Shader::u_mat4(kShaderUniform id, const glm::mat4& m)
{ {
assert(App::I.is_render_thread());
if (m_umap.count(id) == 0) if (m_umap.count(id) == 0)
LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name) LOG("UNIFORM mat4 %d NOT FOUND in shader %d", (int)id, (int)name)
else glUniformMatrix4fv(m_umap[id], 1, GL_FALSE, glm::value_ptr(m)); else glUniformMatrix4fv(m_umap[id], 1, GL_FALSE, glm::value_ptr(m));
} }
void Shader::u_int(kShaderUniform id, int i) void Shader::u_int(kShaderUniform id, int i)
{ {
assert(App::I.is_render_thread());
if (m_umap.count(id) == 0) if (m_umap.count(id) == 0)
LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name) LOG("UNIFORM int %d NOT FOUND in shader %d", (int)id, (int)name)
else else
@@ -313,12 +333,14 @@ void Shader::u_int(kShaderUniform id, int i)
} }
void Shader::u_float(kShaderUniform id, float f) void Shader::u_float(kShaderUniform id, float f)
{ {
assert(App::I.is_render_thread());
if (m_umap.count(id) == 0) if (m_umap.count(id) == 0)
LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name) LOG("UNIFORM float %d NOT FOUND in shader %d", (int)id, (int)name)
else glUniform1f(m_umap[id], f); else glUniform1f(m_umap[id], f);
} }
GLint Shader::GetAttribLocation(const char* name) GLint Shader::GetAttribLocation(const char* name)
{ {
assert(App::I.is_render_thread());
return glGetAttribLocation(prog, name); return glGetAttribLocation(prog, name);
} }

View File

@@ -1,6 +1,7 @@
#include "pch.h" #include "pch.h"
#include "log.h" #include "log.h"
#include "shape.h" #include "shape.h"
#include "app.h"
bool Shape::create_buffers(GLushort * idx, GLvoid * vertices, int isize, int vsize) bool Shape::create_buffers(GLushort * idx, GLvoid * vertices, int isize, int vsize)
{ {
@@ -20,11 +21,17 @@ bool Shape::create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsi
{ {
use_idx = true; use_idx = true;
bool ret = false;
App::I.render_task([&]
{
destroy(); destroy();
glGenBuffers(2, buffers); glGenBuffers(2, buffers);
if (!(buffers[0] && buffers[1])) if (!(buffers[0] && buffers[1]))
return false; {
ret = false;
return;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, isize, idx, GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, isize, idx, GL_STATIC_DRAW);
@@ -36,7 +43,10 @@ bool Shape::create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsi
#if USE_VBO #if USE_VBO
glGenVertexArrays(2, arrays); glGenVertexArrays(2, arrays);
if (!(arrays[0] && arrays[1])) if (!(arrays[0] && arrays[1]))
return false; {
ret = false;
return;
}
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
glBindVertexArray(arrays[i]); glBindVertexArray(arrays[i]);
@@ -53,17 +63,24 @@ bool Shape::create_buffers_imp(GLvoid* idx, GLvoid* vertices, int isize, int vsi
} }
glBindVertexArray(0); glBindVertexArray(0);
#endif #endif
return true; });
return ret;
} }
bool Shape::create_buffers(GLvoid* vertices, int vsize) bool Shape::create_buffers(GLvoid* vertices, int vsize)
{ {
use_idx = false; use_idx = false;
bool ret = false;
App::I.render_task([&]
{
destroy(); destroy();
glGenBuffers(1, buffers); glGenBuffers(1, buffers);
if (!buffers[0]) if (!buffers[0])
return false; {
ret = false;
return;
}
if (vsize) if (vsize)
{ {
@@ -76,7 +93,10 @@ bool Shape::create_buffers(GLvoid* vertices, int vsize)
#if USE_VBO #if USE_VBO
glGenVertexArrays(2, arrays); glGenVertexArrays(2, arrays);
if (!(arrays[0] && arrays[1])) if (!(arrays[0] && arrays[1]))
return false; {
ret = false;
return;
}
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
glBindVertexArray(arrays[i]); glBindVertexArray(arrays[i]);
@@ -92,7 +112,8 @@ bool Shape::create_buffers(GLvoid* vertices, int vsize)
} }
glBindVertexArray(0); glBindVertexArray(0);
#endif #endif
return true; });
return ret;
} }
void Shape::draw_fill() const void Shape::draw_fill() const
{ {
@@ -103,6 +124,8 @@ void Shape::draw_fill() const
type = GL_POINTS; type = GL_POINTS;
if (count[0] == 2) if (count[0] == 2)
type = GL_LINES; type = GL_LINES;
App::I.render_task([=]
{
#if USE_VBO #if USE_VBO
glBindVertexArray(arrays[0]); glBindVertexArray(arrays[0]);
if (use_idx) if (use_idx)
@@ -128,6 +151,7 @@ void Shape::draw_fill() const
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#endif // USE_VBO #endif // USE_VBO
});
} }
void Shape::draw_stroke() const void Shape::draw_stroke() const
{ {
@@ -136,6 +160,8 @@ void Shape::draw_stroke() const
GLenum type = GL_LINES; GLenum type = GL_LINES;
if (count[1] == 1) if (count[1] == 1)
type = GL_POINTS; type = GL_POINTS;
App::I.render_task([=]
{
#if USE_VBO #if USE_VBO
glBindVertexArray(arrays[1]); glBindVertexArray(arrays[1]);
if (use_idx) if (use_idx)
@@ -162,6 +188,33 @@ void Shape::draw_stroke() const
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
#endif // USE_VBO #endif // USE_VBO
});
}
void Shape::destroy()
{
App::I.render_task_async([b1=buffers[0],b2=buffers[1],a1=arrays[0],a2=arrays[1]]
{
if (b1 || b2)
{
glDeleteBuffers(1, &b1);
glDeleteBuffers(1, &b2);
}
#if USE_VBO
if (a1 || a2)
{
glDeleteVertexArrays(1, &a1);
glDeleteVertexArrays(1, &a2);
}
#endif // USE_VBO
});
buffers[0] = buffers[1] = 0;
arrays[0] = arrays[1] = 0;
}
Shape::~Shape()
{
destroy();
} }
bool RectShape::create(float w, float h) bool RectShape::create(float w, float h)
@@ -437,6 +490,8 @@ void Plane::update_vertices(const glm::vec4* data, const glm::vec2* uvs, const g
vertices[i].pos.z = q; vertices[i].pos.z = q;
} }
App::I.render_task([this]
{
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
static GLushort idx[6 + 8]{ static GLushort idx[6 + 8]{
@@ -452,6 +507,7 @@ void Plane::update_vertices(const glm::vec4* data, const glm::vec2* uvs, const g
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
});
} }
void Circle::create_impl(float radius, int div, GLushort* idx, vertex_t* vertices) void Circle::create_impl(float radius, int div, GLushort* idx, vertex_t* vertices)
{ {
@@ -704,18 +760,24 @@ void Sphere::create_impl(int rings, int sectors, float radius,
} }
void LineSegment::update_vertices(const glm::vec4 data[2]) void LineSegment::update_vertices(const glm::vec4 data[2])
{ {
App::I.render_task([&]
{
static vertex_t vertices[2]; static vertex_t vertices[2];
vertices[0] = { data[0], { 0, 0 } }; // A vertices[0] = { data[0], { 0, 0 } }; // A
vertices[1] = { data[1], { 0, 1 } }; // B vertices[1] = { data[1], { 0, 1 } }; // B
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
});
} }
void DynamicShape::update_vertices(vertex_t* vertices, int vcount) void DynamicShape::update_vertices(vertex_t* vertices, int vcount)
{ {
App::I.render_task([&]
{
count[0] = vcount; count[0] = vcount;
count[1] = vcount; count[1] = vcount;
glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_t) * vcount, vertices, GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_t) * vcount, vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
});
} }

View File

@@ -25,22 +25,9 @@ public:
bool create_buffers(GLvoid* vertices, int vsize); bool create_buffers(GLvoid* vertices, int vsize);
void draw_fill() const; void draw_fill() const;
void draw_stroke() const; void draw_stroke() const;
void destroy() void destroy();
{
if (buffers[0] || buffers[1])
glDeleteBuffers(2, buffers);
#if USE_VBO
if (arrays[0] || arrays[1])
glDeleteVertexArrays(2, arrays);
#endif // USE_VBO
buffers[0] = buffers[1] = 0;
arrays[0] = arrays[1] = 0;
}
virtual bool create_attrib() { return true; }; virtual bool create_attrib() { return true; };
~Shape() ~Shape();
{
destroy();
}
protected: protected:
glm::vec2 quad_mid_point(glm::vec2 a, glm::vec2 b, glm::vec2 c, glm::vec2 d) glm::vec2 quad_mid_point(glm::vec2 a, glm::vec2 b, glm::vec2 c, glm::vec2 d)
{ {

View File

@@ -41,6 +41,8 @@ void TextureManager::invalidate()
bool Texture2D::create(int width, int height, GLint internal_format, GLint format, const uint8_t* data) bool Texture2D::create(int width, int height, GLint internal_format, GLint format, const uint8_t* data)
{ {
App::I.render_task([=]
{
destroy(); destroy();
m_width = width; m_width = width;
m_height = height; m_height = height;
@@ -54,6 +56,7 @@ bool Texture2D::create(int width, int height, GLint internal_format, GLint forma
if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT; if (internal_format == GL_RGBA16F) ifmt = GL_HALF_FLOAT;
glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, ifmt, data); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, ifmt, data);
unbind(); unbind();
});
return true; return true;
} }
bool Texture2D::create(const Image& img) bool Texture2D::create(const Image& img)
@@ -65,10 +68,13 @@ bool Texture2D::create(const Image& img)
void Texture2D::create_mipmaps() void Texture2D::create_mipmaps()
{ {
App::I.render_task([this]
{
bind(); bind();
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
unbind(); unbind();
has_mips = true; has_mips = true;
});
} }
void Texture2D::assign(GLuint tex, int w/* = -1*/, int h/* = -1*/, GLuint internal_format/* = GL_RGBA8*/, GLuint format/* = GL_RGBA*/) void Texture2D::assign(GLuint tex, int w/* = -1*/, int h/* = -1*/, GLuint internal_format/* = GL_RGBA8*/, GLuint format/* = GL_RGBA*/)
@@ -98,10 +104,37 @@ bool Texture2D::load_file(std::string filename)
return create(img); return create(img);
} }
void Texture2D::destroy()
{
if (m_tex)
{
App::I.render_task_async([id = m_tex]
{
glDeleteTextures(1, &id);
});
m_tex = 0;
}
}
void Texture2D::bind() const
{
assert(App::I.is_render_thread());
glBindTexture(GL_TEXTURE_2D, m_tex);
}
void Texture2D::unbind() const
{
assert(App::I.is_render_thread());
glBindTexture(GL_TEXTURE_2D, 0);
}
void Texture2D::update(const uint8_t* data) void Texture2D::update(const uint8_t* data)
{ {
App::I.render_task([this, data]
{
bind(); bind();
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_width, m_height, m_format, GL_UNSIGNED_BYTE, data);
});
} }
glm::vec2 Texture2D::size() const glm::vec2 Texture2D::size() const
@@ -112,26 +145,37 @@ glm::vec2 Texture2D::size() const
Texture2D::~Texture2D() Texture2D::~Texture2D()
{ {
if (auto_destroy) if (auto_destroy)
{
App::I.render_task_async([this]
{ {
LOG("Texture2D auto destroy"); LOG("Texture2D auto destroy");
App::I.async_start();
destroy(); destroy();
App::I.async_end(); });
} }
} }
bool Sampler::create(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/) bool Sampler::create(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/)
{ {
bool ret = false;
App::I.render_task([this, &ret, filter, wrap]
{
#if USE_SAMPLER #if USE_SAMPLER
glGenSamplers(1, &id); glGenSamplers(1, &id);
#endif // USE_SAMPLER #endif // USE_SAMPLER
if (id == 0) if (id == 0)
return false; {
ret = false;
return;
}
set(filter, wrap); set(filter, wrap);
return true; ret = true;
});
return ret;
} }
void Sampler::set(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/) void Sampler::set(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*/)
{ {
App::I.render_task([=]
{
#if USE_SAMPLER #if USE_SAMPLER
glSamplerParameteri(id, GL_TEXTURE_WRAP_S, wrap); glSamplerParameteri(id, GL_TEXTURE_WRAP_S, wrap);
glSamplerParameteri(id, GL_TEXTURE_WRAP_T, wrap); glSamplerParameteri(id, GL_TEXTURE_WRAP_T, wrap);
@@ -139,31 +183,44 @@ void Sampler::set(GLint filter /*= GL_LINEAR*/, GLint wrap /*= GL_CLAMP_TO_EDGE*
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter); glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter);
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter); glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter);
#endif // USE_SAMPLER #endif // USE_SAMPLER
});
} }
void Sampler::set_filter(GLint filter_min, GLint filter_mag) void Sampler::set_filter(GLint filter_min, GLint filter_mag)
{ {
App::I.render_task([=]
{
#if USE_SAMPLER #if USE_SAMPLER
glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter_min); glSamplerParameteri(id, GL_TEXTURE_MIN_FILTER, filter_min);
glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter_mag); glSamplerParameteri(id, GL_TEXTURE_MAG_FILTER, filter_mag);
#endif // USE_SAMPLER #endif // USE_SAMPLER
});
} }
void Sampler::set_border(glm::vec4 rgba) void Sampler::set_border(glm::vec4 rgba)
{ {
App::I.render_task([this, rgba]
{
#if USE_SAMPLER && !defined(__IOS__) && !defined(__ANDROID__) #if USE_SAMPLER && !defined(__IOS__) && !defined(__ANDROID__)
glSamplerParameterfv(id, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(rgba)); glSamplerParameterfv(id, GL_TEXTURE_BORDER_COLOR, glm::value_ptr(rgba));
#endif // USE_SAMPLER #endif // USE_SAMPLER
});
} }
void Sampler::bind(int unit) const void Sampler::bind(int unit) const
{ {
App::I.render_task([=]
{
current_unit = unit; current_unit = unit;
#if USE_SAMPLER #if USE_SAMPLER
glBindSampler(unit, id); glBindSampler(unit, id);
#endif // USE_SAMPLER #endif // USE_SAMPLER
});
} }
void Sampler::unbind() void Sampler::unbind()
{ {
App::I.render_task([=]
{
#if USE_SAMPLER #if USE_SAMPLER
glBindSampler(current_unit, 0); glBindSampler(current_unit, 0);
#endif // USE_SAMPLER #endif // USE_SAMPLER
});
} }

View File

@@ -16,9 +16,9 @@ public:
void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA); void assign(GLuint tex, int w = -1, int h = -1, GLuint internal_format = GL_RGBA8, GLuint format = GL_RGBA);
bool load(std::string filename); bool load(std::string filename);
bool load_file(std::string filename); bool load_file(std::string filename);
void destroy() { if (m_tex) /*LOG("TEX destroy %d", m_tex);*/ glDeleteTextures(1, &m_tex); m_tex = 0; } void destroy();
void bind() const { glBindTexture(GL_TEXTURE_2D, m_tex); } void bind() const;
void unbind() const { glBindTexture(GL_TEXTURE_2D, 0); } void unbind() const;
void update(const uint8_t* data); void update(const uint8_t* data);
bool ready() const { return m_tex != 0; } bool ready() const { return m_tex != 0; }
void create_mipmaps(); void create_mipmaps();