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