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 #include "GLcommon/GLutils.h"
     22 #ifdef WITH_GLES2
     23 #include "GL2Dispatch.h"
     24 #endif
     25 #include <stdio.h>
     26 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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