I'm trying to create a borderless window that fills the screen with an OpenGL viewport. The problem is, when I set the window and viewport to be the same size as the desktop, the window flashes black on losing and gaining focus, on exit, and on creation. This may have to do with Windows setting the window to some type of true "fullscreen" mode. This doesn't seem to happen in other applications (DirectX?) that use this type of borderless fullscreen window.
I believe SFML has/had a variant of this problem.
There is a workaround: don't set the window to the exact size of the desktop. For instance, make the width of the window one pixel more than the width of the desktop.
Below is an SSCCE without error checking that shows what I'm talking about. This will create a borderless fullscreen window with a desktop-sized OpenGL viewport displaying an ugly green color (exit with AltF4). You can change the line #define FIX_BUG 0
to #define FIX_BUG 1
which just adds one extra pixel to the window's width to see what the behavior I want looks like.
#define WIN32_LEAN_AND_MEAN
#include "windows.h"
#pragma comment(lib, "OpenGL32.lib")
#define FIX_BUG 0
void MyRegisterClass(HINSTANCE hInstance);
HWND MyCreateWindow(HINSTANCE hInstance);
void MySetupOpenGLContext(HWND hWnd);
void MySetPixelFormat(HDC hDC);
RECT MyGetDesktopRect();
void MyLoadOpenGLFunctions();
#define APIENTRYP APIENTRY *
#define GLAPI extern
#define GL_COLOR 0x1800
typedef int GLint;
typedef int GLsizei;
typedef unsigned int GLenum;
typedef float GLfloat;
typedef void (APIENTRYP PFNGLVIEWPORTPROC) (GLint x, GLint y, GLsizei width, GLsizei height);
PFNGLVIEWPORTPROC glViewport;
typedef void (APIENTRYP PFNGLCLEARBUFFERFVPROC) (GLenum buffer, GLint drawbuffer, const GLfloat *value);
PFNGLCLEARBUFFERFVPROC glClearBufferfv;
static const char *windowClass = "CLASS";
static const char *windowTitle = "TITLE";
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) {
MyRegisterClass(hInstance);
const HWND hWnd = MyCreateWindow(hInstance);
MySetupOpenGLContext(hWnd);
ShowWindow(hWnd, nCmdShow);
HDC hDC = GetDC(hWnd);
MSG msg;
while (IsWindow(hWnd)) {
while (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
const GLfloat color[] = {0.5f, 0.5f, 0.0f, 1.0f};
glClearBufferfv(GL_COLOR, 0, color);
SwapBuffers(hDC);
}
return 0;
}
void MyRegisterClass(HINSTANCE hInstance) {
WNDCLASSEX wcex = {0};
wcex.cbSize = sizeof wcex;
wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wcex.lpfnWndProc = &DefWindowProc;
wcex.hInstance = hInstance;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH) (COLOR_WINDOWFRAME + 1);
wcex.lpszClassName = windowClass;
RegisterClassEx(&wcex);
}
HWND MyCreateWindow(HINSTANCE hInstance) {
RECT dRect = MyGetDesktopRect();
return CreateWindow(windowClass, windowTitle, WS_POPUP,
0, 0, dRect.right + FIX_BUG, dRect.bottom,
NULL, NULL, hInstance, NULL);
}
void MySetupOpenGLContext(HWND hWnd) {
HDC hDC = GetDC(hWnd);
MySetPixelFormat(hDC);
HGLRC hGLRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hGLRC);
MyLoadOpenGLFunctions();
RECT dRect = MyGetDesktopRect();
glViewport(0, 0, dRect.right, dRect.bottom);
}
void MySetPixelFormat(HDC hDC) {
PIXELFORMATDESCRIPTOR pfd = {0};
pfd.nSize = sizeof pfd;
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 8;
pfd.iLayerType = PFD_MAIN_PLANE;
int format = ChoosePixelFormat(hDC, &pfd);
SetPixelFormat(hDC, format, &pfd);
}
RECT MyGetDesktopRect() {
RECT desktopRect;
const HWND hDesktop = GetDesktopWindow();
GetWindowRect(hDesktop, &desktopRect);
return desktopRect;
}
void MyLoadOpenGLFunctions() {
glViewport = (PFNGLVIEWPORTPROC) GetProcAddress(GetModuleHandleA("OpenGL32.dll"), "glViewport");
glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) wglGetProcAddress("glClearBufferfv");
}
Github Gist | Raw Text
Why does this happen? Is there a way to get the behavior I want with the window set to the exact size of the desktop?
My platform: Visual Studio 2013 / 64-bit Windows 8 / AMD Radeon HD6850.
PFD_SWAP_EXCHAGNE
andPFD_SWAP_COPY
. – Banquer#define FIX_BUG 0
the window gets around 1.5-2x the FPS since the DWM is disabled (obviously the gap would narrow if actual work was done in the loop). – Loincloth