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 | |
39 | using WTF::ThreadSpecific; |
40 | |
41 | namespace WebCore { |
42 | |
43 | class ThreadGlobalGLContext { |
44 | public: |
45 | static ThreadSpecific<ThreadGlobalGLContext>* staticGLContext; |
46 | |
47 | void setContext(GLContext* context) { m_context = context; } |
48 | GLContext* context() { return m_context; } |
49 | |
50 | private: |
51 | GLContext* m_context { nullptr }; |
52 | }; |
53 | |
54 | ThreadSpecific<ThreadGlobalGLContext>* ThreadGlobalGLContext::staticGLContext; |
55 | |
56 | inline ThreadGlobalGLContext* currentContext() |
57 | { |
58 | if (!ThreadGlobalGLContext::staticGLContext) |
59 | ThreadGlobalGLContext::staticGLContext = new ThreadSpecific<ThreadGlobalGLContext>; |
60 | return *ThreadGlobalGLContext::staticGLContext; |
61 | } |
62 | |
63 | static 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 | |
78 | std::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 | |
103 | std::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 | |
111 | std::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 | |
131 | GLContext::GLContext(PlatformDisplay& display) |
132 | : m_display(display) |
133 | { |
134 | } |
135 | |
136 | GLContext::~GLContext() |
137 | { |
138 | if (this == currentContext()->context()) |
139 | currentContext()->setContext(nullptr); |
140 | } |
141 | |
142 | bool GLContext::makeContextCurrent() |
143 | { |
144 | currentContext()->setContext(this); |
145 | return true; |
146 | } |
147 | |
148 | GLContext* GLContext::current() |
149 | { |
150 | return currentContext()->context(); |
151 | } |
152 | |
153 | bool 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 | |
169 | unsigned 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 | |