/glwindow.cpp Secret
Created
July 30, 2020 00:00
Star
You must be signed in to star a gist
Minimal repro for Intel Graphics OpenGL driver issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <gl/GL.h> | |
#include <cmath> | |
#pragma comment(lib, "opengl32") | |
#define GL_COLOR_ATTACHMENT0 0x8CE0 | |
#define GL_DEPTH_ATTACHMENT 0x8D00 | |
#define GL_DRAW_FRAMEBUFFER 0x8CA9 | |
static int width = 512; | |
static int height = 512; | |
extern "C" { | |
// Uncomment the following line to test with Nvidia on Optimus-enabled hardware. | |
//__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; | |
// Uncomment the following line to test with AMD on PowerXpress-enabled hardware. | |
//__declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; | |
} | |
LRESULT __stdcall WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) | |
{ | |
switch (uMsg) { | |
case WM_CLOSE: | |
PostQuitMessage(0); | |
break; | |
case WM_SIZE: | |
width = LOWORD(lParam); | |
height = HIWORD(lParam); | |
break; | |
} | |
return DefWindowProcW(hWnd, uMsg, wParam, lParam); | |
} | |
bool MessagePump() | |
{ | |
MSG msg; | |
while (PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE)) { | |
if (!GetMessageW(&msg, NULL, 0, 0)) { | |
return false; | |
} | |
TranslateMessage(&msg); | |
DispatchMessageW(&msg); | |
} | |
return true; | |
} | |
int __stdcall WinMain(HINSTANCE hinstance, HINSTANCE, LPSTR, int) | |
{ | |
// | |
// Window initialization | |
// | |
constexpr wchar_t classname[] = L"GlWindowClassName"; | |
WNDCLASSEXW wcex{ | |
sizeof(wcex), | |
0, | |
WndProc, | |
0, | |
0, | |
hinstance, | |
NULL, | |
LoadIconW(hinstance, IDC_ARROW), | |
(HBRUSH)0, | |
NULL, | |
classname, | |
NULL | |
}; | |
RegisterClassExW(&wcex); | |
HWND hwnd = CreateWindowExW( | |
0, | |
classname, | |
L"glwindow", | |
WS_OVERLAPPED | WS_THICKFRAME | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_VISIBLE, | |
CW_USEDEFAULT, | |
CW_USEDEFAULT, | |
width, | |
height, | |
NULL, | |
NULL, | |
hinstance, | |
NULL); | |
// | |
// OpenGL initialization | |
// | |
PIXELFORMATDESCRIPTOR pfd = { | |
sizeof(pfd), | |
1, | |
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA, | |
24, | |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
24, 8, 0, | |
PFD_MAIN_PLANE, | |
0, 0, 0, 0, | |
}; | |
HDC hdc = GetDC(hwnd); | |
int pf = ChoosePixelFormat(hdc, &pfd); | |
SetPixelFormat(hdc, pf, &pfd); | |
HGLRC hrc = wglCreateContext(hdc); | |
wglMakeCurrent(hdc, hrc); | |
// Explicitly set swap interval (workaround for separate Intel bug) | |
// cf. https://software.intel.com/en-us/forums/graphics-driver-bug-reporting/topic/856923 | |
auto wglSwapIntervalEXT = (BOOL (APIENTRY*)(GLint interval))wglGetProcAddress("wglSwapIntervalEXT"); | |
wglSwapIntervalEXT(1); | |
// Create off-screen render target | |
auto glCreateFramebuffers = (void (APIENTRY*)(GLsizei n, GLuint* framebuffers))wglGetProcAddress("glCreateFramebuffers"); | |
auto glDeleteFramebuffers = (void (APIENTRY*)(GLsizei n, GLuint* framebuffers))wglGetProcAddress("glDeleteFramebuffers"); | |
auto glBindFramebuffer = (void (APIENTRY*)(GLenum target, GLuint framebuffer))wglGetProcAddress("glBindFramebuffer"); | |
auto glBlitNamedFramebuffer = (void (APIENTRY*)(GLuint readFramebuffer, GLuint drawFramebuffer, GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter))wglGetProcAddress("glBlitNamedFramebuffer"); | |
auto glNamedFramebufferTexture = (void (APIENTRY*)(GLuint framebuffer, GLenum attachment, GLuint texture, GLint level))wglGetProcAddress("glNamedFramebufferTexture"); | |
GLuint fb; glCreateFramebuffers(1, &fb); | |
GLuint tex[2]; glGenTextures(2, tex); | |
glBindTexture(GL_TEXTURE_2D, tex[0]); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); | |
glBindTexture(GL_TEXTURE_2D, tex[1]); | |
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); | |
glNamedFramebufferTexture(fb, GL_COLOR_ATTACHMENT0, tex[0], 0); | |
glNamedFramebufferTexture(fb, GL_DEPTH_ATTACHMENT, tex[1], 0); | |
// | |
// Main loop | |
// | |
int prev_width = width; | |
int prev_height = height; | |
// Pump messages until the window is closed. Update `width` and `height` | |
// with the client area dimensions when a WM_SIZE message is received. | |
for (int n = 0; MessagePump(); ++n) { | |
#if 0 // Enable this check to workaround the issue | |
if (width != prev_width || height != prev_height) { | |
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); | |
glDrawBuffer(GL_BACK); | |
// glClear will invalidate the default framebuffer dimensions | |
glClear(0); | |
prev_width = width; | |
prev_height = height; | |
} | |
#endif | |
// Clear the off-screen render target for visual contrast | |
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb); | |
glDrawBuffer(GL_COLOR_ATTACHMENT0); | |
glClearColor( | |
std::sin(n / 61.f) * .5f + .5f, | |
std::sin(n / 79.f) * .5f + .5f, | |
std::sin(n / 113.f) * .5f + .5f, | |
0.f); | |
glClear(GL_COLOR_BUFFER_BIT); | |
// When the window is resized the GL will not recognize that the | |
// dimensions of the default framebuffer have changed until it is | |
// cleared. This causes the blit operation to fail to copy the source | |
// framebuffer contents into the full extents of the default framebuffer. | |
// This issue does not reproduce with Nvidia graphics. | |
glBlitNamedFramebuffer(fb, 0, 0, 0, 1, 1, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR); | |
SwapBuffers(hdc); | |
} | |
// | |
// OpenGL shutdown | |
// | |
glDeleteFramebuffers(1, &fb); | |
glDeleteTextures(2, tex); | |
wglMakeCurrent(NULL, NULL); | |
wglDeleteContext(hrc); | |
ReleaseDC(hwnd, hdc); | |
// | |
// Window shutdown | |
// | |
CloseWindow(hwnd); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment