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 
     23 #ifndef MAX
     24 #define MAX(a, b) ((a) < (b) ? (b) : (a))
     25 #endif
     26 
     27 GLClientState::GLClientState(int nLocations)
     28 {
     29     if (nLocations < LAST_LOCATION) {
     30         nLocations = LAST_LOCATION;
     31     }
     32     m_nLocations = nLocations;
     33     m_states = new VertexAttribState[m_nLocations];
     34     for (int i = 0; i < m_nLocations; i++) {
     35         m_states[i].enabled = 0;
     36         m_states[i].enableDirty = false;
     37     }
     38     m_currentArrayVbo = 0;
     39     m_currentIndexVbo = 0;
     40     // init gl constans;
     41     m_states[VERTEX_LOCATION].glConst = GL_VERTEX_ARRAY;
     42     m_states[NORMAL_LOCATION].glConst = GL_NORMAL_ARRAY;
     43     m_states[COLOR_LOCATION].glConst = GL_COLOR_ARRAY;
     44     m_states[POINTSIZE_LOCATION].glConst = GL_POINT_SIZE_ARRAY_OES;
     45     m_states[TEXCOORD0_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     46     m_states[TEXCOORD1_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     47     m_states[TEXCOORD2_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     48     m_states[TEXCOORD3_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     49     m_states[TEXCOORD4_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     50     m_states[TEXCOORD5_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     51     m_states[TEXCOORD6_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     52     m_states[TEXCOORD7_LOCATION].glConst = GL_TEXTURE_COORD_ARRAY;
     53     m_states[MATRIXINDEX_LOCATION].glConst = GL_MATRIX_INDEX_ARRAY_OES;
     54     m_states[WEIGHT_LOCATION].glConst = GL_WEIGHT_ARRAY_OES;
     55     m_activeTexture = 0;
     56     m_currentProgram = 0;
     57 
     58     m_pixelStore.unpack_alignment = 4;
     59     m_pixelStore.pack_alignment = 4;
     60 
     61     memset(m_tex.unit, 0, sizeof(m_tex.unit));
     62     m_tex.activeUnit = &m_tex.unit[0];
     63     m_tex.textures = NULL;
     64     m_tex.numTextures = 0;
     65     m_tex.allocTextures = 0;
     66 }
     67 
     68 GLClientState::~GLClientState()
     69 {
     70     delete m_states;
     71 }
     72 
     73 void GLClientState::enable(int location, int state)
     74 {
     75     if (!validLocation(location)) {
     76         return;
     77     }
     78 
     79     m_states[location].enableDirty |= (state != m_states[location].enabled);
     80     m_states[location].enabled = state;
     81 }
     82 
     83 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data)
     84 {
     85     if (!validLocation(location)) {
     86         return;
     87     }
     88     m_states[location].size = size;
     89     m_states[location].type = type;
     90     m_states[location].stride = stride;
     91     m_states[location].data = (void*)data;
     92     m_states[location].bufferObject = m_currentArrayVbo;
     93     m_states[location].elementSize = glSizeof(type) * size;
     94     m_states[location].normalized = normalized;
     95 }
     96 
     97 void GLClientState::setBufferObject(int location, GLuint id)
     98 {
     99     if (!validLocation(location)) {
    100         return;
    101     }
    102 
    103     m_states[location].bufferObject = id;
    104 }
    105 
    106 const GLClientState::VertexAttribState * GLClientState::getState(int location)
    107 {
    108     if (!validLocation(location)) {
    109         return NULL;
    110     }
    111     return & m_states[location];
    112 }
    113 
    114 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged)
    115 {
    116     if (!validLocation(location)) {
    117         return NULL;
    118     }
    119 
    120     if (enableChanged) {
    121         *enableChanged = m_states[location].enableDirty;
    122     }
    123 
    124     m_states[location].enableDirty = false;
    125     return & m_states[location];
    126 }
    127 
    128 int GLClientState::getLocation(GLenum loc)
    129 {
    130     int retval;
    131 
    132     switch(loc) {
    133     case GL_VERTEX_ARRAY:
    134         retval = int(VERTEX_LOCATION);
    135         break;
    136     case GL_NORMAL_ARRAY:
    137         retval = int(NORMAL_LOCATION);
    138         break;
    139     case GL_COLOR_ARRAY:
    140         retval = int(COLOR_LOCATION);
    141         break;
    142     case GL_POINT_SIZE_ARRAY_OES:
    143         retval = int(POINTSIZE_LOCATION);
    144         break;
    145     case GL_TEXTURE_COORD_ARRAY:
    146         retval = int (TEXCOORD0_LOCATION + m_activeTexture);
    147         break;
    148     case GL_MATRIX_INDEX_ARRAY_OES:
    149         retval = int (MATRIXINDEX_LOCATION);
    150         break;
    151     case GL_WEIGHT_ARRAY_OES:
    152         retval = int (WEIGHT_LOCATION);
    153         break;
    154     default:
    155         retval = loc;
    156     }
    157     return retval;
    158 }
    159 
    160 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params)
    161 {
    162     const GLClientState::VertexAttribState *state = NULL;
    163     switch (pname) {
    164     case GL_VERTEX_ARRAY_POINTER: {
    165         state = getState(GLClientState::VERTEX_LOCATION);
    166         break;
    167         }
    168     case GL_NORMAL_ARRAY_POINTER: {
    169         state = getState(GLClientState::NORMAL_LOCATION);
    170         break;
    171         }
    172     case GL_COLOR_ARRAY_POINTER: {
    173         state = getState(GLClientState::COLOR_LOCATION);
    174         break;
    175         }
    176     case GL_TEXTURE_COORD_ARRAY_POINTER: {
    177         state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION);
    178         break;
    179         }
    180     case GL_POINT_SIZE_ARRAY_POINTER_OES: {
    181         state = getState(GLClientState::POINTSIZE_LOCATION);
    182         break;
    183         }
    184     case GL_MATRIX_INDEX_ARRAY_POINTER_OES: {
    185         state = getState(GLClientState::MATRIXINDEX_LOCATION);
    186         break;
    187         }
    188     case GL_WEIGHT_ARRAY_POINTER_OES: {
    189         state = getState(GLClientState::WEIGHT_LOCATION);
    190         break;
    191         }
    192     }
    193     if (state && params)
    194         *params = state->data;
    195 }
    196 
    197 int GLClientState::setPixelStore(GLenum param, GLint value)
    198 {
    199     int retval = 0;
    200     switch(param) {
    201     case GL_UNPACK_ALIGNMENT:
    202         if (value == 1 || value == 2 || value == 4 || value == 8) {
    203             m_pixelStore.unpack_alignment = value;
    204         } else {
    205             retval =  GL_INVALID_VALUE;
    206         }
    207         break;
    208     case GL_PACK_ALIGNMENT:
    209         if (value == 1 || value == 2 || value == 4 || value == 8) {
    210             m_pixelStore.pack_alignment = value;
    211         } else {
    212             retval =  GL_INVALID_VALUE;
    213         }
    214         break;
    215         default:
    216             retval = GL_INVALID_ENUM;
    217     }
    218     return retval;
    219 }
    220 
    221 
    222 
    223 
    224 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const
    225 {
    226     int pixelsize = glUtilsPixelBitSize(format, type) >> 3;
    227 
    228     int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment;
    229 
    230     if (pixelsize == 0 ) {
    231         ERR("unknown pixel size: width: %d height: %d format: %d type: %d pack: %d align: %d\n",
    232              width, height, format, type, pack, alignment);
    233     }
    234     size_t linesize = pixelsize * width;
    235     size_t aligned_linesize = int(linesize / alignment) * alignment;
    236     if (aligned_linesize < linesize) {
    237         aligned_linesize += alignment;
    238     }
    239     return aligned_linesize * height;
    240 }
    241 
    242 GLenum GLClientState::setActiveTextureUnit(GLenum texture)
    243 {
    244     GLuint unit = texture - GL_TEXTURE0;
    245     if (unit >= MAX_TEXTURE_UNITS) {
    246         return GL_INVALID_OPERATION;
    247     }
    248     m_tex.activeUnit = &m_tex.unit[unit];
    249     return GL_NO_ERROR;
    250 }
    251 
    252 GLenum GLClientState::getActiveTextureUnit() const
    253 {
    254     return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
    255 }
    256 
    257 void GLClientState::enableTextureTarget(GLenum target)
    258 {
    259     switch (target) {
    260     case GL_TEXTURE_2D:
    261         m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
    262         break;
    263     case GL_TEXTURE_EXTERNAL_OES:
    264         m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
    265         break;
    266     }
    267 }
    268 
    269 void GLClientState::disableTextureTarget(GLenum target)
    270 {
    271     switch (target) {
    272     case GL_TEXTURE_2D:
    273         m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
    274         break;
    275     case GL_TEXTURE_EXTERNAL_OES:
    276         m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
    277         break;
    278     }
    279 }
    280 
    281 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
    282 {
    283     unsigned int enables = m_tex.activeUnit->enables;
    284     if (enables & (1u << TEXTURE_EXTERNAL)) {
    285         return GL_TEXTURE_EXTERNAL_OES;
    286     } else if (enables & (1u << TEXTURE_2D)) {
    287         return GL_TEXTURE_2D;
    288     } else {
    289         return allDisabled;
    290     }
    291 }
    292 
    293 int GLClientState::compareTexId(const void* pid, const void* prec)
    294 {
    295     const GLuint* id = (const GLuint*)pid;
    296     const TextureRec* rec = (const TextureRec*)prec;
    297     return (GLint)(*id) - (GLint)rec->id;
    298 }
    299 
    300 GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
    301         GLboolean* firstUse)
    302 {
    303     GLboolean first = GL_FALSE;
    304     TextureRec* texrec = NULL;
    305     if (texture != 0) {
    306         if (m_tex.textures) {
    307             texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
    308                     m_tex.numTextures, sizeof(TextureRec), compareTexId);
    309         }
    310         if (!texrec) {
    311             if (!(texrec = addTextureRec(texture, target))) {
    312                 return GL_OUT_OF_MEMORY;
    313             }
    314             first = GL_TRUE;
    315         }
    316         if (target != texrec->target) {
    317             return GL_INVALID_OPERATION;
    318         }
    319     }
    320 
    321     switch (target) {
    322     case GL_TEXTURE_2D:
    323         m_tex.activeUnit->texture[TEXTURE_2D] = texture;
    324         break;
    325     case GL_TEXTURE_EXTERNAL_OES:
    326         m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
    327         break;
    328     }
    329 
    330     if (firstUse) {
    331         *firstUse = first;
    332     }
    333 
    334     return GL_NO_ERROR;
    335 }
    336 
    337 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
    338         GLenum target)
    339 {
    340     if (m_tex.numTextures == m_tex.allocTextures) {
    341         const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
    342 
    343         GLuint newAlloc;
    344         if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
    345             newAlloc = MAX(4, 2 * m_tex.allocTextures);
    346         } else {
    347             if (m_tex.allocTextures == MAX_TEXTURES) {
    348                 return NULL;
    349             }
    350             newAlloc = MAX_TEXTURES;
    351         }
    352 
    353         TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
    354                 newAlloc * sizeof(TextureRec));
    355         if (!newTextures) {
    356             return NULL;
    357         }
    358 
    359         m_tex.textures = newTextures;
    360         m_tex.allocTextures = newAlloc;
    361     }
    362 
    363     TextureRec* tex = m_tex.textures + m_tex.numTextures;
    364     TextureRec* prev = tex - 1;
    365     while (tex != m_tex.textures && id < prev->id) {
    366         *tex-- = *prev--;
    367     }
    368     tex->id = id;
    369     tex->target = target;
    370     m_tex.numTextures++;
    371 
    372     return tex;
    373 }
    374 
    375 GLuint GLClientState::getBoundTexture(GLenum target) const
    376 {
    377     switch (target) {
    378     case GL_TEXTURE_2D:
    379         return m_tex.activeUnit->texture[TEXTURE_2D];
    380     case GL_TEXTURE_EXTERNAL_OES:
    381         return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
    382     default:
    383         return 0;
    384     }
    385 }
    386 
    387 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
    388 {
    389     // Updating the textures array could be made more efficient when deleting
    390     // several textures:
    391     // - compacting the array could be done in a single pass once the deleted
    392     //   textures are marked, or
    393     // - could swap deleted textures to the end and re-sort.
    394     TextureRec* texrec;
    395     for (const GLuint* texture = textures; texture != textures + n; texture++) {
    396         texrec = (TextureRec*)bsearch(texture, m_tex.textures,
    397                 m_tex.numTextures, sizeof(TextureRec), compareTexId);
    398         if (texrec) {
    399             const TextureRec* end = m_tex.textures + m_tex.numTextures;
    400             memmove(texrec, texrec + 1,
    401                     (end - texrec - 1) * sizeof(TextureRec));
    402             m_tex.numTextures--;
    403 
    404             for (TextureUnit* unit = m_tex.unit;
    405                  unit != m_tex.unit + MAX_TEXTURE_UNITS;
    406                  unit++)
    407             {
    408                 if (unit->texture[TEXTURE_2D] == *texture) {
    409                     unit->texture[TEXTURE_2D] = 0;
    410                 } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) {
    411                     unit->texture[TEXTURE_EXTERNAL] = 0;
    412                 }
    413             }
    414         }
    415     }
    416 }
    417