1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
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
37 GLWinWindow::GLWinWindow()
44 class WinOpenGLContext
: public OpenGLContext
47 bool init( HDC hDC
, HWND hWnd
);
48 virtual void initWindow() override
;
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()
66 SwapBuffers(m_aGLWin
.hDC
);
71 void WinOpenGLContext::resetCurrent()
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()
94 if (!g_bAnyCurrent
|| !m_aGLWin
.hRC
)
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()
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
));
125 g_bAnyCurrent
= true;
130 bool WinOpenGLContext::init(HDC hDC
, HWND hWnd
)
136 m_aGLWin
.hWnd
= hWnd
;
140 void WinOpenGLContext::initWindow()
142 if( !m_pChildWindow
)
144 SystemWindowData winData
= generateWinData(mpWindow
, false);
145 m_pChildWindow
= VclPtr
<SystemChildWindow
>::Create(mpWindow
, 0, &winData
, false);
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()
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
)
189 return DefWindowProcW(hwnd
, message
, wParam
, lParam
);
193 static bool InitTempWindow(HWND
& hwnd
, int width
, int height
, const PIXELFORMATDESCRIPTOR
& inPfd
, GLWinWindow
& glWin
)
197 PIXELFORMATDESCRIPTOR pfd
= inPfd
;
201 wc
.lpfnWndProc
= WndProc
;
202 wc
.cbClsExtra
= wc
.cbWndExtra
= 0;
203 wc
.hInstance
= nullptr;
205 wc
.hCursor
= nullptr;
206 wc
.hbrBackground
= nullptr;
207 wc
.lpszMenuName
= nullptr;
208 wc
.lpszClassName
= L
"GLRenderer";
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
);
216 ReleaseDC(hwnd
, glWin
.hDC
);
220 ret
= SetPixelFormat(glWin
.hDC
, nPixelFormat
, &pfd
);
223 ReleaseDC(hwnd
, glWin
.hDC
);
227 glWin
.hRC
= wglCreateContext(glWin
.hDC
);
230 ReleaseDC(hwnd
, glWin
.hDC
);
234 ret
= wglMakeCurrent(glWin
.hDC
, glWin
.hRC
);
237 wglMakeCurrent(nullptr, nullptr);
238 g_bAnyCurrent
= false;
239 wglDeleteContext(glWin
.hRC
);
240 ReleaseDC(hwnd
, glWin
.hDC
);
244 g_bAnyCurrent
= false;
249 static bool WGLisExtensionSupported(const char *extension
)
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");
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)
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
);
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
)
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");
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
);
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
);
324 // Get our current device context
325 HDC hDC
= GetDC(hWnd
);
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.
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
,
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
);
379 return bArbMultisampleSupported
;
381 // Our pixel format with 8 samples failed, test for 2 samples
382 assert(iAttributes
[18] == WGL_SAMPLES_ARB
);
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
);
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
);
403 return bArbMultisampleSupported
;
409 bool tryShaders(const OUString
& rVertexShader
, const OUString
& rFragmentShader
, const OUString
& rGeometryShader
= "", const OString
& rPreamble
= "")
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
));
423 assert(rPreamble
.isEmpty());
424 nId
= OpenGLHelper::LoadShaders(rVertexShader
, rFragmentShader
, rGeometryShader
);
429 // We're interested in the error returned by glDeleteProgram().
432 glDeleteProgram(nId
);
433 return glGetError() == GL_NO_ERROR
;
436 bool compiledShaderBinariesWork()
438 static bool bBeenHere
= false;
448 #if 0 // Only look at shaders used by vcl for now
450 tryShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader") &&
451 tryShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader") &&
452 tryShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader") &&
453 tryShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader") &&
454 tryShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader") &&
455 tryShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader") &&
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") &&
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") &&
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"));
502 } // unnamed namespace
504 bool WinOpenGLContext::ImplInit()
506 static bool bFirstCall
= true;
510 VCL_GL_INFO("OpenGLContext::ImplInit----start");
511 // PixelFormat tells Windows how we want things to be
512 PIXELFORMATDESCRIPTOR PixelFormatFront
=
514 sizeof(PIXELFORMATDESCRIPTOR
),
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
526 0, // No Auxiliary Buffer
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
537 bool bMultiSampleSupport
= false;
540 bMultiSampleSupport
= InitMultisample(PixelFormatFront
, WindowPix
, /*bUseDoubleBufferedRendering*/true, false);
542 VCL_GL_INFO("Skipping multisample detection for VCL.");
544 if (bMultiSampleSupport
&& WindowPix
!= 0)
546 m_aGLWin
.bMultiSampleSupported
= true;
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));
561 SAL_WARN("vcl.opengl", "Invalid pixelformat");
565 if (!SetPixelFormat(m_aGLWin
.hDC
, WindowPix
, &PixelFormatFront
))
567 SAL_WARN("vcl.opengl", "SetPixelFormat failed: " << WindowsErrorString(GetLastError()));
571 HGLRC hTempRC
= wglCreateContext(m_aGLWin
.hDC
);
572 if (hTempRC
== nullptr)
574 SAL_WARN("vcl.opengl", "wglCreateContext failed: "<< WindowsErrorString(GetLastError()));
578 if (!wglMakeCurrent(m_aGLWin
.hDC
, hTempRC
))
580 g_bAnyCurrent
= false;
581 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: "<< WindowsErrorString(GetLastError()));
585 g_bAnyCurrent
= true;
589 wglMakeCurrent(nullptr, nullptr);
590 g_bAnyCurrent
= false;
591 wglDeleteContext(hTempRC
);
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
);
607 // now setup the shared context; this needs a temporary context already
608 // set up in order to work
609 int const attribs
[] =
612 WGL_CONTEXT_FLAGS_ARB
, WGL_CONTEXT_DEBUG_BIT_ARB
,
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
);
626 if (!compiledShaderBinariesWork())
628 wglMakeCurrent(nullptr, nullptr);
629 g_bAnyCurrent
= false;
630 wglDeleteContext(hTempRC
);
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()));
645 g_bAnyCurrent
= true;
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.");
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);
663 if (glGetError() == GL_NO_ERROR
)
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
);
673 SAL_WARN("vcl.opengl", "Error when creating a " << nWidthHeight
<< ", " << nWidthHeight
<< " test texture.");
680 g_vShareList
.push_back(m_aGLWin
.hRC
);
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
);
693 static OString
aVendor(reinterpret_cast<const char*>(glGetString(GL_VENDOR
)));
695 if (aVendor
.equalsIgnoreAsciiCase("intel"))
696 maOpenGLCapabilitySwitch
.mbLimitedShaderRegisters
= 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");
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");
766 auto & gTextureCache
= TheTextureCache::get();
767 ControlCacheType::const_iterator iterator
= gTextureCache
.find(rControlCacheKey
);
769 if (iterator
== gTextureCache
.end())
772 const std::unique_ptr
<TextureCombo
>& pCombo
= iterator
->second
;
778 bRet
= RenderTextureCombo(*pCombo
, nX
, nY
);
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);
797 bool WinOpenGLSalGraphicsImpl::RenderCompatibleDC(OpenGLCompatibleDC
& rWhite
, OpenGLCompatibleDC
& rBlack
,
798 int nX
, int nY
, TextureCombo
& rCombo
)
804 rCombo
.mpTexture
.reset(rWhite
.getTexture());
805 rCombo
.mpMask
.reset(rBlack
.getTexture());
807 bRet
= RenderTextureCombo(rCombo
, nX
, nY
);
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
);
822 if (!aControlCacheKey
.canCacheControl())
825 ControlCachePair
pair(aControlCacheKey
, std::move(pCombo
));
826 TheTextureCache::get().insert(std::move(pair
));
831 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */