Home | History | Annotate | Download | only in libOpenglRender
      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