1/*
2 * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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 INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28
29#if USE(3D_GRAPHICS)
30
31#include "GraphicsContext3D.h"
32#if PLATFORM(IOS)
33#include "GraphicsContext3DIOS.h"
34#endif
35
36#include "Extensions3DOpenGL.h"
37#include "IntRect.h"
38#include "IntSize.h"
39#include "NotImplemented.h"
40#include "TemporaryOpenGLSetting.h"
41
42#include <algorithm>
43#include <cstring>
44#include <wtf/MainThread.h>
45#include <wtf/text/CString.h>
46
47#if PLATFORM(IOS)
48#import <OpenGLES/ES2/glext.h>
49// From <OpenGLES/glext.h>
50#define GL_RGBA32F_ARB                      0x8814
51#define GL_RGB32F_ARB                       0x8815
52#elif PLATFORM(MAC)
53#include <OpenGL/gl.h>
54#elif PLATFORM(GTK) || PLATFORM(EFL) || PLATFORM(WIN)
55#include "OpenGLShims.h"
56#endif
57
58namespace WebCore {
59
60void GraphicsContext3D::releaseShaderCompiler()
61{
62    makeContextCurrent();
63    notImplemented();
64}
65
66void GraphicsContext3D::readPixelsAndConvertToBGRAIfNecessary(int x, int y, int width, int height, unsigned char* pixels)
67{
68    ::glReadPixels(x, y, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
69}
70
71void GraphicsContext3D::validateAttributes()
72{
73    validateDepthStencil("GL_EXT_packed_depth_stencil");
74}
75
76bool GraphicsContext3D::reshapeFBOs(const IntSize& size)
77{
78    const int width = size.width();
79    const int height = size.height();
80    GLuint colorFormat, internalDepthStencilFormat = 0;
81    if (m_attrs.alpha) {
82        m_internalColorFormat = GL_RGBA8;
83        colorFormat = GL_RGBA;
84    } else {
85        m_internalColorFormat = GL_RGB8;
86        colorFormat = GL_RGB;
87    }
88    if (m_attrs.stencil || m_attrs.depth) {
89        // We don't allow the logic where stencil is required and depth is not.
90        // See GraphicsContext3D::validateAttributes.
91
92        Extensions3D* extensions = getExtensions();
93        // Use a 24 bit depth buffer where we know we have it.
94        if (extensions->supports("GL_EXT_packed_depth_stencil"))
95            internalDepthStencilFormat = GL_DEPTH24_STENCIL8_EXT;
96        else
97#if PLATFORM(IOS)
98            internalDepthStencilFormat = GL_DEPTH_COMPONENT16;
99#else
100            internalDepthStencilFormat = GL_DEPTH_COMPONENT;
101#endif
102    }
103
104    // Resize multisample FBO.
105    if (m_attrs.antialias) {
106        GLint maxSampleCount;
107        ::glGetIntegerv(GL_MAX_SAMPLES_EXT, &maxSampleCount);
108        GLint sampleCount = std::min(8, maxSampleCount);
109        if (sampleCount > maxSampleCount)
110            sampleCount = maxSampleCount;
111        ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
112        ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleColorBuffer);
113        ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, m_internalColorFormat, width, height);
114        ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, m_multisampleColorBuffer);
115        if (m_attrs.stencil || m_attrs.depth) {
116            ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
117            ::glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, sampleCount, internalDepthStencilFormat, width, height);
118            if (m_attrs.stencil)
119                ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
120            if (m_attrs.depth)
121                ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_multisampleDepthStencilBuffer);
122        }
123        ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
124        if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
125            // FIXME: cleanup.
126            notImplemented();
127        }
128    }
129
130    // resize regular FBO
131    ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
132    ASSERT(m_texture);
133#if PLATFORM(IOS)
134    ::glBindRenderbuffer(GL_RENDERBUFFER, m_texture);
135    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_texture);
136    setRenderbufferStorageFromDrawable(m_currentWidth, m_currentHeight);
137#else
138    ::glBindTexture(GL_TEXTURE_2D, m_texture);
139    ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0);
140    ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_texture, 0);
141
142    if (m_compositorTexture) {
143        ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture);
144        ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0);
145        ::glBindTexture(GL_TEXTURE_2D, 0);
146    }
147#endif
148
149    if (!m_attrs.antialias && (m_attrs.stencil || m_attrs.depth)) {
150        ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
151        ::glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, internalDepthStencilFormat, width, height);
152        if (m_attrs.stencil)
153            ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
154        if (m_attrs.depth)
155            ::glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthStencilBuffer);
156        ::glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
157    }
158
159    if (glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
160        // FIXME: cleanup
161        notImplemented();
162    }
163
164    bool mustRestoreFBO = true;
165    if (m_attrs.antialias) {
166        ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_multisampleFBO);
167        if (m_state.boundFBO == m_multisampleFBO)
168            mustRestoreFBO = false;
169    } else {
170        if (m_state.boundFBO == m_fbo)
171            mustRestoreFBO = false;
172    }
173
174    return mustRestoreFBO;
175}
176
177void GraphicsContext3D::resolveMultisamplingIfNecessary(const IntRect& rect)
178{
179    TemporaryOpenGLSetting scopedScissor(GL_SCISSOR_TEST, GL_FALSE);
180    TemporaryOpenGLSetting scopedDither(GL_DITHER, GL_FALSE);
181    TemporaryOpenGLSetting scopedDepth(GL_DEPTH_TEST, GL_FALSE);
182    TemporaryOpenGLSetting scopedStencil(GL_STENCIL_TEST, GL_FALSE);
183
184    ::glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, m_multisampleFBO);
185    ::glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, m_fbo);
186#if PLATFORM(IOS)
187    UNUSED_PARAM(rect);
188    ::glResolveMultisampleFramebufferAPPLE();
189#else
190    IntRect resolveRect = rect;
191    if (rect.isEmpty())
192        resolveRect = IntRect(0, 0, m_currentWidth, m_currentHeight);
193
194    ::glBlitFramebufferEXT(resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), resolveRect.x(), resolveRect.y(), resolveRect.maxX(), resolveRect.maxY(), GL_COLOR_BUFFER_BIT, GL_LINEAR);
195#endif
196}
197
198void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
199{
200    makeContextCurrent();
201#if !PLATFORM(IOS)
202    switch (internalformat) {
203    case DEPTH_STENCIL:
204        internalformat = GL_DEPTH24_STENCIL8_EXT;
205        break;
206    case DEPTH_COMPONENT16:
207        internalformat = GL_DEPTH_COMPONENT;
208        break;
209    case RGBA4:
210    case RGB5_A1:
211        internalformat = GL_RGBA;
212        break;
213    case RGB565:
214        internalformat = GL_RGB;
215        break;
216    }
217#endif
218    ::glRenderbufferStorageEXT(target, internalformat, width, height);
219}
220
221void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value)
222{
223    // Need to emulate MAX_FRAGMENT/VERTEX_UNIFORM_VECTORS and MAX_VARYING_VECTORS
224    // because desktop GL's corresponding queries return the number of components
225    // whereas GLES2 return the number of vectors (each vector has 4 components).
226    // Therefore, the value returned by desktop GL needs to be divided by 4.
227    makeContextCurrent();
228    switch (pname) {
229#if !PLATFORM(IOS)
230    case MAX_FRAGMENT_UNIFORM_VECTORS:
231        ::glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, value);
232        *value /= 4;
233        break;
234    case MAX_VERTEX_UNIFORM_VECTORS:
235        ::glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, value);
236        *value /= 4;
237        break;
238    case MAX_VARYING_VECTORS:
239        ::glGetIntegerv(GL_MAX_VARYING_FLOATS, value);
240        *value /= 4;
241        break;
242#endif
243    case MAX_TEXTURE_SIZE:
244        ::glGetIntegerv(MAX_TEXTURE_SIZE, value);
245        if (getExtensions()->requiresRestrictedMaximumTextureSize())
246            *value = std::min(4096, *value);
247        break;
248    case MAX_CUBE_MAP_TEXTURE_SIZE:
249        ::glGetIntegerv(MAX_CUBE_MAP_TEXTURE_SIZE, value);
250        if (getExtensions()->requiresRestrictedMaximumTextureSize())
251            *value = std::min(1024, *value);
252        break;
253    default:
254        ::glGetIntegerv(pname, value);
255    }
256}
257
258void GraphicsContext3D::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision)
259{
260    UNUSED_PARAM(shaderType);
261    ASSERT(range);
262    ASSERT(precision);
263
264    makeContextCurrent();
265
266    switch (precisionType) {
267    case GraphicsContext3D::LOW_INT:
268    case GraphicsContext3D::MEDIUM_INT:
269    case GraphicsContext3D::HIGH_INT:
270        // These values are for a 32-bit twos-complement integer format.
271        range[0] = 31;
272        range[1] = 30;
273        precision[0] = 0;
274        break;
275    case GraphicsContext3D::LOW_FLOAT:
276    case GraphicsContext3D::MEDIUM_FLOAT:
277    case GraphicsContext3D::HIGH_FLOAT:
278        // These values are for an IEEE single-precision floating-point format.
279        range[0] = 127;
280        range[1] = 127;
281        precision[0] = 23;
282        break;
283    default:
284        ASSERT_NOT_REACHED();
285        break;
286    }
287}
288
289bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
290{
291    if (width && height && !pixels) {
292        synthesizeGLError(INVALID_VALUE);
293        return false;
294    }
295
296    GC3Denum openGLInternalFormat = internalformat;
297#if !PLATFORM(IOS)
298    if (type == GL_FLOAT) {
299        if (format == GL_RGBA)
300            openGLInternalFormat = GL_RGBA32F_ARB;
301        else if (format == GL_RGB)
302            openGLInternalFormat = GL_RGB32F_ARB;
303    } else if (type == HALF_FLOAT_OES) {
304        if (format == GL_RGBA)
305            openGLInternalFormat = GL_RGBA16F_ARB;
306        else if (format == GL_RGB)
307            openGLInternalFormat = GL_RGB16F_ARB;
308        else if (format == GL_LUMINANCE)
309            openGLInternalFormat = GL_LUMINANCE16F_ARB;
310        else if (format == GL_ALPHA)
311            openGLInternalFormat = GL_ALPHA16F_ARB;
312        else if (format == GL_LUMINANCE_ALPHA)
313            openGLInternalFormat = GL_LUMINANCE_ALPHA16F_ARB;
314        type = GL_HALF_FLOAT_ARB;
315    }
316#endif
317    texImage2DDirect(target, level, openGLInternalFormat, width, height, border, format, type, pixels);
318    return true;
319}
320
321void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar)
322{
323    makeContextCurrent();
324#if PLATFORM(IOS)
325    ::glDepthRangef(static_cast<float>(zNear), static_cast<float>(zFar));
326#else
327    ::glDepthRange(zNear, zFar);
328#endif
329}
330
331void GraphicsContext3D::clearDepth(GC3Dclampf depth)
332{
333    makeContextCurrent();
334#if PLATFORM(IOS)
335    ::glClearDepthf(static_cast<float>(depth));
336#else
337    ::glClearDepth(depth);
338#endif
339}
340
341Extensions3D* GraphicsContext3D::getExtensions()
342{
343    if (!m_extensions)
344        m_extensions = adoptPtr(new Extensions3DOpenGL(this));
345    return m_extensions.get();
346}
347
348void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data)
349{
350    // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e.,
351    // all previous rendering calls should be done before reading pixels.
352    makeContextCurrent();
353    ::glFlush();
354    if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) {
355        resolveMultisamplingIfNecessary(IntRect(x, y, width, height));
356        ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_fbo);
357        ::glFlush();
358    }
359    ::glReadPixels(x, y, width, height, format, type, data);
360    if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO)
361        ::glBindFramebufferEXT(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
362}
363
364}
365
366#endif // USE(3D_GRAPHICS)
367