1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
4 * Copyright (C) 2014 Collabora Ltd. All rights reserved.
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 *
10 * 1.  Redistributions of source code must retain the above copyright
11 *     notice, this list of conditions and the following disclaimer.
12 * 2.  Redistributions in binary form must reproduce the above copyright
13 *     notice, this list of conditions and the following disclaimer in the
14 *     documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "config.h"
29#if USE(3D_GRAPHICS)
30#include "Extensions3DOpenGLES.h"
31
32#include "GraphicsContext3D.h"
33#include "NotImplemented.h"
34#include <EGL/egl.h>
35#include <wtf/Vector.h>
36
37namespace WebCore {
38
39Extensions3DOpenGLES::Extensions3DOpenGLES(GraphicsContext3D* context)
40    : Extensions3DOpenGLCommon(context)
41    , m_contextResetStatus(GL_NO_ERROR)
42    , m_supportsOESvertexArrayObject(false)
43    , m_supportsIMGMultisampledRenderToTexture(false)
44    , m_supportsANGLEinstancedArrays(false)
45    , m_glFramebufferTexture2DMultisampleIMG(0)
46    , m_glRenderbufferStorageMultisampleIMG(0)
47    , m_glBindVertexArrayOES(0)
48    , m_glDeleteVertexArraysOES(0)
49    , m_glGenVertexArraysOES(0)
50    , m_glIsVertexArrayOES(0)
51    , m_glGetGraphicsResetStatusEXT(0)
52    , m_glReadnPixelsEXT(0)
53    , m_glGetnUniformfvEXT(0)
54    , m_glGetnUniformivEXT(0)
55    , m_glVertexAttribDivisorANGLE(nullptr)
56    , m_glDrawArraysInstancedANGLE(nullptr)
57    , m_glDrawElementsInstancedANGLE(nullptr)
58{
59}
60
61Extensions3DOpenGLES::~Extensions3DOpenGLES()
62{
63}
64
65void Extensions3DOpenGLES::framebufferTexture2DMultisampleIMG(unsigned long target, unsigned long attachment, unsigned long textarget, unsigned int texture, int level, unsigned long samples)
66{
67    if (m_glFramebufferTexture2DMultisampleIMG)
68        m_glFramebufferTexture2DMultisampleIMG(target, attachment, textarget, texture, level, samples);
69    else
70        m_context->synthesizeGLError(GL_INVALID_OPERATION);
71}
72
73void Extensions3DOpenGLES::renderbufferStorageMultisampleIMG(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height)
74{
75    if (m_glRenderbufferStorageMultisampleIMG)
76        m_glRenderbufferStorageMultisampleIMG(target, samples, internalformat, width, height);
77    else
78        m_context->synthesizeGLError(GL_INVALID_OPERATION);
79}
80
81void Extensions3DOpenGLES::blitFramebuffer(long /* srcX0 */, long /* srcY0 */, long /* srcX1 */, long /* srcY1 */, long /* dstX0 */, long /* dstY0 */, long /* dstX1 */, long /* dstY1 */, unsigned long /* mask */, unsigned long /* filter */)
82{
83    notImplemented();
84}
85
86void Extensions3DOpenGLES::renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height)
87{
88    if (m_glRenderbufferStorageMultisampleIMG)
89        renderbufferStorageMultisampleIMG(target, samples, internalformat, width, height);
90    else
91        notImplemented();
92}
93
94void Extensions3DOpenGLES::insertEventMarkerEXT(const String&)
95{
96    notImplemented();
97}
98
99void Extensions3DOpenGLES::pushGroupMarkerEXT(const String&)
100{
101    notImplemented();
102}
103
104void Extensions3DOpenGLES::popGroupMarkerEXT(void)
105{
106    notImplemented();
107}
108
109Platform3DObject Extensions3DOpenGLES::createVertexArrayOES()
110{
111    m_context->makeContextCurrent();
112    if (m_glGenVertexArraysOES) {
113        GLuint array = 0;
114        m_glGenVertexArraysOES(1, &array);
115        return array;
116    }
117
118    m_context->synthesizeGLError(GL_INVALID_OPERATION);
119    return 0;
120}
121
122void Extensions3DOpenGLES::deleteVertexArrayOES(Platform3DObject array)
123{
124    if (!array)
125        return;
126
127    m_context->makeContextCurrent();
128    if (m_glDeleteVertexArraysOES)
129        m_glDeleteVertexArraysOES(1, &array);
130    else
131        m_context->synthesizeGLError(GL_INVALID_OPERATION);
132}
133
134GC3Dboolean Extensions3DOpenGLES::isVertexArrayOES(Platform3DObject array)
135{
136    if (!array)
137        return GL_FALSE;
138
139    m_context->makeContextCurrent();
140    if (m_glIsVertexArrayOES)
141        return m_glIsVertexArrayOES(array);
142
143    m_context->synthesizeGLError(GL_INVALID_OPERATION);
144    return false;
145}
146
147void Extensions3DOpenGLES::bindVertexArrayOES(Platform3DObject array)
148{
149    if (!array)
150        return;
151
152    m_context->makeContextCurrent();
153    if (m_glBindVertexArrayOES)
154        m_glBindVertexArrayOES(array);
155    else
156        m_context->synthesizeGLError(GL_INVALID_OPERATION);
157}
158
159void Extensions3DOpenGLES::drawBuffersEXT(GC3Dsizei /* n */, const GC3Denum* /* bufs */)
160{
161    // FIXME: implement the support.
162    notImplemented();
163}
164
165int Extensions3DOpenGLES::getGraphicsResetStatusARB()
166{
167    // FIXME: This does not call getGraphicsResetStatusARB, but instead getGraphicsResetStatusEXT.
168    // The return codes from the two extensions are identical and their purpose is the same, so it
169    // may be best to rename getGraphicsResetStatusARB() to getGraphicsResetStatus().
170    if (m_contextResetStatus != GL_NO_ERROR)
171        return m_contextResetStatus;
172    if (m_glGetGraphicsResetStatusEXT) {
173        m_context->makeContextCurrent();
174        int reasonForReset = m_glGetGraphicsResetStatusEXT();
175        if (reasonForReset != GL_NO_ERROR) {
176            ASSERT(m_contextLostCallback);
177            if (m_contextLostCallback)
178                m_contextLostCallback->onContextLost();
179            m_contextResetStatus = reasonForReset;
180        }
181        return reasonForReset;
182    }
183
184    m_context->synthesizeGLError(GL_INVALID_OPERATION);
185    return false;
186}
187
188void Extensions3DOpenGLES::setEXTContextLostCallback(std::unique_ptr<GraphicsContext3D::ContextLostCallback> callback)
189{
190    m_contextLostCallback = WTF::move(callback);
191}
192
193void Extensions3DOpenGLES::readnPixelsEXT(int x, int y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, GC3Dsizei bufSize, void *data)
194{
195    if (m_glReadnPixelsEXT) {
196        m_context->makeContextCurrent();
197        // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e.,
198        // all previous rendering calls should be done before reading pixels.
199        ::glFlush();
200
201        // FIXME: If non-BlackBerry platforms use this, they will need to implement
202        // their anti-aliasing code here.
203        m_glReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
204        return;
205    }
206
207    m_context->synthesizeGLError(GL_INVALID_OPERATION);
208}
209
210void Extensions3DOpenGLES::getnUniformfvEXT(GC3Duint program, int location, GC3Dsizei bufSize, float *params)
211{
212    if (m_glGetnUniformfvEXT) {
213        m_context->makeContextCurrent();
214        m_glGetnUniformfvEXT(program, location, bufSize, params);
215        return;
216    }
217
218    m_context->synthesizeGLError(GL_INVALID_OPERATION);
219}
220
221void Extensions3DOpenGLES::getnUniformivEXT(GC3Duint program, int location, GC3Dsizei bufSize, int *params)
222{
223    if (m_glGetnUniformivEXT) {
224        m_context->makeContextCurrent();
225        m_glGetnUniformivEXT(program, location, bufSize, params);
226        return;
227    }
228
229    m_context->synthesizeGLError(GL_INVALID_OPERATION);
230}
231
232void Extensions3DOpenGLES::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
233{
234    if (!m_glDrawArraysInstancedANGLE) {
235        m_context->synthesizeGLError(GL_INVALID_OPERATION);
236        return;
237    }
238
239    m_context->makeContextCurrent();
240    m_glDrawArraysInstancedANGLE(mode, first, count, primcount);
241}
242
243void Extensions3DOpenGLES::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, GC3Dsizei primcount)
244{
245    if (!m_glDrawElementsInstancedANGLE) {
246        m_context->synthesizeGLError(GL_INVALID_OPERATION);
247        return;
248    }
249
250    m_context->makeContextCurrent();
251    m_glDrawElementsInstancedANGLE(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)), primcount);
252}
253
254void Extensions3DOpenGLES::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
255{
256    if (!m_glVertexAttribDivisorANGLE) {
257        m_context->synthesizeGLError(GL_INVALID_OPERATION);
258        return;
259    }
260
261    m_context->makeContextCurrent();
262    m_glVertexAttribDivisorANGLE(index, divisor);
263}
264
265bool Extensions3DOpenGLES::supportsExtension(const String& name)
266{
267    if (m_availableExtensions.contains(name)) {
268        if (!m_supportsOESvertexArrayObject && name == "GL_OES_vertex_array_object") {
269            m_glBindVertexArrayOES = reinterpret_cast<PFNGLBINDVERTEXARRAYOESPROC>(eglGetProcAddress("glBindVertexArrayOES"));
270            m_glGenVertexArraysOES = reinterpret_cast<PFNGLGENVERTEXARRAYSOESPROC>(eglGetProcAddress("glGenVertexArraysOES"));
271            m_glDeleteVertexArraysOES = reinterpret_cast<PFNGLDELETEVERTEXARRAYSOESPROC>(eglGetProcAddress("glDeleteVertexArraysOES"));
272            m_glIsVertexArrayOES = reinterpret_cast<PFNGLISVERTEXARRAYOESPROC>(eglGetProcAddress("glIsVertexArrayOES"));
273            m_supportsOESvertexArrayObject = true;
274        } else if (!m_supportsIMGMultisampledRenderToTexture && name == "GL_IMG_multisampled_render_to_texture") {
275            m_glFramebufferTexture2DMultisampleIMG = reinterpret_cast<PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC>(eglGetProcAddress("glFramebufferTexture2DMultisampleIMG"));
276            m_glRenderbufferStorageMultisampleIMG = reinterpret_cast<PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC>(eglGetProcAddress("glRenderbufferStorageMultisampleIMG"));
277            m_supportsIMGMultisampledRenderToTexture = true;
278        } else if (!m_glGetGraphicsResetStatusEXT && name == "GL_EXT_robustness") {
279            m_glGetGraphicsResetStatusEXT = reinterpret_cast<PFNGLGETGRAPHICSRESETSTATUSEXTPROC>(eglGetProcAddress("glGetGraphicsResetStatusEXT"));
280            m_glReadnPixelsEXT = reinterpret_cast<PFNGLREADNPIXELSEXTPROC>(eglGetProcAddress("glReadnPixelsEXT"));
281            m_glGetnUniformfvEXT = reinterpret_cast<PFNGLGETNUNIFORMFVEXTPROC>(eglGetProcAddress("glGetnUniformfvEXT"));
282            m_glGetnUniformivEXT = reinterpret_cast<PFNGLGETNUNIFORMIVEXTPROC>(eglGetProcAddress("glGetnUniformivEXT"));
283        } else if (!m_supportsANGLEinstancedArrays && name == "GL_ANGLE_instanced_arrays") {
284            m_glVertexAttribDivisorANGLE = reinterpret_cast<PFNGLVERTEXATTRIBDIVISORANGLEPROC>(eglGetProcAddress("glVertexAttribDivisorANGLE"));
285            m_glDrawArraysInstancedANGLE = reinterpret_cast<PFNGLDRAWARRAYSINSTANCEDANGLEPROC >(eglGetProcAddress("glDrawArraysInstancedANGLE"));
286            m_glDrawElementsInstancedANGLE = reinterpret_cast<PFNGLDRAWELEMENTSINSTANCEDANGLEPROC >(eglGetProcAddress("glDrawElementsInstancedANGLE"));
287            m_supportsANGLEinstancedArrays = true;
288        } else if (name == "GL_EXT_draw_buffers") {
289            // FIXME: implement the support.
290            return false;
291        }
292        return true;
293    }
294
295    return false;
296}
297
298String Extensions3DOpenGLES::getExtensions()
299{
300    return String(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS)));
301}
302
303} // namespace WebCore
304
305#endif // USE(3D_GRAPHICS)
306