render implement thread, wrap GL commands into tasks
This commit is contained in:
185
src/main.cpp
185
src/main.cpp
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user