[WPE] Use libepoxy
[WebKit.git] / Source / WebCore / platform / graphics / GLContext.cpp
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 ENABLE(GRAPHICS_CONTEXT_3D)
22 #include "GLContext.h"
23 #include <wtf/ThreadSpecific.h>
24
25 #if USE(EGL)
26 #include "GLContextEGL.h"
27 #endif
28
29 #if USE(LIBEPOXY)
30 #include <epoxy/gl.h>
31 #elif USE(OPENGL_ES_2)
32 #define GL_GLEXT_PROTOTYPES 1
33 #include <GLES2/gl2.h>
34 #include <GLES3/gl3.h>
35 #endif
36
37 #if USE(GLX)
38 #include "GLContextGLX.h"
39 #endif
40
41 using WTF::ThreadSpecific;
42
43 namespace WebCore {
44
45 class ThreadGlobalGLContext {
46 public:
47     static ThreadSpecific<ThreadGlobalGLContext>* staticGLContext;
48
49     void setContext(GLContext* context) { m_context = context; }
50     GLContext* context() { return m_context; }
51
52 private:
53     GLContext* m_context;
54 };
55
56 ThreadSpecific<ThreadGlobalGLContext>* ThreadGlobalGLContext::staticGLContext;
57
58 inline ThreadGlobalGLContext* currentContext()
59 {
60     if (!ThreadGlobalGLContext::staticGLContext)
61         ThreadGlobalGLContext::staticGLContext = new ThreadSpecific<ThreadGlobalGLContext>;
62     return *ThreadGlobalGLContext::staticGLContext;
63 }
64
65 static bool initializeOpenGLShimsIfNeeded()
66 {
67 #if USE(OPENGL_ES_2) || USE(LIBEPOXY)
68     return true;
69 #else
70     static bool initialized = false;
71     static bool success = true;
72     if (!initialized) {
73         success = initializeOpenGLShims();
74         initialized = true;
75     }
76     return success;
77 #endif
78 }
79
80 std::unique_ptr<GLContext> GLContext::createContextForWindow(GLNativeWindowType windowHandle, PlatformDisplay* platformDisplay)
81 {
82     if (!initializeOpenGLShimsIfNeeded())
83         return nullptr;
84
85     PlatformDisplay& display = platformDisplay ? *platformDisplay : PlatformDisplay::sharedDisplay();
86 #if PLATFORM(WAYLAND)
87     if (display.type() == PlatformDisplay::Type::Wayland) {
88         if (auto eglContext = GLContextEGL::createContext(windowHandle, display))
89             return WTFMove(eglContext);
90         return nullptr;
91     }
92 #endif
93
94 #if USE(GLX)
95     if (auto glxContext = GLContextGLX::createContext(windowHandle, display))
96         return WTFMove(glxContext);
97 #endif
98 #if USE(EGL)
99     if (auto eglContext = GLContextEGL::createContext(windowHandle, display))
100         return WTFMove(eglContext);
101 #endif
102     return nullptr;
103 }
104
105 std::unique_ptr<GLContext> GLContext::createOffscreenContext(PlatformDisplay* platformDisplay)
106 {
107     if (!initializeOpenGLShimsIfNeeded())
108         return nullptr;
109
110     return createContextForWindow(0, platformDisplay ? platformDisplay : &PlatformDisplay::sharedDisplay());
111 }
112
113 std::unique_ptr<GLContext> GLContext::createSharingContext(PlatformDisplay& display)
114 {
115     if (!initializeOpenGLShimsIfNeeded())
116         return nullptr;
117
118 #if USE(GLX)
119     if (display.type() == PlatformDisplay::Type::X11) {
120         if (auto glxContext = GLContextGLX::createSharingContext(display))
121             return WTFMove(glxContext);
122     }
123 #endif
124
125 #if USE(EGL) || PLATFORM(WAYLAND) || PLATFORM(WPE)
126     if (auto eglContext = GLContextEGL::createSharingContext(display))
127         return WTFMove(eglContext);
128 #endif
129
130     return nullptr;
131 }
132
133 GLContext::GLContext(PlatformDisplay& display)
134     : m_display(display)
135 {
136 }
137
138 GLContext::~GLContext()
139 {
140     if (this == currentContext()->context())
141         currentContext()->setContext(nullptr);
142 }
143
144 bool GLContext::makeContextCurrent()
145 {
146     currentContext()->setContext(this);
147     return true;
148 }
149
150 GLContext* GLContext::current()
151 {
152     return currentContext()->context();
153 }
154
155 bool GLContext::isExtensionSupported(const char* extensionList, const char* extension)
156 {
157     if (!extensionList)
158         return false;
159
160     ASSERT(extension);
161     int extensionLen = strlen(extension);
162     const char* extensionListPtr = extensionList;
163     while ((extensionListPtr = strstr(extensionListPtr, extension))) {
164         if (extensionListPtr[extensionLen] == ' ' || extensionListPtr[extensionLen] == '\0')
165             return true;
166         extensionListPtr += extensionLen;
167     }
168     return false;
169 }
170
171 unsigned GLContext::version()
172 {
173     if (!m_version) {
174         // Version string can start with the version number (all versions except GLES 1 and 2) or with
175         // "OpenGL". Different fields inside the version string are separated by spaces.
176         String versionString = String(reinterpret_cast<const char*>(::glGetString(GL_VERSION)));
177         Vector<String> versionStringComponents;
178         versionString.split(' ', versionStringComponents);
179
180         Vector<String> versionDigits;
181         if (versionStringComponents[0] == "OpenGL") {
182             // If the version string starts with "OpenGL" it can be GLES 1 or 2. In GLES1 version string starts
183             // with "OpenGL ES-<profile> major.minor" and in GLES2 with "OpenGL ES major.minor". Version is the
184             // third component in both cases.
185             versionStringComponents[2].split('.', versionDigits);
186         } else {
187             // Version is the first component. The version number is always "major.minor" or
188             // "major.minor.release". Ignore the release number.
189             versionStringComponents[0].split('.', versionDigits);
190         }
191
192         m_version = versionDigits[0].toUInt() * 100 + versionDigits[1].toUInt() * 10;
193     }
194     return m_version;
195 }
196
197 } // namespace WebCore
198
199 #endif