• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2010, 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 
33 #if ENABLE(ACCELERATED_2D_CANVAS) || ENABLE(WEBGL)
34 
35 #include "DrawingBuffer.h"
36 
37 #include "Extensions3D.h"
38 
39 namespace WebCore {
40 
create(GraphicsContext3D * context,const IntSize & size)41 PassRefPtr<DrawingBuffer> DrawingBuffer::create(GraphicsContext3D* context, const IntSize& size)
42 {
43     Extensions3D* extensions = context->getExtensions();
44     bool multisampleSupported = extensions->supports("GL_ANGLE_framebuffer_blit") && extensions->supports("GL_ANGLE_framebuffer_multisample") && extensions->supports("GL_OES_rgb8_rgba8");
45     if (multisampleSupported) {
46         extensions->ensureEnabled("GL_ANGLE_framebuffer_blit");
47         extensions->ensureEnabled("GL_ANGLE_framebuffer_multisample");
48         extensions->ensureEnabled("GL_OES_rgb8_rgba8");
49     }
50     bool packedDepthStencilSupported = extensions->supports("GL_OES_packed_depth_stencil");
51     if (packedDepthStencilSupported)
52         extensions->ensureEnabled("GL_OES_packed_depth_stencil");
53     RefPtr<DrawingBuffer> drawingBuffer = adoptRef(new DrawingBuffer(context, size, multisampleSupported, packedDepthStencilSupported));
54     return (drawingBuffer->m_context) ? drawingBuffer.release() : 0;
55 }
56 
clear()57 void DrawingBuffer::clear()
58 {
59     if (!m_context)
60         return;
61 
62     m_context->makeContextCurrent();
63     m_context->deleteTexture(m_colorBuffer);
64     m_colorBuffer = 0;
65 
66     if (m_multisampleColorBuffer) {
67         m_context->deleteRenderbuffer(m_multisampleColorBuffer);
68         m_multisampleColorBuffer = 0;
69     }
70 
71     if (m_depthStencilBuffer) {
72         m_context->deleteRenderbuffer(m_depthStencilBuffer);
73         m_depthStencilBuffer = 0;
74     }
75 
76     if (m_depthBuffer) {
77         m_context->deleteRenderbuffer(m_depthBuffer);
78         m_depthBuffer = 0;
79     }
80 
81     if (m_stencilBuffer) {
82         m_context->deleteRenderbuffer(m_stencilBuffer);
83         m_stencilBuffer = 0;
84     }
85 
86     if (m_multisampleFBO) {
87         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
88         m_context->deleteFramebuffer(m_multisampleFBO);
89         m_multisampleFBO = 0;
90     }
91 
92     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
93     m_context->deleteFramebuffer(m_fbo);
94     m_fbo = 0;
95 
96     m_context.clear();
97 }
98 
createSecondaryBuffers()99 void DrawingBuffer::createSecondaryBuffers()
100 {
101     // create a multisample FBO
102     if (multisample()) {
103         m_multisampleFBO = m_context->createFramebuffer();
104         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
105         m_multisampleColorBuffer = m_context->createRenderbuffer();
106     }
107 }
108 
resizeDepthStencil(int sampleCount)109 void DrawingBuffer::resizeDepthStencil(int sampleCount)
110 {
111     const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes();
112     if (attributes.depth && attributes.stencil && m_packedDepthStencilExtensionSupported) {
113         if (!m_depthStencilBuffer)
114             m_depthStencilBuffer = m_context->createRenderbuffer();
115         m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthStencilBuffer);
116         if (multisample())
117             m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, Extensions3D::DEPTH24_STENCIL8, m_size.width(), m_size.height());
118         else
119             m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, Extensions3D::DEPTH24_STENCIL8, m_size.width(), m_size.height());
120         m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthStencilBuffer);
121         m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthStencilBuffer);
122     } else {
123         if (attributes.depth) {
124             if (!m_depthBuffer)
125                 m_depthBuffer = m_context->createRenderbuffer();
126             m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
127             if (multisample())
128                 m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, GraphicsContext3D::DEPTH_COMPONENT16, m_size.width(), m_size.height());
129             else
130                 m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::DEPTH_COMPONENT16, m_size.width(), m_size.height());
131             m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::DEPTH_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_depthBuffer);
132         }
133         if (attributes.stencil) {
134             if (!m_stencilBuffer)
135                 m_stencilBuffer = m_context->createRenderbuffer();
136             m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_stencilBuffer);
137             if (multisample())
138                 m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, GraphicsContext3D::STENCIL_INDEX8, m_size.width(), m_size.height());
139             else
140                 m_context->renderbufferStorage(GraphicsContext3D::RENDERBUFFER, GraphicsContext3D::STENCIL_INDEX8, m_size.width(), m_size.height());
141             m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::STENCIL_ATTACHMENT, GraphicsContext3D::RENDERBUFFER, m_stencilBuffer);
142         }
143     }
144     m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, 0);
145 }
146 
clearFramebuffer()147 void DrawingBuffer::clearFramebuffer()
148 {
149     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo);
150     const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes();
151     float clearDepth = 0;
152     int clearStencil = 0;
153     unsigned char depthMask = false;
154     unsigned int stencilMask = 0xffffffff;
155     unsigned char isScissorEnabled = false;
156     unsigned long clearMask = GraphicsContext3D::COLOR_BUFFER_BIT;
157     if (attributes.depth) {
158         m_context->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &clearDepth);
159         m_context->clearDepth(1);
160         m_context->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
161         m_context->depthMask(true);
162         clearMask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
163     }
164     if (attributes.stencil) {
165         m_context->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &clearStencil);
166         m_context->clearStencil(0);
167         m_context->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<int*>(&stencilMask));
168         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, 0xffffffff);
169         clearMask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
170     }
171     isScissorEnabled = m_context->isEnabled(GraphicsContext3D::SCISSOR_TEST);
172     m_context->disable(GraphicsContext3D::SCISSOR_TEST);
173 
174     float clearColor[4];
175     m_context->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, clearColor);
176     m_context->clearColor(0, 0, 0, 0);
177     m_context->clear(clearMask);
178     m_context->clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
179 
180     if (attributes.depth) {
181         m_context->clearDepth(clearDepth);
182         m_context->depthMask(depthMask);
183     }
184     if (attributes.stencil) {
185         m_context->clearStencil(clearStencil);
186         m_context->stencilMaskSeparate(GraphicsContext3D::FRONT, stencilMask);
187     }
188     if (isScissorEnabled)
189         m_context->enable(GraphicsContext3D::SCISSOR_TEST);
190     else
191         m_context->disable(GraphicsContext3D::SCISSOR_TEST);
192 }
193 
reset(const IntSize & newSize)194 bool DrawingBuffer::reset(const IntSize& newSize)
195 {
196     if (!m_context)
197         return false;
198 
199     m_context->makeContextCurrent();
200 
201     int maxTextureSize = 0;
202     m_context->getIntegerv(GraphicsContext3D::MAX_TEXTURE_SIZE, &maxTextureSize);
203     if (newSize.height() > maxTextureSize || newSize.width() > maxTextureSize) {
204       clear();
205       return false;
206     }
207 
208     const GraphicsContext3D::Attributes& attributes = m_context->getContextAttributes();
209 
210     if (newSize != m_size) {
211         m_size = newSize;
212 
213         unsigned long internalColorFormat, colorFormat, internalRenderbufferFormat;
214         if (attributes.alpha) {
215             internalColorFormat = GraphicsContext3D::RGBA;
216             colorFormat = GraphicsContext3D::RGBA;
217             internalRenderbufferFormat = Extensions3D::RGBA8_OES;
218         } else {
219             internalColorFormat = GraphicsContext3D::RGB;
220             colorFormat = GraphicsContext3D::RGB;
221             internalRenderbufferFormat = Extensions3D::RGB8_OES;
222         }
223 
224 
225         // resize multisample FBO
226         if (multisample()) {
227             int maxSampleCount = 0;
228 
229             m_context->getIntegerv(Extensions3D::MAX_SAMPLES, &maxSampleCount);
230             int sampleCount = std::min(8, maxSampleCount);
231 
232             m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO);
233 
234             m_context->bindRenderbuffer(GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer);
235             m_context->getExtensions()->renderbufferStorageMultisample(GraphicsContext3D::RENDERBUFFER, sampleCount, internalRenderbufferFormat, m_size.width(), m_size.height());
236             m_context->framebufferRenderbuffer(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::RENDERBUFFER, m_multisampleColorBuffer);
237             resizeDepthStencil(sampleCount);
238             if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
239                 // Cleanup
240                 clear();
241                 return false;
242             }
243         }
244 
245         // resize regular FBO
246         m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
247 
248         m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, m_colorBuffer);
249 
250         m_context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, internalColorFormat, m_size.width(), m_size.height(), 0, colorFormat, GraphicsContext3D::UNSIGNED_BYTE);
251 
252         m_context->framebufferTexture2D(GraphicsContext3D::FRAMEBUFFER, GraphicsContext3D::COLOR_ATTACHMENT0, GraphicsContext3D::TEXTURE_2D, m_colorBuffer, 0);
253         m_context->bindTexture(GraphicsContext3D::TEXTURE_2D, 0);
254 
255         if (!multisample())
256             resizeDepthStencil(0);
257         if (m_context->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE) {
258             // Cleanup
259             clear();
260             return false;
261         }
262     }
263 
264     clearFramebuffer();
265 
266     didReset();
267 
268     return true;
269 }
270 
commit(long x,long y,long width,long height)271 void DrawingBuffer::commit(long x, long y, long width, long height)
272 {
273     if (!m_context)
274         return;
275 
276     if (width < 0)
277         width = m_size.width();
278     if (height < 0)
279         height = m_size.height();
280 
281     m_context->makeContextCurrent();
282 
283     if (m_multisampleFBO) {
284         m_context->bindFramebuffer(Extensions3D::READ_FRAMEBUFFER, m_multisampleFBO);
285         m_context->bindFramebuffer(Extensions3D::DRAW_FRAMEBUFFER, m_fbo);
286         m_context->getExtensions()->blitFramebuffer(x, y, width, height, x, y, width, height, GraphicsContext3D::COLOR_BUFFER_BIT, GraphicsContext3D::LINEAR);
287     }
288 
289     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_fbo);
290 }
291 
bind()292 void DrawingBuffer::bind()
293 {
294     if (!m_context)
295         return;
296 
297     m_context->bindFramebuffer(GraphicsContext3D::FRAMEBUFFER, m_multisampleFBO ? m_multisampleFBO : m_fbo);
298     m_context->viewport(0, 0, m_size.width(), m_size.height());
299 }
300 
301 } // namespace WebCore
302 
303 #endif
304