Home | History | Annotate | Download | only in GLcommon
      1 /*
      2 * Copyright (C) 2011 The Android Open Source Project
      3 *
      4 * Licensed under the Apache License, Version 2.0 (the "License");
      5 * you may not use this file except in compliance with the License.
      6 * You may obtain a copy of the License at
      7 *
      8 * http://www.apache.org/licenses/LICENSE-2.0
      9 *
     10 * Unless required by applicable law or agreed to in writing, software
     11 * distributed under the License is distributed on an "AS IS" BASIS,
     12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 * See the License for the specific language governing permissions and
     14 * limitations under the License.
     15 */
     16 #include <GLES/gl.h>
     17 #include <GLES/glext.h>
     18 #include <GLcommon/FramebufferData.h>
     19 #include <GLcommon/GLEScontext.h>
     20 
     21 RenderbufferData::RenderbufferData() : sourceEGLImage(0),
     22                          eglImageDetach(NULL),
     23                          attachedFB(0),
     24                          attachedPoint(0),
     25                          eglImageGlobalTexName(0) {
     26 }
     27 
     28 RenderbufferData::~RenderbufferData() {
     29     if (sourceEGLImage && eglImageDetach) (*eglImageDetach)(sourceEGLImage);
     30 }
     31 
     32 
     33 FramebufferData::FramebufferData(GLuint name):m_dirty(false) {
     34     m_fbName = name;
     35     for (int i=0; i<MAX_ATTACH_POINTS; i++) {
     36         m_attachPoints[i].target = 0;
     37         m_attachPoints[i].name = 0;
     38         m_attachPoints[i].obj = ObjectDataPtr(NULL);
     39         m_attachPoints[i].owned = false;
     40     }
     41 }
     42 
     43 FramebufferData::~FramebufferData() {
     44 for (int i=0; i<MAX_ATTACH_POINTS; i++) {
     45     detachObject(i);
     46 }
     47 }
     48 
     49 void FramebufferData::setAttachment(GLenum attachment,
     50                GLenum target,
     51                GLuint name,
     52                ObjectDataPtr obj,
     53                bool takeOwnership) {
     54 int idx = attachmentPointIndex(attachment);
     55 
     56     if (m_attachPoints[idx].target != target ||
     57         m_attachPoints[idx].name != name ||
     58         m_attachPoints[idx].obj.Ptr() != obj.Ptr() ||
     59         m_attachPoints[idx].owned != takeOwnership) {
     60 
     61         detachObject(idx);
     62 
     63         m_attachPoints[idx].target = target;
     64         m_attachPoints[idx].name = name;
     65         m_attachPoints[idx].obj = obj;
     66         m_attachPoints[idx].owned = takeOwnership;
     67 
     68         if (target == GL_RENDERBUFFER_OES && obj.Ptr() != NULL) {
     69             RenderbufferData *rbData = (RenderbufferData *)obj.Ptr();
     70             rbData->attachedFB = m_fbName;
     71             rbData->attachedPoint = attachment;
     72         }
     73 
     74         m_dirty = true;
     75     }
     76 }
     77 
     78 GLuint FramebufferData::getAttachment(GLenum attachment,
     79                  GLenum *outTarget,
     80                  ObjectDataPtr *outObj) {
     81     int idx = attachmentPointIndex(attachment);
     82     if (outTarget) *outTarget = m_attachPoints[idx].target;
     83     if (outObj) *outObj = m_attachPoints[idx].obj;
     84     return m_attachPoints[idx].name;
     85 }
     86 
     87 int FramebufferData::attachmentPointIndex(GLenum attachment)
     88 {
     89     switch(attachment) {
     90     case GL_COLOR_ATTACHMENT0_OES:
     91         return 0;
     92     case GL_DEPTH_ATTACHMENT_OES:
     93         return 1;
     94     case GL_STENCIL_ATTACHMENT_OES:
     95         return 2;
     96     default:
     97         return MAX_ATTACH_POINTS;
     98     }
     99 }
    100 
    101 void FramebufferData::detachObject(int idx) {
    102     if (m_attachPoints[idx].target == GL_RENDERBUFFER_OES && m_attachPoints[idx].obj.Ptr() != NULL) {
    103         RenderbufferData *rbData = (RenderbufferData *)m_attachPoints[idx].obj.Ptr();
    104         rbData->attachedFB = 0;
    105         rbData->attachedPoint = 0;
    106     }
    107 
    108     if(m_attachPoints[idx].owned)
    109     {
    110         switch(m_attachPoints[idx].target)
    111         {
    112         case GL_RENDERBUFFER_OES:
    113             GLEScontext::dispatcher().glDeleteRenderbuffersEXT(1, &(m_attachPoints[idx].name));
    114             break;
    115         case GL_TEXTURE_2D:
    116             GLEScontext::dispatcher().glDeleteTextures(1, &(m_attachPoints[idx].name));
    117             break;
    118         }
    119     }
    120 
    121     m_attachPoints[idx].target = 0;
    122     m_attachPoints[idx].name = 0;
    123     m_attachPoints[idx].obj = ObjectDataPtr(NULL);
    124     m_attachPoints[idx].owned = false;
    125 }
    126 
    127 void FramebufferData::validate(GLEScontext* ctx)
    128 {
    129     if(!getAttachment(GL_COLOR_ATTACHMENT0_OES, NULL, NULL))
    130     {
    131         // GLES does not require the framebuffer to have a color attachment.
    132         // OpenGL does. Therefore, if no color is attached, create a dummy
    133         // color texture and attach it.
    134         // This dummy color texture will is owned by the FramebufferObject,
    135         // and will be released by it when its object is detached.
    136 
    137         GLint type = GL_NONE;
    138         GLint name = 0;
    139 
    140         ctx->dispatcher().glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
    141         if(type != GL_NONE)
    142         {
    143             ctx->dispatcher().glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
    144         }
    145         else
    146         {
    147             ctx->dispatcher().glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, &type);
    148             if(type != GL_NONE)
    149             {
    150                 ctx->dispatcher().glGetFramebufferAttachmentParameterivEXT(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT_OES, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, &name);
    151             }
    152             else
    153             {
    154                 // No color, depth or stencil attachments - do nothing
    155                 return;
    156             }
    157         }
    158 
    159         // Find the existing attachment(s) dimensions
    160         GLint width = 0;
    161         GLint height = 0;
    162 
    163         if(type == GL_RENDERBUFFER)
    164         {
    165             GLint prev;
    166             ctx->dispatcher().glGetIntegerv(GL_RENDERBUFFER_BINDING, &prev);
    167             ctx->dispatcher().glBindRenderbufferEXT(GL_RENDERBUFFER, name);
    168             ctx->dispatcher().glGetRenderbufferParameterivEXT(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
    169             ctx->dispatcher().glGetRenderbufferParameterivEXT(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
    170             ctx->dispatcher().glBindRenderbufferEXT(GL_RENDERBUFFER, prev);
    171         }
    172         else if(type == GL_TEXTURE)
    173         {
    174             GLint prev;
    175             ctx->dispatcher().glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev);
    176             ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, name);
    177             ctx->dispatcher().glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
    178             ctx->dispatcher().glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
    179             ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, prev);
    180         }
    181 
    182         // Create the color attachment and attch it
    183         unsigned int tex = ctx->shareGroup()->genGlobalName(TEXTURE);
    184         GLint prev;
    185         ctx->dispatcher().glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev);
    186         ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, tex);
    187 
    188         ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    189         ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
    190         ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    191         ctx->dispatcher().glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    192         ctx->dispatcher().glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    193 
    194         ctx->dispatcher().glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tex, 0);
    195         setAttachment(GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tex, ObjectDataPtr(NULL), true);
    196 
    197         ctx->dispatcher().glBindTexture(GL_TEXTURE_2D, prev);
    198     }
    199 
    200     if(m_dirty)
    201     {
    202         // This is a workaround for a bug found in several OpenGL
    203         // drivers (e.g. ATI's) - after the framebuffer attachments
    204         // have changed, and before the next draw, unbind and rebind
    205         // the framebuffer to sort things out.
    206         ctx->dispatcher().glBindFramebufferEXT(GL_FRAMEBUFFER,0);
    207         ctx->dispatcher().glBindFramebufferEXT(GL_FRAMEBUFFER,ctx->shareGroup()->getGlobalName(FRAMEBUFFER,m_fbName));
    208 
    209         m_dirty = false;
    210     }
    211 }
    212 
    213