GLClientState.cpp revision 0d75675ad262120982918f806102ddfceec23a10
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 28GLClientState::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 70GLClientState::~GLClientState() 71{ 72 delete m_states; 73} 74 75void 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 85void 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 = size ? (glSizeof(type) * size) : 0; 96 m_states[location].normalized = normalized; 97} 98 99void GLClientState::setBufferObject(int location, GLuint id) 100{ 101 if (!validLocation(location)) { 102 return; 103 } 104 105 m_states[location].bufferObject = id; 106} 107 108const GLClientState::VertexAttribState * GLClientState::getState(int location) 109{ 110 if (!validLocation(location)) { 111 return NULL; 112 } 113 return & m_states[location]; 114} 115 116const 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 130int 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 162void 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 199int 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 226size_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 246GLenum 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 256GLenum GLClientState::getActiveTextureUnit() const 257{ 258 return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]); 259} 260 261void 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 273void 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 285GLenum 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 297int 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 304GLenum 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 341GLClientState::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 379GLuint 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 391void 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