1/* 2 * Copyright (C) 2011, 2012 Igalia, S.L. 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19#include "config.h" 20 21#if USE(OPENGL) 22#include "GLContext.h" 23 24#if USE(EGL) 25#include "GLContextEGL.h" 26#endif 27 28#if USE(GLX) 29#include "GLContextGLX.h" 30#endif 31 32#include <wtf/ThreadSpecific.h> 33 34#if PLATFORM(X11) 35#include <X11/Xlib.h> 36#endif 37 38#if PLATFORM(GTK) 39#include <gdk/gdk.h> 40#if PLATFORM(WAYLAND) && !defined(GTK_API_VERSION_2) && defined(GDK_WINDOWING_WAYLAND) 41#include <gdk/gdkwayland.h> 42#endif 43#endif 44 45using WTF::ThreadSpecific; 46 47namespace WebCore { 48 49class ThreadGlobalGLContext { 50public: 51 static ThreadSpecific<ThreadGlobalGLContext>* staticGLContext; 52 53 void setContext(GLContext* context) { m_context = context; } 54 GLContext* context() { return m_context; } 55 56private: 57 GLContext* m_context; 58}; 59 60ThreadSpecific<ThreadGlobalGLContext>* ThreadGlobalGLContext::staticGLContext; 61 62inline ThreadGlobalGLContext* currentContext() 63{ 64 if (!ThreadGlobalGLContext::staticGLContext) 65 ThreadGlobalGLContext::staticGLContext = new ThreadSpecific<ThreadGlobalGLContext>; 66 return *ThreadGlobalGLContext::staticGLContext; 67} 68 69GLContext* GLContext::sharingContext() 70{ 71 DEPRECATED_DEFINE_STATIC_LOCAL(OwnPtr<GLContext>, sharing, (createOffscreenContext())); 72 return sharing.get(); 73} 74 75#if PLATFORM(X11) 76// We do not want to call glXMakeContextCurrent using different Display pointers, 77// because it might lead to crashes in some drivers (fglrx). We use a shared display 78// pointer here. 79static Display* gSharedX11Display = 0; 80Display* GLContext::sharedX11Display() 81{ 82 if (!gSharedX11Display) 83 gSharedX11Display = XOpenDisplay(0); 84 return gSharedX11Display; 85} 86 87void GLContext::cleanupSharedX11Display() 88{ 89 if (!gSharedX11Display) 90 return; 91 XCloseDisplay(gSharedX11Display); 92 gSharedX11Display = 0; 93} 94 95// Because of driver bugs, exiting the program when there are active pbuffers 96// can crash the X server (this has been observed with the official Nvidia drivers). 97// We need to ensure that we clean everything up on exit. There are several reasons 98// that GraphicsContext3Ds will still be alive at exit, including user error (memory 99// leaks) and the page cache. In any case, we don't want the X server to crash. 100typedef Vector<GLContext*> ActiveContextList; 101static ActiveContextList& activeContextList() 102{ 103 DEPRECATED_DEFINE_STATIC_LOCAL(ActiveContextList, activeContexts, ()); 104 return activeContexts; 105} 106 107void GLContext::addActiveContext(GLContext* context) 108{ 109 static bool addedAtExitHandler = false; 110 if (!addedAtExitHandler) { 111 atexit(&GLContext::cleanupActiveContextsAtExit); 112 addedAtExitHandler = true; 113 } 114 activeContextList().append(context); 115} 116 117static bool gCleaningUpAtExit = false; 118 119void GLContext::removeActiveContext(GLContext* context) 120{ 121 // If we are cleaning up the context list at exit, don't bother removing the context 122 // from the list, since we don't want to modify the list while it's being iterated. 123 if (gCleaningUpAtExit) 124 return; 125 126 ActiveContextList& contextList = activeContextList(); 127 size_t i = contextList.find(context); 128 if (i != notFound) 129 contextList.remove(i); 130} 131 132void GLContext::cleanupActiveContextsAtExit() 133{ 134 gCleaningUpAtExit = true; 135 136 ActiveContextList& contextList = activeContextList(); 137 for (size_t i = 0; i < contextList.size(); ++i) 138 delete contextList[i]; 139 140 cleanupSharedX11Display(); 141} 142#endif // PLATFORM(X11) 143 144 145PassOwnPtr<GLContext> GLContext::createContextForWindow(GLNativeWindowType windowHandle, GLContext* sharingContext) 146{ 147#if PLATFORM(GTK) && PLATFORM(WAYLAND) && !defined(GTK_API_VERSION_2) && defined(GDK_WINDOWING_WAYLAND) && USE(EGL) 148 GdkDisplay* display = gdk_display_manager_get_default_display(gdk_display_manager_get()); 149 150 if (GDK_IS_WAYLAND_DISPLAY(display)) { 151 if (OwnPtr<GLContext> eglContext = GLContextEGL::createContext(windowHandle, sharingContext)) 152 return eglContext.release(); 153 return nullptr; 154 } 155#endif 156 157#if USE(GLX) 158 if (OwnPtr<GLContext> glxContext = GLContextGLX::createContext(windowHandle, sharingContext)) 159 return glxContext.release(); 160#endif 161#if USE(EGL) 162 if (OwnPtr<GLContext> eglContext = GLContextEGL::createContext(windowHandle, sharingContext)) 163 return eglContext.release(); 164#endif 165 return nullptr; 166} 167 168GLContext::GLContext() 169{ 170#if PLATFORM(X11) 171 addActiveContext(this); 172#endif 173} 174 175PassOwnPtr<GLContext> GLContext::createOffscreenContext(GLContext* sharingContext) 176{ 177 return createContextForWindow(0, sharingContext); 178} 179 180GLContext::~GLContext() 181{ 182 if (this == currentContext()->context()) 183 currentContext()->setContext(0); 184#if PLATFORM(X11) 185 removeActiveContext(this); 186#endif 187} 188 189bool GLContext::makeContextCurrent() 190{ 191 currentContext()->setContext(this); 192 return true; 193} 194 195GLContext* GLContext::getCurrent() 196{ 197 return currentContext()->context(); 198} 199 200} // namespace WebCore 201 202#endif // USE(OPENGL) 203 204