Home | History | Annotate | Download | only in OpenglCodecCommon
      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 "GLClientState.h"
     17 #include "ErrorLog.h"
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 #include "glUtils.h"
     22 #include <cutils/log.h>
     23 
     24 #ifndef MAX
     25 #define MAX(a, b) ((a) < (b) ? (b) : (a))
     26 #endif
     27 
     28 GLClientState::GLClientState(int nLocations)
     29 {
     30     if (nLocations < LAST_LOCATION) {
     31         nLocations = LAST_LOCATION;
     32     }
     33     m_nLocations = nLocations;
     34     m_states = new VertexAttribState[m_nLocations];
     35     for (int i = 0; i < m_nLocations; i++) {
     36         m_states[i].enabled = 0;
     37         m_states[i].enableDirty = false;
     38         m_states[i].data = 0;
     39     }
     40     m_currentArrayVbo = 0;
     41     m_currentIndexVbo = 0;
     42     // init gl constans;
     43     m_states[VERTEX_LOCATION].glConst = GL_VERTEX_ARRAY;
     44     m_states[NORMAL_LOCATION].glConst = GL_NORMAL_ARRAY;
     45     m_states[COLOR_LOCATION].glConst = GL_COLOR_ARRAY;
     46     m_states[POINTSIZE_LOCATION].glConst = GL_POINT_SIZE_ARRAY_OES;
     47     m_states[TEXCOORD0_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     48     m_states[TEXCOORD1_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     49     m_states[TEXCOORD2_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     50     m_states[TEXCOORD3_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     51     m_states[TEXCOORD4_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     52     m_states[TEXCOORD5_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     53     m_states[TEXCOORD6_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     54     m_states[TEXCOORD7_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     55     m_states[MATRIXINDEX_LOCATION].glConst = GL_MATRIX_INDEX_ARRAY_OES;
     56     m_states[WEIGHT_LOCATION].glConst = GL_WEIGHT_ARRAY_OES;
     57     m_activeTexture = 0;
     58     m_currentProgram = 0;
     59 
     60     m_pixelStore.unpack_alignment = 4;
     61     m_pixelStore.pack_alignment = 4;
     62 
     63     memset(m_tex.unit, 0, sizeof(m_tex.unit));
     64     m_tex.activeUnit = &m_tex.unit[0];
     65     m_tex.textures = NULL;
     66     m_tex.numTextures = 0;
     67     m_tex.allocTextures = 0;
     68 
     69     mRboState.boundRenderbuffer = 0;
     70     mRboState.boundRenderbufferIndex = 0;
     71     addFreshRenderbuffer(0);
     72 
     73     mFboState.boundFramebuffer = 0;
     74     mFboState.boundFramebufferIndex = 0;
     75     mFboState.fboCheckStatus = GL_NONE;
     76     addFreshFramebuffer(0);
     77 
     78     m_maxVertexAttribsDirty = true;
     79 }
     80 
     81 GLClientState::~GLClientState()
     82 {
     83     delete m_states;
     84 }
     85 
     86 void GLClientState::enable(int location, int state)
     87 {
     88     if (!validLocation(location)) {
     89         return;
     90     }
     91 
     92     m_states[location].enableDirty |= (state != m_states[location].enabled);
     93     m_states[location].enabled = state;
     94 }
     95 
     96 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data)
     97 {
     98     if (!validLocation(location)) {
     99         return;
    100     }
    101     m_states[location].size = size;
    102     m_states[location].type = type;
    103     m_states[location].stride = stride;
    104     m_states[location].data = (void*)data;
    105     m_states[location].bufferObject = m_currentArrayVbo;
    106     m_states[location].elementSize = size ? (glSizeof(type) * size) : 0;
    107     m_states[location].normalized = normalized;
    108 }
    109 
    110 void GLClientState::setBufferObject(int location, GLuint id)
    111 {
    112     if (!validLocation(location)) {
    113         return;
    114     }
    115 
    116     m_states[location].bufferObject = id;
    117 }
    118 
    119 const GLClientState::VertexAttribState * GLClientState::getState(int location)
    120 {
    121     if (!validLocation(location)) {
    122         return NULL;
    123     }
    124     return & m_states[location];
    125 }
    126 
    127 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged)
    128 {
    129     if (!validLocation(location)) {
    130         return NULL;
    131     }
    132 
    133     if (enableChanged) {
    134         *enableChanged = m_states[location].enableDirty;
    135     }
    136 
    137     m_states[location].enableDirty = false;
    138     return & m_states[location];
    139 }
    140 
    141 int GLClientState::getLocation(GLenum loc)
    142 {
    143     int retval;
    144 
    145     switch(loc) {
    146     case GL_VERTEX_ARRAY:
    147         retval = int(VERTEX_LOCATION);
    148         break;
    149     case GL_NORMAL_ARRAY:
    150         retval = int(NORMAL_LOCATION);
    151         break;
    152     case GL_COLOR_ARRAY:
    153         retval = int(COLOR_LOCATION);
    154         break;
    155     case GL_POINT_SIZE_ARRAY_OES:
    156         retval = int(POINTSIZE_LOCATION);
    157         break;
    158     case GL_TEXTURE_COORD_ARRAY:
    159         retval = int (TEXCOORD0_LOCATION + m_activeTexture);
    160         break;
    161     case GL_MATRIX_INDEX_ARRAY_OES:
    162         retval = int (MATRIXINDEX_LOCATION);
    163         break;
    164     case GL_WEIGHT_ARRAY_OES:
    165         retval = int (WEIGHT_LOCATION);
    166         break;
    167     default:
    168         retval = loc;
    169     }
    170     return retval;
    171 }
    172 
    173 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params)
    174 {
    175     const GLClientState::VertexAttribState *state = NULL;
    176     switch (pname) {
    177     case GL_VERTEX_ARRAY_POINTER: {
    178         state = getState(GLClientState::VERTEX_LOCATION);
    179         break;
    180         }
    181     case GL_NORMAL_ARRAY_POINTER: {
    182         state = getState(GLClientState::NORMAL_LOCATION);
    183         break;
    184         }
    185     case GL_COLOR_ARRAY_POINTER: {
    186         state = getState(GLClientState::COLOR_LOCATION);
    187         break;
    188         }
    189     case GL_TEXTURE_COORD_ARRAY_POINTER: {
    190         state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION);
    191         break;
    192         }
    193     case GL_POINT_SIZE_ARRAY_POINTER_OES: {
    194         state = getState(GLClientState::POINTSIZE_LOCATION);
    195         break;
    196         }
    197     case GL_MATRIX_INDEX_ARRAY_POINTER_OES: {
    198         state = getState(GLClientState::MATRIXINDEX_LOCATION);
    199         break;
    200         }
    201     case GL_WEIGHT_ARRAY_POINTER_OES: {
    202         state = getState(GLClientState::WEIGHT_LOCATION);
    203         break;
    204         }
    205     }
    206     if (state && params)
    207         *params = state->data;
    208 }
    209 
    210 int GLClientState::setPixelStore(GLenum param, GLint value)
    211 {
    212     int retval = 0;
    213     switch(param) {
    214     case GL_UNPACK_ALIGNMENT:
    215         if (value == 1 || value == 2 || value == 4 || value == 8) {
    216             m_pixelStore.unpack_alignment = value;
    217         } else {
    218             retval =  GL_INVALID_VALUE;
    219         }
    220         break;
    221     case GL_PACK_ALIGNMENT:
    222         if (value == 1 || value == 2 || value == 4 || value == 8) {
    223             m_pixelStore.pack_alignment = value;
    224         } else {
    225             retval =  GL_INVALID_VALUE;
    226         }
    227         break;
    228         default:
    229             retval = GL_INVALID_ENUM;
    230     }
    231     return retval;
    232 }
    233 
    234 
    235 
    236 
    237 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const
    238 {
    239     if (width <= 0 || height <= 0) return 0;
    240 
    241     int pixelsize = glUtilsPixelBitSize(format, type) >> 3;
    242 
    243     int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment;
    244 
    245     if (pixelsize == 0 ) {
    246         ERR("unknown pixel size: width: %d height: %d format: %d type: %d pack: %d align: %d\n",
    247              width, height, format, type, pack, alignment);
    248     }
    249     size_t linesize = pixelsize * width;
    250     size_t aligned_linesize = int(linesize / alignment) * alignment;
    251     if (aligned_linesize < linesize) {
    252         aligned_linesize += alignment;
    253     }
    254     return aligned_linesize * height;
    255 }
    256 
    257 GLenum GLClientState::setActiveTextureUnit(GLenum texture)
    258 {
    259     GLuint unit = texture - GL_TEXTURE0;
    260     if (unit >= MAX_TEXTURE_UNITS) {
    261         return GL_INVALID_ENUM;
    262     }
    263     m_tex.activeUnit = &m_tex.unit[unit];
    264     return GL_NO_ERROR;
    265 }
    266 
    267 GLenum GLClientState::getActiveTextureUnit() const
    268 {
    269     return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
    270 }
    271 
    272 void GLClientState::enableTextureTarget(GLenum target)
    273 {
    274     switch (target) {
    275     case GL_TEXTURE_2D:
    276         m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
    277         break;
    278     case GL_TEXTURE_EXTERNAL_OES:
    279         m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
    280         break;
    281     }
    282 }
    283 
    284 void GLClientState::disableTextureTarget(GLenum target)
    285 {
    286     switch (target) {
    287     case GL_TEXTURE_2D:
    288         m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
    289         break;
    290     case GL_TEXTURE_EXTERNAL_OES:
    291         m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
    292         break;
    293     }
    294 }
    295 
    296 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
    297 {
    298     unsigned int enables = m_tex.activeUnit->enables;
    299     if (enables & (1u << TEXTURE_EXTERNAL)) {
    300         return GL_TEXTURE_EXTERNAL_OES;
    301     } else if (enables & (1u << TEXTURE_2D)) {
    302         return GL_TEXTURE_2D;
    303     } else {
    304         return allDisabled;
    305     }
    306 }
    307 
    308 int GLClientState::compareTexId(const void* pid, const void* prec)
    309 {
    310     const GLuint* id = (const GLuint*)pid;
    311     const TextureRec* rec = (const TextureRec*)prec;
    312     return (GLint)(*id) - (GLint)rec->id;
    313 }
    314 
    315 GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
    316         GLboolean* firstUse)
    317 {
    318     GLboolean first = GL_FALSE;
    319     TextureRec* texrec = NULL;
    320     if (texture != 0) {
    321         if (m_tex.textures) {
    322             texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
    323                     m_tex.numTextures, sizeof(TextureRec), compareTexId);
    324         }
    325         if (!texrec) {
    326             if (!(texrec = addTextureRec(texture, target))) {
    327                 return GL_OUT_OF_MEMORY;
    328             }
    329             first = GL_TRUE;
    330         }
    331         if (target != texrec->target) {
    332             return GL_INVALID_OPERATION;
    333         }
    334     }
    335 
    336     switch (target) {
    337     case GL_TEXTURE_2D:
    338         m_tex.activeUnit->texture[TEXTURE_2D] = texture;
    339         break;
    340     case GL_TEXTURE_EXTERNAL_OES:
    341         m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
    342         break;
    343     }
    344 
    345     if (firstUse) {
    346         *firstUse = first;
    347     }
    348 
    349     return GL_NO_ERROR;
    350 }
    351 
    352 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
    353         GLenum target)
    354 {
    355     if (m_tex.numTextures == m_tex.allocTextures) {
    356         const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
    357 
    358         GLuint newAlloc;
    359         if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
    360             newAlloc = MAX(4, 2 * m_tex.allocTextures);
    361         } else {
    362             if (m_tex.allocTextures == MAX_TEXTURES) {
    363                 return NULL;
    364             }
    365             newAlloc = MAX_TEXTURES;
    366         }
    367 
    368         TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
    369                 newAlloc * sizeof(TextureRec));
    370         if (!newTextures) {
    371             return NULL;
    372         }
    373 
    374         m_tex.textures = newTextures;
    375         m_tex.allocTextures = newAlloc;
    376     }
    377 
    378     TextureRec* tex = m_tex.textures + m_tex.numTextures;
    379     TextureRec* prev = tex - 1;
    380     while (tex != m_tex.textures && id < prev->id) {
    381         *tex-- = *prev--;
    382     }
    383     tex->id = id;
    384     tex->target = target;
    385     tex->format = -1;
    386     m_tex.numTextures++;
    387 
    388     return tex;
    389 }
    390 
    391 void GLClientState::setBoundTextureInternalFormat(GLenum target, GLint internalformat) {
    392     GLuint texture = getBoundTexture(target);
    393     TextureRec* texrec = NULL;
    394     texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
    395                                   m_tex.numTextures,
    396                                   sizeof(TextureRec),
    397                                   compareTexId);
    398     if (!texrec) return;
    399     texrec->internalformat = internalformat;
    400 }
    401 
    402 void GLClientState::setBoundTextureFormat(GLenum target, GLenum format) {
    403     GLuint texture = getBoundTexture(target);
    404     TextureRec* texrec = NULL;
    405     texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
    406                                   m_tex.numTextures,
    407                                   sizeof(TextureRec),
    408                                   compareTexId);
    409     if (!texrec) return;
    410     texrec->format = format;
    411 }
    412 
    413 void GLClientState::setBoundTextureType(GLenum target, GLenum type) {
    414     GLuint texture = getBoundTexture(target);
    415     TextureRec* texrec = NULL;
    416     texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
    417                                   m_tex.numTextures,
    418                                   sizeof(TextureRec),
    419                                   compareTexId);
    420     if (!texrec) return;
    421     texrec->type = type;
    422 }
    423 
    424 GLuint GLClientState::getBoundTexture(GLenum target) const
    425 {
    426     switch (target) {
    427     case GL_TEXTURE_2D:
    428         return m_tex.activeUnit->texture[TEXTURE_2D];
    429     case GL_TEXTURE_EXTERNAL_OES:
    430         return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
    431     default:
    432         return 0;
    433     }
    434 }
    435 
    436 // BEGIN driver workarounds-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
    437 // (>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')>
    438 
    439 static bool unreliableInternalFormat(GLenum internalformat) {
    440     switch (internalformat) {
    441     case GL_LUMINANCE:
    442         return true;
    443     default:
    444         return false;
    445     }
    446 }
    447 
    448 void GLClientState::writeCopyTexImageState
    449     (GLenum target, GLint level, GLenum internalformat) {
    450     if (unreliableInternalFormat(internalformat)) {
    451         CubeMapDef entry;
    452         entry.id = getBoundTexture(GL_TEXTURE_2D);
    453         entry.target = target;
    454         entry.level = level;
    455         entry.internalformat = internalformat;
    456         m_cubeMapDefs.insert(entry);
    457     }
    458 }
    459 
    460 static GLenum identifyPositiveCubeMapComponent(GLenum target) {
    461     switch (target) {
    462     case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
    463         return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
    464     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
    465         return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
    466     case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
    467         return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
    468     default:
    469         return 0;
    470     }
    471 }
    472 
    473 GLenum GLClientState::copyTexImageNeededTarget
    474     (GLenum target, GLint level, GLenum internalformat) {
    475     if (unreliableInternalFormat(internalformat)) {
    476         GLenum positiveComponent =
    477             identifyPositiveCubeMapComponent(target);
    478         if (positiveComponent) {
    479             CubeMapDef query;
    480             query.id = getBoundTexture(GL_TEXTURE_2D);
    481             query.target = positiveComponent;
    482             query.level = level;
    483             query.internalformat = internalformat;
    484             if (m_cubeMapDefs.find(query) ==
    485                 m_cubeMapDefs.end()) {
    486                 return positiveComponent;
    487             }
    488         }
    489     }
    490     return 0;
    491 }
    492 
    493 GLenum GLClientState::copyTexImageLuminanceCubeMapAMDWorkaround
    494     (GLenum target, GLint level, GLenum internalformat) {
    495     writeCopyTexImageState(target, level, internalformat);
    496     return copyTexImageNeededTarget(target, level, internalformat);
    497 }
    498 
    499 // (>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')>
    500 // END driver workarounds-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-
    501 
    502 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
    503 {
    504     // Updating the textures array could be made more efficient when deleting
    505     // several textures:
    506     // - compacting the array could be done in a single pass once the deleted
    507     //   textures are marked, or
    508     // - could swap deleted textures to the end and re-sort.
    509     TextureRec* texrec;
    510     for (const GLuint* texture = textures; texture != textures + n; texture++) {
    511         texrec = (TextureRec*)bsearch(texture, m_tex.textures,
    512                 m_tex.numTextures, sizeof(TextureRec), compareTexId);
    513         if (texrec) {
    514             const TextureRec* end = m_tex.textures + m_tex.numTextures;
    515             memmove(texrec, texrec + 1,
    516                     (end - texrec - 1) * sizeof(TextureRec));
    517             m_tex.numTextures--;
    518 
    519             for (TextureUnit* unit = m_tex.unit;
    520                  unit != m_tex.unit + MAX_TEXTURE_UNITS;
    521                  unit++)
    522             {
    523                 if (unit->texture[TEXTURE_2D] == *texture) {
    524                     unit->texture[TEXTURE_2D] = 0;
    525                 } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) {
    526                     unit->texture[TEXTURE_EXTERNAL] = 0;
    527                 }
    528             }
    529         }
    530     }
    531 }
    532 
    533 // RBO//////////////////////////////////////////////////////////////////////////
    534 
    535 void GLClientState::addFreshRenderbuffer(GLuint name) {
    536     mRboState.rboData.push_back(RboProps());
    537     RboProps& props = mRboState.rboData.back();
    538     props.target = GL_RENDERBUFFER;
    539     props.name = name;
    540     props.format = GL_NONE;
    541     props.previouslyBound = false;
    542 }
    543 
    544 void GLClientState::addRenderbuffers(GLsizei n, GLuint* renderbuffers) {
    545     for (size_t i = 0; i < n; i++) {
    546         addFreshRenderbuffer(renderbuffers[i]);
    547     }
    548 }
    549 
    550 size_t GLClientState::getRboIndex(GLuint name) const {
    551     for (size_t i = 0; i < mRboState.rboData.size(); i++) {
    552         if (mRboState.rboData[i].name == name) {
    553             return i;
    554         }
    555     }
    556     return -1;
    557 }
    558 
    559 void GLClientState::removeRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
    560     size_t bound_rbo_idx = getRboIndex(boundRboProps_const().name);
    561 
    562     std::vector<GLuint> to_remove;
    563     for (size_t i = 0; i < n; i++) {
    564         if (renderbuffers[i] != 0) { // Never remove the zero rb.
    565             to_remove.push_back(getRboIndex(renderbuffers[i]));
    566         }
    567     }
    568 
    569     for (size_t i = 0; i < to_remove.size(); i++) {
    570         mRboState.rboData[to_remove[i]] = mRboState.rboData.back();
    571         mRboState.rboData.pop_back();
    572     }
    573 
    574     // If we just deleted the currently bound rb,
    575     // bind the zero rb
    576     if (getRboIndex(boundRboProps_const().name) != bound_rbo_idx) {
    577         bindRenderbuffer(GL_RENDERBUFFER, 0);
    578     }
    579 }
    580 
    581 bool GLClientState::usedRenderbufferName(GLuint name) const {
    582     for (size_t i = 0; i < mRboState.rboData.size(); i++) {
    583         if (mRboState.rboData[i].name == name) {
    584             return true;
    585         }
    586     }
    587     return false;
    588 }
    589 
    590 void GLClientState::setBoundRenderbufferIndex() {
    591     for (size_t i = 0; i < mRboState.rboData.size(); i++) {
    592         if (mRboState.rboData[i].name == mRboState.boundRenderbuffer) {
    593             mRboState.boundRenderbufferIndex = i;
    594             break;
    595         }
    596     }
    597 }
    598 
    599 RboProps& GLClientState::boundRboProps() {
    600     return mRboState.rboData[mRboState.boundRenderbufferIndex];
    601 }
    602 
    603 const RboProps& GLClientState::boundRboProps_const() const {
    604     return mRboState.rboData[mRboState.boundRenderbufferIndex];
    605 }
    606 
    607 void GLClientState::bindRenderbuffer(GLenum target, GLuint name) {
    608     // If unused, add it.
    609     if (!usedRenderbufferName(name)) {
    610         addFreshRenderbuffer(name);
    611     }
    612     mRboState.boundRenderbuffer = name;
    613     setBoundRenderbufferIndex();
    614     boundRboProps().target = target;
    615     boundRboProps().previouslyBound = true;
    616 }
    617 
    618 GLuint GLClientState::boundRenderbuffer() const {
    619     return boundRboProps_const().name;
    620 }
    621 
    622 void GLClientState::setBoundRenderbufferFormat(GLenum format) {
    623     boundRboProps().format = format;
    624 }
    625 
    626 // FBO//////////////////////////////////////////////////////////////////////////
    627 
    628 // Format querying
    629 
    630 GLenum GLClientState::queryRboFormat(GLuint rbo_name) const {
    631     return mRboState.rboData[getRboIndex(rbo_name)].format;
    632 }
    633 
    634 GLint GLClientState::queryTexInternalFormat(GLuint tex_name) const {
    635     TextureRec* texrec = NULL;
    636     texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures,
    637                                   m_tex.numTextures, sizeof(TextureRec), compareTexId);
    638     if (!texrec) return -1;
    639     return texrec->internalformat;
    640 }
    641 
    642 GLenum GLClientState::queryTexFormat(GLuint tex_name) const {
    643     TextureRec* texrec = NULL;
    644     texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures,
    645                                   m_tex.numTextures, sizeof(TextureRec), compareTexId);
    646     if (!texrec) return -1;
    647     return texrec->format;
    648 }
    649 
    650 GLenum GLClientState::queryTexType(GLuint tex_name) const {
    651     TextureRec* texrec = NULL;
    652     texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures,
    653                                   m_tex.numTextures, sizeof(TextureRec), compareTexId);
    654     if (!texrec) return -1;
    655     return texrec->type;
    656 }
    657 
    658 void GLClientState::getBoundFramebufferFormat(
    659         GLenum attachment, FboFormatInfo* res_info) const {
    660     const FboProps& props = boundFboProps_const();
    661 
    662     res_info->type = FBO_ATTACHMENT_NONE;
    663     res_info->rb_format = GL_NONE;
    664     res_info->tex_internalformat = -1;
    665     res_info->tex_format = GL_NONE;
    666     res_info->tex_type = GL_NONE;
    667 
    668     switch (attachment) {
    669     case GL_COLOR_ATTACHMENT0:
    670         if (props.colorAttachment0_hasRbo) {
    671             res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
    672             res_info->rb_format = queryRboFormat(props.colorAttachment0_rbo);
    673         } else if (props.colorAttachment0_hasTexObj) {
    674             res_info->type = FBO_ATTACHMENT_TEXTURE;
    675             res_info->tex_internalformat = queryTexInternalFormat(props.colorAttachment0_texture);
    676             res_info->tex_format = queryTexFormat(props.colorAttachment0_texture);
    677             res_info->tex_type = queryTexType(props.colorAttachment0_texture);
    678         } else {
    679             res_info->type = FBO_ATTACHMENT_NONE;
    680         }
    681         break;
    682     case GL_DEPTH_ATTACHMENT:
    683         if (props.depthAttachment_hasRbo) {
    684             res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
    685             res_info->rb_format = queryRboFormat(props.depthAttachment_rbo);
    686         } else if (props.depthAttachment_hasTexObj) {
    687             res_info->type = FBO_ATTACHMENT_TEXTURE;
    688             res_info->tex_internalformat = queryTexInternalFormat(props.depthAttachment_texture);
    689             res_info->tex_format = queryTexFormat(props.depthAttachment_texture);
    690             res_info->tex_type = queryTexType(props.depthAttachment_texture);
    691         } else {
    692             res_info->type = FBO_ATTACHMENT_NONE;
    693         }
    694         break;
    695     case GL_STENCIL_ATTACHMENT:
    696         if (props.stencilAttachment_hasRbo) {
    697             res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
    698             res_info->rb_format = queryRboFormat(props.stencilAttachment_rbo);
    699         } else if (props.stencilAttachment_hasTexObj) {
    700             res_info->type = FBO_ATTACHMENT_TEXTURE;
    701             res_info->tex_internalformat = queryTexInternalFormat(props.stencilAttachment_texture);
    702             res_info->tex_format = queryTexFormat(props.stencilAttachment_texture);
    703             res_info->tex_type = queryTexType(props.stencilAttachment_texture);
    704         } else {
    705             res_info->type = FBO_ATTACHMENT_NONE;
    706         }
    707         break;
    708     default:
    709         res_info->type = FBO_ATTACHMENT_NONE;
    710         break;
    711     }
    712 }
    713 
    714 void GLClientState::addFreshFramebuffer(GLuint name) {
    715     mFboState.fboData.push_back(FboProps());
    716     FboProps& props = mFboState.fboData.back();
    717     props.target = GL_FRAMEBUFFER;
    718     props.name = name;
    719     props.previouslyBound = false;
    720 
    721     props.colorAttachment0_texture = 0;
    722     props.depthAttachment_texture = 0;
    723     props.stencilAttachment_texture = 0;
    724 
    725     props.colorAttachment0_hasTexObj = false;
    726     props.depthAttachment_hasTexObj = false;
    727     props.stencilAttachment_hasTexObj = false;
    728 
    729     props.colorAttachment0_rbo = 0;
    730     props.depthAttachment_rbo = 0;
    731     props.stencilAttachment_rbo = 0;
    732 
    733     props.colorAttachment0_hasRbo = false;
    734     props.depthAttachment_hasRbo = false;
    735     props.stencilAttachment_hasRbo = false;
    736 }
    737 
    738 void GLClientState::addFramebuffers(GLsizei n, GLuint* framebuffers) {
    739     for (size_t i = 0; i < n; i++) {
    740         addFreshFramebuffer(framebuffers[i]);
    741     }
    742 }
    743 
    744 size_t GLClientState::getFboIndex(GLuint name) const {
    745     for (size_t i = 0; i < mFboState.fboData.size(); i++) {
    746         if (mFboState.fboData[i].name == name) {
    747             return i;
    748         }
    749     }
    750     return -1;
    751 }
    752 
    753 
    754 void GLClientState::removeFramebuffers(GLsizei n, const GLuint* framebuffers) {
    755     size_t bound_fbo_idx = getFboIndex(boundFboProps_const().name);
    756 
    757     std::vector<GLuint> to_remove;
    758     for (size_t i = 0; i < n; i++) {
    759         if (framebuffers[i] != 0) { // Never remove the zero fb.
    760             to_remove.push_back(getFboIndex(framebuffers[i]));
    761         }
    762     }
    763 
    764     for (size_t i = 0; i < to_remove.size(); i++) {
    765         mFboState.fboData[to_remove[i]] = mFboState.fboData.back();
    766         mFboState.fboData.pop_back();
    767     }
    768 
    769     // If we just deleted the currently bound fb<
    770     // bind the zero fb
    771     if (getFboIndex(boundFboProps_const().name) != bound_fbo_idx) {
    772         bindFramebuffer(GL_FRAMEBUFFER, 0);
    773     }
    774 }
    775 
    776 bool GLClientState::usedFramebufferName(GLuint name) const {
    777     for (size_t i = 0; i < mFboState.fboData.size(); i++) {
    778         if (mFboState.fboData[i].name == name) {
    779             return true;
    780         }
    781     }
    782     return false;
    783 }
    784 
    785 void GLClientState::setBoundFramebufferIndex() {
    786     for (size_t i = 0; i < mFboState.fboData.size(); i++) {
    787         if (mFboState.fboData[i].name == mFboState.boundFramebuffer) {
    788             mFboState.boundFramebufferIndex = i;
    789             break;
    790         }
    791     }
    792 }
    793 
    794 FboProps& GLClientState::boundFboProps() {
    795     return mFboState.fboData[mFboState.boundFramebufferIndex];
    796 }
    797 
    798 const FboProps& GLClientState::boundFboProps_const() const {
    799     return mFboState.fboData[mFboState.boundFramebufferIndex];
    800 }
    801 
    802 void GLClientState::bindFramebuffer(GLenum target, GLuint name) {
    803     // If unused, add it.
    804     if (!usedFramebufferName(name)) {
    805         addFreshFramebuffer(name);
    806     }
    807     mFboState.boundFramebuffer = name;
    808     setBoundFramebufferIndex();
    809     boundFboProps().target = target;
    810     boundFboProps().previouslyBound = true;
    811 }
    812 
    813 void GLClientState::setCheckFramebufferStatus(GLenum status) {
    814     mFboState.fboCheckStatus = status;
    815 }
    816 
    817 GLenum GLClientState::getCheckFramebufferStatus() const {
    818     return mFboState.fboCheckStatus;
    819 }
    820 
    821 GLuint GLClientState::boundFramebuffer() const {
    822     return boundFboProps_const().name;
    823 }
    824 
    825 // Texture objects for FBOs/////////////////////////////////////////////////////
    826 
    827 void GLClientState::attachTextureObject(GLenum attachment, GLuint texture) {
    828     switch (attachment) {
    829     case GL_COLOR_ATTACHMENT0:
    830         boundFboProps().colorAttachment0_texture = texture;
    831         boundFboProps().colorAttachment0_hasTexObj = true;
    832         break;
    833     case GL_DEPTH_ATTACHMENT:
    834         boundFboProps().depthAttachment_texture = texture;
    835         boundFboProps().depthAttachment_hasTexObj = true;
    836         break;
    837     case GL_STENCIL_ATTACHMENT:
    838         boundFboProps().stencilAttachment_texture = texture;
    839         boundFboProps().stencilAttachment_hasTexObj = true;
    840         break;
    841     default:
    842         break;
    843     }
    844 }
    845 
    846 GLuint GLClientState::getFboAttachmentTextureId(GLenum attachment) const {
    847     GLuint res;
    848     switch (attachment) {
    849     case GL_COLOR_ATTACHMENT0:
    850         res = boundFboProps_const().colorAttachment0_texture;
    851         break;
    852     case GL_DEPTH_ATTACHMENT:
    853         res = boundFboProps_const().depthAttachment_texture;
    854         break;
    855     case GL_STENCIL_ATTACHMENT:
    856         res = boundFboProps_const().stencilAttachment_texture;
    857         break;
    858     default:
    859         res = 0; // conservative validation for now
    860     }
    861     return res;
    862 }
    863 
    864 // RBOs for FBOs////////////////////////////////////////////////////////////////
    865 
    866 void GLClientState::attachRbo(GLenum attachment, GLuint renderbuffer) {
    867     switch (attachment) {
    868     case GL_COLOR_ATTACHMENT0:
    869         boundFboProps().colorAttachment0_rbo = renderbuffer;
    870         boundFboProps().colorAttachment0_hasRbo = true;
    871         break;
    872     case GL_DEPTH_ATTACHMENT:
    873         boundFboProps().depthAttachment_rbo = renderbuffer;
    874         boundFboProps().depthAttachment_hasRbo = true;
    875         break;
    876     case GL_STENCIL_ATTACHMENT:
    877         boundFboProps().stencilAttachment_rbo = renderbuffer;
    878         boundFboProps().stencilAttachment_hasRbo = true;
    879         break;
    880     default:
    881         break;
    882     }
    883 }
    884 
    885 GLuint GLClientState::getFboAttachmentRboId(GLenum attachment) const {
    886     GLuint res;
    887     switch (attachment) {
    888     case GL_COLOR_ATTACHMENT0:
    889         res = boundFboProps_const().colorAttachment0_rbo;
    890         break;
    891     case GL_DEPTH_ATTACHMENT:
    892         res = boundFboProps_const().depthAttachment_rbo;
    893         break;
    894     case GL_STENCIL_ATTACHMENT:
    895         res = boundFboProps_const().stencilAttachment_rbo;
    896         break;
    897     default:
    898         res = 0; // conservative validation for now
    899     }
    900     return res;
    901 }
    902 
    903 bool GLClientState::attachmentHasObject(GLenum attachment) const {
    904     bool res;
    905     switch (attachment) {
    906     case GL_COLOR_ATTACHMENT0:
    907         res = (boundFboProps_const().colorAttachment0_hasTexObj) ||
    908               (boundFboProps_const().colorAttachment0_hasRbo);
    909         break;
    910     case GL_DEPTH_ATTACHMENT:
    911         res = (boundFboProps_const().depthAttachment_hasTexObj) ||
    912               (boundFboProps_const().depthAttachment_hasRbo);
    913         break;
    914     case GL_STENCIL_ATTACHMENT:
    915         res = (boundFboProps_const().stencilAttachment_hasTexObj) ||
    916               (boundFboProps_const().stencilAttachment_hasRbo);
    917         break;
    918     default:
    919         res = true; // liberal validation for now
    920     }
    921     return res;
    922 }
    923 
    924 void GLClientState::fromMakeCurrent() {
    925     FboProps& default_fb_props = mFboState.fboData[getFboIndex(0)];
    926     default_fb_props.colorAttachment0_hasRbo = true;
    927     default_fb_props.depthAttachment_hasRbo = true;
    928     default_fb_props.stencilAttachment_hasRbo = true;
    929 }
    930