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 addFreshFramebuffer(0);
77 m_maxVertexAttribsDirty = true;
80 GLClientState::~GLClientState()
85 void GLClientState::enable(int location, int state)
87 if (!validLocation(location)) {
91 m_states[location].enableDirty |= (state != m_states[location].enabled);
92 m_states[location].enabled = state;
95 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data)
97 if (!validLocation(location)) {
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;
109 void GLClientState::setBufferObject(int location, GLuint id)
111 if (!validLocation(location)) {
115 m_states[location].bufferObject = id;
118 const GLClientState::VertexAttribState * GLClientState::getState(int location)
120 if (!validLocation(location)) {
123 return & m_states[location];
126 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged)
128 if (!validLocation(location)) {
133 *enableChanged = m_states[location].enableDirty;
136 m_states[location].enableDirty = false;
137 return & m_states[location];
140 int GLClientState::getLocation(GLenum loc)
145 case GL_VERTEX_ARRAY:
146 retval = int(VERTEX_LOCATION);
148 case GL_NORMAL_ARRAY:
149 retval = int(NORMAL_LOCATION);
152 retval = int(COLOR_LOCATION);
154 case GL_POINT_SIZE_ARRAY_OES:
155 retval = int(POINTSIZE_LOCATION);
157 case GL_TEXTURE_COORD_ARRAY:
158 retval = int (TEXCOORD0_LOCATION + m_activeTexture);
160 case GL_MATRIX_INDEX_ARRAY_OES:
161 retval = int (MATRIXINDEX_LOCATION);
163 case GL_WEIGHT_ARRAY_OES:
164 retval = int (WEIGHT_LOCATION);
172 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params)
174 const GLClientState::VertexAttribState *state = NULL;
176 case GL_VERTEX_ARRAY_POINTER: {
177 state = getState(GLClientState::VERTEX_LOCATION);
180 case GL_NORMAL_ARRAY_POINTER: {
181 state = getState(GLClientState::NORMAL_LOCATION);
184 case GL_COLOR_ARRAY_POINTER: {
185 state = getState(GLClientState::COLOR_LOCATION);
188 case GL_TEXTURE_COORD_ARRAY_POINTER: {
189 state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION);
192 case GL_POINT_SIZE_ARRAY_POINTER_OES: {
193 state = getState(GLClientState::POINTSIZE_LOCATION);
196 case GL_MATRIX_INDEX_ARRAY_POINTER_OES: {
197 state = getState(GLClientState::MATRIXINDEX_LOCATION);
200 case GL_WEIGHT_ARRAY_POINTER_OES: {
201 state = getState(GLClientState::WEIGHT_LOCATION);
206 *params = state->data;
209 int GLClientState::setPixelStore(GLenum param, GLint value)
213 case GL_UNPACK_ALIGNMENT:
214 if (value == 1 || value == 2 || value == 4 || value == 8) {
215 m_pixelStore.unpack_alignment = value;
217 retval = GL_INVALID_VALUE;
220 case GL_PACK_ALIGNMENT:
221 if (value == 1 || value == 2 || value == 4 || value == 8) {
222 m_pixelStore.pack_alignment = value;
224 retval = GL_INVALID_VALUE;
228 retval = GL_INVALID_ENUM;
236 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const
238 if (width <= 0 || height <= 0) return 0;
240 int pixelsize = glUtilsPixelBitSize(format, type) >> 3;
242 int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment;
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);
248 size_t linesize = pixelsize * width;
249 size_t aligned_linesize = int(linesize / alignment) * alignment;
250 if (aligned_linesize < linesize) {
251 aligned_linesize += alignment;
253 return aligned_linesize * height;
256 GLenum GLClientState::setActiveTextureUnit(GLenum texture)
258 GLuint unit = texture - GL_TEXTURE0;
259 if (unit >= MAX_TEXTURE_UNITS) {
260 return GL_INVALID_OPERATION;
262 m_tex.activeUnit = &m_tex.unit[unit];
266 GLenum GLClientState::getActiveTextureUnit() const
268 return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
271 void GLClientState::enableTextureTarget(GLenum target)
275 m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
277 case GL_TEXTURE_EXTERNAL_OES:
278 m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
283 void GLClientState::disableTextureTarget(GLenum target)
287 m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
289 case GL_TEXTURE_EXTERNAL_OES:
290 m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
295 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
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;
307 int GLClientState::compareTexId(const void* pid, const void* prec)
309 const GLuint* id = (const GLuint*)pid;
310 const TextureRec* rec = (const TextureRec*)prec;
311 return (GLint)(*id) - (GLint)rec->id;
314 GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
317 GLboolean first = GL_FALSE;
318 TextureRec* texrec = NULL;
320 if (m_tex.textures) {
321 texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
322 m_tex.numTextures, sizeof(TextureRec), compareTexId);
325 if (!(texrec = addTextureRec(texture, target))) {
326 return GL_OUT_OF_MEMORY;
330 if (target != texrec->target) {
331 return GL_INVALID_OPERATION;
337 m_tex.activeUnit->texture[TEXTURE_2D] = texture;
339 case GL_TEXTURE_EXTERNAL_OES:
340 m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
351 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
354 if (m_tex.numTextures == m_tex.allocTextures) {
355 const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
358 if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
359 newAlloc = MAX(4, 2 * m_tex.allocTextures);
361 if (m_tex.allocTextures == MAX_TEXTURES) {
364 newAlloc = MAX_TEXTURES;
367 TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
368 newAlloc * sizeof(TextureRec));
373 m_tex.textures = newTextures;
374 m_tex.allocTextures = newAlloc;
377 TextureRec* tex = m_tex.textures + m_tex.numTextures;
378 TextureRec* prev = tex - 1;
379 while (tex != m_tex.textures && id < prev->id) {
383 tex->target = target;
389 GLuint GLClientState::getBoundTexture(GLenum target) const
393 return m_tex.activeUnit->texture[TEXTURE_2D];
394 case GL_TEXTURE_EXTERNAL_OES:
395 return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
401 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
403 // Updating the textures array could be made more efficient when deleting
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.
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);
413 const TextureRec* end = m_tex.textures + m_tex.numTextures;
414 memmove(texrec, texrec + 1,
415 (end - texrec - 1) * sizeof(TextureRec));
418 for (TextureUnit* unit = m_tex.unit;
419 unit != m_tex.unit + MAX_TEXTURE_UNITS;
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;
432 // RBO//////////////////////////////////////////////////////////////////////////
434 void GLClientState::addFreshRenderbuffer(GLuint name) {
435 mRboState.rboData.push_back(RboProps());
436 RboProps& props = mRboState.rboData.back();
437 props.target = GL_RENDERBUFFER;
439 props.previouslyBound = false;
442 void GLClientState::addRenderbuffers(GLsizei n, GLuint* renderbuffers) {
443 for (size_t i = 0; i < n; i++) {
444 addFreshRenderbuffer(renderbuffers[i]);
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) {
457 void GLClientState::removeRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
458 size_t bound_rbo_idx = getRboIndex(boundRboProps_const().name);
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]));
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();
472 // If we just deleted the currently bound rb,
474 if (getRboIndex(boundRboProps_const().name) != bound_rbo_idx) {
475 bindRenderbuffer(GL_RENDERBUFFER, 0);
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) {
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;
497 RboProps& GLClientState::boundRboProps() {
498 return mRboState.rboData[mRboState.boundRenderbufferIndex];
501 const RboProps& GLClientState::boundRboProps_const() const {
502 return mRboState.rboData[mRboState.boundRenderbufferIndex];
505 void GLClientState::bindRenderbuffer(GLenum target, GLuint name) {
506 // If unused, add it.
507 if (!usedRenderbufferName(name)) {
508 addFreshRenderbuffer(name);
510 mRboState.boundRenderbuffer = name;
511 setBoundRenderbufferIndex();
512 boundRboProps().target = target;
513 boundRboProps().previouslyBound = true;
516 GLuint GLClientState::boundRenderbuffer() const {
517 return boundRboProps_const().name;
520 // FBO//////////////////////////////////////////////////////////////////////////
522 void GLClientState::addFreshFramebuffer(GLuint name) {
523 mFboState.fboData.push_back(FboProps());
524 FboProps& props = mFboState.fboData.back();
525 props.target = GL_FRAMEBUFFER;
527 props.previouslyBound = false;
529 props.colorAttachment0_texture = 0;
530 props.depthAttachment_texture = 0;
531 props.stencilAttachment_texture = 0;
533 props.colorAttachment0_hasTexObj = false;
534 props.depthAttachment_hasTexObj = false;
535 props.stencilAttachment_hasTexObj = false;
537 props.colorAttachment0_rbo = 0;
538 props.depthAttachment_rbo = 0;
539 props.stencilAttachment_rbo = 0;
541 props.colorAttachment0_hasRbo = false;
542 props.depthAttachment_hasRbo = false;
543 props.stencilAttachment_hasRbo = false;
546 void GLClientState::addFramebuffers(GLsizei n, GLuint* framebuffers) {
547 for (size_t i = 0; i < n; i++) {
548 addFreshFramebuffer(framebuffers[i]);
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) {
562 void GLClientState::removeFramebuffers(GLsizei n, const GLuint* framebuffers) {
563 size_t bound_fbo_idx = getFboIndex(boundFboProps_const().name);
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]));
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();
577 // If we just deleted the currently bound fb<
579 if (getFboIndex(boundFboProps_const().name) != bound_fbo_idx) {
580 bindFramebuffer(GL_FRAMEBUFFER, 0);
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) {
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;
602 FboProps& GLClientState::boundFboProps() {
603 return mFboState.fboData[mFboState.boundFramebufferIndex];
606 const FboProps& GLClientState::boundFboProps_const() const {
607 return mFboState.fboData[mFboState.boundFramebufferIndex];
610 void GLClientState::bindFramebuffer(GLenum target, GLuint name) {
611 // If unused, add it.
612 if (!usedFramebufferName(name)) {
613 addFreshFramebuffer(name);
615 mFboState.boundFramebuffer = name;
616 setBoundFramebufferIndex();
617 boundFboProps().target = target;
618 boundFboProps().previouslyBound = true;
621 GLuint GLClientState::boundFramebuffer() const {
622 return boundFboProps_const().name;
625 // Texture objects for FBOs/////////////////////////////////////////////////////
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;
633 case GL_DEPTH_ATTACHMENT:
634 boundFboProps().depthAttachment_texture = texture;
635 boundFboProps().depthAttachment_hasTexObj = true;
637 case GL_STENCIL_ATTACHMENT:
638 boundFboProps().stencilAttachment_texture = texture;
639 boundFboProps().stencilAttachment_hasTexObj = true;
646 GLuint GLClientState::getFboAttachmentTextureId(GLenum attachment) const {
648 switch (attachment) {
649 case GL_COLOR_ATTACHMENT0:
650 res = boundFboProps_const().colorAttachment0_texture;
652 case GL_DEPTH_ATTACHMENT:
653 res = boundFboProps_const().depthAttachment_texture;
655 case GL_STENCIL_ATTACHMENT:
656 res = boundFboProps_const().stencilAttachment_texture;
659 res = 0; // conservative validation for now
664 // RBOs for FBOs////////////////////////////////////////////////////////////////
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;
672 case GL_DEPTH_ATTACHMENT:
673 boundFboProps().depthAttachment_rbo = renderbuffer;
674 boundFboProps().depthAttachment_hasRbo = true;
676 case GL_STENCIL_ATTACHMENT:
677 boundFboProps().stencilAttachment_rbo = renderbuffer;
678 boundFboProps().stencilAttachment_hasRbo = true;
685 GLuint GLClientState::getFboAttachmentRboId(GLenum attachment) const {
687 switch (attachment) {
688 case GL_COLOR_ATTACHMENT0:
689 res = boundFboProps_const().colorAttachment0_rbo;
691 case GL_DEPTH_ATTACHMENT:
692 res = boundFboProps_const().depthAttachment_rbo;
694 case GL_STENCIL_ATTACHMENT:
695 res = boundFboProps_const().stencilAttachment_rbo;
698 res = 0; // conservative validation for now
703 bool GLClientState::attachmentHasObject(GLenum attachment) const {
705 switch (attachment) {
706 case GL_COLOR_ATTACHMENT0:
707 res = (boundFboProps_const().colorAttachment0_hasTexObj) ||
708 (boundFboProps_const().colorAttachment0_hasRbo);
710 case GL_DEPTH_ATTACHMENT:
711 res = (boundFboProps_const().depthAttachment_hasTexObj) ||
712 (boundFboProps_const().depthAttachment_hasRbo);
714 case GL_STENCIL_ATTACHMENT:
715 res = (boundFboProps_const().stencilAttachment_hasTexObj) ||
716 (boundFboProps_const().stencilAttachment_hasRbo);
719 res = true; // liberal validation for now
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;