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