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