11 #include <string_view>
24 #include <epoxy/wgl.h>
43 GLWinWindow::GLWinWindow()
71 void WinOpenGLContext::swapBuffers()
75 SwapBuffers(m_aGLWin.hDC);
80 void WinOpenGLContext::resetCurrent()
86 wglMakeCurrent(
nullptr,
nullptr);
92 thread_local
bool bEpoxyDispatchMakeCurrentCalled =
false;
93 if (!bEpoxyDispatchMakeCurrentCalled)
95 epoxy_handle_external_wglMakeCurrent();
96 bEpoxyDispatchMakeCurrentCalled =
true;
100 bool WinOpenGLContext::isCurrent()
106 return wglGetCurrentContext() == m_aGLWin.hRC && wglGetCurrentDC() == m_aGLWin.hDC;
109 bool WinOpenGLContext::isAnyCurrent()
114 void WinOpenGLContext::makeCurrent()
125 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
128 DWORD nLastError = GetLastError();
129 if (nLastError != ERROR_SUCCESS)
130 SAL_WARN(
"vcl.opengl",
"wglMakeCurrent failed: " << WindowsErrorString(nLastError));
139 void WinOpenGLContext::initWindow()
141 if( !m_pChildWindow )
149 InitChildWindow(m_pChildWindow.get());
150 const SystemEnvData* sysData(m_pChildWindow->GetSystemData());
151 m_aGLWin.hWnd = sysData->hWnd;
154 m_aGLWin.hDC =
GetDC(m_aGLWin.hWnd);
157 void WinOpenGLContext::destroyCurrentContext()
165 if (wglGetCurrentContext() !=
nullptr)
167 wglMakeCurrent(
nullptr,
nullptr);
170 wglDeleteContext( m_aGLWin.hRC );
171 ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC );
172 m_aGLWin.hRC =
nullptr;
176 static LRESULT
CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
188 return DefWindowProcW(hwnd, message, wParam, lParam);
192 static bool InitTempWindow(HWND& hwnd,
int width,
int height,
const PIXELFORMATDESCRIPTOR& inPfd, GLWinWindow& glWin)
196 PIXELFORMATDESCRIPTOR pfd = inPfd;
201 wc.cbClsExtra = wc.cbWndExtra = 0;
202 wc.hInstance =
nullptr;
204 wc.hCursor =
nullptr;
205 wc.hbrBackground =
nullptr;
206 wc.lpszMenuName =
nullptr;
207 wc.lpszClassName = L
"GLRenderer";
209 hwnd = CreateWindowW(wc.lpszClassName,
nullptr, WS_DISABLED, 0, 0, width, height,
nullptr,
nullptr, wc.hInstance,
nullptr);
210 glWin.hDC =
GetDC(hwnd);
212 int nPixelFormat = ChoosePixelFormat(glWin.hDC, &pfd);
215 ReleaseDC(hwnd, glWin.hDC);
219 ret = SetPixelFormat(glWin.hDC, nPixelFormat, &pfd);
222 ReleaseDC(hwnd, glWin.hDC);
226 glWin.hRC = wglCreateContext(glWin.hDC);
229 ReleaseDC(hwnd, glWin.hDC);
233 ret = wglMakeCurrent(glWin.hDC, glWin.hRC);
236 wglMakeCurrent(
nullptr,
nullptr);
238 wglDeleteContext(glWin.hRC);
239 ReleaseDC(hwnd, glWin.hDC);
252 const size_t extlen = strlen(extension);
253 const char *supported =
nullptr;
256 PROC wglGetExtString = wglGetProcAddress(
"wglGetExtensionsStringARB");
259 supported =
reinterpret_cast<char*(__stdcall*)(HDC)
>(wglGetExtString)(wglGetCurrentDC());
261 if (supported ==
nullptr)
262 supported =
reinterpret_cast<char const *
>(glGetString(GL_EXTENSIONS));
264 if (supported ==
nullptr)
268 for (
const char*
p = supported; ;
p++)
271 p = strstr(
p, extension);
282 if ((
p==supported ||
p[-1]==
' ') && (
p[extlen]==
'\0' ||
p[extlen]==
' '))
288 bool bUseDoubleBufferedRendering,
bool bRequestVirtualDevice)
297 SAL_WARN(
"vcl.opengl",
"Can't create temp window to test");
304 SAL_WARN(
"vcl.opengl",
"Device doesn't support multisample");
305 wglMakeCurrent(
nullptr,
nullptr);
307 wglDeleteContext(glWin.hRC);
308 ReleaseDC(hWnd, glWin.hDC);
313 PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB =
reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC
>(wglGetProcAddress(
"wglChoosePixelFormatARB"));
314 if (!fn_wglChoosePixelFormatARB)
316 wglMakeCurrent(
nullptr,
nullptr);
318 wglDeleteContext(glWin.hRC);
319 ReleaseDC(hWnd, glWin.hDC);
324 HDC hDC =
GetDC(hWnd);
329 float fAttributes[] = {0,0};
337 WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
338 WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
339 WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
340 WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
341 WGL_COLOR_BITS_ARB,24,
342 WGL_ALPHA_BITS_ARB,8,
343 WGL_DEPTH_BITS_ARB,24,
344 WGL_STENCIL_BITS_ARB,0,
345 WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
350 if (!bUseDoubleBufferedRendering)
354 assert(iAttributes[0] == WGL_DOUBLE_BUFFER_ARB);
355 iAttributes[1] = GL_FALSE;
358 if (bRequestVirtualDevice)
360 assert(iAttributes[2] == WGL_DRAW_TO_WINDOW_ARB);
361 iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB;
364 bool bArbMultisampleSupported =
false;
367 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
369 if (valid && numFormats >= 1)
371 bArbMultisampleSupported =
true;
372 rPixelFormat = pixelFormat;
373 wglMakeCurrent(
nullptr,
nullptr);
375 wglDeleteContext(glWin.hRC);
376 ReleaseDC(hWnd, glWin.hDC);
378 return bArbMultisampleSupported;
381 assert(iAttributes[18] == WGL_SAMPLES_ARB);
383 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
384 if (valid && numFormats >= 1)
386 bArbMultisampleSupported =
true;
387 rPixelFormat = pixelFormat;
388 wglMakeCurrent(
nullptr,
nullptr);
390 wglDeleteContext(glWin.hRC);
391 ReleaseDC(hWnd, glWin.hDC);
393 return bArbMultisampleSupported;
396 wglMakeCurrent(
nullptr,
nullptr);
398 wglDeleteContext(glWin.hRC);
399 ReleaseDC(hWnd, glWin.hDC);
402 return bArbMultisampleSupported;
408 bool tryShaders(
const OUString& rVertexShader,
const OUString& rFragmentShader,
const OUString& rGeometryShader =
"", std::string_view rPreamble =
"")
416 if (rGeometryShader.isEmpty())
418 nId =
OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rPreamble, OpenGLHelper::GetDigest( rVertexShader, rFragmentShader, rPreamble));
422 assert(rPreamble.empty());
431 glDeleteProgram(nId);
432 return glGetError() == GL_NO_ERROR;
435 bool compiledShaderBinariesWork()
437 static bool bBeenHere =
false;
447 #if 0 // Only look at shaders used by slideshow for now
449 tryShaders(
"dummyVertexShader",
"linearMultiColorGradientFragmentShader") &&
450 tryShaders(
"dummyVertexShader",
"linearTwoColorGradientFragmentShader") &&
451 tryShaders(
"dummyVertexShader",
"radialMultiColorGradientFragmentShader") &&
452 tryShaders(
"dummyVertexShader",
"radialTwoColorGradientFragmentShader") &&
453 tryShaders(
"dummyVertexShader",
"rectangularMultiColorGradientFragmentShader") &&
454 tryShaders(
"dummyVertexShader",
"rectangularTwoColorGradientFragmentShader") &&
457 tryShaders(
"reflectionVertexShader",
"reflectionFragmentShader") &&
458 tryShaders(
"basicVertexShader",
"basicFragmentShader") &&
459 tryShaders(
"vortexVertexShader",
"vortexFragmentShader",
"vortexGeometryShader") &&
460 tryShaders(
"basicVertexShader",
"rippleFragmentShader") &&
461 tryShaders(
"glitterVertexShader",
"glitterFragmentShader") &&
462 tryShaders(
"honeycombVertexShader",
"honeycombFragmentShader",
"honeycombGeometryShader"));
469 bool WinOpenGLContext::ImplInit()
471 static bool bFirstCall =
true;
477 PIXELFORMATDESCRIPTOR PixelFormatFront =
479 sizeof(PIXELFORMATDESCRIPTOR),
497 PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER;
498 PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW;
502 bool bMultiSampleSupport =
false;
504 bMultiSampleSupport =
InitMultisample(PixelFormatFront, WindowPix,
true,
false);
506 if (bMultiSampleSupport && WindowPix != 0)
508 m_aGLWin.bMultiSampleSupported =
true;
512 WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront);
513 #if OSL_DEBUG_LEVEL > 0
514 PIXELFORMATDESCRIPTOR pfd;
515 DescribePixelFormat(m_aGLWin.hDC, WindowPix,
sizeof(PIXELFORMATDESCRIPTOR), &pfd);
516 SAL_WARN(
"vcl.opengl",
"Render Target: Window: " << static_cast<int>((pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0) <<
", Bitmap: " << static_cast<int>((pfd.dwFlags & PFD_DRAW_TO_BITMAP) != 0));
517 SAL_WARN(
"vcl.opengl",
"Supports OpenGL: " << static_cast<int>((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0));
523 SAL_WARN(
"vcl.opengl",
"Invalid pixelformat");
527 if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront))
529 SAL_WARN(
"vcl.opengl",
"SetPixelFormat failed: " << WindowsErrorString(GetLastError()));
533 HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC);
534 if (hTempRC ==
nullptr)
536 SAL_WARN(
"vcl.opengl",
"wglCreateContext failed: "<< WindowsErrorString(GetLastError()));
540 if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC))
543 SAL_WARN(
"vcl.opengl",
"wglMakeCurrent failed: "<< WindowsErrorString(GetLastError()));
551 wglMakeCurrent(
nullptr,
nullptr);
553 wglDeleteContext(hTempRC);
557 HGLRC hSharedCtx =
nullptr;
561 if (!wglCreateContextAttribsARB)
563 wglMakeCurrent(
nullptr,
nullptr);
565 wglDeleteContext(hTempRC);
571 int const attribs [] =
574 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
578 m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, attribs);
579 if (m_aGLWin.hRC ==
nullptr)
581 SAL_WARN(
"vcl.opengl",
"wglCreateContextAttribsARB failed: "<< WindowsErrorString(GetLastError()));
582 wglMakeCurrent(
nullptr,
nullptr);
584 wglDeleteContext(hTempRC);
588 if (!compiledShaderBinariesWork())
590 wglMakeCurrent(
nullptr,
nullptr);
592 wglDeleteContext(hTempRC);
596 wglMakeCurrent(
nullptr,
nullptr);
598 wglDeleteContext(hTempRC);
600 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
603 SAL_WARN(
"vcl.opengl",
"wglMakeCurrent failed: " << WindowsErrorString(GetLastError()));
612 GLint nMaxTextureSize;
613 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
614 if (nMaxTextureSize <= 4096)
615 SAL_WARN(
"vcl.opengl",
"Max texture size is " << nMaxTextureSize
616 <<
". This may not be enough for normal operation.");
618 VCL_GL_INFO(
"Max texture size: " << nMaxTextureSize);
621 for (GLint nWidthHeight = 1023; nWidthHeight < nMaxTextureSize; nWidthHeight += (nWidthHeight + 1))
623 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, nWidthHeight, nWidthHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8,
nullptr);
625 if (glGetError() == GL_NO_ERROR)
629 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &nWidth);
630 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &nHeight);
631 VCL_GL_INFO(
"Created texture " << nWidthHeight <<
"," << nWidthHeight <<
" reports size: " << nWidth <<
", " << nHeight);
635 SAL_WARN(
"vcl.opengl",
"Error when creating a " << nWidthHeight <<
", " << nWidthHeight <<
" test texture.");
645 GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect);
646 m_aGLWin.Width = clientRect.right - clientRect.left;
647 m_aGLWin.Height = clientRect.bottom - clientRect.top;
649 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
660 return new WinOpenGLContext;
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
virtual void initWindow()
virtual bool isAnyCurrent()
Is any GL context the current context ?
static bool InitTempWindow(HWND &hwnd, int width, int height, const PIXELFORMATDESCRIPTOR &inPfd, GLWinWindow &glWin)
static void ensureDispatchTable()
virtual GLWindow & getModifiableOpenGLWindow()=0
virtual void resetCurrent()
reset the GL context so this context is not implicit in subsequent GL calls.
Holds the information of our new child window.
#define VCL_GL_INFO(stream)
Helper to do a SAL_INFO as well as a GL log.
static std::vector< HGLRC > g_vShareList
virtual void swapBuffers()
virtual const GLWindow & getOpenGLWindow() const =0
We want to be able to detect if a given crash came from the OpenGL code, so use this helper to track ...
virtual void makeCurrent()
make this GL context current - so it is implicit in subsequent GL calls
virtual OpenGLContext * CreateOpenGLContext() override
static GLint LoadShaders(const OUString &rVertexShaderName, const OUString &rFragmentShaderName, const OUString &rGeometryShaderName, std::string_view preamble, std::string_view rDigest)
virtual void destroyCurrentContext()
static bool InitMultisample(const PIXELFORMATDESCRIPTOR &pfd, int &rPixelFormat, bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice)
static VclPtr< reference_type > Create(Arg &&...arg)
A construction helper for VclPtr.
static bool WGLisExtensionSupported(const char *extension)
#define SAL_WARN(area, stream)
static bool g_bAnyCurrent
virtual bool isCurrent()
Is this GL context the current context ?