Windows: Pause the rendering thread while switching to full screen

This commit is contained in:
Henrik Rydgard 2015-09-20 19:45:36 +02:00
parent 5f18390c04
commit 1410d7f6d5
3 changed files with 66 additions and 3 deletions

View File

@ -300,7 +300,12 @@ namespace MainWindow
void ToggleFullscreen(HWND hWnd, bool goingFullscreen) {
// Make sure no rendering is happening during the switch.
Core_NotifyWindowHidden(true);
bool isOpenGL = g_Config.iGPUBackend == GPU_BACKEND_OPENGL;
if (isOpenGL) {
GL_Pause();
}
int oldWindowState = g_WindowState;
g_IgnoreWM_SIZE = true;
@ -361,8 +366,11 @@ namespace MainWindow
ShowOwnedPopups(hwndMain, goingFullscreen ? FALSE : TRUE);
W32Util::MakeTopMost(hwndMain, g_Config.bTopMost);
Core_NotifyWindowHidden(false);
WindowsRawInput::NotifyMenu();
if (isOpenGL) {
GL_Resume();
}
}
RECT DetermineWindowRectangle() {

View File

@ -33,6 +33,10 @@
static HDC hDC; // Private GDI Device Context
static HGLRC hRC; // Permanent Rendering Context
static HWND hWnd; // Holds Our Window Handle
static volatile bool pauseRequested;
static volatile bool resumeRequested;
static HANDLE pauseEvent;
static HANDLE resumeEvent;
static int xres, yres;
@ -42,11 +46,47 @@ static bool enableGLDebug = false;
void GL_SwapBuffers() {
SwapBuffers(hDC);
if (pauseRequested) {
SetEvent(pauseEvent);
resumeRequested = true;
DWORD result = WaitForSingleObject(resumeEvent, INFINITE);
if (result == WAIT_TIMEOUT) {
ERROR_LOG(G3D, "Wait for resume timed out. Resuming rendering");
}
pauseRequested = false;
}
// According to some sources, doing this *after* swapbuffers can reduce frame latency
// at a large performance cost.
// at a large performance cost. So let's not.
// glFinish();
}
void GL_Pause() {
if (!hRC) {
return;
}
pauseRequested = true;
DWORD result = WaitForSingleObject(pauseEvent, INFINITE);
if (result == WAIT_TIMEOUT) {
ERROR_LOG(G3D, "Wait for pause timed out");
}
// OK, we now know the rendering thread is paused.
}
void GL_Resume() {
if (!hRC) {
return;
}
if (!resumeRequested) {
ERROR_LOG(G3D, "Not waiting to get resumed");
} else {
SetEvent(resumeEvent);
}
resumeRequested = false;
}
void FormatDebugOutputARB(char outStr[], size_t outStrSize, GLenum source, GLenum type,
GLuint id, GLenum severity, const char *msg) {
char sourceStr[32];
@ -270,6 +310,14 @@ bool GL_Init(HWND window, std::string *error_message) {
glDebugMessageCallbackARB((GLDEBUGPROCARB)&DebugCallbackARB, 0); // print debug output to stderr
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
}
pauseRequested = false;
resumeRequested = false;
// These are auto-reset events.
pauseEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
resumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
return true; // Success
}
@ -280,6 +328,8 @@ void GL_SwapInterval(int interval) {
}
void GL_Shutdown() {
CloseHandle(pauseEvent);
CloseHandle(resumeEvent);
if (hRC) {
// Are we able to release the DC and RC contexts?
if (!wglMakeCurrent(NULL,NULL)) {

View File

@ -6,3 +6,8 @@ bool GL_Init(HWND window, std::string *error_message);
void GL_Shutdown();
void GL_SwapInterval(int interval);
void GL_SwapBuffers();
// Used during window resize. Must be called from the window thread,
// not the rendering thread or CPU thread.
void GL_Pause();
void GL_Resume();