1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Copyright (C) 2012 ChangSeok Oh <shivamidow@gmail.com>
5 * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
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 INC. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30
31#if USE(3D_GRAPHICS)
32
33#include "GraphicsContext3D.h"
34
35#include "Extensions3DOpenGLES.h"
36#include "IntRect.h"
37#include "IntSize.h"
38#include "NotImplemented.h"
39
40namespace WebCore {
41
42void GraphicsContext3D::releaseShaderCompiler()
43{
44    makeContextCurrent();
45    ::glReleaseShaderCompiler();
46}
47
48void GraphicsContext3D::readPixels(GC3Dint x, GC3Dint y, GC3Dsizei width, GC3Dsizei height, GC3Denum format, GC3Denum type, void* data)
49{
50    makeContextCurrent();
51    // FIXME: remove the two glFlush calls when the driver bug is fixed, i.e.,
52    // all previous rendering calls should be done before reading pixels.
53    ::glFlush();
54    if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO) {
55         resolveMultisamplingIfNecessary(IntRect(x, y, width, height));
56        ::glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
57        ::glFlush();
58    }
59
60    ::glReadPixels(x, y, width, height, format, type, data);
61
62    if (m_attrs.antialias && m_state.boundFBO == m_multisampleFBO)
63        ::glBindFramebuffer(GL_FRAMEBUFFER, m_multisampleFBO);
64}
65
66void GraphicsContext3D::readPixelsAndConvertToBGRAIfNecessary(int x, int y, int width, int height, unsigned char* pixels)
67{
68    ::glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
69    int totalBytes = width * height * 4;
70    if (isGLES2Compliant()) {
71        for (int i = 0; i < totalBytes; i += 4)
72            std::swap(pixels[i], pixels[i + 2]); // Convert to BGRA.
73    }
74}
75
76bool GraphicsContext3D::reshapeFBOs(const IntSize& size)
77{
78    const int width = size.width();
79    const int height = size.height();
80    GLuint colorFormat = 0, pixelDataType = 0;
81    if (m_attrs.alpha) {
82        m_internalColorFormat = GL_RGBA;
83        colorFormat = GL_RGBA;
84        pixelDataType = GL_UNSIGNED_BYTE;
85    } else {
86        m_internalColorFormat = GL_RGB;
87        colorFormat = GL_RGB;
88        pixelDataType = GL_UNSIGNED_SHORT_5_6_5;
89    }
90
91    // We don't allow the logic where stencil is required and depth is not.
92    // See GraphicsContext3D::validateAttributes.
93    bool supportPackedDepthStencilBuffer = (m_attrs.stencil || m_attrs.depth) && getExtensions()->supports("GL_OES_packed_depth_stencil");
94
95    // Resize regular FBO.
96    bool mustRestoreFBO = false;
97    if (m_state.boundFBO != m_fbo) {
98        mustRestoreFBO = true;
99        ::glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
100    }
101
102    ASSERT(m_texture);
103    ::glBindTexture(GL_TEXTURE_2D, m_texture);
104    ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, pixelDataType, 0);
105    ::glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0);
106
107    if (m_compositorTexture) {
108        ::glBindTexture(GL_TEXTURE_2D, m_compositorTexture);
109        ::glTexImage2D(GL_TEXTURE_2D, 0, m_internalColorFormat, width, height, 0, colorFormat, GL_UNSIGNED_BYTE, 0);
110        ::glBindTexture(GL_TEXTURE_2D, 0);
111    }
112
113    Extensions3DOpenGLES* extensions = static_cast<Extensions3DOpenGLES*>(getExtensions());
114    if (extensions->isImagination() && m_attrs.antialias) {
115        GLint maxSampleCount;
116        ::glGetIntegerv(Extensions3D::MAX_SAMPLES_IMG, &maxSampleCount);
117        GLint sampleCount = std::min(8, maxSampleCount);
118
119        extensions->framebufferTexture2DMultisampleIMG(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture, 0, sampleCount);
120
121        if (m_attrs.stencil || m_attrs.depth) {
122            // Use a 24 bit depth buffer where we know we have it.
123            if (supportPackedDepthStencilBuffer) {
124                ::glBindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
125                extensions->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH24_STENCIL8_OES, width, height);
126                if (m_attrs.stencil)
127                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
128                if (m_attrs.depth)
129                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
130            } else {
131                if (m_attrs.stencil) {
132                    ::glBindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer);
133                    extensions->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_STENCIL_INDEX8, width, height);
134                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer);
135                }
136                if (m_attrs.depth) {
137                    ::glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
138                    extensions->renderbufferStorageMultisample(GL_RENDERBUFFER, sampleCount, GL_DEPTH_COMPONENT16, width, height);
139                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
140                }
141            }
142            ::glBindRenderbuffer(GL_RENDERBUFFER, 0);
143        }
144    } else {
145        if (m_attrs.stencil || m_attrs.depth) {
146            // Use a 24 bit depth buffer where we know we have it.
147            if (supportPackedDepthStencilBuffer) {
148                ::glBindRenderbuffer(GL_RENDERBUFFER, m_depthStencilBuffer);
149                ::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, width, height);
150                if (m_attrs.stencil)
151                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
152                if (m_attrs.depth)
153                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthStencilBuffer);
154            } else {
155                if (m_attrs.stencil) {
156                    ::glBindRenderbuffer(GL_RENDERBUFFER, m_stencilBuffer);
157                    ::glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);
158                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilBuffer);
159                }
160                if (m_attrs.depth) {
161                    ::glBindRenderbuffer(GL_RENDERBUFFER, m_depthBuffer);
162                    ::glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
163                    ::glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBuffer);
164                }
165            }
166            ::glBindRenderbuffer(GL_RENDERBUFFER, 0);
167        }
168    }
169    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
170        // FIXME: cleanup
171        notImplemented();
172    }
173
174    return mustRestoreFBO;
175}
176
177void GraphicsContext3D::resolveMultisamplingIfNecessary(const IntRect& rect)
178{
179    // FIXME: We don't support antialiasing yet.
180    notImplemented();
181}
182
183void GraphicsContext3D::renderbufferStorage(GC3Denum target, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height)
184{
185    makeContextCurrent();
186    ::glRenderbufferStorage(target, internalformat, width, height);
187}
188
189void GraphicsContext3D::getIntegerv(GC3Denum pname, GC3Dint* value)
190{
191    makeContextCurrent();
192    ::glGetIntegerv(pname, value);
193}
194
195void GraphicsContext3D::getShaderPrecisionFormat(GC3Denum shaderType, GC3Denum precisionType, GC3Dint* range, GC3Dint* precision)
196{
197    ASSERT(range);
198    ASSERT(precision);
199
200    makeContextCurrent();
201    ::glGetShaderPrecisionFormat(shaderType, precisionType, range, precision);
202}
203
204bool GraphicsContext3D::texImage2D(GC3Denum target, GC3Dint level, GC3Denum internalformat, GC3Dsizei width, GC3Dsizei height, GC3Dint border, GC3Denum format, GC3Denum type, const void* pixels)
205{
206    if (width && height && !pixels) {
207        synthesizeGLError(INVALID_VALUE);
208        return false;
209    }
210
211    texImage2DDirect(target, level, internalformat, width, height, border, format, type, pixels);
212    return true;
213}
214
215void GraphicsContext3D::validateAttributes()
216{
217    validateDepthStencil("GL_OES_packed_depth_stencil");
218
219    if (m_attrs.antialias) {
220        Extensions3D* extensions = getExtensions();
221        if (!extensions->supports("GL_IMG_multisampled_render_to_texture"))
222            m_attrs.antialias = false;
223    }
224}
225
226void GraphicsContext3D::depthRange(GC3Dclampf zNear, GC3Dclampf zFar)
227{
228    makeContextCurrent();
229    ::glDepthRangef(zNear, zFar);
230}
231
232void GraphicsContext3D::clearDepth(GC3Dclampf depth)
233{
234    makeContextCurrent();
235    ::glClearDepthf(depth);
236}
237
238Extensions3D* GraphicsContext3D::getExtensions()
239{
240    if (!m_extensions)
241        m_extensions = adoptPtr(new Extensions3DOpenGLES(this));
242    return m_extensions.get();
243}
244
245}
246
247#endif // USE(3D_GRAPHICS)
248