Home | History | Annotate | Download | only in gpu
      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