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