Home | History | Annotate | Download | only in libGLESv2
      1 //
      2 // Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
      3 // Use of this source code is governed by a BSD-style license that can be
      4 // found in the LICENSE file.
      5 //
      6 
      7 // Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer
      8 // objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105.
      9 
     10 #include "libGLESv2/Framebuffer.h"
     11 
     12 #include "libGLESv2/main.h"
     13 #include "libGLESv2/Renderbuffer.h"
     14 #include "libGLESv2/Texture.h"
     15 #include "libGLESv2/utilities.h"
     16 
     17 namespace gl
     18 {
     19 
     20 Framebuffer::Framebuffer()
     21 {
     22     mColorbufferType = GL_NONE;
     23     mDepthbufferType = GL_NONE;
     24     mStencilbufferType = GL_NONE;
     25 }
     26 
     27 Framebuffer::~Framebuffer()
     28 {
     29     mColorbufferPointer.set(NULL);
     30     mDepthbufferPointer.set(NULL);
     31     mStencilbufferPointer.set(NULL);
     32 }
     33 
     34 Renderbuffer *Framebuffer::lookupRenderbuffer(GLenum type, GLuint handle) const
     35 {
     36     gl::Context *context = gl::getContext();
     37     Renderbuffer *buffer = NULL;
     38 
     39     if (type == GL_NONE)
     40     {
     41         buffer = NULL;
     42     }
     43     else if (type == GL_RENDERBUFFER)
     44     {
     45         buffer = context->getRenderbuffer(handle);
     46     }
     47     else if (IsTextureTarget(type))
     48     {
     49         buffer = context->getTexture(handle)->getColorbuffer(type);
     50     }
     51     else
     52     {
     53         UNREACHABLE();
     54     }
     55 
     56     return buffer;
     57 }
     58 
     59 void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer)
     60 {
     61     mColorbufferType = type;
     62     mColorbufferPointer.set(lookupRenderbuffer(type, colorbuffer));
     63 }
     64 
     65 void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer)
     66 {
     67     mDepthbufferType = type;
     68     mDepthbufferPointer.set(lookupRenderbuffer(type, depthbuffer));
     69 }
     70 
     71 void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer)
     72 {
     73     mStencilbufferType = type;
     74     mStencilbufferPointer.set(lookupRenderbuffer(type, stencilbuffer));
     75 }
     76 
     77 void Framebuffer::detachTexture(GLuint texture)
     78 {
     79     if (mColorbufferPointer.id() == texture && IsTextureTarget(mColorbufferType))
     80     {
     81         mColorbufferType = GL_NONE;
     82         mColorbufferPointer.set(NULL);
     83     }
     84 
     85     if (mDepthbufferPointer.id() == texture && IsTextureTarget(mDepthbufferType))
     86     {
     87         mDepthbufferType = GL_NONE;
     88         mDepthbufferPointer.set(NULL);
     89     }
     90 
     91     if (mStencilbufferPointer.id() == texture && IsTextureTarget(mStencilbufferType))
     92     {
     93         mStencilbufferType = GL_NONE;
     94         mStencilbufferPointer.set(NULL);
     95     }
     96 }
     97 
     98 void Framebuffer::detachRenderbuffer(GLuint renderbuffer)
     99 {
    100     if (mColorbufferPointer.id() == renderbuffer && mColorbufferType == GL_RENDERBUFFER)
    101     {
    102         mColorbufferType = GL_NONE;
    103         mColorbufferPointer.set(NULL);
    104     }
    105 
    106     if (mDepthbufferPointer.id() == renderbuffer && mDepthbufferType == GL_RENDERBUFFER)
    107     {
    108         mDepthbufferType = GL_NONE;
    109         mDepthbufferPointer.set(NULL);
    110     }
    111 
    112     if (mStencilbufferPointer.id() == renderbuffer && mStencilbufferType == GL_RENDERBUFFER)
    113     {
    114         mStencilbufferType = GL_NONE;
    115         mStencilbufferPointer.set(NULL);
    116     }
    117 }
    118 
    119 unsigned int Framebuffer::getRenderTargetSerial()
    120 {
    121     Renderbuffer *colorbuffer = mColorbufferPointer.get();
    122 
    123     if (colorbuffer)
    124     {
    125         return colorbuffer->getSerial();
    126     }
    127 
    128     return 0;
    129 }
    130 
    131 IDirect3DSurface9 *Framebuffer::getRenderTarget()
    132 {
    133     Renderbuffer *colorbuffer = mColorbufferPointer.get();
    134 
    135     if (colorbuffer)
    136     {
    137         return colorbuffer->getRenderTarget();
    138     }
    139 
    140     return NULL;
    141 }
    142 
    143 IDirect3DSurface9 *Framebuffer::getDepthStencil()
    144 {
    145     Renderbuffer *depthstencilbuffer = mDepthbufferPointer.get();
    146 
    147     if (!depthstencilbuffer)
    148     {
    149         depthstencilbuffer = mStencilbufferPointer.get();
    150     }
    151 
    152     if (depthstencilbuffer)
    153     {
    154         return depthstencilbuffer->getDepthStencil();
    155     }
    156 
    157     return NULL;
    158 }
    159 
    160 unsigned int Framebuffer::getDepthbufferSerial()
    161 {
    162     Renderbuffer *depthbuffer = mDepthbufferPointer.get();
    163 
    164     if (depthbuffer)
    165     {
    166         return depthbuffer->getSerial();
    167     }
    168 
    169     return 0;
    170 }
    171 
    172 unsigned int Framebuffer::getStencilbufferSerial()
    173 {
    174     Renderbuffer *stencilbuffer = mStencilbufferPointer.get();
    175 
    176     if (stencilbuffer)
    177     {
    178         return stencilbuffer->getSerial();
    179     }
    180 
    181     return 0;
    182 }
    183 
    184 Colorbuffer *Framebuffer::getColorbuffer()
    185 {
    186     Renderbuffer *rb = mColorbufferPointer.get();
    187 
    188     if (rb != NULL && rb->isColorbuffer())
    189     {
    190         return static_cast<Colorbuffer*>(rb->getStorage());
    191     }
    192     else
    193     {
    194         return NULL;
    195     }
    196 }
    197 
    198 DepthStencilbuffer *Framebuffer::getDepthbuffer()
    199 {
    200     Renderbuffer *rb = mDepthbufferPointer.get();
    201 
    202     if (rb != NULL && rb->isDepthbuffer())
    203     {
    204         return static_cast<DepthStencilbuffer*>(rb->getStorage());
    205     }
    206     else
    207     {
    208         return NULL;
    209     }
    210 }
    211 
    212 DepthStencilbuffer *Framebuffer::getStencilbuffer()
    213 {
    214     Renderbuffer *rb = mStencilbufferPointer.get();
    215 
    216     if (rb != NULL && rb->isStencilbuffer())
    217     {
    218         return static_cast<DepthStencilbuffer*>(rb->getStorage());
    219     }
    220     else
    221     {
    222         return NULL;
    223     }
    224 }
    225 
    226 GLenum Framebuffer::getColorbufferType()
    227 {
    228     return mColorbufferType;
    229 }
    230 
    231 GLenum Framebuffer::getDepthbufferType()
    232 {
    233     return mDepthbufferType;
    234 }
    235 
    236 GLenum Framebuffer::getStencilbufferType()
    237 {
    238     return mStencilbufferType;
    239 }
    240 
    241 GLuint Framebuffer::getColorbufferHandle()
    242 {
    243     return mColorbufferPointer.id();
    244 }
    245 
    246 GLuint Framebuffer::getDepthbufferHandle()
    247 {
    248     return mDepthbufferPointer.id();
    249 }
    250 
    251 GLuint Framebuffer::getStencilbufferHandle()
    252 {
    253     return mStencilbufferPointer.id();
    254 }
    255 
    256 bool Framebuffer::hasStencil()
    257 {
    258     if (mStencilbufferType != GL_NONE)
    259     {
    260         DepthStencilbuffer *stencilbufferObject = getStencilbuffer();
    261 
    262         if (stencilbufferObject)
    263         {
    264             return stencilbufferObject->getStencilSize() > 0;
    265         }
    266     }
    267 
    268     return false;
    269 }
    270 
    271 bool Framebuffer::isMultisample()
    272 {
    273     // If the framebuffer is not complete, attachment samples may be mismatched, and it
    274     // cannot be used as a multisample framebuffer. If it is complete, it is required to
    275     // have a color attachment, and all its attachments must have the same number of samples,
    276     // so the number of samples for the colorbuffer will indicate whether the framebuffer is
    277     // multisampled.
    278     if (completeness() == GL_FRAMEBUFFER_COMPLETE && getColorbuffer()->getSamples() > 0)
    279     {
    280         return true;
    281     }
    282     else
    283     {
    284         return false;
    285     }
    286 }
    287 
    288 GLenum Framebuffer::completeness()
    289 {
    290     int width = 0;
    291     int height = 0;
    292     int samples = -1;
    293 
    294     if (mColorbufferType != GL_NONE)
    295     {
    296         Colorbuffer *colorbuffer = getColorbuffer();
    297 
    298         if (!colorbuffer)
    299         {
    300             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    301         }
    302 
    303         if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0)
    304         {
    305             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    306         }
    307 
    308         if (mColorbufferType == GL_RENDERBUFFER)
    309         {
    310             if (!gl::IsColorRenderable(colorbuffer->getFormat()))
    311             {
    312                 return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    313             }
    314         }
    315         else if (IsTextureTarget(mColorbufferType))
    316         {
    317             if (IsCompressed(colorbuffer->getFormat()))
    318             {
    319                 return GL_FRAMEBUFFER_UNSUPPORTED;
    320             }
    321 
    322             if (colorbuffer->isFloatingPoint() && (!getContext()->supportsFloatRenderableTextures() ||
    323                                                    !getContext()->supportsHalfFloatRenderableTextures()))
    324             {
    325                 return GL_FRAMEBUFFER_UNSUPPORTED;
    326             }
    327 
    328             if (colorbuffer->getFormat() == GL_LUMINANCE || colorbuffer->getFormat() == GL_LUMINANCE_ALPHA)
    329             {
    330                 return GL_FRAMEBUFFER_UNSUPPORTED;
    331             }
    332         }
    333         else UNREACHABLE();
    334 
    335         width = colorbuffer->getWidth();
    336         height = colorbuffer->getHeight();
    337         samples = colorbuffer->getSamples();
    338     }
    339     else
    340     {
    341         return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
    342     }
    343 
    344     DepthStencilbuffer *depthbuffer = NULL;
    345     DepthStencilbuffer *stencilbuffer = NULL;
    346 
    347     if (mDepthbufferType != GL_NONE)
    348     {
    349         if (mDepthbufferType != GL_RENDERBUFFER)
    350         {
    351             return GL_FRAMEBUFFER_UNSUPPORTED;   // Requires GL_OES_depth_texture
    352         }
    353 
    354         depthbuffer = getDepthbuffer();
    355 
    356         if (!depthbuffer)
    357         {
    358             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    359         }
    360 
    361         if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0)
    362         {
    363             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    364         }
    365 
    366         if (width == 0)
    367         {
    368             width = depthbuffer->getWidth();
    369             height = depthbuffer->getHeight();
    370         }
    371         else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight())
    372         {
    373             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
    374         }
    375 
    376         if (samples == -1)
    377         {
    378             samples = depthbuffer->getSamples();
    379         }
    380         else if (samples != depthbuffer->getSamples())
    381         {
    382             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
    383         }
    384     }
    385 
    386     if (mStencilbufferType != GL_NONE)
    387     {
    388         if (mStencilbufferType != GL_RENDERBUFFER)
    389         {
    390             return GL_FRAMEBUFFER_UNSUPPORTED;
    391         }
    392 
    393         stencilbuffer = getStencilbuffer();
    394 
    395         if (!stencilbuffer)
    396         {
    397             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    398         }
    399 
    400         if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0)
    401         {
    402             return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
    403         }
    404 
    405         if (width == 0)
    406         {
    407             width = stencilbuffer->getWidth();
    408             height = stencilbuffer->getHeight();
    409         }
    410         else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight())
    411         {
    412             return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
    413         }
    414 
    415         if (samples == -1)
    416         {
    417             samples = stencilbuffer->getSamples();
    418         }
    419         else if (samples != stencilbuffer->getSamples())
    420         {
    421             return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE;
    422         }
    423     }
    424 
    425     if (mDepthbufferType == GL_RENDERBUFFER && mStencilbufferType == GL_RENDERBUFFER)
    426     {
    427         if (depthbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
    428             stencilbuffer->getFormat() != GL_DEPTH24_STENCIL8_OES ||
    429             depthbuffer->getSerial() != stencilbuffer->getSerial())
    430         {
    431             return GL_FRAMEBUFFER_UNSUPPORTED;
    432         }
    433     }
    434 
    435     return GL_FRAMEBUFFER_COMPLETE;
    436 }
    437 
    438 DefaultFramebuffer::DefaultFramebuffer(Colorbuffer *color, DepthStencilbuffer *depthStencil)
    439 {
    440     mColorbufferType = GL_RENDERBUFFER;
    441     mDepthbufferType = (depthStencil->getDepthSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
    442     mStencilbufferType = (depthStencil->getStencilSize() != 0) ? GL_RENDERBUFFER : GL_NONE;
    443 
    444     mColorbufferPointer.set(new Renderbuffer(0, color));
    445 
    446     Renderbuffer *depthStencilRenderbuffer = new Renderbuffer(0, depthStencil);
    447     mDepthbufferPointer.set(depthStencilRenderbuffer);
    448     mStencilbufferPointer.set(depthStencilRenderbuffer);
    449 }
    450 
    451 int Framebuffer::getSamples()
    452 {
    453     if (completeness() == GL_FRAMEBUFFER_COMPLETE)
    454     {
    455         return getColorbuffer()->getSamples();
    456     }
    457     else
    458     {
    459         return 0;
    460     }
    461 }
    462 
    463 GLenum DefaultFramebuffer::completeness()
    464 {
    465     // The default framebuffer should always be complete
    466     ASSERT(Framebuffer::completeness() == GL_FRAMEBUFFER_COMPLETE);
    467 
    468     return GL_FRAMEBUFFER_COMPLETE;
    469 }
    470 
    471 }
    472