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 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 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 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 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 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 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 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 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