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>
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
35 GLWinWindow::GLWinWindow()
42 class WinOpenGLContext
: public OpenGLContext
45 bool init( HDC hDC
, HWND hWnd
);
46 virtual void initWindow() override
;
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()
64 SwapBuffers(m_aGLWin
.hDC
);
69 void WinOpenGLContext::resetCurrent()
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()
92 if (!g_bAnyCurrent
|| !m_aGLWin
.hRC
)
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()
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
));
123 g_bAnyCurrent
= true;
128 bool WinOpenGLContext::init(HDC hDC
, HWND hWnd
)
134 m_aGLWin
.hWnd
= hWnd
;
138 void WinOpenGLContext::initWindow()
140 if( !m_pChildWindow
)
142 SystemWindowData winData
= generateWinData(mpWindow
, false);
143 m_pChildWindow
= VclPtr
<SystemChildWindow
>::Create(mpWindow
, 0, &winData
, false);
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()
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
)
187 return DefWindowProcW(hwnd
, message
, wParam
, lParam
);
191 bool InitTempWindow(HWND
& hwnd
, int width
, int height
, const PIXELFORMATDESCRIPTOR
& inPfd
, GLWinWindow
& glWin
)
195 PIXELFORMATDESCRIPTOR pfd
= inPfd
;
199 wc
.lpfnWndProc
= WndProc
;
200 wc
.cbClsExtra
= wc
.cbWndExtra
= 0;
201 wc
.hInstance
= nullptr;
203 wc
.hCursor
= nullptr;
204 wc
.hbrBackground
= nullptr;
205 wc
.lpszMenuName
= nullptr;
206 wc
.lpszClassName
= L
"GLRenderer";
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
);
214 ReleaseDC(hwnd
, glWin
.hDC
);
218 ret
= SetPixelFormat(glWin
.hDC
, nPixelFormat
, &pfd
);
221 ReleaseDC(hwnd
, glWin
.hDC
);
225 glWin
.hRC
= wglCreateContext(glWin
.hDC
);
228 ReleaseDC(hwnd
, glWin
.hDC
);
232 ret
= wglMakeCurrent(glWin
.hDC
, glWin
.hRC
);
235 wglMakeCurrent(nullptr, nullptr);
236 g_bAnyCurrent
= false;
237 wglDeleteContext(glWin
.hRC
);
238 ReleaseDC(hwnd
, glWin
.hDC
);
242 g_bAnyCurrent
= false;
247 bool WGLisExtensionSupported(const char *extension
)
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");
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)
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
);
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
)
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");
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
);
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
);
322 // Get our current device context
323 HDC hDC
= GetDC(hWnd
);
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.
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
,
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
);
377 return bArbMultisampleSupported
;
379 // Our pixel format with 8 samples failed, test for 2 samples
380 assert(iAttributes
[18] == WGL_SAMPLES_ARB
);
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
);
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
);
401 return bArbMultisampleSupported
;
407 bool tryShaders(const OUString
& rVertexShader
, const OUString
& rFragmentShader
, const OUString
& rGeometryShader
= "", const OString
& rPreamble
= "")
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
));
421 assert(rPreamble
.isEmpty());
422 nId
= OpenGLHelper::LoadShaders(rVertexShader
, rFragmentShader
, rGeometryShader
);
426 glDeleteProgram(nId
);
427 return glGetError() == GL_NO_ERROR
;
430 bool compiledShaderBinariesWork()
432 static bool bBeenHere
= false;
442 #if 0 // Only look at shaders used by vcl for now
444 tryShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader") &&
445 tryShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader") &&
446 tryShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader") &&
447 tryShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader") &&
448 tryShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader") &&
449 tryShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader") &&
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") &&
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") &&
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"));
497 } // unnamed namespace
499 bool WinOpenGLContext::ImplInit()
501 static bool bFirstCall
= true;
505 VCL_GL_INFO("OpenGLContext::ImplInit----start");
506 // PixelFormat tells Windows how we want things to be
507 PIXELFORMATDESCRIPTOR PixelFormatFront
=
509 sizeof(PIXELFORMATDESCRIPTOR
),
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
521 0, // No Auxiliary Buffer
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
534 bool bMultiSampleSupport
= false;
537 bMultiSampleSupport
= InitMultisample(PixelFormatFront
, WindowPix
, mbUseDoubleBufferedRendering
, false);
539 VCL_GL_INFO("Skipping multisample detection for VCL.");
541 if (bMultiSampleSupport
&& WindowPix
!= 0)
543 m_aGLWin
.bMultiSampleSupported
= true;
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));
558 SAL_WARN("vcl.opengl", "Invalid pixelformat");
562 if (!SetPixelFormat(m_aGLWin
.hDC
, WindowPix
, &PixelFormatFront
))
564 SAL_WARN("vcl.opengl", "SetPixelFormat failed: " << WindowsErrorString(GetLastError()));
568 HGLRC hTempRC
= wglCreateContext(m_aGLWin
.hDC
);
569 if (hTempRC
== nullptr)
571 SAL_WARN("vcl.opengl", "wglCreateContext failed: "<< WindowsErrorString(GetLastError()));
575 if (!wglMakeCurrent(m_aGLWin
.hDC
, hTempRC
))
577 g_bAnyCurrent
= false;
578 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: "<< WindowsErrorString(GetLastError()));
582 g_bAnyCurrent
= true;
586 wglMakeCurrent(nullptr, nullptr);
587 g_bAnyCurrent
= false;
588 wglDeleteContext(hTempRC
);
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
);
604 // now setup the shared context; this needs a temporary context already
605 // set up in order to work
606 int const attribs
[] =
609 WGL_CONTEXT_FLAGS_ARB
, WGL_CONTEXT_DEBUG_BIT_ARB
,
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
);
623 if (!compiledShaderBinariesWork())
625 wglMakeCurrent(nullptr, nullptr);
626 g_bAnyCurrent
= false;
627 wglDeleteContext(hTempRC
);
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()));
642 g_bAnyCurrent
= true;
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.");
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);
660 if (glGetError() == GL_NO_ERROR
)
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
);
670 SAL_WARN("vcl.opengl", "Error when creating a " << nWidthHeight
<< ", " << nWidthHeight
<< " test texture.");
677 g_vShareList
.push_back(m_aGLWin
.hRC
);
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
);
690 static OString
aVendor(reinterpret_cast<const char*>(glGetString(GL_VENDOR
)));
692 if (aVendor
.equalsIgnoreAsciiCase("intel"))
693 maOpenGLCapabilitySwitch
.mbLimitedShaderRegisters
= 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");
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");
763 auto & gTextureCache
= TheTextureCache::get();
764 ControlCacheType::const_iterator iterator
= gTextureCache
.find(rControlCacheKey
);
766 if (iterator
== gTextureCache
.end())
769 const std::unique_ptr
<TextureCombo
>& pCombo
= iterator
->second
;
775 bRet
= RenderTextureCombo(*pCombo
, nX
, nY
);
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);
794 bool WinOpenGLSalGraphicsImpl::RenderCompatibleDC(OpenGLCompatibleDC
& rWhite
, OpenGLCompatibleDC
& rBlack
,
795 int nX
, int nY
, TextureCombo
& rCombo
)
801 rCombo
.mpTexture
.reset(rWhite
.getTexture());
802 rCombo
.mpMask
.reset(rBlack
.getTexture());
804 bRet
= RenderTextureCombo(rCombo
, nX
, nY
);
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
);
819 if (!aControlCacheKey
.canCacheControl())
822 ControlCachePair
pair(aControlCacheKey
, std::move(pCombo
));
823 TheTextureCache::get().insert(std::move(pair
));
828 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */