OSDN Git Service

Merge remote-tracking branch 'goog/stage-aosp-master' into HEAD
[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     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 }