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

@@ -33,12 +33,19 @@ std::thread::id gl_thread;
std::map<kKey, int> vkey_map;
std::thread hmd_renderer;
std::thread renderer;
std::thread ui_renderer;
int vr_frames = 0;
int running = -1;
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::thread render_thread;
std::thread::id render_thread_id;
bool render_running = false;
int gl_count = 0;
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()
{
//std::lock_guard<std::mutex> _lock(async_mutex);
@@ -166,7 +230,7 @@ void async_unlock()
void win32_render_thread_notify()
{
render_cv.notify_all();
ui_render_cv.notify_all();
}
void win32_show_cursor(bool visible)
@@ -257,12 +321,6 @@ std::string win32_open_dir()
return Buffer;
}
struct async_locker
{
async_locker() { async_lock(); }
~async_locker() { async_unlock(); }
};
int read_WMI_info()
{
// 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->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())
{
delete vive;
vive = nullptr;
LOG("VR: failed to initialize vive");
async_unlock();
return false;
}
async_unlock();
hmd_renderer = std::thread([&] {
if (!vive)
@@ -726,6 +781,46 @@ 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<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)
{
WNDCLASS wc;
@@ -917,7 +1012,10 @@ int main(int argc, char** argv)
LOG("RegisterTouchWindow error: %s", GetLastErrorAsString().c_str());
}
async_lock();
wglMakeCurrent(NULL, NULL);
running = 1;
render_thread = std::thread(render_thread_main);
LOG("init app");
App::I.init();
@@ -932,15 +1030,11 @@ 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)));
running = 1;
renderer = std::thread([&] {
ui_renderer = std::thread([&] {
BT_SetTerminate();
LOG("start render thread");
const float target_fps = 10;
@@ -989,13 +1083,11 @@ int main(int argc, char** argv)
if (!working_list.empty())
{
async_lock();
while (!working_list.empty())
{
working_list.front()();
working_list.pop_front();
}
async_unlock();
//LOG("clear");
//WacomTablet::I.m_stylus = false;
//WacomTablet::I.m_eraser = false;
@@ -1016,7 +1108,7 @@ int main(int argc, char** argv)
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)
{
App::I.redraw = true;
@@ -1041,19 +1133,20 @@ int main(int argc, char** argv)
if (App::I.redraw)
{
async_lock();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
App::I.clear();
App::I.update(frame_timer);
SwapBuffers(hDC);
async_unlock();
render_task([frame_timer]
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
App::I.clear();
App::I.update(frame_timer);
SwapBuffers(hDC);
});
frame_timer = 0;
frames++;
}
const int framerate = (1.f / target_tick_rate) * 1000;
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));
t0 = t1;
}
@@ -1109,10 +1202,11 @@ int main(int argc, char** argv)
}
if (!tasklist.empty())
render_cv.notify_all();
ui_render_cv.notify_all();
}
// Clean up
WacomTablet::I.terminate();
render_cv.notify_all();
UnregisterClass(className, hInst);
LogRemote::I.stop();
@@ -1132,13 +1226,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
case WM_USER_CLOSE:
running = 0;
render_cv.notify_all();
if (renderer.joinable())
renderer.join();
ui_render_cv.notify_all();
if (ui_renderer.joinable())
ui_renderer.join();
if (hmd_renderer.joinable())
hmd_renderer.join();
App::I.terminate();
PostQuitMessage(0);
render_running = false;
if (render_thread.joinable())
render_thread.join();
return 0;
case WM_PAINT:
App::I.redraw = true;
@@ -1150,13 +1247,16 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
if (App::I.request_close())
{
running = 0;
render_cv.notify_all();
if (renderer.joinable())
renderer.join();
ui_render_cv.notify_all();
if (ui_renderer.joinable())
ui_renderer.join();
if (hmd_renderer.joinable())
hmd_renderer.join();
App::I.terminate();
PostQuitMessage(0);
render_running = false;
if (render_thread.joinable())
render_thread.join();
return 0;
}
else
@@ -1170,12 +1270,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
auto h = (float)HIWORD(lp);
if (h != 0 && running == 1)
{
async_locker lock;
App::I.resize(w, h);
App::I.clear();
App::I.redraw = true;
App::I.update(0.f);
SwapBuffers(hDC);
App::I.render_task([=]
{
App::I.resize(w, h);
App::I.clear();
App::I.redraw = true;
App::I.update(0.f);
SwapBuffers(hDC);
});
}
break;
}
@@ -1374,7 +1476,6 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
break;
case WM_MOUSEWHEEL:
{
async_locker lock;
POINT pt;
pt.x = GET_X_LPARAM(lp);
pt.y = GET_Y_LPARAM(lp);