Home | History | Annotate | Download | only in canvas
      1 /*
      2  * Copyright (C) 2009 Apple 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
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 
     28 #if ENABLE(WEBGL)
     29 
     30 #include "WebGLFramebuffer.h"
     31 
     32 #include "WebGLRenderingContext.h"
     33 
     34 namespace WebCore {
     35 
     36 namespace {
     37 
     38     // This function is only for depth/stencil/depth_stencil attachment.
     39     // Currently we assume these attachments are all renderbuffers.
     40     GC3Denum getInternalFormat(WebGLObject* buffer)
     41     {
     42         ASSERT(buffer && buffer->isRenderbuffer());
     43         return (reinterpret_cast<WebGLRenderbuffer*>(buffer))->getInternalFormat();
     44     }
     45 
     46     bool isUninitialized(WebGLObject* attachedObject)
     47     {
     48         if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()
     49             && !(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isInitialized())
     50             return true;
     51         return false;
     52     }
     53 
     54     void setInitialized(WebGLObject* attachedObject)
     55     {
     56         if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer())
     57             (reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->setInitialized();
     58     }
     59 
     60     bool isValid(WebGLObject* attachedObject)
     61     {
     62         if (attachedObject && attachedObject->object() && attachedObject->isRenderbuffer()) {
     63             if (!(reinterpret_cast<WebGLRenderbuffer*>(attachedObject))->isValid())
     64                 return false;
     65         }
     66         return true;
     67     }
     68 
     69 } // anonymous namespace
     70 
     71 PassRefPtr<WebGLFramebuffer> WebGLFramebuffer::create(WebGLRenderingContext* ctx)
     72 {
     73     return adoptRef(new WebGLFramebuffer(ctx));
     74 }
     75 
     76 WebGLFramebuffer::WebGLFramebuffer(WebGLRenderingContext* ctx)
     77     : WebGLObject(ctx)
     78     , m_hasEverBeenBound(false)
     79     , m_texTarget(0)
     80     , m_texLevel(-1)
     81 {
     82     setObject(context()->graphicsContext3D()->createFramebuffer());
     83 }
     84 
     85 void WebGLFramebuffer::setAttachment(GC3Denum attachment, GC3Denum texTarget, WebGLTexture* texture, GC3Dint level)
     86 {
     87     if (!object())
     88         return;
     89     if (texture && !texture->object())
     90         texture = 0;
     91     switch (attachment) {
     92     case GraphicsContext3D::COLOR_ATTACHMENT0:
     93         m_colorAttachment = texture;
     94         if (texture) {
     95             m_texTarget = texTarget;
     96             m_texLevel = level;
     97         }
     98         break;
     99     case GraphicsContext3D::DEPTH_ATTACHMENT:
    100         m_depthAttachment = texture;
    101         break;
    102     case GraphicsContext3D::STENCIL_ATTACHMENT:
    103         m_stencilAttachment = texture;
    104         break;
    105     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
    106         m_depthStencilAttachment = texture;
    107         break;
    108     default:
    109         return;
    110     }
    111 }
    112 
    113 void WebGLFramebuffer::setAttachment(GC3Denum attachment, WebGLRenderbuffer* renderbuffer)
    114 {
    115     if (!object())
    116         return;
    117     if (renderbuffer && !renderbuffer->object())
    118         renderbuffer = 0;
    119     switch (attachment) {
    120     case GraphicsContext3D::COLOR_ATTACHMENT0:
    121         m_colorAttachment = renderbuffer;
    122         break;
    123     case GraphicsContext3D::DEPTH_ATTACHMENT:
    124         m_depthAttachment = renderbuffer;
    125         break;
    126     case GraphicsContext3D::STENCIL_ATTACHMENT:
    127         m_stencilAttachment = renderbuffer;
    128         break;
    129     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
    130         m_depthStencilAttachment = renderbuffer;
    131         break;
    132     default:
    133         return;
    134     }
    135 }
    136 
    137 WebGLObject* WebGLFramebuffer::getAttachment(GC3Denum attachment) const
    138 {
    139     if (!object())
    140         return 0;
    141     switch (attachment) {
    142     case GraphicsContext3D::COLOR_ATTACHMENT0:
    143         return m_colorAttachment.get();
    144     case GraphicsContext3D::DEPTH_ATTACHMENT:
    145         return m_depthAttachment.get();
    146     case GraphicsContext3D::STENCIL_ATTACHMENT:
    147         return m_stencilAttachment.get();
    148     case GraphicsContext3D::DEPTH_STENCIL_ATTACHMENT:
    149         return m_depthStencilAttachment.get();
    150     default:
    151         return 0;
    152     }
    153 }
    154 
    155 void WebGLFramebuffer::removeAttachment(WebGLObject* attachment)
    156 {
    157     if (!object())
    158         return;
    159     if (attachment == m_colorAttachment.get())
    160         m_colorAttachment = 0;
    161     else if (attachment == m_depthAttachment.get())
    162         m_depthAttachment = 0;
    163     else if (attachment == m_stencilAttachment.get())
    164         m_stencilAttachment = 0;
    165     else if (attachment == m_depthStencilAttachment.get())
    166         m_depthStencilAttachment = 0;
    167     else
    168         return;
    169 }
    170 
    171 GC3Dsizei WebGLFramebuffer::getWidth() const
    172 {
    173     if (!object() || !isColorAttached())
    174         return 0;
    175     if (m_colorAttachment->isRenderbuffer())
    176         return (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getWidth();
    177     if (m_colorAttachment->isTexture())
    178         return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getWidth(m_texTarget, m_texLevel);
    179     ASSERT_NOT_REACHED();
    180     return 0;
    181 }
    182 
    183 GC3Dsizei WebGLFramebuffer::getHeight() const
    184 {
    185     if (!object() || !isColorAttached())
    186         return 0;
    187     if (m_colorAttachment->isRenderbuffer())
    188         return (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getHeight();
    189     if (m_colorAttachment->isTexture())
    190         return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getHeight(m_texTarget, m_texLevel);
    191     ASSERT_NOT_REACHED();
    192     return 0;
    193 }
    194 
    195 GC3Denum WebGLFramebuffer::getColorBufferFormat() const
    196 {
    197     if (!object() || !isColorAttached())
    198         return 0;
    199     if (m_colorAttachment->isRenderbuffer()) {
    200         unsigned long format = (reinterpret_cast<WebGLRenderbuffer*>(m_colorAttachment.get()))->getInternalFormat();
    201         switch (format) {
    202         case GraphicsContext3D::RGBA4:
    203         case GraphicsContext3D::RGB5_A1:
    204             return GraphicsContext3D::RGBA;
    205         case GraphicsContext3D::RGB565:
    206             return GraphicsContext3D::RGB;
    207         }
    208         return 0;
    209     }
    210     if (m_colorAttachment->isTexture())
    211         return (reinterpret_cast<WebGLTexture*>(m_colorAttachment.get()))->getInternalFormat(m_texTarget, m_texLevel);
    212     ASSERT_NOT_REACHED();
    213     return 0;
    214 }
    215 
    216 bool WebGLFramebuffer::isIncomplete(bool checkInternalFormat) const
    217 {
    218     unsigned int count = 0;
    219     if (isDepthAttached()) {
    220         if (checkInternalFormat && getInternalFormat(m_depthAttachment.get()) != GraphicsContext3D::DEPTH_COMPONENT16)
    221             return true;
    222         count++;
    223     }
    224     if (isStencilAttached()) {
    225         if (checkInternalFormat && getInternalFormat(m_stencilAttachment.get()) != GraphicsContext3D::STENCIL_INDEX8)
    226             return true;
    227         count++;
    228     }
    229     if (isDepthStencilAttached()) {
    230         if (checkInternalFormat && getInternalFormat(m_depthStencilAttachment.get()) != GraphicsContext3D::DEPTH_STENCIL)
    231             return true;
    232         if (!isValid(m_depthStencilAttachment.get()))
    233             return true;
    234         count++;
    235     }
    236     if (count > 1)
    237         return true;
    238     return false;
    239 }
    240 
    241 bool WebGLFramebuffer::onAccess(bool needToInitializeRenderbuffers)
    242 {
    243     if (isIncomplete(true))
    244         return false;
    245     if (needToInitializeRenderbuffers)
    246         return initializeRenderbuffers();
    247     return true;
    248 }
    249 
    250 void WebGLFramebuffer::deleteObjectImpl(Platform3DObject object)
    251 {
    252     context()->graphicsContext3D()->deleteFramebuffer(object);
    253     m_colorAttachment = 0;
    254     m_depthAttachment = 0;
    255     m_stencilAttachment = 0;
    256     m_depthStencilAttachment = 0;
    257 }
    258 
    259 bool WebGLFramebuffer::initializeRenderbuffers()
    260 {
    261     ASSERT(object());
    262     bool initColor = false, initDepth = false, initStencil = false;
    263     GC3Dbitfield mask = 0;
    264     if (isUninitialized(m_colorAttachment.get())) {
    265         initColor = true;
    266         mask |= GraphicsContext3D::COLOR_BUFFER_BIT;
    267     }
    268     if (isUninitialized(m_depthAttachment.get())) {
    269         initDepth = true;
    270         mask |= GraphicsContext3D::DEPTH_BUFFER_BIT;
    271     }
    272     if (isUninitialized(m_stencilAttachment.get())) {
    273         initStencil = true;
    274         mask |= GraphicsContext3D::STENCIL_BUFFER_BIT;
    275     }
    276     if (isUninitialized(m_depthStencilAttachment.get())) {
    277         initDepth = true;
    278         initStencil = true;
    279         mask |= (GraphicsContext3D::DEPTH_BUFFER_BIT | GraphicsContext3D::STENCIL_BUFFER_BIT);
    280     }
    281     if (!initColor && !initDepth && !initStencil)
    282         return true;
    283 
    284     // We only clear un-initialized renderbuffers when they are ready to be
    285     // read, i.e., when the framebuffer is complete.
    286     GraphicsContext3D* g3d = context()->graphicsContext3D();
    287     if (g3d->checkFramebufferStatus(GraphicsContext3D::FRAMEBUFFER) != GraphicsContext3D::FRAMEBUFFER_COMPLETE)
    288         return false;
    289 
    290     GC3Dfloat colorClearValue[] = {0, 0, 0, 0}, depthClearValue = 0;
    291     GC3Dint stencilClearValue = 0;
    292     GC3Dboolean colorMask[] = {0, 0, 0, 0}, depthMask = 0;
    293     GC3Duint stencilMask = 0xffffffff;
    294     GC3Dboolean isScissorEnabled = 0;
    295     GC3Dboolean isDitherEnabled = 0;
    296     if (initColor) {
    297         g3d->getFloatv(GraphicsContext3D::COLOR_CLEAR_VALUE, colorClearValue);
    298         g3d->getBooleanv(GraphicsContext3D::COLOR_WRITEMASK, colorMask);
    299         g3d->clearColor(0, 0, 0, 0);
    300         g3d->colorMask(true, true, true, true);
    301     }
    302     if (initDepth) {
    303         g3d->getFloatv(GraphicsContext3D::DEPTH_CLEAR_VALUE, &depthClearValue);
    304         g3d->getBooleanv(GraphicsContext3D::DEPTH_WRITEMASK, &depthMask);
    305         g3d->clearDepth(0);
    306         g3d->depthMask(true);
    307     }
    308     if (initStencil) {
    309         g3d->getIntegerv(GraphicsContext3D::STENCIL_CLEAR_VALUE, &stencilClearValue);
    310         g3d->getIntegerv(GraphicsContext3D::STENCIL_WRITEMASK, reinterpret_cast<GC3Dint*>(&stencilMask));
    311         g3d->clearStencil(0);
    312         g3d->stencilMask(0xffffffff);
    313     }
    314     isScissorEnabled = g3d->isEnabled(GraphicsContext3D::SCISSOR_TEST);
    315     g3d->disable(GraphicsContext3D::SCISSOR_TEST);
    316     isDitherEnabled = g3d->isEnabled(GraphicsContext3D::DITHER);
    317     g3d->disable(GraphicsContext3D::DITHER);
    318 
    319     g3d->clear(mask);
    320 
    321     if (initColor) {
    322         g3d->clearColor(colorClearValue[0], colorClearValue[1], colorClearValue[2], colorClearValue[3]);
    323         g3d->colorMask(colorMask[0], colorMask[1], colorMask[2], colorMask[3]);
    324     }
    325     if (initDepth) {
    326         g3d->clearDepth(depthClearValue);
    327         g3d->depthMask(depthMask);
    328     }
    329     if (initStencil) {
    330         g3d->clearStencil(stencilClearValue);
    331         g3d->stencilMask(stencilMask);
    332     }
    333     if (isScissorEnabled)
    334         g3d->enable(GraphicsContext3D::SCISSOR_TEST);
    335     else
    336         g3d->disable(GraphicsContext3D::SCISSOR_TEST);
    337     if (isDitherEnabled)
    338         g3d->enable(GraphicsContext3D::DITHER);
    339     else
    340         g3d->disable(GraphicsContext3D::DITHER);
    341 
    342     if (initColor)
    343         setInitialized(m_colorAttachment.get());
    344     if (initDepth && initStencil && m_depthStencilAttachment)
    345         setInitialized(m_depthStencilAttachment.get());
    346     else {
    347         if (initDepth)
    348             setInitialized(m_depthAttachment.get());
    349         if (initStencil)
    350             setInitialized(m_stencilAttachment.get());
    351     }
    352     return true;
    353 }
    354 
    355 }
    356 
    357 #endif // ENABLE(WEBGL)
    358