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;
70 GLClientState::~GLClientState()
75 void GLClientState::enable(int location, int state)
77 if (!validLocation(location)) {
81 m_states[location].enableDirty |= (state != m_states[location].enabled);
82 m_states[location].enabled = state;
85 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data)
87 if (!validLocation(location)) {
90 m_states[location].size = size;
91 m_states[location].type = type;
92 m_states[location].stride = stride;
93 m_states[location].data = (void*)data;
94 m_states[location].bufferObject = m_currentArrayVbo;
95 m_states[location].elementSize = size ? (glSizeof(type) * size) : 0;
96 m_states[location].normalized = normalized;
99 void GLClientState::setBufferObject(int location, GLuint id)
101 if (!validLocation(location)) {
105 m_states[location].bufferObject = id;
108 const GLClientState::VertexAttribState * GLClientState::getState(int location)
110 if (!validLocation(location)) {
113 return & m_states[location];
116 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged)
118 if (!validLocation(location)) {
123 *enableChanged = m_states[location].enableDirty;
126 m_states[location].enableDirty = false;
127 return & m_states[location];
130 int GLClientState::getLocation(GLenum loc)
135 case GL_VERTEX_ARRAY:
136 retval = int(VERTEX_LOCATION);
138 case GL_NORMAL_ARRAY:
139 retval = int(NORMAL_LOCATION);
142 retval = int(COLOR_LOCATION);
144 case GL_POINT_SIZE_ARRAY_OES:
145 retval = int(POINTSIZE_LOCATION);
147 case GL_TEXTURE_COORD_ARRAY:
148 retval = int (TEXCOORD0_LOCATION + m_activeTexture);
150 case GL_MATRIX_INDEX_ARRAY_OES:
151 retval = int (MATRIXINDEX_LOCATION);
153 case GL_WEIGHT_ARRAY_OES:
154 retval = int (WEIGHT_LOCATION);
162 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params)
164 const GLClientState::VertexAttribState *state = NULL;
166 case GL_VERTEX_ARRAY_POINTER: {
167 state = getState(GLClientState::VERTEX_LOCATION);
170 case GL_NORMAL_ARRAY_POINTER: {
171 state = getState(GLClientState::NORMAL_LOCATION);
174 case GL_COLOR_ARRAY_POINTER: {
175 state = getState(GLClientState::COLOR_LOCATION);
178 case GL_TEXTURE_COORD_ARRAY_POINTER: {
179 state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION);
182 case GL_POINT_SIZE_ARRAY_POINTER_OES: {
183 state = getState(GLClientState::POINTSIZE_LOCATION);
186 case GL_MATRIX_INDEX_ARRAY_POINTER_OES: {
187 state = getState(GLClientState::MATRIXINDEX_LOCATION);
190 case GL_WEIGHT_ARRAY_POINTER_OES: {
191 state = getState(GLClientState::WEIGHT_LOCATION);
196 *params = state->data;
199 int GLClientState::setPixelStore(GLenum param, GLint value)
203 case GL_UNPACK_ALIGNMENT:
204 if (value == 1 || value == 2 || value == 4 || value == 8) {
205 m_pixelStore.unpack_alignment = value;
207 retval = GL_INVALID_VALUE;
210 case GL_PACK_ALIGNMENT:
211 if (value == 1 || value == 2 || value == 4 || value == 8) {
212 m_pixelStore.pack_alignment = value;
214 retval = GL_INVALID_VALUE;
218 retval = GL_INVALID_ENUM;
226 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const
228 if (width <= 0 || height <= 0) return 0;
230 int pixelsize = glUtilsPixelBitSize(format, type) >> 3;
232 int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment;
234 if (pixelsize == 0 ) {
235 ERR("unknown pixel size: width: %d height: %d format: %d type: %d pack: %d align: %d\n",
236 width, height, format, type, pack, alignment);
238 size_t linesize = pixelsize * width;
239 size_t aligned_linesize = int(linesize / alignment) * alignment;
240 if (aligned_linesize < linesize) {
241 aligned_linesize += alignment;
243 return aligned_linesize * height;
246 GLenum GLClientState::setActiveTextureUnit(GLenum texture)
248 GLuint unit = texture - GL_TEXTURE0;
249 if (unit >= MAX_TEXTURE_UNITS) {
250 return GL_INVALID_OPERATION;
252 m_tex.activeUnit = &m_tex.unit[unit];
256 GLenum GLClientState::getActiveTextureUnit() const
258 return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
261 void GLClientState::enableTextureTarget(GLenum target)
265 m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
267 case GL_TEXTURE_EXTERNAL_OES:
268 m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
273 void GLClientState::disableTextureTarget(GLenum target)
277 m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
279 case GL_TEXTURE_EXTERNAL_OES:
280 m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
285 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
287 unsigned int enables = m_tex.activeUnit->enables;
288 if (enables & (1u << TEXTURE_EXTERNAL)) {
289 return GL_TEXTURE_EXTERNAL_OES;
290 } else if (enables & (1u << TEXTURE_2D)) {
291 return GL_TEXTURE_2D;
297 int GLClientState::compareTexId(const void* pid, const void* prec)
299 const GLuint* id = (const GLuint*)pid;
300 const TextureRec* rec = (const TextureRec*)prec;
301 return (GLint)(*id) - (GLint)rec->id;
304 GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
307 GLboolean first = GL_FALSE;
308 TextureRec* texrec = NULL;
310 if (m_tex.textures) {
311 texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
312 m_tex.numTextures, sizeof(TextureRec), compareTexId);
315 if (!(texrec = addTextureRec(texture, target))) {
316 return GL_OUT_OF_MEMORY;
320 if (target != texrec->target) {
321 return GL_INVALID_OPERATION;
327 m_tex.activeUnit->texture[TEXTURE_2D] = texture;
329 case GL_TEXTURE_EXTERNAL_OES:
330 m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
341 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
344 if (m_tex.numTextures == m_tex.allocTextures) {
345 const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
348 if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
349 newAlloc = MAX(4, 2 * m_tex.allocTextures);
351 if (m_tex.allocTextures == MAX_TEXTURES) {
354 newAlloc = MAX_TEXTURES;
357 TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
358 newAlloc * sizeof(TextureRec));
363 m_tex.textures = newTextures;
364 m_tex.allocTextures = newAlloc;
367 TextureRec* tex = m_tex.textures + m_tex.numTextures;
368 TextureRec* prev = tex - 1;
369 while (tex != m_tex.textures && id < prev->id) {
373 tex->target = target;
379 GLuint GLClientState::getBoundTexture(GLenum target) const
383 return m_tex.activeUnit->texture[TEXTURE_2D];
384 case GL_TEXTURE_EXTERNAL_OES:
385 return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
391 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
393 // Updating the textures array could be made more efficient when deleting
395 // - compacting the array could be done in a single pass once the deleted
396 // textures are marked, or
397 // - could swap deleted textures to the end and re-sort.
399 for (const GLuint* texture = textures; texture != textures + n; texture++) {
400 texrec = (TextureRec*)bsearch(texture, m_tex.textures,
401 m_tex.numTextures, sizeof(TextureRec), compareTexId);
403 const TextureRec* end = m_tex.textures + m_tex.numTextures;
404 memmove(texrec, texrec + 1,
405 (end - texrec - 1) * sizeof(TextureRec));
408 for (TextureUnit* unit = m_tex.unit;
409 unit != m_tex.unit + MAX_TEXTURE_UNITS;
412 if (unit->texture[TEXTURE_2D] == *texture) {
413 unit->texture[TEXTURE_2D] = 0;
414 } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) {
415 unit->texture[TEXTURE_EXTERNAL] = 0;