OSDN Git Service

Merge aosp/master fixes into lmp-dev
[android-x86/device-generic-goldfish-opengl.git] / shared / OpenglCodecCommon / GLClientState.cpp
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
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
69 GLClientState::~GLClientState()
70 {
71     delete m_states;
72 }
73
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
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
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
107 const GLClientState::VertexAttribState * GLClientState::getState(int location)
108 {
109     if (!validLocation(location)) {
110         return NULL;
111     }
112     return & m_states[location];
113 }
114
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
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
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
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
225 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
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
255 GLenum GLClientState::getActiveTextureUnit() const
256 {
257     return GL_TEXTURE0 + (m_tex.activeUnit - &m_tex.unit[0]);
258 }
259
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
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
284 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
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
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
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
378 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
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 }