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