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
GLClientState(int nLocations)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
~GLClientState()81 GLClientState::~GLClientState()
82 {
83 delete m_states;
84 }
85
enable(int location,int state)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
setState(int location,int size,GLenum type,GLboolean normalized,GLsizei stride,const void * data)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
setBufferObject(int location,GLuint id)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
getState(int location)119 const GLClientState::VertexAttribState * GLClientState::getState(int location)
120 {
121 if (!validLocation(location)) {
122 return NULL;
123 }
124 return & m_states[location];
125 }
126
getStateAndEnableDirty(int location,bool * enableChanged)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
getLocation(GLenum loc)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
getClientStatePointer(GLenum pname,GLvoid ** params)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
setPixelStore(GLenum param,GLint value)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
pixelDataSize(GLsizei width,GLsizei height,GLenum format,GLenum type,int pack) const237 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
setActiveTextureUnit(GLenum texture)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
getActiveTextureUnit() const267 GLenum GLClientState::getActiveTextureUnit() const
268 {
269 return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
270 }
271
enableTextureTarget(GLenum target)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
disableTextureTarget(GLenum target)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
getPriorityEnabledTarget(GLenum allDisabled) const296 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
compareTexId(const void * pid,const void * prec)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
bindTexture(GLenum target,GLuint texture,GLboolean * firstUse)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
addTextureRec(GLuint id,GLenum target)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
setBoundTextureInternalFormat(GLenum target,GLint internalformat)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
setBoundTextureFormat(GLenum target,GLenum format)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
setBoundTextureType(GLenum target,GLenum type)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
getBoundTexture(GLenum target) const424 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
unreliableInternalFormat(GLenum internalformat)439 static bool unreliableInternalFormat(GLenum internalformat) {
440 switch (internalformat) {
441 case GL_LUMINANCE:
442 return true;
443 default:
444 return false;
445 }
446 }
447
writeCopyTexImageState(GLenum target,GLint level,GLenum internalformat)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
identifyPositiveCubeMapComponent(GLenum target)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
copyTexImageNeededTarget(GLenum target,GLint level,GLenum internalformat)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
copyTexImageLuminanceCubeMapAMDWorkaround(GLenum target,GLint level,GLenum internalformat)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
deleteTextures(GLsizei n,const GLuint * textures)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
addFreshRenderbuffer(GLuint name)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
addRenderbuffers(GLsizei n,GLuint * renderbuffers)544 void GLClientState::addRenderbuffers(GLsizei n, GLuint* renderbuffers) {
545 for (size_t i = 0; i < n; i++) {
546 addFreshRenderbuffer(renderbuffers[i]);
547 }
548 }
549
getRboIndex(GLuint name) const550 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
removeRenderbuffers(GLsizei n,const GLuint * renderbuffers)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
usedRenderbufferName(GLuint name) const581 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
setBoundRenderbufferIndex()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
boundRboProps()599 RboProps& GLClientState::boundRboProps() {
600 return mRboState.rboData[mRboState.boundRenderbufferIndex];
601 }
602
boundRboProps_const() const603 const RboProps& GLClientState::boundRboProps_const() const {
604 return mRboState.rboData[mRboState.boundRenderbufferIndex];
605 }
606
bindRenderbuffer(GLenum target,GLuint name)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
boundRenderbuffer() const618 GLuint GLClientState::boundRenderbuffer() const {
619 return boundRboProps_const().name;
620 }
621
setBoundRenderbufferFormat(GLenum format)622 void GLClientState::setBoundRenderbufferFormat(GLenum format) {
623 boundRboProps().format = format;
624 }
625
626 // FBO//////////////////////////////////////////////////////////////////////////
627
628 // Format querying
629
queryRboFormat(GLuint rbo_name) const630 GLenum GLClientState::queryRboFormat(GLuint rbo_name) const {
631 return mRboState.rboData[getRboIndex(rbo_name)].format;
632 }
633
queryTexInternalFormat(GLuint tex_name) const634 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
queryTexFormat(GLuint tex_name) const642 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
queryTexType(GLuint tex_name) const650 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
getBoundFramebufferFormat(GLenum attachment,FboFormatInfo * res_info) const658 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
addFreshFramebuffer(GLuint name)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
addFramebuffers(GLsizei n,GLuint * framebuffers)738 void GLClientState::addFramebuffers(GLsizei n, GLuint* framebuffers) {
739 for (size_t i = 0; i < n; i++) {
740 addFreshFramebuffer(framebuffers[i]);
741 }
742 }
743
getFboIndex(GLuint name) const744 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
removeFramebuffers(GLsizei n,const GLuint * framebuffers)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
usedFramebufferName(GLuint name) const776 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
setBoundFramebufferIndex()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
boundFboProps()794 FboProps& GLClientState::boundFboProps() {
795 return mFboState.fboData[mFboState.boundFramebufferIndex];
796 }
797
boundFboProps_const() const798 const FboProps& GLClientState::boundFboProps_const() const {
799 return mFboState.fboData[mFboState.boundFramebufferIndex];
800 }
801
bindFramebuffer(GLenum target,GLuint name)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
setCheckFramebufferStatus(GLenum status)813 void GLClientState::setCheckFramebufferStatus(GLenum status) {
814 mFboState.fboCheckStatus = status;
815 }
816
getCheckFramebufferStatus() const817 GLenum GLClientState::getCheckFramebufferStatus() const {
818 return mFboState.fboCheckStatus;
819 }
820
boundFramebuffer() const821 GLuint GLClientState::boundFramebuffer() const {
822 return boundFboProps_const().name;
823 }
824
825 // Texture objects for FBOs/////////////////////////////////////////////////////
826
attachTextureObject(GLenum attachment,GLuint texture)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
getFboAttachmentTextureId(GLenum attachment) const846 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
attachRbo(GLenum attachment,GLuint renderbuffer)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
getFboAttachmentRboId(GLenum attachment) const885 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
attachmentHasObject(GLenum attachment) const903 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
fromMakeCurrent()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