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     m_warYInvertBug(false)
    118 {
    119 #if __APPLE__
    120     // On Macs running OS X 10.6 and 10.7 with Intel HD Graphics 3000, some
    121     // screens or parts of the screen are displayed upside down. The exact
    122     // conditions/sequence that triggers this aren't known yet; I haven't
    123     // been able to reproduce it in a standalone test. This way of enabling the
    124     // workaround will break if it is a driver bug (rather than a bug in this
    125     // code which works by accident elsewhere) and Apple/Intel release a fix for
    126     // it. Running a standalone test to detect the problem at runtime would be
    127     // more robust.
    128     if (strstr((const char*)s_gl.glGetString(GL_RENDERER), "Intel HD Graphics 3000"))
    129         m_warYInvertBug = true;
    130 #endif
    131 }
    132 
    133 ColorBuffer::~ColorBuffer()
    134 {
    135     FrameBuffer *fb = FrameBuffer::getFB();
    136     fb->bind_locked();
    137     s_gl.glDeleteTextures(1, &m_tex);
    138     if (m_eglImage) {
    139         s_egl.eglDestroyImageKHR(fb->getDisplay(), m_eglImage);
    140     }
    141     if (m_fbo) {
    142         s_gl.glDeleteFramebuffersOES(1, &m_fbo);
    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 = getRenderThreadInfo();
    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.glCopyTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat,
    179                                0, 0, m_width, m_height, 0);
    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.glCopyTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat,
    187                               0, 0, m_width, m_height, 0);
    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(!m_warYInvertBug);
    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 = getRenderThreadInfo();
    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 = getRenderThreadInfo();
    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         s_gl.glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
    302         s_gl.glDeleteFramebuffersOES(1, &m_fbo);
    303         m_fbo = 0;
    304         return false;
    305     }
    306 
    307     return true;
    308 }
    309 
    310 bool ColorBuffer::post()
    311 {
    312     s_gl.glBindTexture(GL_TEXTURE_2D, m_tex);
    313     s_gl.glEnable(GL_TEXTURE_2D);
    314     s_gl.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
    315     drawTexQuad(true);
    316 
    317     return true;
    318 }
    319 
    320 void ColorBuffer::drawTexQuad(bool flipy)
    321 {
    322     GLfloat verts[] = { -1.0f, -1.0f, 0.0f,
    323                          -1.0f, +1.0f, 0.0f,
    324                          +1.0f, -1.0f, 0.0f,
    325                          +1.0f, +1.0f, 0.0f };
    326 
    327     GLfloat tcoords[] = { 0.0f, 1.0f,
    328                            0.0f, 0.0f,
    329                            1.0f, 1.0f,
    330                            1.0f, 0.0f };
    331 
    332     if (!flipy) {
    333         for (int i = 0; i < 4; i++) {
    334             // swap 0.0/1.0 in second element of each tcoord vector
    335             tcoords[2*i + 1] = tcoords[2*i + 1] == 0.0f ? 1.0f : 0.0f;
    336         }
    337     }
    338 
    339     s_gl.glClientActiveTexture(GL_TEXTURE0);
    340     s_gl.glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    341     s_gl.glTexCoordPointer(2, GL_FLOAT, 0, tcoords);
    342 
    343     s_gl.glEnableClientState(GL_VERTEX_ARRAY);
    344     s_gl.glVertexPointer(3, GL_FLOAT, 0, verts);
    345     s_gl.glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    346 }
    347