Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / vcl / opengl / x11 / gdiimpl.cxx
bloba8391999ec1e12bdf442499a6d6a47425f75580c
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 <vcl/salbtype.hxx>
12 #include <vcl/lazydelete.hxx>
14 #include <svdata.hxx>
16 #include <unx/pixmap.hxx>
17 #include <unx/saldisp.hxx>
18 #include <unx/salframe.h>
19 #include <unx/salgdi.h>
20 #include <unx/salinst.h>
21 #include <unx/salvd.h>
22 #include <unx/x11/xlimits.hxx>
24 #include <opengl/texture.hxx>
25 #include <opengl/zone.hxx>
26 #include <opengl/RenderState.hxx>
27 #include <opengl/x11/gdiimpl.hxx>
28 #include <opengl/x11/salvd.hxx>
30 #include <vcl/opengl/OpenGLContext.hxx>
31 #include <vcl/opengl/OpenGLHelper.hxx>
33 #include <o3tl/lru_map.hxx>
34 #include <ControlCacheKey.hxx>
36 static std::vector<GLXContext> g_vShareList;
37 static bool g_bAnyCurrent;
39 class X11OpenGLContext : public OpenGLContext
41 public:
42 void init(Display* dpy, Window win, int screen);
43 virtual void initWindow() override;
44 private:
45 GLX11Window m_aGLWin;
46 virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
47 virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
48 virtual bool ImplInit() override;
49 void initGLWindow(Visual* pVisual);
50 virtual SystemWindowData generateWinData(vcl::Window* pParent, bool bRequestLegacyContext) override;
51 virtual void makeCurrent() override;
52 virtual void destroyCurrentContext() override;
53 virtual bool isCurrent() override;
54 virtual bool isAnyCurrent() override;
55 virtual void sync() override;
56 virtual void resetCurrent() override;
57 virtual void swapBuffers() override;
60 namespace
63 #ifdef DBG_UTIL
64 int unxErrorHandler(Display* dpy, XErrorEvent* event)
66 char err[256];
67 char req[256];
68 char minor[256];
69 XGetErrorText(dpy, event->error_code, err, 256);
70 XGetErrorText(dpy, event->request_code, req, 256);
71 XGetErrorText(dpy, event->minor_code, minor, 256);
72 SAL_WARN("vcl.opengl", "Error: " << err << ", Req: " << req << ", Minor: " << minor);
73 return 0;
75 #endif
77 typedef int (*errorHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/);
79 class TempErrorHandler
81 private:
82 errorHandler oldErrorHandler;
83 Display* mdpy;
85 public:
86 TempErrorHandler(Display* dpy, errorHandler newErrorHandler)
87 : oldErrorHandler(nullptr)
88 , mdpy(dpy)
90 if (mdpy)
92 XLockDisplay(dpy);
93 XSync(dpy, false);
94 oldErrorHandler = XSetErrorHandler(newErrorHandler);
98 ~TempErrorHandler()
100 if (mdpy)
102 // sync so that we possibly get an XError
103 glXWaitGL();
104 XSync(mdpy, false);
105 XSetErrorHandler(oldErrorHandler);
106 XUnlockDisplay(mdpy);
111 static bool errorTriggered;
112 int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ )
114 errorTriggered = true;
116 return 0;
119 GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC, bool bUseDoubleBufferedRendering)
121 OpenGLZone aZone;
123 if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) )
124 return nullptr;
126 VCL_GL_INFO("window: " << win);
128 XWindowAttributes xattr;
129 if( !XGetWindowAttributes( dpy, win, &xattr ) )
131 SAL_WARN("vcl.opengl", "Failed to get window attributes for fbconfig " << win);
132 xattr.screen = nullptr;
133 xattr.visual = nullptr;
136 int screen = XScreenNumberOfScreen( xattr.screen );
138 // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */
139 static int visual_attribs[] =
141 GLX_DOUBLEBUFFER, True,
142 GLX_X_RENDERABLE, True,
143 GLX_RED_SIZE, 8,
144 GLX_GREEN_SIZE, 8,
145 GLX_BLUE_SIZE, 8,
146 GLX_ALPHA_SIZE, 8,
147 GLX_DEPTH_SIZE, 24,
148 GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
149 None
152 if (!bUseDoubleBufferedRendering)
153 visual_attribs[1] = False;
155 int fbCount = 0;
156 GLXFBConfig* pFBC = glXChooseFBConfig( dpy,
157 screen,
158 visual_attribs, &fbCount );
160 if(!pFBC)
162 SAL_WARN("vcl.opengl", "no suitable fb format found");
163 return nullptr;
166 int best_num_samp = -1;
167 for(int i = 0; i < fbCount; ++i)
169 XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] );
170 if(pVi && (xattr.visual && pVi->visualid == xattr.visual->visualid) )
172 // pick the one with the most samples per pixel
173 int nSampleBuf = 0;
174 int nSamples = 0;
175 glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf );
176 glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples );
178 if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) )
180 nBestFBC = i;
181 best_num_samp = nSamples;
184 XFree( pVi );
187 return pFBC;
190 Visual* getVisual(Display* dpy, Window win)
192 OpenGLZone aZone;
194 XWindowAttributes xattr;
195 if( !XGetWindowAttributes( dpy, win, &xattr ) )
197 SAL_WARN("vcl.opengl", "Failed to get window attributes for getVisual " << win);
198 xattr.visual = nullptr;
200 VCL_GL_INFO("using VisualID " << xattr.visual);
201 return xattr.visual;
205 void X11OpenGLContext::sync()
207 OpenGLZone aZone;
208 glXWaitGL();
209 XSync(m_aGLWin.dpy, false);
212 void X11OpenGLContext::swapBuffers()
214 OpenGLZone aZone;
216 glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win);
218 BuffersSwapped();
221 void X11OpenGLContext::resetCurrent()
223 clearCurrent();
225 OpenGLZone aZone;
227 if (m_aGLWin.dpy)
229 glXMakeCurrent(m_aGLWin.dpy, None, nullptr);
230 g_bAnyCurrent = false;
234 bool X11OpenGLContext::isCurrent()
236 OpenGLZone aZone;
237 return g_bAnyCurrent && m_aGLWin.ctx && glXGetCurrentContext() == m_aGLWin.ctx &&
238 glXGetCurrentDrawable() == m_aGLWin.win;
241 bool X11OpenGLContext::isAnyCurrent()
243 return g_bAnyCurrent && glXGetCurrentContext() != None;
246 SystemWindowData X11OpenGLContext::generateWinData(vcl::Window* pParent, bool /*bRequestLegacyContext*/)
248 OpenGLZone aZone;
250 SystemWindowData aWinData;
251 aWinData.pVisual = nullptr;
253 const SystemEnvData* sysData(pParent->GetSystemData());
255 Display *dpy = static_cast<Display*>(sysData->pDisplay);
256 Window win = sysData->aWindow;
258 if( dpy == nullptr || !glXQueryExtension( dpy, nullptr, nullptr ) )
259 return aWinData;
261 int best_fbc = -1;
262 GLXFBConfig* pFBC = getFBConfig(dpy, win, best_fbc, true);
264 if (!pFBC)
265 return aWinData;
267 XVisualInfo* vi = nullptr;
268 if( best_fbc != -1 )
269 vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] );
271 XFree(pFBC);
273 if( vi )
275 VCL_GL_INFO("using VisualID " << vi->visualid);
276 aWinData.pVisual = static_cast<void*>(vi->visual);
279 return aWinData;
282 bool X11OpenGLContext::ImplInit()
284 if (!m_aGLWin.dpy)
285 return false;
287 OpenGLZone aZone;
289 GLXContext pSharedCtx( nullptr );
290 #ifdef DBG_UTIL
291 TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
292 #endif
294 VCL_GL_INFO("OpenGLContext::ImplInit----start");
296 if (!g_vShareList.empty())
297 pSharedCtx = g_vShareList.front();
299 //tdf#112166 for, e.g. VirtualBox GL, claiming OpenGL 2.1
300 static bool hasCreateContextAttribsARB = glXGetProcAddress(reinterpret_cast<const GLubyte*>("glXCreateContextAttribsARB")) != nullptr;
301 if (hasCreateContextAttribsARB && !mbRequestLegacyContext)
303 int best_fbc = -1;
304 GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc, mbUseDoubleBufferedRendering);
306 if (pFBC && best_fbc != -1)
308 int const pContextAttribs[] =
310 #if 0 // defined(DBG_UTIL)
311 GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
312 GLX_CONTEXT_MINOR_VERSION_ARB, 2,
313 #endif
314 None
317 m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], pSharedCtx, /* direct, not via X */ GL_TRUE, pContextAttribs);
318 SAL_INFO_IF(m_aGLWin.ctx, "vcl.opengl", "created a 3.2 core context");
320 else
321 SAL_WARN("vcl.opengl", "unable to find correct FBC");
324 if (!m_aGLWin.ctx)
326 if (!m_aGLWin.vi)
327 return false;
329 SAL_WARN("vcl.opengl", "attempting to create a non-double-buffered "
330 "visual matching the context");
332 m_aGLWin.ctx = glXCreateContext(m_aGLWin.dpy,
333 m_aGLWin.vi,
334 pSharedCtx,
335 GL_TRUE /* direct, not via X server */);
338 if( m_aGLWin.ctx )
340 g_vShareList.push_back( m_aGLWin.ctx );
342 else
344 SAL_WARN("vcl.opengl", "unable to create GLX context");
345 return false;
348 if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) )
350 g_bAnyCurrent = false;
351 SAL_WARN("vcl.opengl", "unable to select current GLX context");
352 return false;
355 g_bAnyCurrent = true;
357 int glxMinor, glxMajor;
358 double nGLXVersion = 0;
359 if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) )
360 nGLXVersion = glxMajor + 0.1*glxMinor;
361 SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion);
363 SAL_INFO("vcl.opengl", "available GL extensions: " << glGetString(GL_EXTENSIONS));
365 XWindowAttributes aWinAttr;
366 if( !XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &aWinAttr ) )
368 SAL_WARN("vcl.opengl", "Failed to get window attributes on " << m_aGLWin.win);
369 m_aGLWin.Width = 0;
370 m_aGLWin.Height = 0;
372 else
374 m_aGLWin.Width = aWinAttr.width;
375 m_aGLWin.Height = aWinAttr.height;
378 if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) )
380 // enable vsync
381 typedef GLint (*glXSwapIntervalProc)(GLint);
382 glXSwapIntervalProc glXSwapInterval = reinterpret_cast<glXSwapIntervalProc>(glXGetProcAddress( reinterpret_cast<const GLubyte*>("glXSwapIntervalSGI") ));
383 if( glXSwapInterval )
385 TempErrorHandler aLocalErrorHandler(m_aGLWin.dpy, oglErrorHandler);
387 errorTriggered = false;
389 glXSwapInterval( 1 );
391 if( errorTriggered )
392 SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?");
393 else
394 VCL_GL_INFO("set swap interval to 1 (enable vsync)");
398 bool bRet = InitGL();
399 InitGLDebugging();
401 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
403 registerAsCurrent();
405 return bRet;
408 void X11OpenGLContext::makeCurrent()
410 if (isCurrent())
411 return;
413 OpenGLZone aZone;
415 clearCurrent();
417 #ifdef DBG_UTIL
418 TempErrorHandler aErrorHandler(m_aGLWin.dpy, unxErrorHandler);
419 #endif
421 if (m_aGLWin.dpy)
423 if (!glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ))
425 g_bAnyCurrent = false;
426 SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed "
427 "on drawable " << m_aGLWin.win);
428 return;
430 g_bAnyCurrent = true;
433 registerAsCurrent();
436 void X11OpenGLContext::destroyCurrentContext()
438 if(m_aGLWin.ctx)
440 std::vector<GLXContext>::iterator itr = std::remove( g_vShareList.begin(), g_vShareList.end(), m_aGLWin.ctx );
441 if (itr != g_vShareList.end())
442 g_vShareList.erase(itr);
444 glXMakeCurrent(m_aGLWin.dpy, None, nullptr);
445 g_bAnyCurrent = false;
446 if( glGetError() != GL_NO_ERROR )
448 SAL_WARN("vcl.opengl", "glError: " << glGetError());
450 glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx);
451 m_aGLWin.ctx = nullptr;
455 void X11OpenGLContext::init(Display* dpy, Window win, int screen)
457 if (isInitialized())
458 return;
460 if (!dpy)
461 return;
463 OpenGLZone aZone;
465 m_aGLWin.dpy = dpy;
466 m_aGLWin.win = win;
467 m_aGLWin.screen = screen;
469 Visual* pVisual = getVisual(dpy, win);
471 initGLWindow(pVisual);
473 ImplInit();
476 void X11OpenGLContext::initGLWindow(Visual* pVisual)
478 OpenGLZone aZone;
480 // Get visual info
482 XVisualInfo aTemplate;
483 aTemplate.visualid = XVisualIDFromVisual( pVisual );
484 int nVisuals = 0;
485 XVisualInfo* pInfo = XGetVisualInfo( m_aGLWin.dpy, VisualIDMask, &aTemplate, &nVisuals );
486 if( nVisuals != 1 )
487 SAL_WARN( "vcl.opengl", "match count for visual id is not 1" );
488 m_aGLWin.vi = pInfo;
491 // Check multisample support
492 /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks
493 * an FBConfig instead ... */
494 int nSamples = 0;
495 glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples);
496 if( nSamples > 0 )
497 m_aGLWin.bMultiSampleSupported = true;
499 m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen );
500 SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin.GLXExtensions);
503 void X11OpenGLContext::initWindow()
505 const SystemEnvData* pChildSysData = nullptr;
506 SystemWindowData winData = generateWinData(mpWindow, false);
507 if( winData.pVisual )
509 if( !m_pChildWindow )
511 m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
513 pChildSysData = m_pChildWindow->GetSystemData();
516 if (!m_pChildWindow || !pChildSysData)
517 return;
519 InitChildWindow(m_pChildWindow.get());
521 m_aGLWin.dpy = static_cast<Display*>(pChildSysData->pDisplay);
522 m_aGLWin.win = pChildSysData->aWindow;
523 m_aGLWin.screen = pChildSysData->nScreen;
525 Visual* pVisual = static_cast<Visual*>(pChildSysData->pVisual);
526 initGLWindow(pVisual);
529 GLX11Window::GLX11Window()
530 : dpy(nullptr)
531 , screen(0)
532 , win(0)
533 , vi(nullptr)
534 , ctx(nullptr)
538 bool GLX11Window::HasGLXExtension( const char* name ) const
540 for (sal_Int32 i = 0; i != -1;) {
541 if (GLXExtensions.getToken(0, ' ', i) == name) {
542 return true;
545 return false;
548 GLX11Window::~GLX11Window()
550 XFree(vi);
553 bool GLX11Window::Synchronize(bool bOnoff) const
555 XSynchronize(dpy, bOnoff);
556 return true;
559 OpenGLContext* X11SalInstance::CreateOpenGLContext()
561 return new X11OpenGLContext;
564 X11OpenGLSalGraphicsImpl::X11OpenGLSalGraphicsImpl( X11SalGraphics& rParent ):
565 OpenGLSalGraphicsImpl(rParent,rParent.GetGeometryProvider()),
566 mrX11Parent(rParent)
570 X11OpenGLSalGraphicsImpl::~X11OpenGLSalGraphicsImpl()
574 void X11OpenGLSalGraphicsImpl::Init()
576 // The m_pFrame and m_pVDev pointers are updated late in X11
577 mpProvider = mrX11Parent.GetGeometryProvider();
578 OpenGLSalGraphicsImpl::Init();
581 rtl::Reference<OpenGLContext> X11OpenGLSalGraphicsImpl::CreateWinContext()
583 NativeWindowHandleProvider *pProvider = dynamic_cast<NativeWindowHandleProvider*>(mrX11Parent.m_pFrame);
585 if( !pProvider )
586 return nullptr;
588 sal_uIntPtr aWin = pProvider->GetNativeWindowHandle();
589 rtl::Reference<X11OpenGLContext> xContext = new X11OpenGLContext;
590 xContext->setVCLOnly();
591 xContext->init( mrX11Parent.GetXDisplay(), aWin,
592 mrX11Parent.m_nXScreen.getXScreen() );
593 return rtl::Reference<OpenGLContext>(xContext.get());
596 void X11OpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics )
598 OpenGLSalGraphicsImpl *pImpl = pSrcGraphics ? static_cast< OpenGLSalGraphicsImpl* >(pSrcGraphics->GetImpl()) : static_cast< OpenGLSalGraphicsImpl *>(mrX11Parent.GetImpl());
599 OpenGLSalGraphicsImpl::DoCopyBits( rPosAry, *pImpl );
602 void X11OpenGLSalGraphicsImpl::FillPixmapFromScreen( X11Pixmap* pPixmap, int nX, int nY )
604 Display* pDisplay = mrX11Parent.GetXDisplay();
605 SalX11Screen nScreen = mrX11Parent.GetScreenNumber();
606 XVisualInfo aVisualInfo;
607 XImage* pImage;
608 char* pData;
610 SAL_INFO( "vcl.opengl", "FillPixmapFromScreen" );
612 if (!SalDisplay::BestOpenGLVisual(pDisplay, nScreen.getXScreen(), aVisualInfo))
613 return;
615 // make sure everything is synced up before reading back
616 mpContext->makeCurrent();
617 glXWaitX();
619 // TODO: lfrb: What if offscreen?
620 pData = static_cast<char*>(malloc( pPixmap->GetWidth() * pPixmap->GetHeight() * 4 ));
621 glPixelStorei( GL_PACK_ALIGNMENT, 1 );
622 CHECK_GL_ERROR();
623 glReadPixels( nX, GetHeight() - nY, pPixmap->GetWidth(), pPixmap->GetHeight(),
624 GL_RGBA, GL_UNSIGNED_BYTE, pData );
625 CHECK_GL_ERROR();
627 pImage = XCreateImage( pDisplay, aVisualInfo.visual, 24, ZPixmap, 0, pData,
628 pPixmap->GetWidth(), pPixmap->GetHeight(), 8, 0 );
629 XInitImage( pImage );
630 GC aGC = XCreateGC( pDisplay, pPixmap->GetPixmap(), 0, nullptr );
631 XPutImage( pDisplay, pPixmap->GetDrawable(), aGC, pImage,
632 0, 0, 0, 0, pPixmap->GetWidth(), pPixmap->GetHeight() );
633 XFreeGC( pDisplay, aGC );
634 XDestroyImage( pImage );
637 typedef typename std::pair<ControlCacheKey, std::unique_ptr<TextureCombo>> ControlCachePair;
638 typedef o3tl::lru_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> ControlCacheType;
640 static vcl::DeleteOnDeinit<ControlCacheType> gTextureCache(new ControlCacheType(200));
642 namespace
644 GLXFBConfig GetPixmapFBConfig( Display* pDisplay, bool& bInverted )
646 OpenGLZone aZone;
648 int nScreen = DefaultScreen( pDisplay );
649 GLXFBConfig *aFbConfigs;
650 int i, nFbConfigs, nValue;
652 aFbConfigs = glXGetFBConfigs( pDisplay, nScreen, &nFbConfigs );
653 for( i = 0; i < nFbConfigs; i++ )
655 glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_DRAWABLE_TYPE, &nValue );
656 if( !(nValue & GLX_PIXMAP_BIT) )
657 continue;
659 glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &nValue );
660 if( !(nValue & GLX_TEXTURE_2D_BIT_EXT) )
661 continue;
663 glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_DEPTH_SIZE, &nValue );
664 if( nValue != 24 )
665 continue;
667 glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_RED_SIZE, &nValue );
668 if( nValue != 8 )
669 continue;
670 SAL_INFO( "vcl.opengl", "Red is " << nValue );
672 // TODO: lfrb: Make it configurable wrt RGB/RGBA
673 glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &nValue );
674 if( nValue == False )
676 glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &nValue );
677 if( nValue == False )
678 continue;
681 glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_Y_INVERTED_EXT, &nValue );
683 // Looks like that X sends GLX_DONT_CARE but this usually means "true" for most
684 // of the X implementations. Investigation on internet pointed that this could be
685 // safely "true" all the time (for example gnome-shell always assumes "true").
686 bInverted = nValue == True || nValue == int(GLX_DONT_CARE);
688 break;
691 if( i == nFbConfigs )
693 SAL_WARN( "vcl.opengl", "Unable to find FBconfig for pixmap texturing" );
694 return nullptr;
697 CHECK_GL_ERROR();
698 return aFbConfigs[i];
702 bool X11OpenGLSalGraphicsImpl::RenderPixmap(X11Pixmap const * pPixmap, X11Pixmap const * pMask, int nX, int nY, TextureCombo& rCombo)
704 const int aAttribs[] =
706 GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
707 GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
708 None
711 Display* pDisplay = mrX11Parent.GetXDisplay();
712 bool bInverted = false;
714 const long nWidth = pPixmap->GetWidth();
715 const long nHeight = pPixmap->GetHeight();
716 SalTwoRect aPosAry(0, 0, nWidth, nHeight, nX, nY, nWidth, nHeight);
718 PreDraw();
719 //glClear( GL_COLOR_BUFFER_BIT );
721 XSync( pDisplay, 0 );
722 GLXFBConfig pFbConfig = GetPixmapFBConfig( pDisplay, bInverted );
723 GLXPixmap pGlxPixmap = glXCreatePixmap( pDisplay, pFbConfig, pPixmap->GetPixmap(), aAttribs);
724 GLXPixmap pGlxMask;
725 if( pMask != nullptr )
726 pGlxMask = glXCreatePixmap( pDisplay, pFbConfig, pMask->GetPixmap(), aAttribs);
727 else
728 pGlxMask = 0;
729 XSync( pDisplay, 0 );
731 if( !pGlxPixmap )
732 SAL_WARN( "vcl.opengl", "Couldn't create GLXPixmap" );
734 //TODO: lfrb: glXGetProc to get the functions
736 rCombo.mpTexture.reset(new OpenGLTexture(pPixmap->GetWidth(), pPixmap->GetHeight(), false));
738 mpContext->state().texture().active(0);
740 rCombo.mpTexture->Bind();
741 glXBindTexImageEXT( pDisplay, pGlxPixmap, GLX_FRONT_LEFT_EXT, nullptr );
742 rCombo.mpTexture->Unbind();
744 if( pMask != nullptr && pGlxMask )
746 rCombo.mpMask.reset(new OpenGLTexture(pPixmap->GetWidth(), pPixmap->GetHeight(), false));
747 rCombo.mpMask->Bind();
748 glXBindTexImageEXT( pDisplay, pGlxMask, GLX_FRONT_LEFT_EXT, nullptr );
749 rCombo.mpMask->Unbind();
751 DrawTextureDiff(*rCombo.mpTexture, *rCombo.mpMask, aPosAry, bInverted);
753 glXReleaseTexImageEXT( pDisplay, pGlxMask, GLX_FRONT_LEFT_EXT );
754 glXDestroyPixmap( pDisplay, pGlxMask );
756 else
758 DrawTexture(*rCombo.mpTexture, aPosAry, bInverted);
761 CHECK_GL_ERROR();
763 glXReleaseTexImageEXT( pDisplay, pGlxPixmap, GLX_FRONT_LEFT_EXT );
764 glXDestroyPixmap( pDisplay, pGlxPixmap );
766 PostDraw();
768 CHECK_GL_ERROR();
770 return true;
773 bool X11OpenGLSalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY )
775 SAL_INFO( "vcl.opengl", "RenderPixmapToScreen (" << nX << " " << nY << ")" );
777 TextureCombo aCombo;
778 return RenderPixmap(pPixmap, pMask, nX, nY, aCombo);
781 bool X11OpenGLSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey& rControlCacheKey, int nX, int nY)
783 static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE");
785 if (!gbCacheEnabled || !gTextureCache.get())
786 return false;
788 ControlCacheType::const_iterator iterator = gTextureCache.get()->find(rControlCacheKey);
790 if (iterator == gTextureCache.get()->end())
791 return false;
793 const std::unique_ptr<TextureCombo>& pCombo = iterator->second;
795 PreDraw();
797 OpenGLTexture& rTexture = *pCombo->mpTexture;
799 SalTwoRect aPosAry(0, 0, rTexture.GetWidth(), rTexture.GetHeight(),
800 nX, nY, rTexture.GetWidth(), rTexture.GetHeight());
802 if (pCombo->mpMask)
803 DrawTextureDiff(rTexture, *pCombo->mpMask, aPosAry, true);
804 else
805 DrawTexture(rTexture, aPosAry, true);
807 PostDraw();
809 return true;
812 bool X11OpenGLSalGraphicsImpl::RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY,
813 ControlCacheKey& aControlCacheKey)
815 std::unique_ptr<TextureCombo> pCombo(new TextureCombo);
816 bool bResult = RenderPixmap(pPixmap, pMask, nX, nY, *pCombo);
817 if (!bResult)
818 return false;
820 if (!aControlCacheKey.canCacheControl())
821 return true;
823 ControlCachePair pair(aControlCacheKey, std::move(pCombo));
824 if (gTextureCache.get())
825 gTextureCache.get()->insert(std::move(pair));
827 return bResult;
830 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */