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 m_maxVertexAttribsDirty = true;
70 }
71
~GLClientState()72 GLClientState::~GLClientState()
73 {
74 delete m_states;
75 }
76
enable(int location,int state)77 void GLClientState::enable(int location, int state)
78 {
79 if (!validLocation(location)) {
80 return;
81 }
82
83 m_states[location].enableDirty |= (state != m_states[location].enabled);
84 m_states[location].enabled = state;
85 }
86
setState(int location,int size,GLenum type,GLboolean normalized,GLsizei stride,const void * data)87 void GLClientState::setState(int location, int size, GLenum type, GLboolean normalized, GLsizei stride, const void *data)
88 {
89 if (!validLocation(location)) {
90 return;
91 }
92 m_states[location].size = size;
93 m_states[location].type = type;
94 m_states[location].stride = stride;
95 m_states[location].data = (void*)data;
96 m_states[location].bufferObject = m_currentArrayVbo;
97 m_states[location].elementSize = size ? (glSizeof(type) * size) : 0;
98 m_states[location].normalized = normalized;
99 }
100
setBufferObject(int location,GLuint id)101 void GLClientState::setBufferObject(int location, GLuint id)
102 {
103 if (!validLocation(location)) {
104 return;
105 }
106
107 m_states[location].bufferObject = id;
108 }
109
getState(int location)110 const GLClientState::VertexAttribState * GLClientState::getState(int location)
111 {
112 if (!validLocation(location)) {
113 return NULL;
114 }
115 return & m_states[location];
116 }
117
getStateAndEnableDirty(int location,bool * enableChanged)118 const GLClientState::VertexAttribState * GLClientState::getStateAndEnableDirty(int location, bool *enableChanged)
119 {
120 if (!validLocation(location)) {
121 return NULL;
122 }
123
124 if (enableChanged) {
125 *enableChanged = m_states[location].enableDirty;
126 }
127
128 m_states[location].enableDirty = false;
129 return & m_states[location];
130 }
131
getLocation(GLenum loc)132 int GLClientState::getLocation(GLenum loc)
133 {
134 int retval;
135
136 switch(loc) {
137 case GL_VERTEX_ARRAY:
138 retval = int(VERTEX_LOCATION);
139 break;
140 case GL_NORMAL_ARRAY:
141 retval = int(NORMAL_LOCATION);
142 break;
143 case GL_COLOR_ARRAY:
144 retval = int(COLOR_LOCATION);
145 break;
146 case GL_POINT_SIZE_ARRAY_OES:
147 retval = int(POINTSIZE_LOCATION);
148 break;
149 case GL_TEXTURE_COORD_ARRAY:
150 retval = int (TEXCOORD0_LOCATION + m_activeTexture);
151 break;
152 case GL_MATRIX_INDEX_ARRAY_OES:
153 retval = int (MATRIXINDEX_LOCATION);
154 break;
155 case GL_WEIGHT_ARRAY_OES:
156 retval = int (WEIGHT_LOCATION);
157 break;
158 default:
159 retval = loc;
160 }
161 return retval;
162 }
163
getClientStatePointer(GLenum pname,GLvoid ** params)164 void GLClientState::getClientStatePointer(GLenum pname, GLvoid** params)
165 {
166 const GLClientState::VertexAttribState *state = NULL;
167 switch (pname) {
168 case GL_VERTEX_ARRAY_POINTER: {
169 state = getState(GLClientState::VERTEX_LOCATION);
170 break;
171 }
172 case GL_NORMAL_ARRAY_POINTER: {
173 state = getState(GLClientState::NORMAL_LOCATION);
174 break;
175 }
176 case GL_COLOR_ARRAY_POINTER: {
177 state = getState(GLClientState::COLOR_LOCATION);
178 break;
179 }
180 case GL_TEXTURE_COORD_ARRAY_POINTER: {
181 state = getState(getActiveTexture() + GLClientState::TEXCOORD0_LOCATION);
182 break;
183 }
184 case GL_POINT_SIZE_ARRAY_POINTER_OES: {
185 state = getState(GLClientState::POINTSIZE_LOCATION);
186 break;
187 }
188 case GL_MATRIX_INDEX_ARRAY_POINTER_OES: {
189 state = getState(GLClientState::MATRIXINDEX_LOCATION);
190 break;
191 }
192 case GL_WEIGHT_ARRAY_POINTER_OES: {
193 state = getState(GLClientState::WEIGHT_LOCATION);
194 break;
195 }
196 }
197 if (state && params)
198 *params = state->data;
199 }
200
setPixelStore(GLenum param,GLint value)201 int GLClientState::setPixelStore(GLenum param, GLint value)
202 {
203 int retval = 0;
204 switch(param) {
205 case GL_UNPACK_ALIGNMENT:
206 if (value == 1 || value == 2 || value == 4 || value == 8) {
207 m_pixelStore.unpack_alignment = value;
208 } else {
209 retval = GL_INVALID_VALUE;
210 }
211 break;
212 case GL_PACK_ALIGNMENT:
213 if (value == 1 || value == 2 || value == 4 || value == 8) {
214 m_pixelStore.pack_alignment = value;
215 } else {
216 retval = GL_INVALID_VALUE;
217 }
218 break;
219 default:
220 retval = GL_INVALID_ENUM;
221 }
222 return retval;
223 }
224
225
226
227
pixelDataSize(GLsizei width,GLsizei height,GLenum format,GLenum type,int pack) const228 size_t GLClientState::pixelDataSize(GLsizei width, GLsizei height, GLenum format, GLenum type, int pack) const
229 {
230 if (width <= 0 || height <= 0) return 0;
231
232 int pixelsize = glUtilsPixelBitSize(format, type) >> 3;
233
234 int alignment = pack ? m_pixelStore.pack_alignment : m_pixelStore.unpack_alignment;
235
236 if (pixelsize == 0 ) {
237 ERR("unknown pixel size: width: %d height: %d format: %d type: %d pack: %d align: %d\n",
238 width, height, format, type, pack, alignment);
239 }
240 size_t linesize = pixelsize * width;
241 size_t aligned_linesize = int(linesize / alignment) * alignment;
242 if (aligned_linesize < linesize) {
243 aligned_linesize += alignment;
244 }
245 return aligned_linesize * height;
246 }
247
setActiveTextureUnit(GLenum texture)248 GLenum GLClientState::setActiveTextureUnit(GLenum texture)
249 {
250 GLuint unit = texture - GL_TEXTURE0;
251 if (unit >= MAX_TEXTURE_UNITS) {
252 return GL_INVALID_ENUM;
253 }
254 m_tex.activeUnit = &m_tex.unit[unit];
255 return GL_NO_ERROR;
256 }
257
getActiveTextureUnit() const258 GLenum GLClientState::getActiveTextureUnit() const
259 {
260 return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
261 }
262
enableTextureTarget(GLenum target)263 void GLClientState::enableTextureTarget(GLenum target)
264 {
265 switch (target) {
266 case GL_TEXTURE_2D:
267 m_tex.activeUnit->enables |= (1u << TEXTURE_2D);
268 break;
269 case GL_TEXTURE_EXTERNAL_OES:
270 m_tex.activeUnit->enables |= (1u << TEXTURE_EXTERNAL);
271 break;
272 }
273 }
274
disableTextureTarget(GLenum target)275 void GLClientState::disableTextureTarget(GLenum target)
276 {
277 switch (target) {
278 case GL_TEXTURE_2D:
279 m_tex.activeUnit->enables &= ~(1u << TEXTURE_2D);
280 break;
281 case GL_TEXTURE_EXTERNAL_OES:
282 m_tex.activeUnit->enables &= ~(1u << TEXTURE_EXTERNAL);
283 break;
284 }
285 }
286
getPriorityEnabledTarget(GLenum allDisabled) const287 GLenum GLClientState::getPriorityEnabledTarget(GLenum allDisabled) const
288 {
289 unsigned int enables = m_tex.activeUnit->enables;
290 if (enables & (1u << TEXTURE_EXTERNAL)) {
291 return GL_TEXTURE_EXTERNAL_OES;
292 } else if (enables & (1u << TEXTURE_2D)) {
293 return GL_TEXTURE_2D;
294 } else {
295 return allDisabled;
296 }
297 }
298
compareTexId(const void * pid,const void * prec)299 int GLClientState::compareTexId(const void* pid, const void* prec)
300 {
301 const GLuint* id = (const GLuint*)pid;
302 const TextureRec* rec = (const TextureRec*)prec;
303 return (GLint)(*id) - (GLint)rec->id;
304 }
305
bindTexture(GLenum target,GLuint texture,GLboolean * firstUse)306 GLenum GLClientState::bindTexture(GLenum target, GLuint texture,
307 GLboolean* firstUse)
308 {
309 GLboolean first = GL_FALSE;
310 TextureRec* texrec = NULL;
311 if (texture != 0) {
312 if (m_tex.textures) {
313 texrec = (TextureRec*)bsearch(&texture, m_tex.textures,
314 m_tex.numTextures, sizeof(TextureRec), compareTexId);
315 }
316 if (!texrec) {
317 if (!(texrec = addTextureRec(texture, target))) {
318 return GL_OUT_OF_MEMORY;
319 }
320 first = GL_TRUE;
321 }
322 if (target != texrec->target) {
323 return GL_INVALID_OPERATION;
324 }
325 }
326
327 switch (target) {
328 case GL_TEXTURE_2D:
329 m_tex.activeUnit->texture[TEXTURE_2D] = texture;
330 break;
331 case GL_TEXTURE_EXTERNAL_OES:
332 m_tex.activeUnit->texture[TEXTURE_EXTERNAL] = texture;
333 break;
334 }
335
336 if (firstUse) {
337 *firstUse = first;
338 }
339
340 return GL_NO_ERROR;
341 }
342
addTextureRec(GLuint id,GLenum target)343 GLClientState::TextureRec* GLClientState::addTextureRec(GLuint id,
344 GLenum target)
345 {
346 if (m_tex.numTextures == m_tex.allocTextures) {
347 const GLuint MAX_TEXTURES = 0xFFFFFFFFu;
348
349 GLuint newAlloc;
350 if (MAX_TEXTURES - m_tex.allocTextures >= m_tex.allocTextures) {
351 newAlloc = MAX(4, 2 * m_tex.allocTextures);
352 } else {
353 if (m_tex.allocTextures == MAX_TEXTURES) {
354 return NULL;
355 }
356 newAlloc = MAX_TEXTURES;
357 }
358
359 TextureRec* newTextures = (TextureRec*)realloc(m_tex.textures,
360 newAlloc * sizeof(TextureRec));
361 if (!newTextures) {
362 return NULL;
363 }
364
365 m_tex.textures = newTextures;
366 m_tex.allocTextures = newAlloc;
367 }
368
369 TextureRec* tex = m_tex.textures + m_tex.numTextures;
370 TextureRec* prev = tex - 1;
371 while (tex != m_tex.textures && id < prev->id) {
372 *tex-- = *prev--;
373 }
374 tex->id = id;
375 tex->target = target;
376 m_tex.numTextures++;
377
378 return tex;
379 }
380
getBoundTexture(GLenum target) const381 GLuint GLClientState::getBoundTexture(GLenum target) const
382 {
383 switch (target) {
384 case GL_TEXTURE_2D:
385 return m_tex.activeUnit->texture[TEXTURE_2D];
386 case GL_TEXTURE_EXTERNAL_OES:
387 return m_tex.activeUnit->texture[TEXTURE_EXTERNAL];
388 default:
389 return 0;
390 }
391 }
392
deleteTextures(GLsizei n,const GLuint * textures)393 void GLClientState::deleteTextures(GLsizei n, const GLuint* textures)
394 {
395 // Updating the textures array could be made more efficient when deleting
396 // several textures:
397 // - compacting the array could be done in a single pass once the deleted
398 // textures are marked, or
399 // - could swap deleted textures to the end and re-sort.
400 TextureRec* texrec;
401 for (const GLuint* texture = textures; texture != textures + n; texture++) {
402 texrec = (TextureRec*)bsearch(texture, m_tex.textures,
403 m_tex.numTextures, sizeof(TextureRec), compareTexId);
404 if (texrec) {
405 const TextureRec* end = m_tex.textures + m_tex.numTextures;
406 memmove(texrec, texrec + 1,
407 (end - texrec - 1) * sizeof(TextureRec));
408 m_tex.numTextures--;
409
410 for (TextureUnit* unit = m_tex.unit;
411 unit != m_tex.unit + MAX_TEXTURE_UNITS;
412 unit++)
413 {
414 if (unit->texture[TEXTURE_2D] == *texture) {
415 unit->texture[TEXTURE_2D] = 0;
416 } else if (unit->texture[TEXTURE_EXTERNAL] == *texture) {
417 unit->texture[TEXTURE_EXTERNAL] = 0;
418 }
419 }
420 }
421 }
422 }
423