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 "ColorBuffer.h"
17 #include "FrameBuffer.h"
18 #include "EGLDispatch.h"
19 #include "GLDispatch.h"
20 #include "ThreadInfo.h"
21 #include "GLcommon/GLutils.h"
22 #ifdef WITH_GLES2
23 #include "GL2Dispatch.h"
24 #endif
25 #include <stdio.h>
26
create(int p_width,int p_height,GLenum p_internalFormat)27 ColorBuffer *ColorBuffer::create(int p_width, int p_height,
28 GLenum p_internalFormat)
29 {
30 FrameBuffer *fb = FrameBuffer::getFB();
31
32 GLenum texInternalFormat = 0;
33
34 switch(p_internalFormat) {
35 case GL_RGB:
36 case GL_RGB565_OES:
37 texInternalFormat = GL_RGB;
38 break;
39
40 case GL_RGBA:
41 case GL_RGB5_A1_OES:
42 case GL_RGBA4_OES:
43 texInternalFormat = GL_RGBA;
44 break;
45
46 default:
47 return NULL;
48 break;
49 }
50
51 if (!fb->bind_locked()) {
52 return NULL;
53 }
54
55 ColorBuffer *cb = new ColorBuffer();
56
57
58 s_gl.glGenTextures(1, &cb->m_tex);
59 s_gl.glBindTexture(GL_TEXTURE_2D, cb->m_tex);
60 int nComp = (texInternalFormat == GL_RGB ? 3 : 4);
61 char *zBuff = new char[nComp*p_width*p_height];
62 if (zBuff) {
63 memset(zBuff, 0, nComp*p_width*p_height);
64 }
65 s_gl.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat,
66 p_width, p_height, 0,
67 texInternalFormat,
68 GL_UNSIGNED_BYTE, zBuff);
69 delete [] zBuff;
70 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
71 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
72 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
73 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
74 s_gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
75
76 //
77 // create another texture for that colorbuffer for blit
78 //
79 s_gl.glGenTextures(1, &cb->m_blitTex);
80 s_gl.glBindTexture(GL_TEXTURE_2D, cb->m_blitTex);
81 s_gl.glTexImage2D(GL_TEXTURE_2D, 0, texInternalFormat,
82 p_width, p_height, 0,
83 texInternalFormat,
84 GL_UNSIGNED_BYTE, NULL);
85 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
86 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
87 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
88 s_gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
89 s_gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
90
91 cb->m_width = p_width;
92 cb->m_height = p_height;
93 cb->m_internalFormat = texInternalFormat;
94
95 if (fb->getCaps().has_eglimage_texture_2d) {
96 cb->m_eglImage = s_egl.eglCreateImageKHR(
97 fb->getDisplay(),
98 s_egl.eglGetCurrentContext(),
99 EGL_GL_TEXTURE_2D_KHR,
100 (EGLClientBuffer)SafePointerFromUInt(cb->m_tex),
101 NULL);
102
103 cb->m_blitEGLImage = s_egl.eglCreateImageKHR(
104 fb->getDisplay(),
105 s_egl.eglGetCurrentContext(),
106 EGL_GL_TEXTURE_2D_KHR,
107 (EGLClientBuffer)SafePointerFromUInt(cb->m_blitTex),
108 NULL);
109 }
110
111 fb->unbind_locked();
112 return cb;
113 }
114
ColorBuffer()115 ColorBuffer::ColorBuffer() :
116 m_tex(0),
117 m_blitTex(0),
118 m_eglImage(NULL),
119 m_blitEGLImage(NULL),
120 m_fbo(0),
121 m_internalFormat(0)
122 {
123 }
124
~ColorBuffer()125 ColorBuffer::~ColorBuffer()
126 {
127 FrameBuffer *fb = FrameBuffer::getFB();
128 fb->bind_locked();
129
130 if (m_blitEGLImage) {
131 s_egl.eglDestroyImageKHR(fb->getDisplay(), m_blitEGLImage);
132 }
133 if (m_eglImage) {
134 s_egl.eglDestroyImageKHR(fb->getDisplay(), m_eglImage);
135 }
136
137 if (m_fbo) {
138 s_gl.glDeleteFramebuffersOES(1, &m_fbo);
139 }
140
141 GLuint tex[2] = {m_tex, m_blitTex};
142 s_gl.glDeleteTextures(2, tex);
143
144 fb->unbind_locked();
145 }
146
subUpdate(int x,int y,int width,int height,GLenum p_format,GLenum p_type,void * pixels)147 void ColorBuffer::subUpdate(int x, int y, int width, int height, GLenum p_format, GLenum p_type, void *pixels)
148 {
149 FrameBuffer *fb = FrameBuffer::getFB();
150 if (!fb->bind_locked()) return;
151 s_gl.glBindTexture(GL_TEXTURE_2D, m_tex);
152 s_gl.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
153 s_gl.glTexSubImage2D(GL_TEXTURE_2D, 0, x, y,
154 width, height, p_format, p_type, pixels);
155 fb->unbind_locked();
156 }
157
blitFromCurrentReadBuffer()158 bool ColorBuffer::blitFromCurrentReadBuffer()
159 {
160 RenderThreadInfo *tInfo = RenderThreadInfo::get();
161 if (!tInfo->currContext.Ptr()) {
162 // no Current context
163 return false;
164 }
165
166 //
167 // Create a temporary texture inside the current context
168 // from the blit_texture EGLImage and copy the pixels
169 // from the current read buffer to that texture
170 //
171 GLuint tmpTex;
172 GLint currTexBind;
173 if (tInfo->currContext->isGL2()) {
174 s_gl2.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
175 s_gl2.glGenTextures(1,&tmpTex);
176 s_gl2.glBindTexture(GL_TEXTURE_2D, tmpTex);
177 s_gl2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
178 s_gl2.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
179 m_width, m_height);
180 }
181 else {
182 s_gl.glGetIntegerv(GL_TEXTURE_BINDING_2D, &currTexBind);
183 s_gl.glGenTextures(1,&tmpTex);
184 s_gl.glBindTexture(GL_TEXTURE_2D, tmpTex);
185 s_gl.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_blitEGLImage);
186 s_gl.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
187 m_width, m_height);
188 }
189
190
191 //
192 // Now bind the frame buffer context and blit from
193 // m_blitTex into m_tex
194 //
195 FrameBuffer *fb = FrameBuffer::getFB();
196 if (fb->bind_locked()) {
197
198 //
199 // bind FBO object which has this colorbuffer as render target
200 //
201 if (bind_fbo()) {
202
203 //
204 // save current viewport and match it to the current
205 // colorbuffer size
206 //
207 GLint vport[4] = {};
208 s_gl.glGetIntegerv(GL_VIEWPORT, vport);
209 s_gl.glViewport(0, 0, m_width, m_height);
210
211 // render m_blitTex
212 s_gl.glBindTexture(GL_TEXTURE_2D, m_blitTex);
213 s_gl.glEnable(GL_TEXTURE_2D);
214 s_gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
215 drawTexQuad(); // this will render the texture flipped
216
217 // unbind the fbo
218 s_gl.glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
219
220 // restrore previous viewport
221 s_gl.glViewport(vport[0], vport[1], vport[2], vport[3]);
222 }
223
224 // unbind from the FrameBuffer context
225 fb->unbind_locked();
226 }
227
228 //
229 // delete the temporary texture and restore the texture binding
230 // inside the current context
231 //
232 if (tInfo->currContext->isGL2()) {
233 s_gl2.glDeleteTextures(1, &tmpTex);
234 s_gl2.glBindTexture(GL_TEXTURE_2D, currTexBind);
235 }
236 else {
237 s_gl.glDeleteTextures(1, &tmpTex);
238 s_gl.glBindTexture(GL_TEXTURE_2D, currTexBind);
239 }
240
241 return true;
242 }
243
bindToTexture()244 bool ColorBuffer::bindToTexture()
245 {
246 if (m_eglImage) {
247 RenderThreadInfo *tInfo = RenderThreadInfo::get();
248 if (tInfo->currContext.Ptr()) {
249 #ifdef WITH_GLES2
250 if (tInfo->currContext->isGL2()) {
251 s_gl2.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
252 }
253 else {
254 s_gl.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
255 }
256 #else
257 s_gl.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
258 #endif
259 return true;
260 }
261 }
262 return false;
263 }
264
bindToRenderbuffer()265 bool ColorBuffer::bindToRenderbuffer()
266 {
267 if (m_eglImage) {
268 RenderThreadInfo *tInfo = RenderThreadInfo::get();
269 if (tInfo->currContext.Ptr()) {
270 #ifdef WITH_GLES2
271 if (tInfo->currContext->isGL2()) {
272 s_gl2.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, m_eglImage);
273 }
274 else {
275 s_gl.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, m_eglImage);
276 }
277 #else
278 s_gl.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER_OES, m_eglImage);
279 #endif
280 return true;
281 }
282 }
283 return false;
284 }
285
bind_fbo()286 bool ColorBuffer::bind_fbo()
287 {
288 if (m_fbo) {
289 // fbo already exist - just bind
290 s_gl.glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_fbo);
291 return true;
292 }
293
294 s_gl.glGenFramebuffersOES(1, &m_fbo);
295 s_gl.glBindFramebufferOES(GL_FRAMEBUFFER_OES, m_fbo);
296 s_gl.glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
297 GL_COLOR_ATTACHMENT0_OES,
298 GL_TEXTURE_2D, m_tex, 0);
299 GLenum status = s_gl.glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
300 if (status != GL_FRAMEBUFFER_COMPLETE_OES) {
301 ERR("ColorBuffer::bind_fbo: FBO not complete: %#x\n", status);
302 s_gl.glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
303 s_gl.glDeleteFramebuffersOES(1, &m_fbo);
304 m_fbo = 0;
305 return false;
306 }
307
308 return true;
309 }
310
post()311 bool ColorBuffer::post()
312 {
313 s_gl.glBindTexture(GL_TEXTURE_2D, m_tex);
314 s_gl.glEnable(GL_TEXTURE_2D);
315 s_gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
316 drawTexQuad();
317
318 return true;
319 }
320
drawTexQuad()321 void ColorBuffer::drawTexQuad()
322 {
323 GLfloat verts[] = { -1.0f, -1.0f, 0.0f,
324 -1.0f, +1.0f, 0.0f,
325 +1.0f, -1.0f, 0.0f,
326 +1.0f, +1.0f, 0.0f };
327
328 GLfloat tcoords[] = { 0.0f, 1.0f,
329 0.0f, 0.0f,
330 1.0f, 1.0f,
331 1.0f, 0.0f };
332
333 s_gl.glClientActiveTexture(GL_TEXTURE0);
334 s_gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
335 s_gl.glTexCoordPointer(2, GL_FLOAT, 0, tcoords);
336
337 s_gl.glEnableClientState(GL_VERTEX_ARRAY);
338 s_gl.glVertexPointer(3, GL_FLOAT, 0, verts);
339 s_gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
340 }
341
readback(unsigned char * img)342 void ColorBuffer::readback(unsigned char* img)
343 {
344 FrameBuffer *fb = FrameBuffer::getFB();
345 if (fb->bind_locked()) {
346 if (bind_fbo()) {
347 s_gl.glReadPixels(0, 0, m_width, m_height,
348 GL_RGBA, GL_UNSIGNED_BYTE, img);
349 }
350 fb->unbind_locked();
351 }
352 }
353