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