Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / vcl / opengl / win / gdiimpl.cxx
blob96f0b8bce57d2962110fc60cac3b142962f38af9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <memory>
11 #include <thread>
12 #include <opengl/win/gdiimpl.hxx>
14 #include <comphelper/windowserrorstring.hxx>
15 #include <opengl/zone.hxx>
16 #include <win/wincomp.hxx>
17 #include <win/saldata.hxx>
18 #include <win/salframe.h>
19 #include <win/salinst.h>
20 #include <epoxy/wgl.h>
21 #include <ControlCacheKey.hxx>
23 static std::vector<HGLRC> g_vShareList;
24 static bool g_bAnyCurrent;
26 class GLWinWindow : public GLWindow
28 public:
29 HWND hWnd;
30 HDC hDC;
31 HGLRC hRC;
32 GLWinWindow();
35 GLWinWindow::GLWinWindow()
36 : hWnd(nullptr)
37 , hDC(nullptr)
38 , hRC(nullptr)
42 class WinOpenGLContext : public OpenGLContext
44 public:
45 bool init( HDC hDC, HWND hWnd );
46 virtual void initWindow() override;
47 private:
48 GLWinWindow m_aGLWin;
49 virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
50 virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
51 virtual bool ImplInit() override;
52 virtual void makeCurrent() override;
53 virtual void destroyCurrentContext() override;
54 virtual bool isCurrent() override;
55 virtual bool isAnyCurrent() override;
56 virtual void resetCurrent() override;
57 virtual void swapBuffers() override;
60 void WinOpenGLContext::swapBuffers()
62 OpenGLZone aZone;
64 SwapBuffers(m_aGLWin.hDC);
66 BuffersSwapped();
69 void WinOpenGLContext::resetCurrent()
71 clearCurrent();
73 OpenGLZone aZone;
75 wglMakeCurrent(nullptr, nullptr);
76 g_bAnyCurrent = false;
79 void ensureDispatchTable()
81 thread_local bool bEpoxyDispatchMakeCurrentCalled = false;
82 if (!bEpoxyDispatchMakeCurrentCalled)
84 epoxy_handle_external_wglMakeCurrent();
85 bEpoxyDispatchMakeCurrentCalled = true;
89 bool WinOpenGLContext::isCurrent()
91 OpenGLZone aZone;
92 if (!g_bAnyCurrent || !m_aGLWin.hRC)
93 return false;
94 ensureDispatchTable();
95 return wglGetCurrentContext() == m_aGLWin.hRC && wglGetCurrentDC() == m_aGLWin.hDC;
98 bool WinOpenGLContext::isAnyCurrent()
100 return g_bAnyCurrent && wglGetCurrentContext() != nullptr;
103 void WinOpenGLContext::makeCurrent()
105 if (isCurrent())
106 return;
108 OpenGLZone aZone;
110 clearCurrent();
112 ensureDispatchTable();
114 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
116 g_bAnyCurrent = false;
117 DWORD nLastError = GetLastError();
118 if (nLastError != ERROR_SUCCESS)
119 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(nLastError));
120 return;
123 g_bAnyCurrent = true;
125 registerAsCurrent();
128 bool WinOpenGLContext::init(HDC hDC, HWND hWnd)
130 if (isInitialized())
131 return true;
133 m_aGLWin.hDC = hDC;
134 m_aGLWin.hWnd = hWnd;
135 return ImplInit();
138 void WinOpenGLContext::initWindow()
140 if( !m_pChildWindow )
142 SystemWindowData winData = generateWinData(mpWindow, false);
143 m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
146 if (m_pChildWindow)
148 InitChildWindow(m_pChildWindow.get());
149 const SystemEnvData* sysData(m_pChildWindow->GetSystemData());
150 m_aGLWin.hWnd = sysData->hWnd;
153 m_aGLWin.hDC = GetDC(m_aGLWin.hWnd);
156 void WinOpenGLContext::destroyCurrentContext()
158 if (m_aGLWin.hRC)
160 std::vector<HGLRC>::iterator itr = std::remove(g_vShareList.begin(), g_vShareList.end(), m_aGLWin.hRC);
161 if (itr != g_vShareList.end())
162 g_vShareList.erase(itr);
164 if (wglGetCurrentContext() != nullptr)
166 wglMakeCurrent(nullptr, nullptr);
167 g_bAnyCurrent = false;
169 wglDeleteContext( m_aGLWin.hRC );
170 ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC );
171 m_aGLWin.hRC = nullptr;
175 static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
177 switch (message)
179 case WM_CREATE:
180 return 0;
181 case WM_CLOSE:
182 PostQuitMessage(0);
183 return 0;
184 case WM_DESTROY:
185 return 0;
186 default:
187 return DefWindowProcW(hwnd, message, wParam, lParam);
191 bool InitTempWindow(HWND& hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWinWindow& glWin)
193 OpenGLZone aZone;
195 PIXELFORMATDESCRIPTOR pfd = inPfd;
196 int ret;
197 WNDCLASSW wc;
198 wc.style = 0;
199 wc.lpfnWndProc = WndProc;
200 wc.cbClsExtra = wc.cbWndExtra = 0;
201 wc.hInstance = nullptr;
202 wc.hIcon = nullptr;
203 wc.hCursor = nullptr;
204 wc.hbrBackground = nullptr;
205 wc.lpszMenuName = nullptr;
206 wc.lpszClassName = L"GLRenderer";
207 RegisterClassW(&wc);
208 hwnd = CreateWindowW(wc.lpszClassName, nullptr, WS_DISABLED, 0, 0, width, height, nullptr, nullptr, wc.hInstance, nullptr);
209 glWin.hDC = GetDC(hwnd);
211 int nPixelFormat = ChoosePixelFormat(glWin.hDC, &pfd);
212 if (!nPixelFormat)
214 ReleaseDC(hwnd, glWin.hDC);
215 DestroyWindow(hwnd);
216 return false;
218 ret = SetPixelFormat(glWin.hDC, nPixelFormat, &pfd);
219 if(!ret)
221 ReleaseDC(hwnd, glWin.hDC);
222 DestroyWindow(hwnd);
223 return false;
225 glWin.hRC = wglCreateContext(glWin.hDC);
226 if(!(glWin.hRC))
228 ReleaseDC(hwnd, glWin.hDC);
229 DestroyWindow(hwnd);
230 return false;
232 ret = wglMakeCurrent(glWin.hDC, glWin.hRC);
233 if(!ret)
235 wglMakeCurrent(nullptr, nullptr);
236 g_bAnyCurrent = false;
237 wglDeleteContext(glWin.hRC);
238 ReleaseDC(hwnd, glWin.hDC);
239 DestroyWindow(hwnd);
240 return false;
242 g_bAnyCurrent = false;
244 return true;
247 bool WGLisExtensionSupported(const char *extension)
249 OpenGLZone aZone;
251 const size_t extlen = strlen(extension);
252 const char *supported = nullptr;
254 // Try to use wglGetExtensionStringARB on current DC, if possible
255 PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");
257 if (wglGetExtString)
258 supported = reinterpret_cast<char*(__stdcall*)(HDC)>(wglGetExtString)(wglGetCurrentDC());
259 // If that failed, try standard OpenGL extensions string
260 if (supported == nullptr)
261 supported = reinterpret_cast<char const *>(glGetString(GL_EXTENSIONS));
262 // If that failed too, must be no extensions supported
263 if (supported == nullptr)
264 return false;
266 // Begin examination at start of string, increment by 1 on false match
267 for (const char* p = supported; ; p++)
269 // Advance p up to the next possible match
270 p = strstr(p, extension);
272 if (p == nullptr)
273 return false; // No Match
275 // Make sure that match is at the start of the string or that
276 // the previous char is a space, or else we could accidentally
277 // match "wglFunkywglExtension" with "wglExtension"
279 // Also, make sure that the following character is space or null
280 // or else "wglExtensionTwo" might match "wglExtension"
281 if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
282 return true; // Match
286 bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat,
287 bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice)
289 OpenGLZone aZone;
291 HWND hWnd = nullptr;
292 GLWinWindow glWin;
293 // Create a temp window to check whether support multi-sample, if support, get the format
294 if (!InitTempWindow(hWnd, 32, 32, pfd, glWin))
296 SAL_WARN("vcl.opengl", "Can't create temp window to test");
297 return false;
300 // See if the string exists in WGL
301 if (!WGLisExtensionSupported("WGL_ARB_multisample"))
303 SAL_WARN("vcl.opengl", "Device doesn't support multisample");
304 wglMakeCurrent(nullptr, nullptr);
305 g_bAnyCurrent = false;
306 wglDeleteContext(glWin.hRC);
307 ReleaseDC(hWnd, glWin.hDC);
308 DestroyWindow(hWnd);
309 return false;
311 // Get our pixel format
312 PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
313 if (!fn_wglChoosePixelFormatARB)
315 wglMakeCurrent(nullptr, nullptr);
316 g_bAnyCurrent = false;
317 wglDeleteContext(glWin.hRC);
318 ReleaseDC(hWnd, glWin.hDC);
319 DestroyWindow(hWnd);
320 return false;
322 // Get our current device context
323 HDC hDC = GetDC(hWnd);
325 int pixelFormat;
326 int valid;
327 UINT numFormats;
328 float fAttributes[] = {0,0};
329 // These attributes are the bits we want to test for in our sample.
330 // Everything is pretty standard, the only one we want to
331 // really focus on is the WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB.
332 // These two are going to do the main testing for whether or not
333 // we support multisampling on this hardware.
334 int iAttributes[] =
336 WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
337 WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
338 WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
339 WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
340 WGL_COLOR_BITS_ARB,24,
341 WGL_ALPHA_BITS_ARB,8,
342 WGL_DEPTH_BITS_ARB,24,
343 WGL_STENCIL_BITS_ARB,0,
344 WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
345 WGL_SAMPLES_ARB,8,
349 if (!bUseDoubleBufferedRendering)
351 // Use asserts to make sure the iAttributes array is not changed without changing these ugly
352 // hardcode indexes into it.
353 assert(iAttributes[0] == WGL_DOUBLE_BUFFER_ARB);
354 iAttributes[1] = GL_FALSE;
357 if (bRequestVirtualDevice)
359 assert(iAttributes[2] == WGL_DRAW_TO_WINDOW_ARB);
360 iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB;
363 bool bArbMultisampleSupported = false;
365 // First we check to see if we can get a pixel format for 8 samples
366 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
367 // If we returned true, and our format count is greater than 1
368 if (valid && numFormats >= 1)
370 bArbMultisampleSupported = true;
371 rPixelFormat = pixelFormat;
372 wglMakeCurrent(nullptr, nullptr);
373 g_bAnyCurrent = false;
374 wglDeleteContext(glWin.hRC);
375 ReleaseDC(hWnd, glWin.hDC);
376 DestroyWindow(hWnd);
377 return bArbMultisampleSupported;
379 // Our pixel format with 8 samples failed, test for 2 samples
380 assert(iAttributes[18] == WGL_SAMPLES_ARB);
381 iAttributes[19] = 2;
382 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
383 if (valid && numFormats >= 1)
385 bArbMultisampleSupported = true;
386 rPixelFormat = pixelFormat;
387 wglMakeCurrent(nullptr, nullptr);
388 g_bAnyCurrent = false;
389 wglDeleteContext(glWin.hRC);
390 ReleaseDC(hWnd, glWin.hDC);
391 DestroyWindow(hWnd);
392 return bArbMultisampleSupported;
394 // Return the valid format
395 wglMakeCurrent(nullptr, nullptr);
396 g_bAnyCurrent = false;
397 wglDeleteContext(glWin.hRC);
398 ReleaseDC(hWnd, glWin.hDC);
399 DestroyWindow(hWnd);
401 return bArbMultisampleSupported;
404 namespace
407 bool tryShaders(const OUString& rVertexShader, const OUString& rFragmentShader, const OUString& rGeometryShader = "", const OString& rPreamble = "")
409 GLint nId;
411 // Somewhat mysteriously, the OpenGLHelper::LoadShaders() API saves a compiled binary of the
412 // shader only if you give it the digest of the shaders. We have API to calculate the digest
413 // only of the combination of vertex and fragment (but not geometry) shader. So if we have a
414 // geometry shader, we should not save the binary.
415 if (rGeometryShader.isEmpty())
417 nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rPreamble, OpenGLHelper::GetDigest( rVertexShader, rFragmentShader, rPreamble));
419 else
421 assert(rPreamble.isEmpty());
422 nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rGeometryShader);
424 if (!nId)
425 return false;
426 glDeleteProgram(nId);
427 return glGetError() == GL_NO_ERROR;
430 bool compiledShaderBinariesWork()
432 static bool bBeenHere = false;
433 static bool bResult;
435 if (bBeenHere)
436 return bResult;
438 bBeenHere = true;
440 bResult =
442 #if 0 // Only look at shaders used by vcl for now
443 // canvas
444 tryShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader") &&
445 tryShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader") &&
446 tryShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader") &&
447 tryShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader") &&
448 tryShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader") &&
449 tryShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader") &&
450 // chart2
451 (GLEW_VERSION_3_3 ?
452 (tryShaders("shape3DVertexShader", "shape3DFragmentShader") &&
453 tryShaders("shape3DVertexShaderBatchScroll", "shape3DFragmentShaderBatchScroll") &&
454 tryShaders("shape3DVertexShaderBatch", "shape3DFragmentShaderBatch") &&
455 tryShaders("textVertexShaderBatch", "textFragmentShaderBatch")) :
456 (tryShaders("shape3DVertexShaderV300", "shape3DFragmentShaderV300"))) &&
457 tryShaders("textVertexShader", "textFragmentShader") &&
458 tryShaders("screenTextVertexShader", "screenTextFragmentShader") &&
459 tryShaders("commonVertexShader", "commonFragmentShader") &&
460 tryShaders("pickingVertexShader", "pickingFragmentShader") &&
461 tryShaders("backgroundVertexShader", "backgroundFragmentShader") &&
462 tryShaders("symbolVertexShader", "symbolFragmentShader") &&
463 tryShaders("symbolVertexShader", "symbolFragmentShader") &&
464 // slideshow
465 tryShaders("reflectionVertexShader", "reflectionFragmentShader") &&
466 tryShaders("basicVertexShader", "basicFragmentShader") &&
467 tryShaders("vortexVertexShader", "vortexFragmentShader", "vortexGeometryShader") &&
468 tryShaders("basicVertexShader", "rippleFragmentShader") &&
469 tryShaders("glitterVertexShader", "glitterFragmentShader") &&
470 tryShaders("honeycombVertexShader", "honeycombFragmentShader", "honeycombGeometryShader") &&
471 #endif
472 // vcl
473 tryShaders("combinedVertexShader", "combinedFragmentShader") &&
474 tryShaders("dumbVertexShader", "invert50FragmentShader") &&
475 tryShaders("combinedTextureVertexShader", "combinedTextureFragmentShader") &&
476 tryShaders("textureVertexShader", "areaScaleFragmentShader") &&
477 tryShaders("transformedTextureVertexShader", "maskedTextureFragmentShader") &&
478 tryShaders("transformedTextureVertexShader", "areaScaleFastFragmentShader") &&
479 tryShaders("transformedTextureVertexShader", "areaScaleFastFragmentShader", "", "#define MASKED") &&
480 tryShaders("transformedTextureVertexShader", "areaScaleFragmentShader") &&
481 tryShaders("transformedTextureVertexShader", "areaScaleFragmentShader", "", "#define MASKED") &&
482 tryShaders("transformedTextureVertexShader", "textureFragmentShader") &&
483 tryShaders("combinedTextureVertexShader", "combinedTextureFragmentShader") &&
484 tryShaders("combinedTextureVertexShader", "combinedTextureFragmentShader", "", "// flush shader\n") &&
485 tryShaders("textureVertexShader", "linearGradientFragmentShader") &&
486 tryShaders("textureVertexShader", "radialGradientFragmentShader") &&
487 tryShaders("textureVertexShader", "areaHashCRC64TFragmentShader") &&
488 tryShaders("textureVertexShader", "replaceColorFragmentShader") &&
489 tryShaders("textureVertexShader", "greyscaleFragmentShader") &&
490 tryShaders("textureVertexShader", "textureFragmentShader") &&
491 tryShaders("textureVertexShader", "convolutionFragmentShader") &&
492 tryShaders("textureVertexShader", "areaScaleFastFragmentShader"));
494 return bResult;
497 } // unnamed namespace
499 bool WinOpenGLContext::ImplInit()
501 static bool bFirstCall = true;
503 OpenGLZone aZone;
505 VCL_GL_INFO("OpenGLContext::ImplInit----start");
506 // PixelFormat tells Windows how we want things to be
507 PIXELFORMATDESCRIPTOR PixelFormatFront =
509 sizeof(PIXELFORMATDESCRIPTOR),
510 1, // Version Number
511 PFD_SUPPORT_OPENGL,
512 PFD_TYPE_RGBA, // Request An RGBA Format
513 BYTE(32), // Select Our Color Depth
514 0, 0, 0, 0, 0, 0, // Color Bits Ignored
515 0, // No Alpha Buffer
516 0, // Shift Bit Ignored
517 0, // No Accumulation Buffer
518 0, 0, 0, 0, // Accumulation Bits Ignored
519 24, // 24 bit z-buffer
520 8, // stencil buffer
521 0, // No Auxiliary Buffer
522 0, // now ignored
523 0, // Reserved
524 0, 0, 0 // Layer Masks Ignored
527 if (mbUseDoubleBufferedRendering)
528 PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER;
530 PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW;
532 // we must check whether can set the MSAA
533 int WindowPix = 0;
534 bool bMultiSampleSupport = false;
536 if (!mbVCLOnly)
537 bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix, mbUseDoubleBufferedRendering, false);
538 else
539 VCL_GL_INFO("Skipping multisample detection for VCL.");
541 if (bMultiSampleSupport && WindowPix != 0)
543 m_aGLWin.bMultiSampleSupported = true;
545 else
547 WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront);
548 #if OSL_DEBUG_LEVEL > 0
549 PIXELFORMATDESCRIPTOR pfd;
550 DescribePixelFormat(m_aGLWin.hDC, WindowPix, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
551 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));
552 SAL_WARN("vcl.opengl", "Supports OpenGL: " << static_cast<int>((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0));
553 #endif
556 if (WindowPix == 0)
558 SAL_WARN("vcl.opengl", "Invalid pixelformat");
559 return false;
562 if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront))
564 SAL_WARN("vcl.opengl", "SetPixelFormat failed: " << WindowsErrorString(GetLastError()));
565 return false;
568 HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC);
569 if (hTempRC == nullptr)
571 SAL_WARN("vcl.opengl", "wglCreateContext failed: "<< WindowsErrorString(GetLastError()));
572 return false;
575 if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC))
577 g_bAnyCurrent = false;
578 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: "<< WindowsErrorString(GetLastError()));
579 return false;
582 g_bAnyCurrent = true;
584 if (!InitGL())
586 wglMakeCurrent(nullptr, nullptr);
587 g_bAnyCurrent = false;
588 wglDeleteContext(hTempRC);
589 return false;
592 HGLRC hSharedCtx = nullptr;
593 if (!g_vShareList.empty())
594 hSharedCtx = g_vShareList.front();
596 if (!wglCreateContextAttribsARB)
598 wglMakeCurrent(nullptr, nullptr);
599 g_bAnyCurrent = false;
600 wglDeleteContext(hTempRC);
601 return false;
604 // now setup the shared context; this needs a temporary context already
605 // set up in order to work
606 int const attribs [] =
608 #ifdef DBG_UTIL
609 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
610 #endif
613 m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, attribs);
614 if (m_aGLWin.hRC == nullptr)
616 SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed: "<< WindowsErrorString(GetLastError()));
617 wglMakeCurrent(nullptr, nullptr);
618 g_bAnyCurrent = false;
619 wglDeleteContext(hTempRC);
620 return false;
623 if (!compiledShaderBinariesWork())
625 wglMakeCurrent(nullptr, nullptr);
626 g_bAnyCurrent = false;
627 wglDeleteContext(hTempRC);
628 return false;
631 wglMakeCurrent(nullptr, nullptr);
632 g_bAnyCurrent = false;
633 wglDeleteContext(hTempRC);
635 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
637 g_bAnyCurrent = false;
638 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(GetLastError()));
639 return false;
642 g_bAnyCurrent = true;
644 if (bFirstCall)
646 // Checking texture size
647 GLint nMaxTextureSize;
648 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
649 if (nMaxTextureSize <= 4096)
650 SAL_WARN("vcl.opengl", "Max texture size is " << nMaxTextureSize
651 << ". This may not be enough for normal operation.");
652 else
653 VCL_GL_INFO("Max texture size: " << nMaxTextureSize);
655 // Trying to make a texture and check its size
656 for (GLint nWidthHeight = 1023; nWidthHeight < nMaxTextureSize; nWidthHeight += (nWidthHeight + 1))
658 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, nWidthHeight, nWidthHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, nullptr);
659 CHECK_GL_ERROR();
660 if (glGetError() == GL_NO_ERROR)
662 GLint nWidth = 0;
663 GLint nHeight = 0;
664 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &nWidth);
665 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &nHeight);
666 VCL_GL_INFO("Created texture " << nWidthHeight << "," << nWidthHeight << " reports size: " << nWidth << ", " << nHeight);
668 else
670 SAL_WARN("vcl.opengl", "Error when creating a " << nWidthHeight << ", " << nWidthHeight << " test texture.");
675 InitGLDebugging();
677 g_vShareList.push_back(m_aGLWin.hRC);
679 RECT clientRect;
680 GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect);
681 m_aGLWin.Width = clientRect.right - clientRect.left;
682 m_aGLWin.Height = clientRect.bottom - clientRect.top;
684 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
686 registerAsCurrent();
688 bFirstCall = false;
690 static OString aVendor(reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
692 if (aVendor.equalsIgnoreAsciiCase("intel"))
693 maOpenGLCapabilitySwitch.mbLimitedShaderRegisters = true;
695 return true;
698 OpenGLContext* WinSalInstance::CreateOpenGLContext()
700 return new WinOpenGLContext;
703 WinOpenGLSalGraphicsImpl::WinOpenGLSalGraphicsImpl(WinSalGraphics& rGraphics,
704 SalGeometryProvider *mpProvider):
705 OpenGLSalGraphicsImpl(rGraphics,mpProvider),
706 mrWinParent(rGraphics)
710 void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics )
712 OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrParent.GetImpl());
713 OpenGLSalGraphicsImpl::DoCopyBits( rPosAry, *pImpl );
716 rtl::Reference<OpenGLContext> WinOpenGLSalGraphicsImpl::CreateWinContext()
718 rtl::Reference<WinOpenGLContext> xContext(new WinOpenGLContext);
719 xContext->setVCLOnly();
720 if (!xContext->init(mrWinParent.mhLocalDC, mrWinParent.mhWnd))
722 SAL_WARN("vcl.opengl", "Context could not be created.");
723 return rtl::Reference<OpenGLContext>();
725 return rtl::Reference<OpenGLContext>(xContext.get());
728 void WinOpenGLSalGraphicsImpl::Init()
730 if (!IsOffscreen() && mpContext.is() && mpContext->isInitialized())
732 const GLWinWindow& rGLWindow = static_cast<const GLWinWindow&>(mpContext->getOpenGLWindow());
733 if (rGLWindow.hWnd != mrWinParent.mhWnd || rGLWindow.hDC == mrWinParent.mhLocalDC)
735 // This can legitimately happen, SalFrame keeps 2x
736 // SalGraphics which share the same hWnd and hDC.
737 // The shape 'Area' dialog does reparenting to trigger this.
738 SAL_WARN("vcl.opengl", "Unusual: Windows handle / DC changed without DeInit");
739 DeInit();
743 OpenGLSalGraphicsImpl::Init();
746 TheTextureCache::TheTextureCache(): cache(200) {}
748 ControlCacheType & TheTextureCache::get() {
749 SalData * data = GetSalData();
750 if (!data->m_pTextureCache) {
751 data->m_pTextureCache.reset(new TheTextureCache);
753 return data->m_pTextureCache->cache;
756 bool WinOpenGLSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const & rControlCacheKey, int nX, int nY)
758 static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE");
760 if (!gbCacheEnabled)
761 return false;
763 auto & gTextureCache = TheTextureCache::get();
764 ControlCacheType::const_iterator iterator = gTextureCache.find(rControlCacheKey);
766 if (iterator == gTextureCache.end())
767 return false;
769 const std::unique_ptr<TextureCombo>& pCombo = iterator->second;
771 bool bRet = false;
773 PreDraw();
775 bRet = RenderTextureCombo(*pCombo, nX, nY);
777 PostDraw();
779 return bRet;
782 bool WinOpenGLSalGraphicsImpl::RenderTextureCombo(TextureCombo const & rCombo, int nX, int nY)
784 OpenGLTexture& rTexture = *rCombo.mpTexture;
786 SalTwoRect aPosAry(0, 0, rTexture.GetWidth(), rTexture.GetHeight(),
787 nX, nY, rTexture.GetWidth(), rTexture.GetHeight());
789 DrawTextureDiff(rTexture, *rCombo.mpMask, aPosAry, false);
791 return true;
794 bool WinOpenGLSalGraphicsImpl::RenderCompatibleDC(OpenGLCompatibleDC& rWhite, OpenGLCompatibleDC& rBlack,
795 int nX, int nY, TextureCombo& rCombo)
797 bool bRet = false;
799 PreDraw();
801 rCombo.mpTexture.reset(rWhite.getTexture());
802 rCombo.mpMask.reset(rBlack.getTexture());
804 bRet = RenderTextureCombo(rCombo, nX, nY);
806 PostDraw();
807 return bRet;
810 bool WinOpenGLSalGraphicsImpl::RenderAndCacheNativeControl(OpenGLCompatibleDC& rWhite, OpenGLCompatibleDC& rBlack,
811 int nX, int nY , ControlCacheKey& aControlCacheKey)
813 std::unique_ptr<TextureCombo> pCombo(new TextureCombo);
815 bool bResult = RenderCompatibleDC(rWhite, rBlack, nX, nY, *pCombo);
816 if (!bResult)
817 return false;
819 if (!aControlCacheKey.canCacheControl())
820 return true;
822 ControlCachePair pair(aControlCacheKey, std::move(pCombo));
823 TheTextureCache::get().insert(std::move(pair));
825 return bResult;
828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */