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