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