1 | /* |
2 | * Copyright (C) 2010 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2010 Google Inc. All rights reserved. |
4 | * Copyright (C) 2011 Igalia S.L. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
9 | * 1. Redistributions of source code must retain the above copyright |
10 | * notice, this list of conditions and the following disclaimer. |
11 | * 2. Redistributions in binary form must reproduce the above copyright |
12 | * notice, this list of conditions and the following disclaimer in the |
13 | * documentation and/or other materials provided with the distribution. |
14 | * |
15 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
16 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
18 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
19 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
21 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
22 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
23 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | #include "config.h" |
29 | #include "GraphicsContext3D.h" |
30 | |
31 | #if ENABLE(GRAPHICS_CONTEXT_3D) && USE(TEXTURE_MAPPER) |
32 | |
33 | #include "GraphicsContext3DPrivate.h" |
34 | #include "TextureMapperGC3DPlatformLayer.h" |
35 | #include <wtf/Deque.h> |
36 | #include <wtf/NeverDestroyed.h> |
37 | |
38 | #include <ANGLE/ShaderLang.h> |
39 | |
40 | #if USE(LIBEPOXY) |
41 | #include <epoxy/gl.h> |
42 | #elif !USE(OPENGL_ES) |
43 | #include "OpenGLShims.h" |
44 | #endif |
45 | |
46 | #if USE(OPENGL_ES) |
47 | #include "Extensions3DOpenGLES.h" |
48 | #else |
49 | #include "Extensions3DOpenGL.h" |
50 | #endif |
51 | |
52 | #if USE(NICOSIA) |
53 | #include "NicosiaGC3DLayer.h" |
54 | #endif |
55 | |
56 | namespace WebCore { |
57 | |
58 | static const size_t MaxActiveContexts = 16; |
59 | static Deque<GraphicsContext3D*, MaxActiveContexts>& activeContexts() |
60 | { |
61 | static NeverDestroyed<Deque<GraphicsContext3D*, MaxActiveContexts>> s_activeContexts; |
62 | return s_activeContexts; |
63 | } |
64 | |
65 | RefPtr<GraphicsContext3D> GraphicsContext3D::create(GraphicsContext3DAttributes attributes, HostWindow* hostWindow, GraphicsContext3D::RenderStyle renderStyle) |
66 | { |
67 | // This implementation doesn't currently support rendering directly to the HostWindow. |
68 | if (renderStyle == RenderDirectlyToHostWindow) |
69 | return nullptr; |
70 | |
71 | static bool initialized = false; |
72 | static bool success = true; |
73 | if (!initialized) { |
74 | #if !USE(OPENGL_ES) && !USE(LIBEPOXY) |
75 | success = initializeOpenGLShims(); |
76 | #endif |
77 | initialized = true; |
78 | } |
79 | if (!success) |
80 | return nullptr; |
81 | |
82 | auto& contexts = activeContexts(); |
83 | if (contexts.size() >= MaxActiveContexts) |
84 | contexts.first()->recycleContext(); |
85 | |
86 | // Calling recycleContext() above should have lead to the graphics context being |
87 | // destroyed and thus removed from the active contexts list. |
88 | if (contexts.size() >= MaxActiveContexts) |
89 | return nullptr; |
90 | |
91 | // Create the GraphicsContext3D object first in order to establist a current context on this thread. |
92 | auto context = adoptRef(new GraphicsContext3D(attributes, hostWindow, renderStyle)); |
93 | |
94 | #if USE(LIBEPOXY) && USE(OPENGL_ES) |
95 | // Bail if GLES3 was requested but cannot be provided. |
96 | if (attributes.isWebGL2 && !epoxy_is_desktop_gl() && epoxy_gl_version() < 30) |
97 | return nullptr; |
98 | #endif |
99 | |
100 | contexts.append(context.get()); |
101 | return context; |
102 | } |
103 | |
104 | GraphicsContext3D::GraphicsContext3D(GraphicsContext3DAttributes attributes, HostWindow*, GraphicsContext3D::RenderStyle renderStyle, GraphicsContext3D* sharedContext) |
105 | : m_attrs(attributes) |
106 | { |
107 | ASSERT_UNUSED(sharedContext, !sharedContext); |
108 | #if USE(NICOSIA) |
109 | m_nicosiaLayer = std::make_unique<Nicosia::GC3DLayer>(*this, renderStyle); |
110 | #else |
111 | m_texmapLayer = std::make_unique<TextureMapperGC3DPlatformLayer>(*this, renderStyle); |
112 | #endif |
113 | |
114 | makeContextCurrent(); |
115 | |
116 | validateAttributes(); |
117 | |
118 | if (renderStyle == RenderOffscreen) { |
119 | // Create a texture to render into. |
120 | ::glGenTextures(1, &m_texture); |
121 | ::glBindTexture(GL_TEXTURE_2D, m_texture); |
122 | ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
123 | ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
124 | ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
125 | ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
126 | ::glBindTexture(GL_TEXTURE_2D, 0); |
127 | |
128 | // Create an FBO. |
129 | ::glGenFramebuffers(1, &m_fbo); |
130 | ::glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); |
131 | |
132 | #if USE(COORDINATED_GRAPHICS) |
133 | ::glGenTextures(1, &m_compositorTexture); |
134 | ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture); |
135 | ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
136 | ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
137 | ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
138 | ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
139 | |
140 | ::glGenTextures(1, &m_intermediateTexture); |
141 | ::glBindTexture(GL_TEXTURE_2D, m_intermediateTexture); |
142 | ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
143 | ::glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
144 | ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
145 | ::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
146 | |
147 | ::glBindTexture(GL_TEXTURE_2D, 0); |
148 | #endif |
149 | |
150 | |
151 | // Create a multisample FBO. |
152 | if (m_attrs.antialias) { |
153 | ::glGenFramebuffers(1, &m_multisampleFBO); |
154 | ::glBindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO); |
155 | m_state.boundFBO = m_multisampleFBO; |
156 | ::glGenRenderbuffers(1, &m_multisampleColorBuffer); |
157 | if (m_attrs.stencil || m_attrs.depth) |
158 | ::glGenRenderbuffers(1, &m_multisampleDepthStencilBuffer); |
159 | } else { |
160 | // Bind canvas FBO. |
161 | glBindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo); |
162 | m_state.boundFBO = m_fbo; |
163 | #if USE(OPENGL_ES) |
164 | if (m_attrs.depth) |
165 | glGenRenderbuffers(1, &m_depthBuffer); |
166 | if (m_attrs.stencil) |
167 | glGenRenderbuffers(1, &m_stencilBuffer); |
168 | #endif |
169 | if (m_attrs.stencil || m_attrs.depth) |
170 | glGenRenderbuffers(1, &m_depthStencilBuffer); |
171 | } |
172 | } |
173 | |
174 | #if !USE(OPENGL_ES) |
175 | ::glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); |
176 | |
177 | if (GLContext::current()->version() >= 320) { |
178 | m_usingCoreProfile = true; |
179 | |
180 | // From version 3.2 on we use the OpenGL Core profile, so request that ouput to the shader compiler. |
181 | // OpenGL version 3.2 uses GLSL version 1.50. |
182 | m_compiler = ANGLEWebKitBridge(SH_GLSL_150_CORE_OUTPUT); |
183 | |
184 | // From version 3.2 on we use the OpenGL Core profile, and we need a VAO for rendering. |
185 | // A VAO could be created and bound by each component using GL rendering (TextureMapper, WebGL, etc). This is |
186 | // a simpler solution: the first GraphicsContext3D created on a GLContext will create and bind a VAO for that context. |
187 | GC3Dint currentVAO = 0; |
188 | getIntegerv(GraphicsContext3D::VERTEX_ARRAY_BINDING, ¤tVAO); |
189 | if (!currentVAO) { |
190 | m_vao = createVertexArray(); |
191 | bindVertexArray(m_vao); |
192 | } |
193 | } else { |
194 | // For lower versions request the compatibility output to the shader compiler. |
195 | m_compiler = ANGLEWebKitBridge(SH_GLSL_COMPATIBILITY_OUTPUT); |
196 | |
197 | // GL_POINT_SPRITE is needed in lower versions. |
198 | ::glEnable(GL_POINT_SPRITE); |
199 | } |
200 | #else |
201 | // Adjust the shader specification depending on whether GLES3 (i.e. WebGL2 support) was requested. |
202 | m_compiler = ANGLEWebKitBridge(SH_ESSL_OUTPUT, m_attrs.isWebGL2 ? SH_WEBGL2_SPEC : SH_WEBGL_SPEC); |
203 | #endif |
204 | |
205 | // ANGLE initialization. |
206 | ShBuiltInResources ANGLEResources; |
207 | sh::InitBuiltInResources(&ANGLEResources); |
208 | |
209 | getIntegerv(GraphicsContext3D::MAX_VERTEX_ATTRIBS, &ANGLEResources.MaxVertexAttribs); |
210 | getIntegerv(GraphicsContext3D::MAX_VERTEX_UNIFORM_VECTORS, &ANGLEResources.MaxVertexUniformVectors); |
211 | getIntegerv(GraphicsContext3D::MAX_VARYING_VECTORS, &ANGLEResources.MaxVaryingVectors); |
212 | getIntegerv(GraphicsContext3D::MAX_VERTEX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxVertexTextureImageUnits); |
213 | getIntegerv(GraphicsContext3D::MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxCombinedTextureImageUnits); |
214 | getIntegerv(GraphicsContext3D::MAX_TEXTURE_IMAGE_UNITS, &ANGLEResources.MaxTextureImageUnits); |
215 | getIntegerv(GraphicsContext3D::MAX_FRAGMENT_UNIFORM_VECTORS, &ANGLEResources.MaxFragmentUniformVectors); |
216 | |
217 | // Always set to 1 for OpenGL ES. |
218 | ANGLEResources.MaxDrawBuffers = 1; |
219 | |
220 | GC3Dint range[2], precision; |
221 | getShaderPrecisionFormat(GraphicsContext3D::FRAGMENT_SHADER, GraphicsContext3D::HIGH_FLOAT, range, &precision); |
222 | ANGLEResources.FragmentPrecisionHigh = (range[0] || range[1] || precision); |
223 | |
224 | m_compiler.setResources(ANGLEResources); |
225 | |
226 | ::glClearColor(0, 0, 0, 0); |
227 | } |
228 | |
229 | GraphicsContext3D::~GraphicsContext3D() |
230 | { |
231 | makeContextCurrent(); |
232 | if (m_texture) |
233 | ::glDeleteTextures(1, &m_texture); |
234 | #if USE(COORDINATED_GRAPHICS) |
235 | if (m_compositorTexture) |
236 | ::glDeleteTextures(1, &m_compositorTexture); |
237 | #endif |
238 | |
239 | if (m_attrs.antialias) { |
240 | ::glDeleteRenderbuffers(1, &m_multisampleColorBuffer); |
241 | if (m_attrs.stencil || m_attrs.depth) |
242 | ::glDeleteRenderbuffers(1, &m_multisampleDepthStencilBuffer); |
243 | ::glDeleteFramebuffers(1, &m_multisampleFBO); |
244 | } else if (m_attrs.stencil || m_attrs.depth) { |
245 | #if USE(OPENGL_ES) |
246 | if (m_depthBuffer) |
247 | glDeleteRenderbuffers(1, &m_depthBuffer); |
248 | |
249 | if (m_stencilBuffer) |
250 | glDeleteRenderbuffers(1, &m_stencilBuffer); |
251 | #endif |
252 | if (m_depthStencilBuffer) |
253 | ::glDeleteRenderbuffers(1, &m_depthStencilBuffer); |
254 | } |
255 | ::glDeleteFramebuffers(1, &m_fbo); |
256 | #if USE(COORDINATED_GRAPHICS) |
257 | ::glDeleteTextures(1, &m_intermediateTexture); |
258 | #endif |
259 | |
260 | if (m_vao) |
261 | deleteVertexArray(m_vao); |
262 | |
263 | auto* activeContext = activeContexts().takeLast([this](auto* it) { return it == this; }); |
264 | ASSERT_UNUSED(activeContext, !!activeContext); |
265 | } |
266 | |
267 | void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>) |
268 | { |
269 | } |
270 | |
271 | void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>) |
272 | { |
273 | } |
274 | |
275 | bool GraphicsContext3D::makeContextCurrent() |
276 | { |
277 | #if USE(NICOSIA) |
278 | return m_nicosiaLayer->makeContextCurrent(); |
279 | #else |
280 | return m_texmapLayer->makeContextCurrent(); |
281 | #endif |
282 | } |
283 | |
284 | void GraphicsContext3D::checkGPUStatus() |
285 | { |
286 | } |
287 | |
288 | PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D() |
289 | { |
290 | #if USE(NICOSIA) |
291 | return m_nicosiaLayer->platformContext(); |
292 | #else |
293 | return m_texmapLayer->platformContext(); |
294 | #endif |
295 | } |
296 | |
297 | Platform3DObject GraphicsContext3D::platformTexture() const |
298 | { |
299 | return m_texture; |
300 | } |
301 | |
302 | bool GraphicsContext3D::isGLES2Compliant() const |
303 | { |
304 | #if USE(OPENGL_ES) |
305 | return true; |
306 | #else |
307 | return false; |
308 | #endif |
309 | } |
310 | |
311 | PlatformLayer* GraphicsContext3D::platformLayer() const |
312 | { |
313 | #if USE(NICOSIA) |
314 | return &m_nicosiaLayer->contentLayer(); |
315 | #else |
316 | return m_texmapLayer.get(); |
317 | #endif |
318 | } |
319 | |
320 | #if PLATFORM(GTK) |
321 | Extensions3D& GraphicsContext3D::getExtensions() |
322 | { |
323 | if (!m_extensions) { |
324 | #if USE(OPENGL_ES) |
325 | // glGetStringi is not available on GLES2. |
326 | m_extensions = std::make_unique<Extensions3DOpenGLES>(this, false); |
327 | #else |
328 | // From OpenGL 3.2 on we use the Core profile, and there we must use glGetStringi. |
329 | m_extensions = std::make_unique<Extensions3DOpenGL>(this, GLContext::current()->version() >= 320); |
330 | #endif |
331 | } |
332 | return *m_extensions; |
333 | } |
334 | #endif |
335 | |
336 | } // namespace WebCore |
337 | |
338 | #endif // ENABLE(GRAPHICS_CONTEXT_3D) && USE(TEXTURE_MAPPER) |
339 | |