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