2 * Copyright (C) 2011 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "GLClientState.h"
22 #include <cutils/log.h>
25 #define MAX(a, b) ((a) < (b) ? (b) : (a))
28 GLClientState::GLClientState(int nLocations)
30 if (nLocations < LAST_LOCATION) {
31 nLocations = LAST_LOCATION;
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;
40 m_currentArrayVbo = 0;
41 m_currentIndexVbo = 0;
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;
60 m_pixelStore.unpack_alignment = 4;
61 m_pixelStore.pack_alignment = 4;
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;
69 mRboState.boundRenderbuffer = 0;
70 mRboState.boundRenderbufferIndex = 0;
71 addFreshRenderbuffer(0);
73 mFboState.boundFramebuffer = 0;
74 mFboState.boundFramebufferIndex = 0;
75 mFboState.fboCheckStatus = GL_NONE;
76 addFreshFramebuffer(0);
78 m_maxVertexAttribsDirty = true;
81 GLClientState::~GLClientState()
86 void GLClientState::enable(int location, int state)
88 if (!validLocation(location)) {
92 m_states[location].enableDirty |= (state != m_states[location].enabled);
93 m_states[location].enabled = state;
96 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data)
98 if (!validLocation(location)) {
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;
110 void GLClientState::setBufferObject(int location, GLuint id)
112 if (!validLocation(location)) {
116 m_states[location].bufferObject = id;
119 const GLClientState::VertexAttribState * GLClientState::getState(int location)
121 if (!validLocation(location)) {
124 return & m_states[location];
127 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged)
129 if (!validLocation(location)) {
134 *enableChanged = m_states[location].enableDirty;
137 m_states[location].enableDirty = false;
138 return & m_states[location];
141 int GLClientState::getLocation(GLenum loc)
146 case GL_VERTEX_ARRAY:
147 retval = int(VERTEX_LOCATION);
149 case GL_NORMAL_ARRAY:
150 retval = int(NORMAL_LOCATION);
153 retval = int(COLOR_LOCATION);
155 case GL_POINT_SIZE_ARRAY_OES:
156 retval = int(POINTSIZE_LOCATION);
158 case GL_TEXTURE_COORD_ARRAY:
159 retval = int (TEXCOORD0_LOCATION + m_activeTexture);
161 case GL_MATRIX_INDEX_ARRAY_OES:
162 retval = int (MATRIXINDEX_LOCATION);
164 case GL_WEIGHT_ARRAY_OES:
165 retval = int (WEIGHT_LOCATION);
173 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params)
175 const GLClientState::VertexAttribState *state = NULL;
177 case GL_VERTEX_ARRAY_POINTER: {
178 state = getState(GLClientState::VERTEX_LOCATION);
181 case GL_NORMAL_ARRAY_POINTER: {
182 state = getState(GLClientState::NORMAL_LOCATION);
185 case GL_COLOR_ARRAY_POINTER: {
186 state = getState(GLClientState::COLOR_LOCATION);
189 case GL_TEXTURE_COORD_ARRAY_POINTER: {
190 state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION);
193 case GL_POINT_SIZE_ARRAY_POINTER_OES: {
194 state = getState(GLClientState::POINTSIZE_LOCATION);
197 case GL_MATRIX_INDEX_ARRAY_POINTER_OES: {
198 state = getState(GLClientState::MATRIXINDEX_LOCATION);
201 case GL_WEIGHT_ARRAY_POINTER_OES: {
202 state = getState(GLClientState::WEIGHT_LOCATION);
207 *params = state->data;
210 int GLClientState::setPixelStore(GLenum param, GLint value)
214 case GL_UNPACK_ALIGNMENT:
215 if (value == 1 || value == 2 || value == 4 || value == 8) {
216 m_pixelStore.unpack_alignment = value;
218 retval = GL_INVALID_VALUE;
221 case GL_PACK_ALIGNMENT:
222 if (value == 1 || value == 2 || value == 4 || value == 8) {
223 m_pixelStore.pack_alignment = value;
225 retval = GL_INVALID_VALUE;
229 retval = GL_INVALID_ENUM;
237 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const
239 if (width <= 0 || height <= 0) return 0;
241 int pixelsize = glUtilsPixelBitSize(format, type) >> 3;
243 int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment;
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);
249 size_t linesize = pixelsize * width;
250 size_t aligned_linesize = int(linesize / alignment) * alignment;
251 if (aligned_linesize < linesize) {
252 aligned_linesize += alignment;
254 return aligned_linesize * height;
257 GLenum GLClientState::setActiveTextureUnit(GLenum texture)
259 GLuint unit = texture - GL_TEXTURE0;
260 if (unit >= MAX_TEXTURE_UNITS) {
261 return GL_INVALID_OPERATION;
263 m_tex.activeUnit = &m_tex.unit[unit];
267 GLenum GLClientState::getActiveTextureUnit() const
269 return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
272 void GLClientState::enableTextureTarget(GLenum target)
276 m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
278 case GL_TEXTURE_EXTERNAL_OES:
279 m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
284 void GLClientState::disableTextureTarget(GLenum target)
288 m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
290 case GL_TEXTURE_EXTERNAL_OES:
291 m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
296 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
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;
308 int GLClientState::compareTexId(const void* pid, const void* prec)
310 const GLuint* id = (const GLuint*)pid;
311 const TextureRec* rec = (const TextureRec*)prec;
312 return (GLint)(*id) - (GLint)rec->id;
315 GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
318 GLboolean first = GL_FALSE;
319 TextureRec* texrec = NULL;
321 if (m_tex.textures) {
322 texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
323 m_tex.numTextures, sizeof(TextureRec), compareTexId);
326 if (!(texrec = addTextureRec(texture, target))) {
327 return GL_OUT_OF_MEMORY;
331 if (target != texrec->target) {
332 return GL_INVALID_OPERATION;
338 m_tex.activeUnit->texture[TEXTURE_2D] = texture;
340 case GL_TEXTURE_EXTERNAL_OES:
341 m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
352 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
355 if (m_tex.numTextures == m_tex.allocTextures) {
356 const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
359 if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
360 newAlloc = MAX(4, 2 * m_tex.allocTextures);
362 if (m_tex.allocTextures == MAX_TEXTURES) {
365 newAlloc = MAX_TEXTURES;
368 TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
369 newAlloc * sizeof(TextureRec));
374 m_tex.textures = newTextures;
375 m_tex.allocTextures = newAlloc;
378 TextureRec* tex = m_tex.textures + m_tex.numTextures;
379 TextureRec* prev = tex - 1;
380 while (tex != m_tex.textures && id < prev->id) {
384 tex->target = target;
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,
399 texrec->internalformat = internalformat;
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,
410 texrec->format = format;
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,
424 GLuint GLClientState::getBoundTexture(GLenum target) const
428 return m_tex.activeUnit->texture[TEXTURE_2D];
429 case GL_TEXTURE_EXTERNAL_OES:
430 return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
436 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
438 // Updating the textures array could be made more efficient when deleting
440 // - compacting the array could be done in a single pass once the deleted
441 // textures are marked, or
442 // - could swap deleted textures to the end and re-sort.
444 for (const GLuint* texture = textures; texture != textures + n; texture++) {
445 texrec = (TextureRec*)bsearch(texture, m_tex.textures,
446 m_tex.numTextures, sizeof(TextureRec), compareTexId);
448 const TextureRec* end = m_tex.textures + m_tex.numTextures;
449 memmove(texrec, texrec + 1,
450 (end - texrec - 1) * sizeof(TextureRec));
453 for (TextureUnit* unit = m_tex.unit;
454 unit != m_tex.unit + MAX_TEXTURE_UNITS;
457 if (unit->texture[TEXTURE_2D] == *texture) {
458 unit->texture[TEXTURE_2D] = 0;
459 } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) {
460 unit->texture[TEXTURE_EXTERNAL] = 0;
467 // RBO//////////////////////////////////////////////////////////////////////////
469 void GLClientState::addFreshRenderbuffer(GLuint name) {
470 mRboState.rboData.push_back(RboProps());
471 RboProps& props = mRboState.rboData.back();
472 props.target = GL_RENDERBUFFER;
474 props.format = GL_NONE;
475 props.previouslyBound = false;
478 void GLClientState::addRenderbuffers(GLsizei n, GLuint* renderbuffers) {
479 for (size_t i = 0; i < n; i++) {
480 addFreshRenderbuffer(renderbuffers[i]);
484 size_t GLClientState::getRboIndex(GLuint name) const {
485 for (size_t i = 0; i < mRboState.rboData.size(); i++) {
486 if (mRboState.rboData[i].name == name) {
493 void GLClientState::removeRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
494 size_t bound_rbo_idx = getRboIndex(boundRboProps_const().name);
496 std::vector<GLuint> to_remove;
497 for (size_t i = 0; i < n; i++) {
498 if (renderbuffers[i] != 0) { // Never remove the zero rb.
499 to_remove.push_back(getRboIndex(renderbuffers[i]));
503 for (size_t i = 0; i < to_remove.size(); i++) {
504 mRboState.rboData[to_remove[i]] = mRboState.rboData.back();
505 mRboState.rboData.pop_back();
508 // If we just deleted the currently bound rb,
510 if (getRboIndex(boundRboProps_const().name) != bound_rbo_idx) {
511 bindRenderbuffer(GL_RENDERBUFFER, 0);
515 bool GLClientState::usedRenderbufferName(GLuint name) const {
516 for (size_t i = 0; i < mRboState.rboData.size(); i++) {
517 if (mRboState.rboData[i].name == name) {
524 void GLClientState::setBoundRenderbufferIndex() {
525 for (size_t i = 0; i < mRboState.rboData.size(); i++) {
526 if (mRboState.rboData[i].name == mRboState.boundRenderbuffer) {
527 mRboState.boundRenderbufferIndex = i;
533 RboProps& GLClientState::boundRboProps() {
534 return mRboState.rboData[mRboState.boundRenderbufferIndex];
537 const RboProps& GLClientState::boundRboProps_const() const {
538 return mRboState.rboData[mRboState.boundRenderbufferIndex];
541 void GLClientState::bindRenderbuffer(GLenum target, GLuint name) {
542 // If unused, add it.
543 if (!usedRenderbufferName(name)) {
544 addFreshRenderbuffer(name);
546 mRboState.boundRenderbuffer = name;
547 setBoundRenderbufferIndex();
548 boundRboProps().target = target;
549 boundRboProps().previouslyBound = true;
552 GLuint GLClientState::boundRenderbuffer() const {
553 return boundRboProps_const().name;
556 void GLClientState::setBoundRenderbufferFormat(GLenum format) {
557 boundRboProps().format = format;
560 // FBO//////////////////////////////////////////////////////////////////////////
564 GLenum GLClientState::queryRboFormat(GLuint rbo_name) const {
565 return mRboState.rboData[getRboIndex(rbo_name)].format;
568 GLint GLClientState::queryTexInternalFormat(GLuint tex_name) const {
569 TextureRec* texrec = NULL;
570 texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures,
571 m_tex.numTextures, sizeof(TextureRec), compareTexId);
572 if (!texrec) return -1;
573 return texrec->internalformat;
576 GLenum GLClientState::queryTexFormat(GLuint tex_name) const {
577 TextureRec* texrec = NULL;
578 texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures,
579 m_tex.numTextures, sizeof(TextureRec), compareTexId);
580 if (!texrec) return -1;
581 return texrec->format;
584 GLenum GLClientState::queryTexType(GLuint tex_name) const {
585 TextureRec* texrec = NULL;
586 texrec = (TextureRec*)bsearch(&tex_name, m_tex.textures,
587 m_tex.numTextures, sizeof(TextureRec), compareTexId);
588 if (!texrec) return -1;
592 void GLClientState::getBoundFramebufferFormat(
593 GLenum attachment, FboFormatInfo* res_info) const {
594 const FboProps& props = boundFboProps_const();
596 res_info->type = FBO_ATTACHMENT_NONE;
597 res_info->rb_format = GL_NONE;
598 res_info->tex_internalformat = -1;
599 res_info->tex_format = GL_NONE;
600 res_info->tex_type = GL_NONE;
602 switch (attachment) {
603 case GL_COLOR_ATTACHMENT0:
604 if (props.colorAttachment0_hasRbo) {
605 res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
606 res_info->rb_format = queryRboFormat(props.colorAttachment0_rbo);
607 } else if (props.colorAttachment0_hasTexObj) {
608 res_info->type = FBO_ATTACHMENT_TEXTURE;
609 res_info->tex_internalformat = queryTexInternalFormat(props.colorAttachment0_texture);
610 res_info->tex_format = queryTexFormat(props.colorAttachment0_texture);
611 res_info->tex_type = queryTexType(props.colorAttachment0_texture);
613 res_info->type = FBO_ATTACHMENT_NONE;
616 case GL_DEPTH_ATTACHMENT:
617 if (props.depthAttachment_hasRbo) {
618 res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
619 res_info->rb_format = queryRboFormat(props.depthAttachment_rbo);
620 } else if (props.depthAttachment_hasTexObj) {
621 res_info->type = FBO_ATTACHMENT_TEXTURE;
622 res_info->tex_internalformat = queryTexInternalFormat(props.depthAttachment_texture);
623 res_info->tex_format = queryTexFormat(props.depthAttachment_texture);
624 res_info->tex_type = queryTexType(props.depthAttachment_texture);
626 res_info->type = FBO_ATTACHMENT_NONE;
629 case GL_STENCIL_ATTACHMENT:
630 if (props.stencilAttachment_hasRbo) {
631 res_info->type = FBO_ATTACHMENT_RENDERBUFFER;
632 res_info->rb_format = queryRboFormat(props.stencilAttachment_rbo);
633 } else if (props.stencilAttachment_hasTexObj) {
634 res_info->type = FBO_ATTACHMENT_TEXTURE;
635 res_info->tex_internalformat = queryTexInternalFormat(props.stencilAttachment_texture);
636 res_info->tex_format = queryTexFormat(props.stencilAttachment_texture);
637 res_info->tex_type = queryTexType(props.stencilAttachment_texture);
639 res_info->type = FBO_ATTACHMENT_NONE;
643 res_info->type = FBO_ATTACHMENT_NONE;
648 void GLClientState::addFreshFramebuffer(GLuint name) {
649 mFboState.fboData.push_back(FboProps());
650 FboProps& props = mFboState.fboData.back();
651 props.target = GL_FRAMEBUFFER;
653 props.previouslyBound = false;
655 props.colorAttachment0_texture = 0;
656 props.depthAttachment_texture = 0;
657 props.stencilAttachment_texture = 0;
659 props.colorAttachment0_hasTexObj = false;
660 props.depthAttachment_hasTexObj = false;
661 props.stencilAttachment_hasTexObj = false;
663 props.colorAttachment0_rbo = 0;
664 props.depthAttachment_rbo = 0;
665 props.stencilAttachment_rbo = 0;
667 props.colorAttachment0_hasRbo = false;
668 props.depthAttachment_hasRbo = false;
669 props.stencilAttachment_hasRbo = false;
672 void GLClientState::addFramebuffers(GLsizei n, GLuint* framebuffers) {
673 for (size_t i = 0; i < n; i++) {
674 addFreshFramebuffer(framebuffers[i]);
678 size_t GLClientState::getFboIndex(GLuint name) const {
679 for (size_t i = 0; i < mFboState.fboData.size(); i++) {
680 if (mFboState.fboData[i].name == name) {
688 void GLClientState::removeFramebuffers(GLsizei n, const GLuint* framebuffers) {
689 size_t bound_fbo_idx = getFboIndex(boundFboProps_const().name);
691 std::vector<GLuint> to_remove;
692 for (size_t i = 0; i < n; i++) {
693 if (framebuffers[i] != 0) { // Never remove the zero fb.
694 to_remove.push_back(getFboIndex(framebuffers[i]));
698 for (size_t i = 0; i < to_remove.size(); i++) {
699 mFboState.fboData[to_remove[i]] = mFboState.fboData.back();
700 mFboState.fboData.pop_back();
703 // If we just deleted the currently bound fb<
705 if (getFboIndex(boundFboProps_const().name) != bound_fbo_idx) {
706 bindFramebuffer(GL_FRAMEBUFFER, 0);
710 bool GLClientState::usedFramebufferName(GLuint name) const {
711 for (size_t i = 0; i < mFboState.fboData.size(); i++) {
712 if (mFboState.fboData[i].name == name) {
719 void GLClientState::setBoundFramebufferIndex() {
720 for (size_t i = 0; i < mFboState.fboData.size(); i++) {
721 if (mFboState.fboData[i].name == mFboState.boundFramebuffer) {
722 mFboState.boundFramebufferIndex = i;
728 FboProps& GLClientState::boundFboProps() {
729 return mFboState.fboData[mFboState.boundFramebufferIndex];
732 const FboProps& GLClientState::boundFboProps_const() const {
733 return mFboState.fboData[mFboState.boundFramebufferIndex];
736 void GLClientState::bindFramebuffer(GLenum target, GLuint name) {
737 // If unused, add it.
738 if (!usedFramebufferName(name)) {
739 addFreshFramebuffer(name);
741 mFboState.boundFramebuffer = name;
742 setBoundFramebufferIndex();
743 boundFboProps().target = target;
744 boundFboProps().previouslyBound = true;
747 void GLClientState::setCheckFramebufferStatus(GLenum status) {
748 mFboState.fboCheckStatus = status;
751 GLenum GLClientState::getCheckFramebufferStatus() const {
752 return mFboState.fboCheckStatus;
755 GLuint GLClientState::boundFramebuffer() const {
756 return boundFboProps_const().name;
759 // Texture objects for FBOs/////////////////////////////////////////////////////
761 void GLClientState::attachTextureObject(GLenum attachment, GLuint texture) {
762 switch (attachment) {
763 case GL_COLOR_ATTACHMENT0:
764 boundFboProps().colorAttachment0_texture = texture;
765 boundFboProps().colorAttachment0_hasTexObj = true;
767 case GL_DEPTH_ATTACHMENT:
768 boundFboProps().depthAttachment_texture = texture;
769 boundFboProps().depthAttachment_hasTexObj = true;
771 case GL_STENCIL_ATTACHMENT:
772 boundFboProps().stencilAttachment_texture = texture;
773 boundFboProps().stencilAttachment_hasTexObj = true;
780 GLuint GLClientState::getFboAttachmentTextureId(GLenum attachment) const {
782 switch (attachment) {
783 case GL_COLOR_ATTACHMENT0:
784 res = boundFboProps_const().colorAttachment0_texture;
786 case GL_DEPTH_ATTACHMENT:
787 res = boundFboProps_const().depthAttachment_texture;
789 case GL_STENCIL_ATTACHMENT:
790 res = boundFboProps_const().stencilAttachment_texture;
793 res = 0; // conservative validation for now
798 // RBOs for FBOs////////////////////////////////////////////////////////////////
800 void GLClientState::attachRbo(GLenum attachment, GLuint renderbuffer) {
801 switch (attachment) {
802 case GL_COLOR_ATTACHMENT0:
803 boundFboProps().colorAttachment0_rbo = renderbuffer;
804 boundFboProps().colorAttachment0_hasRbo = true;
806 case GL_DEPTH_ATTACHMENT:
807 boundFboProps().depthAttachment_rbo = renderbuffer;
808 boundFboProps().depthAttachment_hasRbo = true;
810 case GL_STENCIL_ATTACHMENT:
811 boundFboProps().stencilAttachment_rbo = renderbuffer;
812 boundFboProps().stencilAttachment_hasRbo = true;
819 GLuint GLClientState::getFboAttachmentRboId(GLenum attachment) const {
821 switch (attachment) {
822 case GL_COLOR_ATTACHMENT0:
823 res = boundFboProps_const().colorAttachment0_rbo;
825 case GL_DEPTH_ATTACHMENT:
826 res = boundFboProps_const().depthAttachment_rbo;
828 case GL_STENCIL_ATTACHMENT:
829 res = boundFboProps_const().stencilAttachment_rbo;
832 res = 0; // conservative validation for now
837 bool GLClientState::attachmentHasObject(GLenum attachment) const {
839 switch (attachment) {
840 case GL_COLOR_ATTACHMENT0:
841 res = (boundFboProps_const().colorAttachment0_hasTexObj) ||
842 (boundFboProps_const().colorAttachment0_hasRbo);
844 case GL_DEPTH_ATTACHMENT:
845 res = (boundFboProps_const().depthAttachment_hasTexObj) ||
846 (boundFboProps_const().depthAttachment_hasRbo);
848 case GL_STENCIL_ATTACHMENT:
849 res = (boundFboProps_const().stencilAttachment_hasTexObj) ||
850 (boundFboProps_const().stencilAttachment_hasRbo);
853 res = true; // liberal validation for now
858 void GLClientState::fromMakeCurrent() {
859 FboProps& default_fb_props = mFboState.fboData[getFboIndex(0)];
860 default_fb_props.colorAttachment0_hasRbo = true;
861 default_fb_props.depthAttachment_hasRbo = true;
862 default_fb_props.stencilAttachment_hasRbo = true;