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 mRboState.boundRenderbuffer = 0; 70 mRboState.boundRenderbufferIndex = 0; 71 addFreshRenderbuffer(0); 72 73 mFboState.boundFramebuffer = 0; 74 mFboState.boundFramebufferIndex = 0; 75 mFboState.fboCheckStatus = GL_NONE; 76 addFreshFramebuffer(0); 77 78 m_maxVertexAttribsDirty = true; 79 } 80 81 GLClientState::~GLClientState() 82 { 83 delete m_states; 84 } 85 86 void GLClientState::enable(int location, int state) 87 { 88 if (!validLocation(location)) { 89 return; 90 } 91 92 m_states[location].enableDirty |= (state != m_states[location].enabled); 93 m_states[location].enabled = state; 94 } 95 96 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data) 97 { 98 if (!validLocation(location)) { 99 return; 100 } 101 m_states[location].size = size; 102 m_states[location].type = type; 103 m_states[location].stride = stride; 104 m_states[location].data = (void*)data; 105 m_states[location].bufferObject = m_currentArrayVbo; 106 m_states[location].elementSize = size ? (glSizeof(type) * size) : 0; 107 m_states[location].normalized = normalized; 108 } 109 110 void GLClientState::setBufferObject(int location, GLuint id) 111 { 112 if (!validLocation(location)) { 113 return; 114 } 115 116 m_states[location].bufferObject = id; 117 } 118 119 const GLClientState::VertexAttribState * GLClientState::getState(int location) 120 { 121 if (!validLocation(location)) { 122 return NULL; 123 } 124 return & m_states[location]; 125 } 126 127 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged) 128 { 129 if (!validLocation(location)) { 130 return NULL; 131 } 132 133 if (enableChanged) { 134 *enableChanged = m_states[location].enableDirty; 135 } 136 137 m_states[location].enableDirty = false; 138 return & m_states[location]; 139 } 140 141 int GLClientState::getLocation(GLenum loc) 142 { 143 int retval; 144 145 switch(loc) { 146 case GL_VERTEX_ARRAY: 147 retval = int(VERTEX_LOCATION); 148 break; 149 case GL_NORMAL_ARRAY: 150 retval = int(NORMAL_LOCATION); 151 break; 152 case GL_COLOR_ARRAY: 153 retval = int(COLOR_LOCATION); 154 break; 155 case GL_POINT_SIZE_ARRAY_OES: 156 retval = int(POINTSIZE_LOCATION); 157 break; 158 case GL_TEXTURE_COORD_ARRAY: 159 retval = int (TEXCOORD0_LOCATION + m_activeTexture); 160 break; 161 case GL_MATRIX_INDEX_ARRAY_OES: 162 retval = int (MATRIXINDEX_LOCATION); 163 break; 164 case GL_WEIGHT_ARRAY_OES: 165 retval = int (WEIGHT_LOCATION); 166 break; 167 default: 168 retval = loc; 169 } 170 return retval; 171 } 172 173 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params) 174 { 175 const GLClientState::VertexAttribState *state = NULL; 176 switch (pname) { 177 case GL_VERTEX_ARRAY_POINTER: { 178 state = getState(GLClientState::VERTEX_LOCATION); 179 break; 180 } 181 case GL_NORMAL_ARRAY_POINTER: { 182 state = getState(GLClientState::NORMAL_LOCATION); 183 break; 184 } 185 case GL_COLOR_ARRAY_POINTER: { 186 state = getState(GLClientState::COLOR_LOCATION); 187 break; 188 } 189 case GL_TEXTURE_COORD_ARRAY_POINTER: { 190 state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION); 191 break; 192 } 193 case GL_POINT_SIZE_ARRAY_POINTER_OES: { 194 state = getState(GLClientState::POINTSIZE_LOCATION); 195 break; 196 } 197 case GL_MATRIX_INDEX_ARRAY_POINTER_OES: { 198 state = getState(GLClientState::MATRIXINDEX_LOCATION); 199 break; 200 } 201 case GL_WEIGHT_ARRAY_POINTER_OES: { 202 state = getState(GLClientState::WEIGHT_LOCATION); 203 break; 204 } 205 } 206 if (state && params) 207 *params = state->data; 208 } 209 210 int GLClientState::setPixelStore(GLenum param, GLint value) 211 { 212 int retval = 0; 213 switch(param) { 214 case GL_UNPACK_ALIGNMENT: 215 if (value == 1 || value == 2 || value == 4 || value == 8) { 216 m_pixelStore.unpack_alignment = value; 217 } else { 218 retval = GL_INVALID_VALUE; 219 } 220 break; 221 case GL_PACK_ALIGNMENT: 222 if (value == 1 || value == 2 || value == 4 || value == 8) { 223 m_pixelStore.pack_alignment = value; 224 } else { 225 retval = GL_INVALID_VALUE; 226 } 227 break; 228 default: 229 retval = GL_INVALID_ENUM; 230 } 231 return retval; 232 } 233 234 235 236 237 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const 238 { 239 if (width <= 0 || height <= 0) return 0; 240 241 int pixelsize = glUtilsPixelBitSize(format, type) >> 3; 242 243 int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment; 244 245 if (pixelsize == 0 ) { 246 ERR("unknown pixel size: width: %d height: %d format: %d type: %d pack: %d align: %d\n", 247 width, height, format, type, pack, alignment); 248 } 249 size_t linesize = pixelsize * width; 250 size_t aligned_linesize = int(linesize / alignment) * alignment; 251 if (aligned_linesize < linesize) { 252 aligned_linesize += alignment; 253 } 254 return aligned_linesize * height; 255 } 256 257 GLenum GLClientState::setActiveTextureUnit(GLenum texture) 258 { 259 GLuint unit = texture - GL_TEXTURE0; 260 if (unit >= MAX_TEXTURE_UNITS) { 261 return GL_INVALID_ENUM; 262 } 263 m_tex.activeUnit = &m_tex.unit[unit]; 264 return GL_NO_ERROR; 265 } 266 267 GLenum GLClientState::getActiveTextureUnit() const 268 { 269 return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]); 270 } 271 272 void GLClientState::enableTextureTarget(GLenum target) 273 { 274 switch (target) { 275 case GL_TEXTURE_2D: 276 m_tex.activeUnit->enables |= (1u << TEXTURE_2D); 277 break; 278 case GL_TEXTURE_EXTERNAL_OES: 279 m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL); 280 break; 281 } 282 } 283 284 void GLClientState::disableTextureTarget(GLenum target) 285 { 286 switch (target) { 287 case GL_TEXTURE_2D: 288 m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D); 289 break; 290 case GL_TEXTURE_EXTERNAL_OES: 291 m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL); 292 break; 293 } 294 } 295 296 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const 297 { 298 unsigned int enables = m_tex.activeUnit->enables; 299 if (enables & (1u << TEXTURE_EXTERNAL)) { 300 return GL_TEXTURE_EXTERNAL_OES; 301 } else if (enables & (1u << TEXTURE_2D)) { 302 return GL_TEXTURE_2D; 303 } else { 304 return allDisabled; 305 } 306 } 307 308 int GLClientState::compareTexId(const void* pid, const void* prec) 309 { 310 const GLuint* id = (const GLuint*)pid; 311 const TextureRec* rec = (const TextureRec*)prec; 312 return (GLint)(*id) - (GLint)rec->id; 313 } 314 315 GLenum GLClientState::bindTexture(GLenum target, GLuint texture, 316 GLboolean* firstUse) 317 { 318 GLboolean first = GL_FALSE; 319 TextureRec* texrec = NULL; 320 if (texture != 0) { 321 if (m_tex.textures) { 322 texrec = (TextureRec*)bsearch(&texture, m_tex.textures, 323 m_tex.numTextures, sizeof(TextureRec), compareTexId); 324 } 325 if (!texrec) { 326 if (!(texrec = addTextureRec(texture, target))) { 327 return GL_OUT_OF_MEMORY; 328 } 329 first = GL_TRUE; 330 } 331 if (target != texrec->target) { 332 return GL_INVALID_OPERATION; 333 } 334 } 335 336 switch (target) { 337 case GL_TEXTURE_2D: 338 m_tex.activeUnit->texture[TEXTURE_2D] = texture; 339 break; 340 case GL_TEXTURE_EXTERNAL_OES: 341 m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture; 342 break; 343 } 344 345 if (firstUse) { 346 *firstUse = first; 347 } 348 349 return GL_NO_ERROR; 350 } 351 352 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id, 353 GLenum target) 354 { 355 if (m_tex.numTextures == m_tex.allocTextures) { 356 const GLuint MAX_TEXTURES = 0xFFFFFFFFu; 357 358 GLuint newAlloc; 359 if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) { 360 newAlloc = MAX(4, 2 * m_tex.allocTextures); 361 } else { 362 if (m_tex.allocTextures == MAX_TEXTURES) { 363 return NULL; 364 } 365 newAlloc = MAX_TEXTURES; 366 } 367 368 TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures, 369 newAlloc * sizeof(TextureRec)); 370 if (!newTextures) { 371 return NULL; 372 } 373 374 m_tex.textures = newTextures; 375 m_tex.allocTextures = newAlloc; 376 } 377 378 TextureRec* tex = m_tex.textures + m_tex.numTextures; 379 TextureRec* prev = tex - 1; 380 while (tex != m_tex.textures && id < prev->id) { 381 *tex-- = *prev--; 382 } 383 tex->id = id; 384 tex->target = target; 385 tex->format = -1; 386 m_tex.numTextures++; 387 388 return tex; 389 } 390 391 void GLClientState::setBoundTextureInternalFormat(GLenum target, GLint internalformat) { 392 GLuint texture = getBoundTexture(target); 393 TextureRec* texrec = NULL; 394 texrec = (TextureRec*)bsearch(&texture, m_tex.textures, 395 m_tex.numTextures, 396 sizeof(TextureRec), 397 compareTexId); 398 if (!texrec) return; 399 texrec->internalformat = internalformat; 400 } 401 402 void GLClientState::setBoundTextureFormat(GLenum target, GLenum format) { 403 GLuint texture = getBoundTexture(target); 404 TextureRec* texrec = NULL; 405 texrec = (TextureRec*)bsearch(&texture, m_tex.textures, 406 m_tex.numTextures, 407 sizeof(TextureRec), 408 compareTexId); 409 if (!texrec) return; 410 texrec->format = format; 411 } 412 413 void GLClientState::setBoundTextureType(GLenum target, GLenum type) { 414 GLuint texture = getBoundTexture(target); 415 TextureRec* texrec = NULL; 416 texrec = (TextureRec*)bsearch(&texture, m_tex.textures, 417 m_tex.numTextures, 418 sizeof(TextureRec), 419 compareTexId); 420 if (!texrec) return; 421 texrec->type = type; 422 } 423 424 GLuint GLClientState::getBoundTexture(GLenum target) const 425 { 426 switch (target) { 427 case GL_TEXTURE_2D: 428 return m_tex.activeUnit->texture[TEXTURE_2D]; 429 case GL_TEXTURE_EXTERNAL_OES: 430 return m_tex.activeUnit->texture[TEXTURE_EXTERNAL]; 431 default: 432 return 0; 433 } 434 } 435 436 // BEGIN driver workarounds-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- 437 // (>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')> 438 439 static bool unreliableInternalFormat(GLenum internalformat) { 440 switch (internalformat) { 441 case GL_LUMINANCE: 442 return true; 443 default: 444 return false; 445 } 446 } 447 448 void GLClientState::writeCopyTexImageState 449 (GLenum target, GLint level, GLenum internalformat) { 450 if (unreliableInternalFormat(internalformat)) { 451 CubeMapDef entry; 452 entry.id = getBoundTexture(GL_TEXTURE_2D); 453 entry.target = target; 454 entry.level = level; 455 entry.internalformat = internalformat; 456 m_cubeMapDefs.insert(entry); 457 } 458 } 459 460 static GLenum identifyPositiveCubeMapComponent(GLenum target) { 461 switch (target) { 462 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 463 return GL_TEXTURE_CUBE_MAP_POSITIVE_X; 464 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 465 return GL_TEXTURE_CUBE_MAP_POSITIVE_Y; 466 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 467 return GL_TEXTURE_CUBE_MAP_POSITIVE_Z; 468 default: 469 return 0; 470 } 471 } 472 473 GLenum GLClientState::copyTexImageNeededTarget 474 (GLenum target, GLint level, GLenum internalformat) { 475 if (unreliableInternalFormat(internalformat)) { 476 GLenum positiveComponent = 477 identifyPositiveCubeMapComponent(target); 478 if (positiveComponent) { 479 CubeMapDef query; 480 query.id = getBoundTexture(GL_TEXTURE_2D); 481 query.target = positiveComponent; 482 query.level = level; 483 query.internalformat = internalformat; 484 if (m_cubeMapDefs.find(query) == 485 m_cubeMapDefs.end()) { 486 return positiveComponent; 487 } 488 } 489 } 490 return 0; 491 } 492 493 GLenum GLClientState::copyTexImageLuminanceCubeMapAMDWorkaround 494 (GLenum target, GLint level, GLenum internalformat) { 495 writeCopyTexImageState(target, level, internalformat); 496 return copyTexImageNeededTarget(target, level, internalformat); 497 } 498 499 // (>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')><(' '<)(>' ')> 500 // END driver workarounds-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~- 501 502 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures) 503 { 504 // Updating the textures array could be made more efficient when deleting 505 // several textures: 506 // - compacting the array could be done in a single pass once the deleted 507 // textures are marked, or 508 // - could swap deleted textures to the end and re-sort. 509 TextureRec* texrec; 510 for (const GLuint* texture = textures; texture != textures + n; texture++) { 511 texrec = (TextureRec*)bsearch(texture, m_tex.textures, 512 m_tex.numTextures, sizeof(TextureRec), compareTexId); 513 if (texrec) { 514 const TextureRec* end = m_tex.textures + m_tex.numTextures; 515 memmove(texrec, texrec + 1, 516 (end - texrec - 1) * sizeof(TextureRec)); 517 m_tex.numTextures--; 518 519 for (TextureUnit* unit = m_tex.unit; 520 unit != m_tex.unit + MAX_TEXTURE_UNITS; 521 unit++) 522 { 523 if (unit->texture[TEXTURE_2D] == *texture) { 524 unit->texture[TEXTURE_2D] = 0; 525 } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) { 526 unit->texture[TEXTURE_EXTERNAL] = 0; 527 } 528 } 529 } 530 } 531 } 532 533 // RBO////////////////////////////////////////////////////////////////////////// 534 535 void GLClientState::addFreshRenderbuffer(GLuint name) { 536 mRboState.rboData.push_back(RboProps()); 537 RboProps& props = mRboState.rboData.back(); 538 props.target = GL_RENDERBUFFER; 539 props.name = name; 540 props.format = GL_NONE; 541 props.previouslyBound = false; 542 } 543 544 void GLClientState::addRenderbuffers(GLsizei n, GLuint* renderbuffers) { 545 for (size_t i = 0; i < n; i++) { 546 addFreshRenderbuffer(renderbuffers[i]); 547 } 548 } 549 550 size_t GLClientState::getRboIndex(GLuint name) const { 551 for (size_t i = 0; i < mRboState.rboData.size(); i++) { 552 if (mRboState.rboData[i].name == name) { 553 return i; 554 } 555 } 556 return -1; 557 } 558 559 void GLClientState::removeRenderbuffers(GLsizei n, const GLuint* renderbuffers) { 560 size_t bound_rbo_idx = getRboIndex(boundRboProps_const().name); 561 562 std::vector<GLuint> to_remove; 563 for (size_t i = 0; i < n; i++) { 564 if (renderbuffers[i] != 0) { // Never remove the zero rb. 565 to_remove.push_back(getRboIndex(renderbuffers[i])); 566 } 567 } 568 569 for (size_t i = 0; i < to_remove.size(); i++) { 570 mRboState.rboData[to_remove[i]] = mRboState.rboData.back(); 571 mRboState.rboData.pop_back(); 572 } 573 574 // If we just deleted the currently bound rb, 575 // bind the zero rb 576 if (getRboIndex(boundRboProps_const().name) != bound_rbo_idx) { 577 bindRenderbuffer(GL_RENDERBUFFER, 0); 578 } 579 } 580 581 bool GLClientState::usedRenderbufferName(GLuint name) const { 582 for (size_t i = 0; i < mRboState.rboData.size(); i++) { 583 if (mRboState.rboData[i].name == name) { 584 return true; 585 } 586 } 587 return false; 588 } 589 590 void GLClientState::setBoundRenderbufferIndex() { 591 for (size_t i = 0; i < mRboState.rboData.size(); i++) { 592 if (mRboState.rboData[i].name == mRboState.boundRenderbuffer) { 593 mRboState.boundRenderbufferIndex = i; 594 break; 595 } 596 } 597 } 598 599 RboProps& GLClientState::boundRboProps() { 600 return mRboState.rboData[mRboState.boundRenderbufferIndex]; 601 } 602 603 const RboProps& GLClientState::boundRboProps_const() const { 604 return mRboState.rboData[mRboState.boundRenderbufferIndex]; 605 } 606 607 void GLClientState::bindRenderbuffer(GLenum target, GLuint name) { 608 // If unused, add it. 609 if (!usedRenderbufferName(name)) { 610 addFreshRenderbuffer(name); 611 } 612 mRboState.boundRenderbuffer = name; 613 setBoundRenderbufferIndex(); 614 boundRboProps().target = target; 615 boundRboProps().previouslyBound = true; 616 } 617 618 GLuint GLClientState::boundRenderbuffer() const { 619 return boundRboProps_const().name; 620 } 621 622 void GLClientState::setBoundRenderbufferFormat(GLenum format) { 623 boundRboProps().format = format; 624 } 625 626 // FBO////////////////////////////////////////////////////////////////////////// 627 628 // Format querying 629 630 GLenum GLClientState::queryRboFormat(GLuint rbo_name) const { 631 return mRboState.rboData[getRboIndex(rbo_name)].format; 632 } 633 634 GLint GLClientState::queryTexInternalFormat(GLuint tex_name) const { 635 TextureRec* texrec = NULL; 636 texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures, 637 m_tex.numTextures, sizeof(TextureRec), compareTexId); 638 if (!texrec) return -1; 639 return texrec->internalformat; 640 } 641 642 GLenum GLClientState::queryTexFormat(GLuint tex_name) const { 643 TextureRec* texrec = NULL; 644 texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures, 645 m_tex.numTextures, sizeof(TextureRec), compareTexId); 646 if (!texrec) return -1; 647 return texrec->format; 648 } 649 650 GLenum GLClientState::queryTexType(GLuint tex_name) const { 651 TextureRec* texrec = NULL; 652 texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures, 653 m_tex.numTextures, sizeof(TextureRec), compareTexId); 654 if (!texrec) return -1; 655 return texrec->type; 656 } 657 658 void GLClientState::getBoundFramebufferFormat( 659 GLenum attachment, FboFormatInfo* res_info) const { 660 const FboProps& props = boundFboProps_const(); 661 662 res_info->type = FBO_ATTACHMENT_NONE; 663 res_info->rb_format = GL_NONE; 664 res_info->tex_internalformat = -1; 665 res_info->tex_format = GL_NONE; 666 res_info->tex_type = GL_NONE; 667 668 switch (attachment) { 669 case GL_COLOR_ATTACHMENT0: 670 if (props.colorAttachment0_hasRbo) { 671 res_info->type = FBO_ATTACHMENT_RENDERBUFFER; 672 res_info->rb_format = queryRboFormat(props.colorAttachment0_rbo); 673 } else if (props.colorAttachment0_hasTexObj) { 674 res_info->type = FBO_ATTACHMENT_TEXTURE; 675 res_info->tex_internalformat = queryTexInternalFormat(props.colorAttachment0_texture); 676 res_info->tex_format = queryTexFormat(props.colorAttachment0_texture); 677 res_info->tex_type = queryTexType(props.colorAttachment0_texture); 678 } else { 679 res_info->type = FBO_ATTACHMENT_NONE; 680 } 681 break; 682 case GL_DEPTH_ATTACHMENT: 683 if (props.depthAttachment_hasRbo) { 684 res_info->type = FBO_ATTACHMENT_RENDERBUFFER; 685 res_info->rb_format = queryRboFormat(props.depthAttachment_rbo); 686 } else if (props.depthAttachment_hasTexObj) { 687 res_info->type = FBO_ATTACHMENT_TEXTURE; 688 res_info->tex_internalformat = queryTexInternalFormat(props.depthAttachment_texture); 689 res_info->tex_format = queryTexFormat(props.depthAttachment_texture); 690 res_info->tex_type = queryTexType(props.depthAttachment_texture); 691 } else { 692 res_info->type = FBO_ATTACHMENT_NONE; 693 } 694 break; 695 case GL_STENCIL_ATTACHMENT: 696 if (props.stencilAttachment_hasRbo) { 697 res_info->type = FBO_ATTACHMENT_RENDERBUFFER; 698 res_info->rb_format = queryRboFormat(props.stencilAttachment_rbo); 699 } else if (props.stencilAttachment_hasTexObj) { 700 res_info->type = FBO_ATTACHMENT_TEXTURE; 701 res_info->tex_internalformat = queryTexInternalFormat(props.stencilAttachment_texture); 702 res_info->tex_format = queryTexFormat(props.stencilAttachment_texture); 703 res_info->tex_type = queryTexType(props.stencilAttachment_texture); 704 } else { 705 res_info->type = FBO_ATTACHMENT_NONE; 706 } 707 break; 708 default: 709 res_info->type = FBO_ATTACHMENT_NONE; 710 break; 711 } 712 } 713 714 void GLClientState::addFreshFramebuffer(GLuint name) { 715 mFboState.fboData.push_back(FboProps()); 716 FboProps& props = mFboState.fboData.back(); 717 props.target = GL_FRAMEBUFFER; 718 props.name = name; 719 props.previouslyBound = false; 720 721 props.colorAttachment0_texture = 0; 722 props.depthAttachment_texture = 0; 723 props.stencilAttachment_texture = 0; 724 725 props.colorAttachment0_hasTexObj = false; 726 props.depthAttachment_hasTexObj = false; 727 props.stencilAttachment_hasTexObj = false; 728 729 props.colorAttachment0_rbo = 0; 730 props.depthAttachment_rbo = 0; 731 props.stencilAttachment_rbo = 0; 732 733 props.colorAttachment0_hasRbo = false; 734 props.depthAttachment_hasRbo = false; 735 props.stencilAttachment_hasRbo = false; 736 } 737 738 void GLClientState::addFramebuffers(GLsizei n, GLuint* framebuffers) { 739 for (size_t i = 0; i < n; i++) { 740 addFreshFramebuffer(framebuffers[i]); 741 } 742 } 743 744 size_t GLClientState::getFboIndex(GLuint name) const { 745 for (size_t i = 0; i < mFboState.fboData.size(); i++) { 746 if (mFboState.fboData[i].name == name) { 747 return i; 748 } 749 } 750 return -1; 751 } 752 753 754 void GLClientState::removeFramebuffers(GLsizei n, const GLuint* framebuffers) { 755 size_t bound_fbo_idx = getFboIndex(boundFboProps_const().name); 756 757 std::vector<GLuint> to_remove; 758 for (size_t i = 0; i < n; i++) { 759 if (framebuffers[i] != 0) { // Never remove the zero fb. 760 to_remove.push_back(getFboIndex(framebuffers[i])); 761 } 762 } 763 764 for (size_t i = 0; i < to_remove.size(); i++) { 765 mFboState.fboData[to_remove[i]] = mFboState.fboData.back(); 766 mFboState.fboData.pop_back(); 767 } 768 769 // If we just deleted the currently bound fb< 770 // bind the zero fb 771 if (getFboIndex(boundFboProps_const().name) != bound_fbo_idx) { 772 bindFramebuffer(GL_FRAMEBUFFER, 0); 773 } 774 } 775 776 bool GLClientState::usedFramebufferName(GLuint name) const { 777 for (size_t i = 0; i < mFboState.fboData.size(); i++) { 778 if (mFboState.fboData[i].name == name) { 779 return true; 780 } 781 } 782 return false; 783 } 784 785 void GLClientState::setBoundFramebufferIndex() { 786 for (size_t i = 0; i < mFboState.fboData.size(); i++) { 787 if (mFboState.fboData[i].name == mFboState.boundFramebuffer) { 788 mFboState.boundFramebufferIndex = i; 789 break; 790 } 791 } 792 } 793 794 FboProps& GLClientState::boundFboProps() { 795 return mFboState.fboData[mFboState.boundFramebufferIndex]; 796 } 797 798 const FboProps& GLClientState::boundFboProps_const() const { 799 return mFboState.fboData[mFboState.boundFramebufferIndex]; 800 } 801 802 void GLClientState::bindFramebuffer(GLenum target, GLuint name) { 803 // If unused, add it. 804 if (!usedFramebufferName(name)) { 805 addFreshFramebuffer(name); 806 } 807 mFboState.boundFramebuffer = name; 808 setBoundFramebufferIndex(); 809 boundFboProps().target = target; 810 boundFboProps().previouslyBound = true; 811 } 812 813 void GLClientState::setCheckFramebufferStatus(GLenum status) { 814 mFboState.fboCheckStatus = status; 815 } 816 817 GLenum GLClientState::getCheckFramebufferStatus() const { 818 return mFboState.fboCheckStatus; 819 } 820 821 GLuint GLClientState::boundFramebuffer() const { 822 return boundFboProps_const().name; 823 } 824 825 // Texture objects for FBOs///////////////////////////////////////////////////// 826 827 void GLClientState::attachTextureObject(GLenum attachment, GLuint texture) { 828 switch (attachment) { 829 case GL_COLOR_ATTACHMENT0: 830 boundFboProps().colorAttachment0_texture = texture; 831 boundFboProps().colorAttachment0_hasTexObj = true; 832 break; 833 case GL_DEPTH_ATTACHMENT: 834 boundFboProps().depthAttachment_texture = texture; 835 boundFboProps().depthAttachment_hasTexObj = true; 836 break; 837 case GL_STENCIL_ATTACHMENT: 838 boundFboProps().stencilAttachment_texture = texture; 839 boundFboProps().stencilAttachment_hasTexObj = true; 840 break; 841 default: 842 break; 843 } 844 } 845 846 GLuint GLClientState::getFboAttachmentTextureId(GLenum attachment) const { 847 GLuint res; 848 switch (attachment) { 849 case GL_COLOR_ATTACHMENT0: 850 res = boundFboProps_const().colorAttachment0_texture; 851 break; 852 case GL_DEPTH_ATTACHMENT: 853 res = boundFboProps_const().depthAttachment_texture; 854 break; 855 case GL_STENCIL_ATTACHMENT: 856 res = boundFboProps_const().stencilAttachment_texture; 857 break; 858 default: 859 res = 0; // conservative validation for now 860 } 861 return res; 862 } 863 864 // RBOs for FBOs//////////////////////////////////////////////////////////////// 865 866 void GLClientState::attachRbo(GLenum attachment, GLuint renderbuffer) { 867 switch (attachment) { 868 case GL_COLOR_ATTACHMENT0: 869 boundFboProps().colorAttachment0_rbo = renderbuffer; 870 boundFboProps().colorAttachment0_hasRbo = true; 871 break; 872 case GL_DEPTH_ATTACHMENT: 873 boundFboProps().depthAttachment_rbo = renderbuffer; 874 boundFboProps().depthAttachment_hasRbo = true; 875 break; 876 case GL_STENCIL_ATTACHMENT: 877 boundFboProps().stencilAttachment_rbo = renderbuffer; 878 boundFboProps().stencilAttachment_hasRbo = true; 879 break; 880 default: 881 break; 882 } 883 } 884 885 GLuint GLClientState::getFboAttachmentRboId(GLenum attachment) const { 886 GLuint res; 887 switch (attachment) { 888 case GL_COLOR_ATTACHMENT0: 889 res = boundFboProps_const().colorAttachment0_rbo; 890 break; 891 case GL_DEPTH_ATTACHMENT: 892 res = boundFboProps_const().depthAttachment_rbo; 893 break; 894 case GL_STENCIL_ATTACHMENT: 895 res = boundFboProps_const().stencilAttachment_rbo; 896 break; 897 default: 898 res = 0; // conservative validation for now 899 } 900 return res; 901 } 902 903 bool GLClientState::attachmentHasObject(GLenum attachment) const { 904 bool res; 905 switch (attachment) { 906 case GL_COLOR_ATTACHMENT0: 907 res = (boundFboProps_const().colorAttachment0_hasTexObj) || 908 (boundFboProps_const().colorAttachment0_hasRbo); 909 break; 910 case GL_DEPTH_ATTACHMENT: 911 res = (boundFboProps_const().depthAttachment_hasTexObj) || 912 (boundFboProps_const().depthAttachment_hasRbo); 913 break; 914 case GL_STENCIL_ATTACHMENT: 915 res = (boundFboProps_const().stencilAttachment_hasTexObj) || 916 (boundFboProps_const().stencilAttachment_hasRbo); 917 break; 918 default: 919 res = true; // liberal validation for now 920 } 921 return res; 922 } 923 924 void GLClientState::fromMakeCurrent() { 925 FboProps& default_fb_props = mFboState.fboData[getFboIndex(0)]; 926 default_fb_props.colorAttachment0_hasRbo = true; 927 default_fb_props.depthAttachment_hasRbo = true; 928 default_fb_props.stencilAttachment_hasRbo = true; 929 } 930