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