• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RenderbufferData()21 RenderbufferData::RenderbufferData() : sourceEGLImage(0),
22                          eglImageDetach(NULL),
23                          attachedFB(0),
24                          attachedPoint(0),
25                          eglImageGlobalTexName(0) {
26 }
27 
~RenderbufferData()28 RenderbufferData::~RenderbufferData() {
29     if (sourceEGLImage && eglImageDetach) (*eglImageDetach)(sourceEGLImage);
30 }
31 
32 
FramebufferData(GLuint name)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 
~FramebufferData()43 FramebufferData::~FramebufferData() {
44 for (int i=0; i<MAX_ATTACH_POINTS; i++) {
45     detachObject(i);
46 }
47 }
48 
setAttachment(GLenum attachment,GLenum target,GLuint name,ObjectDataPtr obj,bool takeOwnership)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 
getAttachment(GLenum attachment,GLenum * outTarget,ObjectDataPtr * outObj)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 
attachmentPointIndex(GLenum attachment)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 
detachObject(int idx)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 
validate(GLEScontext * ctx)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