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