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
56namespace WebCore {
57
58static const size_t MaxActiveContexts = 16;
59static Deque<GraphicsContext3D*, MaxActiveContexts>& activeContexts()
60{
61 static NeverDestroyed<Deque<GraphicsContext3D*, MaxActiveContexts>> s_activeContexts;
62 return s_activeContexts;
63}
64
65RefPtr<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
104GraphicsContext3D::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, &currentVAO);
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
229GraphicsContext3D::~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
267void GraphicsContext3D::setContextLostCallback(std::unique_ptr<ContextLostCallback>)
268{
269}
270
271void GraphicsContext3D::setErrorMessageCallback(std::unique_ptr<ErrorMessageCallback>)
272{
273}
274
275bool GraphicsContext3D::makeContextCurrent()
276{
277#if USE(NICOSIA)
278 return m_nicosiaLayer->makeContextCurrent();
279#else
280 return m_texmapLayer->makeContextCurrent();
281#endif
282}
283
284void GraphicsContext3D::checkGPUStatus()
285{
286}
287
288PlatformGraphicsContext3D GraphicsContext3D::platformGraphicsContext3D()
289{
290#if USE(NICOSIA)
291 return m_nicosiaLayer->platformContext();
292#else
293 return m_texmapLayer->platformContext();
294#endif
295}
296
297Platform3DObject GraphicsContext3D::platformTexture() const
298{
299 return m_texture;
300}
301
302bool GraphicsContext3D::isGLES2Compliant() const
303{
304#if USE(OPENGL_ES)
305 return true;
306#else
307 return false;
308#endif
309}
310
311PlatformLayer* 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)
321Extensions3D& 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