Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / opengl / win / gdiimpl.cxx
blobb0d1188519c2d739bce028ebef5004efafe0b020
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>
13 #include <vcl/opengl/OpenGLHelper.hxx>
15 #include <sal/log.hxx>
16 #include <comphelper/windowserrorstring.hxx>
17 #include <opengl/zone.hxx>
18 #include <win/wincomp.hxx>
19 #include <win/saldata.hxx>
20 #include <win/salframe.h>
21 #include <win/salinst.h>
22 #include <epoxy/wgl.h>
23 #include <ControlCacheKey.hxx>
25 static std::vector<HGLRC> g_vShareList;
26 static bool g_bAnyCurrent;
28 class GLWinWindow : public GLWindow
30 public:
31 HWND hWnd;
32 HDC hDC;
33 HGLRC hRC;
34 GLWinWindow();
37 GLWinWindow::GLWinWindow()
38 : hWnd(nullptr)
39 , hDC(nullptr)
40 , hRC(nullptr)
44 class WinOpenGLContext : public OpenGLContext
46 public:
47 bool init( HDC hDC, HWND hWnd );
48 virtual void initWindow() override;
49 private:
50 GLWinWindow m_aGLWin;
51 virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
52 virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
53 virtual bool ImplInit() override;
54 virtual void makeCurrent() override;
55 virtual void destroyCurrentContext() override;
56 virtual bool isCurrent() override;
57 virtual bool isAnyCurrent() override;
58 virtual void resetCurrent() override;
59 virtual void swapBuffers() override;
62 void WinOpenGLContext::swapBuffers()
64 OpenGLZone aZone;
66 SwapBuffers(m_aGLWin.hDC);
68 BuffersSwapped();
71 void WinOpenGLContext::resetCurrent()
73 clearCurrent();
75 OpenGLZone aZone;
77 wglMakeCurrent(nullptr, nullptr);
78 g_bAnyCurrent = false;
81 static void ensureDispatchTable()
83 thread_local bool bEpoxyDispatchMakeCurrentCalled = false;
84 if (!bEpoxyDispatchMakeCurrentCalled)
86 epoxy_handle_external_wglMakeCurrent();
87 bEpoxyDispatchMakeCurrentCalled = true;
91 bool WinOpenGLContext::isCurrent()
93 OpenGLZone aZone;
94 if (!g_bAnyCurrent || !m_aGLWin.hRC)
95 return false;
96 ensureDispatchTable();
97 return wglGetCurrentContext() == m_aGLWin.hRC && wglGetCurrentDC() == m_aGLWin.hDC;
100 bool WinOpenGLContext::isAnyCurrent()
102 return g_bAnyCurrent && wglGetCurrentContext() != nullptr;
105 void WinOpenGLContext::makeCurrent()
107 if (isCurrent())
108 return;
110 OpenGLZone aZone;
112 clearCurrent();
114 ensureDispatchTable();
116 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
118 g_bAnyCurrent = false;
119 DWORD nLastError = GetLastError();
120 if (nLastError != ERROR_SUCCESS)
121 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(nLastError));
122 return;
125 g_bAnyCurrent = true;
127 registerAsCurrent();
130 bool WinOpenGLContext::init(HDC hDC, HWND hWnd)
132 if (isInitialized())
133 return true;
135 m_aGLWin.hDC = hDC;
136 m_aGLWin.hWnd = hWnd;
137 return ImplInit();
140 void WinOpenGLContext::initWindow()
142 if( !m_pChildWindow )
144 SystemWindowData winData = generateWinData(mpWindow, false);
145 m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
148 if (m_pChildWindow)
150 InitChildWindow(m_pChildWindow.get());
151 const SystemEnvData* sysData(m_pChildWindow->GetSystemData());
152 m_aGLWin.hWnd = sysData->hWnd;
155 m_aGLWin.hDC = GetDC(m_aGLWin.hWnd);
158 void WinOpenGLContext::destroyCurrentContext()
160 if (m_aGLWin.hRC)
162 std::vector<HGLRC>::iterator itr = std::remove(g_vShareList.begin(), g_vShareList.end(), m_aGLWin.hRC);
163 if (itr != g_vShareList.end())
164 g_vShareList.erase(itr);
166 if (wglGetCurrentContext() != nullptr)
168 wglMakeCurrent(nullptr, nullptr);
169 g_bAnyCurrent = false;
171 wglDeleteContext( m_aGLWin.hRC );
172 ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC );
173 m_aGLWin.hRC = nullptr;
177 static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
179 switch (message)
181 case WM_CREATE:
182 return 0;
183 case WM_CLOSE:
184 PostQuitMessage(0);
185 return 0;
186 case WM_DESTROY:
187 return 0;
188 default:
189 return DefWindowProcW(hwnd, message, wParam, lParam);
193 static bool InitTempWindow(HWND& hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWinWindow& glWin)
195 OpenGLZone aZone;
197 PIXELFORMATDESCRIPTOR pfd = inPfd;
198 int ret;
199 WNDCLASSW wc;
200 wc.style = 0;
201 wc.lpfnWndProc = WndProc;
202 wc.cbClsExtra = wc.cbWndExtra = 0;
203 wc.hInstance = nullptr;
204 wc.hIcon = nullptr;
205 wc.hCursor = nullptr;
206 wc.hbrBackground = nullptr;
207 wc.lpszMenuName = nullptr;
208 wc.lpszClassName = L"GLRenderer";
209 RegisterClassW(&wc);
210 hwnd = CreateWindowW(wc.lpszClassName, nullptr, WS_DISABLED, 0, 0, width, height, nullptr, nullptr, wc.hInstance, nullptr);
211 glWin.hDC = GetDC(hwnd);
213 int nPixelFormat = ChoosePixelFormat(glWin.hDC, &pfd);
214 if (!nPixelFormat)
216 ReleaseDC(hwnd, glWin.hDC);
217 DestroyWindow(hwnd);
218 return false;
220 ret = SetPixelFormat(glWin.hDC, nPixelFormat, &pfd);
221 if(!ret)
223 ReleaseDC(hwnd, glWin.hDC);
224 DestroyWindow(hwnd);
225 return false;
227 glWin.hRC = wglCreateContext(glWin.hDC);
228 if(!(glWin.hRC))
230 ReleaseDC(hwnd, glWin.hDC);
231 DestroyWindow(hwnd);
232 return false;
234 ret = wglMakeCurrent(glWin.hDC, glWin.hRC);
235 if(!ret)
237 wglMakeCurrent(nullptr, nullptr);
238 g_bAnyCurrent = false;
239 wglDeleteContext(glWin.hRC);
240 ReleaseDC(hwnd, glWin.hDC);
241 DestroyWindow(hwnd);
242 return false;
244 g_bAnyCurrent = false;
246 return true;
249 static bool WGLisExtensionSupported(const char *extension)
251 OpenGLZone aZone;
253 const size_t extlen = strlen(extension);
254 const char *supported = nullptr;
256 // Try to use wglGetExtensionStringARB on current DC, if possible
257 PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");
259 if (wglGetExtString)
260 supported = reinterpret_cast<char*(__stdcall*)(HDC)>(wglGetExtString)(wglGetCurrentDC());
261 // If that failed, try standard OpenGL extensions string
262 if (supported == nullptr)
263 supported = reinterpret_cast<char const *>(glGetString(GL_EXTENSIONS));
264 // If that failed too, must be no extensions supported
265 if (supported == nullptr)
266 return false;
268 // Begin examination at start of string, increment by 1 on false match
269 for (const char* p = supported; ; p++)
271 // Advance p up to the next possible match
272 p = strstr(p, extension);
274 if (p == nullptr)
275 return false; // No Match
277 // Make sure that match is at the start of the string or that
278 // the previous char is a space, or else we could accidentally
279 // match "wglFunkywglExtension" with "wglExtension"
281 // Also, make sure that the following character is space or null
282 // or else "wglExtensionTwo" might match "wglExtension"
283 if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
284 return true; // Match
288 static bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat,
289 bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice)
291 OpenGLZone aZone;
293 HWND hWnd = nullptr;
294 GLWinWindow glWin;
295 // Create a temp window to check whether support multi-sample, if support, get the format
296 if (!InitTempWindow(hWnd, 32, 32, pfd, glWin))
298 SAL_WARN("vcl.opengl", "Can't create temp window to test");
299 return false;
302 // See if the string exists in WGL
303 if (!WGLisExtensionSupported("WGL_ARB_multisample"))
305 SAL_WARN("vcl.opengl", "Device doesn't support multisample");
306 wglMakeCurrent(nullptr, nullptr);
307 g_bAnyCurrent = false;
308 wglDeleteContext(glWin.hRC);
309 ReleaseDC(hWnd, glWin.hDC);
310 DestroyWindow(hWnd);
311 return false;
313 // Get our pixel format
314 PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
315 if (!fn_wglChoosePixelFormatARB)
317 wglMakeCurrent(nullptr, nullptr);
318 g_bAnyCurrent = false;
319 wglDeleteContext(glWin.hRC);
320 ReleaseDC(hWnd, glWin.hDC);
321 DestroyWindow(hWnd);
322 return false;
324 // Get our current device context
325 HDC hDC = GetDC(hWnd);
327 int pixelFormat;
328 int valid;
329 UINT numFormats;
330 float fAttributes[] = {0,0};
331 // These attributes are the bits we want to test for in our sample.
332 // Everything is pretty standard, the only one we want to
333 // really focus on is the WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB.
334 // These two are going to do the main testing for whether or not
335 // we support multisampling on this hardware.
336 int iAttributes[] =
338 WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
339 WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
340 WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
341 WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
342 WGL_COLOR_BITS_ARB,24,
343 WGL_ALPHA_BITS_ARB,8,
344 WGL_DEPTH_BITS_ARB,24,
345 WGL_STENCIL_BITS_ARB,0,
346 WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
347 WGL_SAMPLES_ARB,8,
351 if (!bUseDoubleBufferedRendering)
353 // Use asserts to make sure the iAttributes array is not changed without changing these ugly
354 // hardcode indexes into it.
355 assert(iAttributes[0] == WGL_DOUBLE_BUFFER_ARB);
356 iAttributes[1] = GL_FALSE;
359 if (bRequestVirtualDevice)
361 assert(iAttributes[2] == WGL_DRAW_TO_WINDOW_ARB);
362 iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB;
365 bool bArbMultisampleSupported = false;
367 // First we check to see if we can get a pixel format for 8 samples
368 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
369 // If we returned true, and our format count is greater than 1
370 if (valid && numFormats >= 1)
372 bArbMultisampleSupported = true;
373 rPixelFormat = pixelFormat;
374 wglMakeCurrent(nullptr, nullptr);
375 g_bAnyCurrent = false;
376 wglDeleteContext(glWin.hRC);
377 ReleaseDC(hWnd, glWin.hDC);
378 DestroyWindow(hWnd);
379 return bArbMultisampleSupported;
381 // Our pixel format with 8 samples failed, test for 2 samples
382 assert(iAttributes[18] == WGL_SAMPLES_ARB);
383 iAttributes[19] = 2;
384 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
385 if (valid && numFormats >= 1)
387 bArbMultisampleSupported = true;
388 rPixelFormat = pixelFormat;
389 wglMakeCurrent(nullptr, nullptr);
390 g_bAnyCurrent = false;
391 wglDeleteContext(glWin.hRC);
392 ReleaseDC(hWnd, glWin.hDC);
393 DestroyWindow(hWnd);
394 return bArbMultisampleSupported;
396 // Return the valid format
397 wglMakeCurrent(nullptr, nullptr);
398 g_bAnyCurrent = false;
399 wglDeleteContext(glWin.hRC);
400 ReleaseDC(hWnd, glWin.hDC);
401 DestroyWindow(hWnd);
403 return bArbMultisampleSupported;
406 namespace
409 bool tryShaders(const OUString& rVertexShader, const OUString& rFragmentShader, const OUString& rGeometryShader = "", const OString& rPreamble = "")
411 GLint nId;
413 // Somewhat mysteriously, the OpenGLHelper::LoadShaders() API saves a compiled binary of the
414 // shader only if you give it the digest of the shaders. We have API to calculate the digest
415 // only of the combination of vertex and fragment (but not geometry) shader. So if we have a
416 // geometry shader, we should not save the binary.
417 if (rGeometryShader.isEmpty())
419 nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rPreamble, OpenGLHelper::GetDigest( rVertexShader, rFragmentShader, rPreamble));
421 else
423 assert(rPreamble.isEmpty());
424 nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rGeometryShader);
426 if (!nId)
427 return false;
429 // We're interested in the error returned by glDeleteProgram().
430 glGetError();
432 glDeleteProgram(nId);
433 return glGetError() == GL_NO_ERROR;
436 bool compiledShaderBinariesWork()
438 static bool bBeenHere = false;
439 static bool bResult;
441 if (bBeenHere)
442 return bResult;
444 bBeenHere = true;
446 bResult =
448 #if 0 // Only look at shaders used by vcl for now
449 // canvas
450 tryShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader") &&
451 tryShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader") &&
452 tryShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader") &&
453 tryShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader") &&
454 tryShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader") &&
455 tryShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader") &&
456 // chart2
457 (GLEW_VERSION_3_3 ?
458 (tryShaders("shape3DVertexShader", "shape3DFragmentShader") &&
459 tryShaders("shape3DVertexShaderBatchScroll", "shape3DFragmentShaderBatchScroll") &&
460 tryShaders("shape3DVertexShaderBatch", "shape3DFragmentShaderBatch") &&
461 tryShaders("textVertexShaderBatch", "textFragmentShaderBatch")) :
462 (tryShaders("shape3DVertexShaderV300", "shape3DFragmentShaderV300"))) &&
463 tryShaders("textVertexShader", "textFragmentShader") &&
464 tryShaders("screenTextVertexShader", "screenTextFragmentShader") &&
465 tryShaders("commonVertexShader", "commonFragmentShader") &&
466 tryShaders("pickingVertexShader", "pickingFragmentShader") &&
467 tryShaders("backgroundVertexShader", "backgroundFragmentShader") &&
468 tryShaders("symbolVertexShader", "symbolFragmentShader") &&
469 tryShaders("symbolVertexShader", "symbolFragmentShader") &&
470 // slideshow
471 tryShaders("reflectionVertexShader", "reflectionFragmentShader") &&
472 tryShaders("basicVertexShader", "basicFragmentShader") &&
473 tryShaders("vortexVertexShader", "vortexFragmentShader", "vortexGeometryShader") &&
474 tryShaders("basicVertexShader", "rippleFragmentShader") &&
475 tryShaders("glitterVertexShader", "glitterFragmentShader") &&
476 tryShaders("honeycombVertexShader", "honeycombFragmentShader", "honeycombGeometryShader") &&
477 #endif
478 // vcl
479 tryShaders("combinedVertexShader", "combinedFragmentShader") &&
480 tryShaders("dumbVertexShader", "invert50FragmentShader") &&
481 tryShaders("textureVertexShader", "areaScaleFragmentShader") &&
482 tryShaders("transformedTextureVertexShader", "maskedTextureFragmentShader") &&
483 tryShaders("transformedTextureVertexShader", "areaScaleFastFragmentShader") &&
484 tryShaders("transformedTextureVertexShader", "areaScaleFastFragmentShader", "", "#define MASKED") &&
485 tryShaders("transformedTextureVertexShader", "areaScaleFragmentShader") &&
486 tryShaders("transformedTextureVertexShader", "areaScaleFragmentShader", "", "#define MASKED") &&
487 tryShaders("transformedTextureVertexShader", "textureFragmentShader") &&
488 tryShaders("combinedTextureVertexShader", "combinedTextureFragmentShader") &&
489 tryShaders("combinedTextureVertexShader", "combinedTextureFragmentShader", "", "// flush shader\n") &&
490 tryShaders("textureVertexShader", "linearGradientFragmentShader") &&
491 tryShaders("textureVertexShader", "radialGradientFragmentShader") &&
492 tryShaders("textureVertexShader", "areaHashCRC64TFragmentShader") &&
493 tryShaders("textureVertexShader", "replaceColorFragmentShader") &&
494 tryShaders("textureVertexShader", "greyscaleFragmentShader") &&
495 tryShaders("textureVertexShader", "textureFragmentShader") &&
496 tryShaders("textureVertexShader", "convolutionFragmentShader") &&
497 tryShaders("textureVertexShader", "areaScaleFastFragmentShader"));
499 return bResult;
502 } // unnamed namespace
504 bool WinOpenGLContext::ImplInit()
506 static bool bFirstCall = true;
508 OpenGLZone aZone;
510 VCL_GL_INFO("OpenGLContext::ImplInit----start");
511 // PixelFormat tells Windows how we want things to be
512 PIXELFORMATDESCRIPTOR PixelFormatFront =
514 sizeof(PIXELFORMATDESCRIPTOR),
515 1, // Version Number
516 PFD_SUPPORT_OPENGL,
517 PFD_TYPE_RGBA, // Request An RGBA Format
518 BYTE(32), // Select Our Color Depth
519 0, 0, 0, 0, 0, 0, // Color Bits Ignored
520 0, // No Alpha Buffer
521 0, // Shift Bit Ignored
522 0, // No Accumulation Buffer
523 0, 0, 0, 0, // Accumulation Bits Ignored
524 24, // 24 bit z-buffer
525 8, // stencil buffer
526 0, // No Auxiliary Buffer
527 0, // now ignored
528 0, // Reserved
529 0, 0, 0 // Layer Masks Ignored
532 PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER;
533 PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW;
535 // we must check whether can set the MSAA
536 int WindowPix = 0;
537 bool bMultiSampleSupport = false;
539 if (!mbVCLOnly)
540 bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix, /*bUseDoubleBufferedRendering*/true, false);
541 else
542 VCL_GL_INFO("Skipping multisample detection for VCL.");
544 if (bMultiSampleSupport && WindowPix != 0)
546 m_aGLWin.bMultiSampleSupported = true;
548 else
550 WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront);
551 #if OSL_DEBUG_LEVEL > 0
552 PIXELFORMATDESCRIPTOR pfd;
553 DescribePixelFormat(m_aGLWin.hDC, WindowPix, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
554 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));
555 SAL_WARN("vcl.opengl", "Supports OpenGL: " << static_cast<int>((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0));
556 #endif
559 if (WindowPix == 0)
561 SAL_WARN("vcl.opengl", "Invalid pixelformat");
562 return false;
565 if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront))
567 SAL_WARN("vcl.opengl", "SetPixelFormat failed: " << WindowsErrorString(GetLastError()));
568 return false;
571 HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC);
572 if (hTempRC == nullptr)
574 SAL_WARN("vcl.opengl", "wglCreateContext failed: "<< WindowsErrorString(GetLastError()));
575 return false;
578 if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC))
580 g_bAnyCurrent = false;
581 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: "<< WindowsErrorString(GetLastError()));
582 return false;
585 g_bAnyCurrent = true;
587 if (!InitGL())
589 wglMakeCurrent(nullptr, nullptr);
590 g_bAnyCurrent = false;
591 wglDeleteContext(hTempRC);
592 return false;
595 HGLRC hSharedCtx = nullptr;
596 if (!g_vShareList.empty())
597 hSharedCtx = g_vShareList.front();
599 if (!wglCreateContextAttribsARB)
601 wglMakeCurrent(nullptr, nullptr);
602 g_bAnyCurrent = false;
603 wglDeleteContext(hTempRC);
604 return false;
607 // now setup the shared context; this needs a temporary context already
608 // set up in order to work
609 int const attribs [] =
611 #ifdef DBG_UTIL
612 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
613 #endif
616 m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, attribs);
617 if (m_aGLWin.hRC == nullptr)
619 SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed: "<< WindowsErrorString(GetLastError()));
620 wglMakeCurrent(nullptr, nullptr);
621 g_bAnyCurrent = false;
622 wglDeleteContext(hTempRC);
623 return false;
626 if (!compiledShaderBinariesWork())
628 wglMakeCurrent(nullptr, nullptr);
629 g_bAnyCurrent = false;
630 wglDeleteContext(hTempRC);
631 return false;
634 wglMakeCurrent(nullptr, nullptr);
635 g_bAnyCurrent = false;
636 wglDeleteContext(hTempRC);
638 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
640 g_bAnyCurrent = false;
641 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(GetLastError()));
642 return false;
645 g_bAnyCurrent = true;
647 if (bFirstCall)
649 // Checking texture size
650 GLint nMaxTextureSize;
651 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
652 if (nMaxTextureSize <= 4096)
653 SAL_WARN("vcl.opengl", "Max texture size is " << nMaxTextureSize
654 << ". This may not be enough for normal operation.");
655 else
656 VCL_GL_INFO("Max texture size: " << nMaxTextureSize);
658 // Trying to make a texture and check its size
659 for (GLint nWidthHeight = 1023; nWidthHeight < nMaxTextureSize; nWidthHeight += (nWidthHeight + 1))
661 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, nWidthHeight, nWidthHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, nullptr);
662 CHECK_GL_ERROR();
663 if (glGetError() == GL_NO_ERROR)
665 GLint nWidth = 0;
666 GLint nHeight = 0;
667 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &nWidth);
668 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &nHeight);
669 VCL_GL_INFO("Created texture " << nWidthHeight << "," << nWidthHeight << " reports size: " << nWidth << ", " << nHeight);
671 else
673 SAL_WARN("vcl.opengl", "Error when creating a " << nWidthHeight << ", " << nWidthHeight << " test texture.");
678 InitGLDebugging();
680 g_vShareList.push_back(m_aGLWin.hRC);
682 RECT clientRect;
683 GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect);
684 m_aGLWin.Width = clientRect.right - clientRect.left;
685 m_aGLWin.Height = clientRect.bottom - clientRect.top;
687 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
689 registerAsCurrent();
691 bFirstCall = false;
693 static OString aVendor(reinterpret_cast<const char*>(glGetString(GL_VENDOR)));
695 if (aVendor.equalsIgnoreAsciiCase("intel"))
696 maOpenGLCapabilitySwitch.mbLimitedShaderRegisters = true;
698 return true;
701 OpenGLContext* WinSalInstance::CreateOpenGLContext()
703 return new WinOpenGLContext;
706 WinOpenGLSalGraphicsImpl::WinOpenGLSalGraphicsImpl(WinSalGraphics& rGraphics,
707 SalGeometryProvider *mpProvider):
708 OpenGLSalGraphicsImpl(rGraphics,mpProvider),
709 mrWinParent(rGraphics)
713 void WinOpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics )
715 OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrParent.GetImpl());
716 OpenGLSalGraphicsImpl::DoCopyBits( rPosAry, *pImpl );
719 rtl::Reference<OpenGLContext> WinOpenGLSalGraphicsImpl::CreateWinContext()
721 rtl::Reference<WinOpenGLContext> xContext(new WinOpenGLContext);
722 xContext->setVCLOnly();
723 if (!xContext->init(mrWinParent.mhLocalDC, mrWinParent.mhWnd))
725 SAL_WARN("vcl.opengl", "Context could not be created.");
726 return rtl::Reference<OpenGLContext>();
728 return rtl::Reference<OpenGLContext>(xContext.get());
731 void WinOpenGLSalGraphicsImpl::Init()
733 if (!IsOffscreen() && mpContext.is() && mpContext->isInitialized())
735 const GLWinWindow& rGLWindow = static_cast<const GLWinWindow&>(mpContext->getOpenGLWindow());
736 if (rGLWindow.hWnd != mrWinParent.mhWnd || rGLWindow.hDC == mrWinParent.mhLocalDC)
738 // This can legitimately happen, SalFrame keeps 2x
739 // SalGraphics which share the same hWnd and hDC.
740 // The shape 'Area' dialog does reparenting to trigger this.
741 SAL_WARN("vcl.opengl", "Unusual: Windows handle / DC changed without DeInit");
742 DeInit();
746 OpenGLSalGraphicsImpl::Init();
749 TheTextureCache::TheTextureCache(): cache(200) {}
751 ControlCacheType & TheTextureCache::get() {
752 SalData * data = GetSalData();
753 if (!data->m_pTextureCache) {
754 data->m_pTextureCache.reset(new TheTextureCache);
756 return data->m_pTextureCache->cache;
759 bool WinOpenGLSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const & rControlCacheKey, int nX, int nY)
761 static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE");
763 if (!gbCacheEnabled)
764 return false;
766 auto & gTextureCache = TheTextureCache::get();
767 ControlCacheType::const_iterator iterator = gTextureCache.find(rControlCacheKey);
769 if (iterator == gTextureCache.end())
770 return false;
772 const std::unique_ptr<TextureCombo>& pCombo = iterator->second;
774 bool bRet = false;
776 PreDraw();
778 bRet = RenderTextureCombo(*pCombo, nX, nY);
780 PostDraw();
782 return bRet;
785 bool WinOpenGLSalGraphicsImpl::RenderTextureCombo(TextureCombo const & rCombo, int nX, int nY)
787 OpenGLTexture& rTexture = *rCombo.mpTexture;
789 SalTwoRect aPosAry(0, 0, rTexture.GetWidth(), rTexture.GetHeight(),
790 nX, nY, rTexture.GetWidth(), rTexture.GetHeight());
792 DrawTextureDiff(rTexture, *rCombo.mpMask, aPosAry, false);
794 return true;
797 bool WinOpenGLSalGraphicsImpl::RenderCompatibleDC(OpenGLCompatibleDC& rWhite, OpenGLCompatibleDC& rBlack,
798 int nX, int nY, TextureCombo& rCombo)
800 bool bRet = false;
802 PreDraw();
804 rCombo.mpTexture.reset(rWhite.getTexture());
805 rCombo.mpMask.reset(rBlack.getTexture());
807 bRet = RenderTextureCombo(rCombo, nX, nY);
809 PostDraw();
810 return bRet;
813 bool WinOpenGLSalGraphicsImpl::RenderAndCacheNativeControl(OpenGLCompatibleDC& rWhite, OpenGLCompatibleDC& rBlack,
814 int nX, int nY , ControlCacheKey& aControlCacheKey)
816 std::unique_ptr<TextureCombo> pCombo(new TextureCombo);
818 bool bResult = RenderCompatibleDC(rWhite, rBlack, nX, nY, *pCombo);
819 if (!bResult)
820 return false;
822 if (!aControlCacheKey.canCacheControl())
823 return true;
825 ControlCachePair pair(aControlCacheKey, std::move(pCombo));
826 TheTextureCache::get().insert(std::move(pair));
828 return bResult;
831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */