OSDN Git Service

Merge "Validate presence of framebuffer attachment's object" into mnc-emu-dev
[android-x86/device-generic-goldfish-opengl.git] / shared / OpenglCodecCommon / GLClientState.cpp
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     addFreshFramebuffer(0);
76
77     m_maxVertexAttribsDirty = true;
78 }
79
80 GLClientState::~GLClientState()
81 {
82     delete m_states;
83 }
84
85 void GLClientState::enable(int location, int state)
86 {
87     if (!validLocation(location)) {
88         return;
89     }
90
91     m_states[location].enableDirty |= (state != m_states[location].enabled);
92     m_states[location].enabled = state;
93 }
94
95 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data)
96 {
97     if (!validLocation(location)) {
98         return;
99     }
100     m_states[location].size = size;
101     m_states[location].type = type;
102     m_states[location].stride = stride;
103     m_states[location].data = (void*)data;
104     m_states[location].bufferObject = m_currentArrayVbo;
105     m_states[location].elementSize = size ? (glSizeof(type) * size) : 0;
106     m_states[location].normalized = normalized;
107 }
108
109 void GLClientState::setBufferObject(int location, GLuint id)
110 {
111     if (!validLocation(location)) {
112         return;
113     }
114
115     m_states[location].bufferObject = id;
116 }
117
118 const GLClientState::VertexAttribState * GLClientState::getState(int location)
119 {
120     if (!validLocation(location)) {
121         return NULL;
122     }
123     return & m_states[location];
124 }
125
126 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged)
127 {
128     if (!validLocation(location)) {
129         return NULL;
130     }
131
132     if (enableChanged) {
133         *enableChanged = m_states[location].enableDirty;
134     }
135
136     m_states[location].enableDirty = false;
137     return & m_states[location];
138 }
139
140 int GLClientState::getLocation(GLenum loc)
141 {
142     int retval;
143
144     switch(loc) {
145     case GL_VERTEX_ARRAY:
146         retval = int(VERTEX_LOCATION);
147         break;
148     case GL_NORMAL_ARRAY:
149         retval = int(NORMAL_LOCATION);
150         break;
151     case GL_COLOR_ARRAY:
152         retval = int(COLOR_LOCATION);
153         break;
154     case GL_POINT_SIZE_ARRAY_OES:
155         retval = int(POINTSIZE_LOCATION);
156         break;
157     case GL_TEXTURE_COORD_ARRAY:
158         retval = int (TEXCOORD0_LOCATION + m_activeTexture);
159         break;
160     case GL_MATRIX_INDEX_ARRAY_OES:
161         retval = int (MATRIXINDEX_LOCATION);
162         break;
163     case GL_WEIGHT_ARRAY_OES:
164         retval = int (WEIGHT_LOCATION);
165         break;
166     default:
167         retval = loc;
168     }
169     return retval;
170 }
171
172 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params)
173 {
174     const GLClientState::VertexAttribState *state = NULL;
175     switch (pname) {
176     case GL_VERTEX_ARRAY_POINTER: {
177         state = getState(GLClientState::VERTEX_LOCATION);
178         break;
179         }
180     case GL_NORMAL_ARRAY_POINTER: {
181         state = getState(GLClientState::NORMAL_LOCATION);
182         break;
183         }
184     case GL_COLOR_ARRAY_POINTER: {
185         state = getState(GLClientState::COLOR_LOCATION);
186         break;
187         }
188     case GL_TEXTURE_COORD_ARRAY_POINTER: {
189         state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION);
190         break;
191         }
192     case GL_POINT_SIZE_ARRAY_POINTER_OES: {
193         state = getState(GLClientState::POINTSIZE_LOCATION);
194         break;
195         }
196     case GL_MATRIX_INDEX_ARRAY_POINTER_OES: {
197         state = getState(GLClientState::MATRIXINDEX_LOCATION);
198         break;
199         }
200     case GL_WEIGHT_ARRAY_POINTER_OES: {
201         state = getState(GLClientState::WEIGHT_LOCATION);
202         break;
203         }
204     }
205     if (state && params)
206         *params = state->data;
207 }
208
209 int GLClientState::setPixelStore(GLenum param, GLint value)
210 {
211     int retval = 0;
212     switch(param) {
213     case GL_UNPACK_ALIGNMENT:
214         if (value == 1 || value == 2 || value == 4 || value == 8) {
215             m_pixelStore.unpack_alignment = value;
216         } else {
217             retval =  GL_INVALID_VALUE;
218         }
219         break;
220     case GL_PACK_ALIGNMENT:
221         if (value == 1 || value == 2 || value == 4 || value == 8) {
222             m_pixelStore.pack_alignment = value;
223         } else {
224             retval =  GL_INVALID_VALUE;
225         }
226         break;
227         default:
228             retval = GL_INVALID_ENUM;
229     }
230     return retval;
231 }
232
233
234
235
236 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const
237 {
238     if (width <= 0 || height <= 0) return 0;
239
240     int pixelsize = glUtilsPixelBitSize(format, type) >> 3;
241
242     int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment;
243
244     if (pixelsize == 0 ) {
245         ERR("unknown pixel size: width: %d height: %d format: %d type: %d pack: %d align: %d\n",
246              width, height, format, type, pack, alignment);
247     }
248     size_t linesize = pixelsize * width;
249     size_t aligned_linesize = int(linesize / alignment) * alignment;
250     if (aligned_linesize < linesize) {
251         aligned_linesize += alignment;
252     }
253     return aligned_linesize * height;
254 }
255
256 GLenum GLClientState::setActiveTextureUnit(GLenum texture)
257 {
258     GLuint unit = texture - GL_TEXTURE0;
259     if (unit >= MAX_TEXTURE_UNITS) {
260         return GL_INVALID_OPERATION;
261     }
262     m_tex.activeUnit = &m_tex.unit[unit];
263     return GL_NO_ERROR;
264 }
265
266 GLenum GLClientState::getActiveTextureUnit() const
267 {
268     return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
269 }
270
271 void GLClientState::enableTextureTarget(GLenum target)
272 {
273     switch (target) {
274     case GL_TEXTURE_2D:
275         m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
276         break;
277     case GL_TEXTURE_EXTERNAL_OES:
278         m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
279         break;
280     }
281 }
282
283 void GLClientState::disableTextureTarget(GLenum target)
284 {
285     switch (target) {
286     case GL_TEXTURE_2D:
287         m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
288         break;
289     case GL_TEXTURE_EXTERNAL_OES:
290         m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
291         break;
292     }
293 }
294
295 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
296 {
297     unsigned int enables = m_tex.activeUnit->enables;
298     if (enables & (1u << TEXTURE_EXTERNAL)) {
299         return GL_TEXTURE_EXTERNAL_OES;
300     } else if (enables & (1u << TEXTURE_2D)) {
301         return GL_TEXTURE_2D;
302     } else {
303         return allDisabled;
304     }
305 }
306
307 int GLClientState::compareTexId(const void* pid, const void* prec)
308 {
309     const GLuint* id = (const GLuint*)pid;
310     const TextureRec* rec = (const TextureRec*)prec;
311     return (GLint)(*id) - (GLint)rec->id;
312 }
313
314 GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
315         GLboolean* firstUse)
316 {
317     GLboolean first = GL_FALSE;
318     TextureRec* texrec = NULL;
319     if (texture != 0) {
320         if (m_tex.textures) {
321             texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
322                     m_tex.numTextures, sizeof(TextureRec), compareTexId);
323         }
324         if (!texrec) {
325             if (!(texrec = addTextureRec(texture, target))) {
326                 return GL_OUT_OF_MEMORY;
327             }
328             first = GL_TRUE;
329         }
330         if (target != texrec->target) {
331             return GL_INVALID_OPERATION;
332         }
333     }
334
335     switch (target) {
336     case GL_TEXTURE_2D:
337         m_tex.activeUnit->texture[TEXTURE_2D] = texture;
338         break;
339     case GL_TEXTURE_EXTERNAL_OES:
340         m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
341         break;
342     }
343
344     if (firstUse) {
345         *firstUse = first;
346     }
347
348     return GL_NO_ERROR;
349 }
350
351 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
352         GLenum target)
353 {
354     if (m_tex.numTextures == m_tex.allocTextures) {
355         const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
356
357         GLuint newAlloc;
358         if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
359             newAlloc = MAX(4, 2 * m_tex.allocTextures);
360         } else {
361             if (m_tex.allocTextures == MAX_TEXTURES) {
362                 return NULL;
363             }
364             newAlloc = MAX_TEXTURES;
365         }
366
367         TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
368                 newAlloc * sizeof(TextureRec));
369         if (!newTextures) {
370             return NULL;
371         }
372
373         m_tex.textures = newTextures;
374         m_tex.allocTextures = newAlloc;
375     }
376
377     TextureRec* tex = m_tex.textures + m_tex.numTextures;
378     TextureRec* prev = tex - 1;
379     while (tex != m_tex.textures && id < prev->id) {
380         *tex-- = *prev--;
381     }
382     tex->id = id;
383     tex->target = target;
384     m_tex.numTextures++;
385
386     return tex;
387 }
388
389 GLuint GLClientState::getBoundTexture(GLenum target) const
390 {
391     switch (target) {
392     case GL_TEXTURE_2D:
393         return m_tex.activeUnit->texture[TEXTURE_2D];
394     case GL_TEXTURE_EXTERNAL_OES:
395         return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
396     default:
397         return 0;
398     }
399 }
400
401 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
402 {
403     // Updating the textures array could be made more efficient when deleting
404     // several textures:
405     // - compacting the array could be done in a single pass once the deleted
406     //   textures are marked, or
407     // - could swap deleted textures to the end and re-sort.
408     TextureRec* texrec;
409     for (const GLuint* texture = textures; texture != textures + n; texture++) {
410         texrec = (TextureRec*)bsearch(texture, m_tex.textures,
411                 m_tex.numTextures, sizeof(TextureRec), compareTexId);
412         if (texrec) {
413             const TextureRec* end = m_tex.textures + m_tex.numTextures;
414             memmove(texrec, texrec + 1,
415                     (end - texrec - 1) * sizeof(TextureRec));
416             m_tex.numTextures--;
417
418             for (TextureUnit* unit = m_tex.unit;
419                  unit != m_tex.unit + MAX_TEXTURE_UNITS;
420                  unit++)
421             {
422                 if (unit->texture[TEXTURE_2D] == *texture) {
423                     unit->texture[TEXTURE_2D] = 0;
424                 } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) {
425                     unit->texture[TEXTURE_EXTERNAL] = 0;
426                 }
427             }
428         }
429     }
430 }
431
432 // RBO//////////////////////////////////////////////////////////////////////////
433
434 void GLClientState::addFreshRenderbuffer(GLuint name) {
435     mRboState.rboData.push_back(RboProps());
436     RboProps& props = mRboState.rboData.back();
437     props.target = GL_RENDERBUFFER;
438     props.name = name;
439     props.previouslyBound = false;
440 }
441
442 void GLClientState::addRenderbuffers(GLsizei n, GLuint* renderbuffers) {
443     for (size_t i = 0; i < n; i++) {
444         addFreshRenderbuffer(renderbuffers[i]);
445     }
446 }
447
448 size_t GLClientState::getRboIndex(GLuint name) const {
449     for (size_t i = 0; i < mRboState.rboData.size(); i++) {
450         if (mRboState.rboData[i].name == name) {
451             return i;
452         }
453     }
454     return -1;
455 }
456
457 void GLClientState::removeRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
458     size_t bound_rbo_idx = getRboIndex(boundRboProps_const().name);
459
460     std::vector<GLuint> to_remove;
461     for (size_t i = 0; i < n; i++) {
462         if (renderbuffers[i] != 0) { // Never remove the zero rb.
463             to_remove.push_back(getRboIndex(renderbuffers[i]));
464         }
465     }
466
467     for (size_t i = 0; i < to_remove.size(); i++) {
468         mRboState.rboData[to_remove[i]] = mRboState.rboData.back();
469         mRboState.rboData.pop_back();
470     }
471
472     // If we just deleted the currently bound rb,
473     // bind the zero rb
474     if (getRboIndex(boundRboProps_const().name) != bound_rbo_idx) {
475         bindRenderbuffer(GL_RENDERBUFFER, 0);
476     }
477 }
478
479 bool GLClientState::usedRenderbufferName(GLuint name) const {
480     for (size_t i = 0; i < mRboState.rboData.size(); i++) {
481         if (mRboState.rboData[i].name == name) {
482             return true;
483         }
484     }
485     return false;
486 }
487
488 void GLClientState::setBoundRenderbufferIndex() {
489     for (size_t i = 0; i < mRboState.rboData.size(); i++) {
490         if (mRboState.rboData[i].name == mRboState.boundRenderbuffer) {
491             mRboState.boundRenderbufferIndex = i;
492             break;
493         }
494     }
495 }
496
497 RboProps& GLClientState::boundRboProps() {
498     return mRboState.rboData[mRboState.boundRenderbufferIndex];
499 }
500
501 const RboProps& GLClientState::boundRboProps_const() const {
502     return mRboState.rboData[mRboState.boundRenderbufferIndex];
503 }
504
505 void GLClientState::bindRenderbuffer(GLenum target, GLuint name) {
506     // If unused, add it.
507     if (!usedRenderbufferName(name)) {
508         addFreshRenderbuffer(name);
509     }
510     mRboState.boundRenderbuffer = name;
511     setBoundRenderbufferIndex();
512     boundRboProps().target = target;
513     boundRboProps().previouslyBound = true;
514 }
515
516 GLuint GLClientState::boundRenderbuffer() const {
517     return boundRboProps_const().name;
518 }
519
520 // FBO//////////////////////////////////////////////////////////////////////////
521
522 void GLClientState::addFreshFramebuffer(GLuint name) {
523     mFboState.fboData.push_back(FboProps());
524     FboProps& props = mFboState.fboData.back();
525     props.target = GL_FRAMEBUFFER;
526     props.name = name;
527     props.previouslyBound = false;
528
529     props.colorAttachment0_texture = 0;
530     props.depthAttachment_texture = 0;
531     props.stencilAttachment_texture = 0;
532
533     props.colorAttachment0_hasTexObj = false;
534     props.depthAttachment_hasTexObj = false;
535     props.stencilAttachment_hasTexObj = false;
536
537     props.colorAttachment0_rbo = 0;
538     props.depthAttachment_rbo = 0;
539     props.stencilAttachment_rbo = 0;
540
541     props.colorAttachment0_hasRbo = false;
542     props.depthAttachment_hasRbo = false;
543     props.stencilAttachment_hasRbo = false;
544 }
545
546 void GLClientState::addFramebuffers(GLsizei n, GLuint* framebuffers) {
547     for (size_t i = 0; i < n; i++) {
548         addFreshFramebuffer(framebuffers[i]);
549     }
550 }
551
552 size_t GLClientState::getFboIndex(GLuint name) const {
553     for (size_t i = 0; i < mFboState.fboData.size(); i++) {
554         if (mFboState.fboData[i].name == name) {
555             return i;
556         }
557     }
558     return -1;
559 }
560
561
562 void GLClientState::removeFramebuffers(GLsizei n, const GLuint* framebuffers) {
563     size_t bound_fbo_idx = getFboIndex(boundFboProps_const().name);
564
565     std::vector<GLuint> to_remove;
566     for (size_t i = 0; i < n; i++) {
567         if (framebuffers[i] != 0) { // Never remove the zero fb.
568             to_remove.push_back(getFboIndex(framebuffers[i]));
569         }
570     }
571
572     for (size_t i = 0; i < to_remove.size(); i++) {
573         mFboState.fboData[to_remove[i]] = mFboState.fboData.back();
574         mFboState.fboData.pop_back();
575     }
576
577     // If we just deleted the currently bound fb<
578     // bind the zero fb
579     if (getFboIndex(boundFboProps_const().name) != bound_fbo_idx) {
580         bindFramebuffer(GL_FRAMEBUFFER, 0);
581     }
582 }
583
584 bool GLClientState::usedFramebufferName(GLuint name) const {
585     for (size_t i = 0; i < mFboState.fboData.size(); i++) {
586         if (mFboState.fboData[i].name == name) {
587             return true;
588         }
589     }
590     return false;
591 }
592
593 void GLClientState::setBoundFramebufferIndex() {
594     for (size_t i = 0; i < mFboState.fboData.size(); i++) {
595         if (mFboState.fboData[i].name == mFboState.boundFramebuffer) {
596             mFboState.boundFramebufferIndex = i;
597             break;
598         }
599     }
600 }
601
602 FboProps& GLClientState::boundFboProps() {
603     return mFboState.fboData[mFboState.boundFramebufferIndex];
604 }
605
606 const FboProps& GLClientState::boundFboProps_const() const {
607     return mFboState.fboData[mFboState.boundFramebufferIndex];
608 }
609
610 void GLClientState::bindFramebuffer(GLenum target, GLuint name) {
611     // If unused, add it.
612     if (!usedFramebufferName(name)) {
613         addFreshFramebuffer(name);
614     }
615     mFboState.boundFramebuffer = name;
616     setBoundFramebufferIndex();
617     boundFboProps().target = target;
618     boundFboProps().previouslyBound = true;
619 }
620
621 GLuint GLClientState::boundFramebuffer() const {
622     return boundFboProps_const().name;
623 }
624
625 // Texture objects for FBOs/////////////////////////////////////////////////////
626
627 void GLClientState::attachTextureObject(GLenum attachment, GLuint texture) {
628     switch (attachment) {
629     case GL_COLOR_ATTACHMENT0:
630         boundFboProps().colorAttachment0_texture = texture;
631         boundFboProps().colorAttachment0_hasTexObj = true;
632         break;
633     case GL_DEPTH_ATTACHMENT:
634         boundFboProps().depthAttachment_texture = texture;
635         boundFboProps().depthAttachment_hasTexObj = true;
636         break;
637     case GL_STENCIL_ATTACHMENT:
638         boundFboProps().stencilAttachment_texture = texture;
639         boundFboProps().stencilAttachment_hasTexObj = true;
640         break;
641     default:
642         break;
643     }
644 }
645
646 GLuint GLClientState::getFboAttachmentTextureId(GLenum attachment) const {
647     GLuint res;
648     switch (attachment) {
649     case GL_COLOR_ATTACHMENT0:
650         res = boundFboProps_const().colorAttachment0_texture;
651         break;
652     case GL_DEPTH_ATTACHMENT:
653         res = boundFboProps_const().depthAttachment_texture;
654         break;
655     case GL_STENCIL_ATTACHMENT:
656         res = boundFboProps_const().stencilAttachment_texture;
657         break;
658     default:
659         res = 0; // conservative validation for now
660     }
661     return res;
662 }
663
664 // RBOs for FBOs////////////////////////////////////////////////////////////////
665
666 void GLClientState::attachRbo(GLenum attachment, GLuint renderbuffer) {
667     switch (attachment) {
668     case GL_COLOR_ATTACHMENT0:
669         boundFboProps().colorAttachment0_rbo = renderbuffer;
670         boundFboProps().colorAttachment0_hasRbo = true;
671         break;
672     case GL_DEPTH_ATTACHMENT:
673         boundFboProps().depthAttachment_rbo = renderbuffer;
674         boundFboProps().depthAttachment_hasRbo = true;
675         break;
676     case GL_STENCIL_ATTACHMENT:
677         boundFboProps().stencilAttachment_rbo = renderbuffer;
678         boundFboProps().stencilAttachment_hasRbo = true;
679         break;
680     default:
681         break;
682     }
683 }
684
685 GLuint GLClientState::getFboAttachmentRboId(GLenum attachment) const {
686     GLuint res;
687     switch (attachment) {
688     case GL_COLOR_ATTACHMENT0:
689         res = boundFboProps_const().colorAttachment0_rbo;
690         break;
691     case GL_DEPTH_ATTACHMENT:
692         res = boundFboProps_const().depthAttachment_rbo;
693         break;
694     case GL_STENCIL_ATTACHMENT:
695         res = boundFboProps_const().stencilAttachment_rbo;
696         break;
697     default:
698         res = 0; // conservative validation for now
699     }
700     return res;
701 }
702
703 bool GLClientState::attachmentHasObject(GLenum attachment) const {
704     bool res;
705     switch (attachment) {
706     case GL_COLOR_ATTACHMENT0:
707         res = (boundFboProps_const().colorAttachment0_hasTexObj) ||
708               (boundFboProps_const().colorAttachment0_hasRbo);
709         break;
710     case GL_DEPTH_ATTACHMENT:
711         res = (boundFboProps_const().depthAttachment_hasTexObj) ||
712               (boundFboProps_const().depthAttachment_hasRbo);
713         break;
714     case GL_STENCIL_ATTACHMENT:
715         res = (boundFboProps_const().stencilAttachment_hasTexObj) ||
716               (boundFboProps_const().stencilAttachment_hasRbo);
717         break;
718     default:
719         res = true; // liberal validation for now
720     }
721     return res;
722 }
723
724 void GLClientState::fromMakeCurrent() {
725     FboProps& default_fb_props = mFboState.fboData[getFboIndex(0)];
726     default_fb_props.colorAttachment0_hasRbo = true;
727     default_fb_props.depthAttachment_hasRbo = true;
728     default_fb_props.stencilAttachment_hasRbo = true;
729 }