1/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if USE(3D_GRAPHICS)
29
30#include "Extensions3DOpenGL.h"
31
32#include "GraphicsContext3D.h"
33#include <wtf/Vector.h>
34
35#if PLATFORM(IOS)
36#include "ANGLE/ShaderLang.h"
37#include <OpenGLES/ES2/glext.h>
38#elif PLATFORM(MAC)
39#include "ANGLE/ShaderLang.h"
40#include <OpenGL/gl.h>
41#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN)
42#include "OpenGLShims.h"
43#endif
44
45#if PLATFORM(IOS)
46#include "GraphicsContext3DIOS.h"
47#endif
48
49namespace WebCore {
50
51Extensions3DOpenGL::Extensions3DOpenGL(GraphicsContext3D* context)
52    : Extensions3DOpenGLCommon(context)
53{
54}
55
56Extensions3DOpenGL::~Extensions3DOpenGL()
57{
58}
59
60
61void Extensions3DOpenGL::blitFramebuffer(long srcX0, long srcY0, long srcX1, long srcY1, long dstX0, long dstY0, long dstX1, long dstY1, unsigned long mask, unsigned long filter)
62{
63#if PLATFORM(IOS)
64    UNUSED_PARAM(srcX0);
65    UNUSED_PARAM(srcY0);
66    UNUSED_PARAM(srcX1);
67    UNUSED_PARAM(srcY1);
68    UNUSED_PARAM(dstX0);
69    UNUSED_PARAM(dstY0);
70    UNUSED_PARAM(dstX1);
71    UNUSED_PARAM(dstY1);
72    UNUSED_PARAM(mask);
73    UNUSED_PARAM(filter);
74    ::glResolveMultisampleFramebufferAPPLE();
75#else
76    ::glBlitFramebufferEXT(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
77#endif
78}
79
80void Extensions3DOpenGL::renderbufferStorageMultisample(unsigned long target, unsigned long samples, unsigned long internalformat, unsigned long width, unsigned long height)
81{
82    ::glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
83}
84
85Platform3DObject Extensions3DOpenGL::createVertexArrayOES()
86{
87    m_context->makeContextCurrent();
88    GLuint array = 0;
89#if (PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) || PLATFORM(IOS))
90    if (isVertexArrayObjectSupported())
91        glGenVertexArrays(1, &array);
92#elif defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object
93    glGenVertexArraysAPPLE(1, &array);
94#endif
95    return array;
96}
97
98void Extensions3DOpenGL::deleteVertexArrayOES(Platform3DObject array)
99{
100    if (!array)
101        return;
102
103    m_context->makeContextCurrent();
104#if (PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) || PLATFORM(IOS))
105    if (isVertexArrayObjectSupported())
106        glDeleteVertexArrays(1, &array);
107#elif defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object
108    glDeleteVertexArraysAPPLE(1, &array);
109#endif
110}
111
112GC3Dboolean Extensions3DOpenGL::isVertexArrayOES(Platform3DObject array)
113{
114    if (!array)
115        return GL_FALSE;
116
117    m_context->makeContextCurrent();
118#if (PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) || PLATFORM(IOS))
119    if (isVertexArrayObjectSupported())
120        return glIsVertexArray(array);
121#elif defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object
122    return glIsVertexArrayAPPLE(array);
123#endif
124    return GL_FALSE;
125}
126
127void Extensions3DOpenGL::bindVertexArrayOES(Platform3DObject array)
128{
129    m_context->makeContextCurrent();
130#if (PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) || PLATFORM(IOS))
131    if (isVertexArrayObjectSupported())
132        glBindVertexArray(array);
133#elif defined(GL_APPLE_vertex_array_object) && GL_APPLE_vertex_array_object
134    glBindVertexArrayAPPLE(array);
135#else
136    UNUSED_PARAM(array);
137#endif
138}
139
140void Extensions3DOpenGL::insertEventMarkerEXT(const String&)
141{
142    // FIXME: implement this function and add GL_EXT_debug_marker in supports().
143    return;
144}
145
146void Extensions3DOpenGL::pushGroupMarkerEXT(const String&)
147{
148    // FIXME: implement this function and add GL_EXT_debug_marker in supports().
149    return;
150}
151
152void Extensions3DOpenGL::popGroupMarkerEXT(void)
153{
154    // FIXME: implement this function and add GL_EXT_debug_marker in supports().
155    return;
156}
157
158bool Extensions3DOpenGL::supportsExtension(const String& name)
159{
160    // GL_ANGLE_framebuffer_blit and GL_ANGLE_framebuffer_multisample are "fake". They are implemented using other
161    // extensions. In particular GL_EXT_framebuffer_blit and GL_EXT_framebuffer_multisample
162    if (name == "GL_ANGLE_framebuffer_blit")
163        return m_availableExtensions.contains("GL_EXT_framebuffer_blit");
164    if (name == "GL_ANGLE_framebuffer_multisample")
165        return m_availableExtensions.contains("GL_EXT_framebuffer_multisample");
166
167    if (name == "GL_ANGLE_instanced_arrays") {
168        return (m_availableExtensions.contains("GL_ARB_instanced_arrays") || m_availableExtensions.contains("GL_EXT_instanced_arrays"))
169            && (m_availableExtensions.contains("GL_ARB_draw_instanced") || m_availableExtensions.contains("GL_EXT_draw_instanced"));
170    }
171
172    // Desktop GL always supports GL_OES_rgb8_rgba8.
173    if (name == "GL_OES_rgb8_rgba8")
174        return true;
175
176    // If GL_ARB_texture_float or GL_OES_texture_float is available then we report
177    // GL_OES_texture_half_float, GL_OES_texture_float_linear and GL_OES_texture_half_float_linear as available.
178    if (name == "GL_OES_texture_float" || name == "GL_OES_texture_half_float" || name == "GL_OES_texture_float_linear" || name == "GL_OES_texture_half_float_linear")
179        return m_availableExtensions.contains("GL_ARB_texture_float") || m_availableExtensions.contains("GL_OES_texture_float");
180
181    // GL_OES_vertex_array_object
182    if (name == "GL_OES_vertex_array_object") {
183#if (PLATFORM(GTK) || PLATFORM(EFL))
184        return m_availableExtensions.contains("GL_ARB_vertex_array_object");
185#elif PLATFORM(IOS)
186        return m_availableExtensions.contains("GL_OES_vertex_array_object");
187#else
188        return m_availableExtensions.contains("GL_APPLE_vertex_array_object");
189#endif
190    }
191
192    // Desktop GL always supports the standard derivative functions
193    if (name == "GL_OES_standard_derivatives")
194        return true;
195
196    // Desktop GL always supports UNSIGNED_INT indices
197    if (name == "GL_OES_element_index_uint")
198        return true;
199
200    if (name == "GL_EXT_shader_texture_lod")
201        return m_availableExtensions.contains("GL_EXT_shader_texture_lod");
202
203    if (name == "GL_EXT_texture_filter_anisotropic")
204        return m_availableExtensions.contains("GL_EXT_texture_filter_anisotropic");
205
206    if (name == "GL_EXT_draw_buffers") {
207#if PLATFORM(MAC) || PLATFORM(GTK)
208        return m_availableExtensions.contains("GL_ARB_draw_buffers");
209#else
210        // FIXME: implement support for other platforms.
211        return false;
212#endif
213    }
214
215#if PLATFORM(IOS)
216    if (name == "GL_EXT_packed_depth_stencil")
217        return m_availableExtensions.contains("GL_OES_packed_depth_stencil");
218#endif
219
220    return m_availableExtensions.contains(name);
221}
222
223void Extensions3DOpenGL::drawBuffersEXT(GC3Dsizei n, const GC3Denum* bufs)
224{
225    //  FIXME: implement support for other platforms.
226#if PLATFORM(MAC)
227    ::glDrawBuffersARB(n, bufs);
228#elif PLATFORM(GTK)
229    ::glDrawBuffers(n, bufs);
230#else
231    UNUSED_PARAM(n);
232    UNUSED_PARAM(bufs);
233#endif
234}
235
236void Extensions3DOpenGL::drawArraysInstanced(GC3Denum mode, GC3Dint first, GC3Dsizei count, GC3Dsizei primcount)
237{
238    m_context->makeContextCurrent();
239#if PLATFORM(GTK)
240    ::glDrawArraysInstanced(mode, first, count, primcount);
241#elif PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
242    ::glDrawArraysInstancedARB(mode, first, count, primcount);
243#else
244    UNUSED_PARAM(mode);
245    UNUSED_PARAM(first);
246    UNUSED_PARAM(count);
247    UNUSED_PARAM(primcount);
248#endif
249}
250
251void Extensions3DOpenGL::drawElementsInstanced(GC3Denum mode, GC3Dsizei count, GC3Denum type, long long offset, GC3Dsizei primcount)
252{
253    m_context->makeContextCurrent();
254#if PLATFORM(GTK)
255    ::glDrawElementsInstanced(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)), primcount);
256#elif PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
257    ::glDrawElementsInstancedARB(mode, count, type, reinterpret_cast<GLvoid*>(static_cast<intptr_t>(offset)), primcount);
258#else
259    UNUSED_PARAM(mode);
260    UNUSED_PARAM(count);
261    UNUSED_PARAM(type);
262    UNUSED_PARAM(offset);
263    UNUSED_PARAM(primcount);
264#endif
265}
266
267void Extensions3DOpenGL::vertexAttribDivisor(GC3Duint index, GC3Duint divisor)
268{
269    m_context->makeContextCurrent();
270#if PLATFORM(GTK)
271    ::glVertexAttribDivisor(index, divisor);
272#elif PLATFORM(IOS) || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
273    ::glVertexAttribDivisorARB(index, divisor);
274#else
275    UNUSED_PARAM(index);
276    UNUSED_PARAM(divisor);
277#endif
278}
279
280String Extensions3DOpenGL::getExtensions()
281{
282    return String(reinterpret_cast<const char*>(::glGetString(GL_EXTENSIONS)));
283}
284
285#if (PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN) || PLATFORM(IOS))
286bool Extensions3DOpenGL::isVertexArrayObjectSupported()
287{
288    static const bool supportsVertexArrayObject = supports("GL_OES_vertex_array_object");
289    return supportsVertexArrayObject;
290}
291#endif
292
293} // namespace WebCore
294
295#endif // USE(3D_GRAPHICS)
296