• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright 2006, 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 
17 #include <stdlib.h>
18 #include <stdio.h>
19 
20 #include "context.h"
21 #include "fp.h"
22 #include "state.h"
23 #include "matrix.h"
24 #include "vertex.h"
25 #include "light.h"
26 #include "primitives.h"
27 #include "texture.h"
28 #include "BufferObjectManager.h"
29 
30 // ----------------------------------------------------------------------------
31 
32 #define VC_CACHE_STATISTICS     0
33 #define VC_CACHE_TYPE_NONE      0
34 #define VC_CACHE_TYPE_INDEXED   1
35 #define VC_CACHE_TYPE_LRU       2
36 #define VC_CACHE_TYPE           VC_CACHE_TYPE_INDEXED
37 
38 #if VC_CACHE_STATISTICS
39 #include <utils/Timers.h>
40 #endif
41 
42 // ----------------------------------------------------------------------------
43 
44 namespace android {
45 
46 static void validate_arrays(ogles_context_t* c, GLenum mode);
47 
48 static void compileElements__generic(ogles_context_t*,
49         vertex_t*, GLint, GLsizei);
50 static void compileElement__generic(ogles_context_t*,
51         vertex_t*, GLint);
52 
53 static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei);
54 static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei);
55 static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei);
56 static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei);
57 static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei);
58 static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei);
59 static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei);
60 
61 static void drawIndexedPrimitivesPoints(ogles_context_t*,
62         GLsizei, const GLvoid*);
63 static void drawIndexedPrimitivesLineStrip(ogles_context_t*,
64         GLsizei, const GLvoid*);
65 static void drawIndexedPrimitivesLineLoop(ogles_context_t*,
66         GLsizei, const GLvoid*);
67 static void drawIndexedPrimitivesLines(ogles_context_t*,
68         GLsizei, const GLvoid*);
69 static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*,
70         GLsizei, const GLvoid*);
71 static void drawIndexedPrimitivesTriangleFan(ogles_context_t*,
72         GLsizei, const GLvoid*);
73 static void drawIndexedPrimitivesTriangles(ogles_context_t*,
74         GLsizei, const GLvoid*);
75 
76 // ----------------------------------------------------------------------------
77 
78 typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei);
79 static const arrays_prims_fct_t drawArraysPrims[] = {
80     drawPrimitivesPoints,
81     drawPrimitivesLines,
82     drawPrimitivesLineLoop,
83     drawPrimitivesLineStrip,
84     drawPrimitivesTriangles,
85     drawPrimitivesTriangleStrip,
86     drawPrimitivesTriangleFan
87 };
88 
89 typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*);
90 static const elements_prims_fct_t drawElementsPrims[] = {
91     drawIndexedPrimitivesPoints,
92     drawIndexedPrimitivesLines,
93     drawIndexedPrimitivesLineLoop,
94     drawIndexedPrimitivesLineStrip,
95     drawIndexedPrimitivesTriangles,
96     drawIndexedPrimitivesTriangleStrip,
97     drawIndexedPrimitivesTriangleFan
98 };
99 
100 // ----------------------------------------------------------------------------
101 #if 0
102 #pragma mark -
103 #endif
104 
ogles_init_array(ogles_context_t * c)105 void ogles_init_array(ogles_context_t* c)
106 {
107     c->arrays.vertex.size = 4;
108     c->arrays.vertex.type = GL_FLOAT;
109     c->arrays.color.size = 4;
110     c->arrays.color.type = GL_FLOAT;
111     c->arrays.normal.size = 4;
112     c->arrays.normal.type = GL_FLOAT;
113     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
114         c->arrays.texture[i].size = 4;
115         c->arrays.texture[i].type = GL_FLOAT;
116     }
117     c->vc.init();
118 
119     if (!c->vc.vBuffer) {
120         // this could have failed
121         ogles_error(c, GL_OUT_OF_MEMORY);
122     }
123 }
124 
ogles_uninit_array(ogles_context_t * c)125 void ogles_uninit_array(ogles_context_t* c)
126 {
127     c->vc.uninit();
128 }
129 
130 // ----------------------------------------------------------------------------
131 #if 0
132 #pragma mark -
133 #pragma mark Array fetchers
134 #endif
135 
currentColor(ogles_context_t * c,GLfixed * v,const GLvoid *)136 static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
137     memcpy(v, c->current.color.v, sizeof(vec4_t));
138 }
currentColor_clamp(ogles_context_t * c,GLfixed * v,const GLvoid *)139 static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
140     memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
141 }
currentNormal(ogles_context_t * c,GLfixed * v,const GLvoid *)142 static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
143     memcpy(v, c->currentNormal.v, sizeof(vec3_t));
144 }
currentTexCoord(ogles_context_t * c,GLfixed * v,const GLvoid *)145 static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) {
146     memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t));
147 }
148 
149 
fetchNop(ogles_context_t *,GLfixed *,const GLvoid *)150 static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
151 }
fetch2b(ogles_context_t *,GLfixed * v,const GLbyte * p)152 static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
153     v[0] = gglIntToFixed(p[0]);
154     v[1] = gglIntToFixed(p[1]);
155 }
fetch2s(ogles_context_t *,GLfixed * v,const GLshort * p)156 static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) {
157     v[0] = gglIntToFixed(p[0]);
158     v[1] = gglIntToFixed(p[1]);
159 }
fetch2x(ogles_context_t *,GLfixed * v,const GLfixed * p)160 static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
161     memcpy(v, p, 2*sizeof(GLfixed));
162 }
fetch2f(ogles_context_t *,GLfixed * v,const GLfloat * p)163 static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
164     v[0] = gglFloatToFixed(p[0]);
165     v[1] = gglFloatToFixed(p[1]);
166 }
fetch3b(ogles_context_t *,GLfixed * v,const GLbyte * p)167 static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
168     v[0] = gglIntToFixed(p[0]);
169     v[1] = gglIntToFixed(p[1]);
170     v[2] = gglIntToFixed(p[2]);
171 }
fetch3s(ogles_context_t *,GLfixed * v,const GLshort * p)172 static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
173     v[0] = gglIntToFixed(p[0]);
174     v[1] = gglIntToFixed(p[1]);
175     v[2] = gglIntToFixed(p[2]);
176 }
fetch3x(ogles_context_t *,GLfixed * v,const GLfixed * p)177 static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
178     memcpy(v, p, 3*sizeof(GLfixed));
179 }
fetch3f(ogles_context_t *,GLfixed * v,const GLfloat * p)180 static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
181     v[0] = gglFloatToFixed(p[0]);
182     v[1] = gglFloatToFixed(p[1]);
183     v[2] = gglFloatToFixed(p[2]);
184 }
fetch4b(ogles_context_t *,GLfixed * v,const GLbyte * p)185 static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
186     v[0] = gglIntToFixed(p[0]);
187     v[1] = gglIntToFixed(p[1]);
188     v[2] = gglIntToFixed(p[2]);
189     v[3] = gglIntToFixed(p[3]);
190 }
fetch4s(ogles_context_t *,GLfixed * v,const GLshort * p)191 static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) {
192     v[0] = gglIntToFixed(p[0]);
193     v[1] = gglIntToFixed(p[1]);
194     v[2] = gglIntToFixed(p[2]);
195     v[3] = gglIntToFixed(p[3]);
196 }
fetch4x(ogles_context_t *,GLfixed * v,const GLfixed * p)197 static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
198     memcpy(v, p, 4*sizeof(GLfixed));
199 }
fetch4f(ogles_context_t *,GLfixed * v,const GLfloat * p)200 static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
201     v[0] = gglFloatToFixed(p[0]);
202     v[1] = gglFloatToFixed(p[1]);
203     v[2] = gglFloatToFixed(p[2]);
204     v[3] = gglFloatToFixed(p[3]);
205 }
fetchExpand4ub(ogles_context_t *,GLfixed * v,const GLubyte * p)206 static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
207     v[0] = GGL_UB_TO_X(p[0]);
208     v[1] = GGL_UB_TO_X(p[1]);
209     v[2] = GGL_UB_TO_X(p[2]);
210     v[3] = GGL_UB_TO_X(p[3]);
211 }
fetchClamp4x(ogles_context_t *,GLfixed * v,const GLfixed * p)212 static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
213     v[0] = gglClampx(p[0]);
214     v[1] = gglClampx(p[1]);
215     v[2] = gglClampx(p[2]);
216     v[3] = gglClampx(p[3]);
217 }
fetchClamp4f(ogles_context_t *,GLfixed * v,const GLfloat * p)218 static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
219     v[0] = gglClampx(gglFloatToFixed(p[0]));
220     v[1] = gglClampx(gglFloatToFixed(p[1]));
221     v[2] = gglClampx(gglFloatToFixed(p[2]));
222     v[3] = gglClampx(gglFloatToFixed(p[3]));
223 }
fetchExpand3ub(ogles_context_t *,GLfixed * v,const GLubyte * p)224 static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
225     v[0] = GGL_UB_TO_X(p[0]);
226     v[1] = GGL_UB_TO_X(p[1]);
227     v[2] = GGL_UB_TO_X(p[2]);
228     v[3] = 0x10000;
229 }
fetchClamp3x(ogles_context_t *,GLfixed * v,const GLfixed * p)230 static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
231     v[0] = gglClampx(p[0]);
232     v[1] = gglClampx(p[1]);
233     v[2] = gglClampx(p[2]);
234     v[3] = 0x10000;
235 }
fetchClamp3f(ogles_context_t *,GLfixed * v,const GLfloat * p)236 static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
237     v[0] = gglClampx(gglFloatToFixed(p[0]));
238     v[1] = gglClampx(gglFloatToFixed(p[1]));
239     v[2] = gglClampx(gglFloatToFixed(p[2]));
240     v[3] = 0x10000;
241 }
fetchExpand3b(ogles_context_t *,GLfixed * v,const GLbyte * p)242 static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
243     v[0] = GGL_B_TO_X(p[0]);
244     v[1] = GGL_B_TO_X(p[1]);
245     v[2] = GGL_B_TO_X(p[2]);
246 }
fetchExpand3s(ogles_context_t *,GLfixed * v,const GLshort * p)247 static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
248     v[0] = GGL_S_TO_X(p[0]);
249     v[1] = GGL_S_TO_X(p[1]);
250     v[2] = GGL_S_TO_X(p[2]);
251 }
252 
253 typedef array_t::fetcher_t fn_t;
254 
255 static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
256     { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
257          (fn_t)fetch3f, 0, 0, 0, 0, 0,
258          (fn_t)fetch3x },
259     { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
260          (fn_t)fetch4f, 0, 0, 0, 0, 0,
261          (fn_t)fetch4x },
262 };
263 static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x}
264     { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
265          (fn_t)fetchClamp3f, 0, 0, 0, 0, 0,
266          (fn_t)fetchClamp3x },
267     { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
268          (fn_t)fetchClamp4f, 0, 0, 0, 0, 0,
269          (fn_t)fetchClamp4x },
270 };
271 static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x}
272     { (fn_t)fetchExpand3b, 0,
273       (fn_t)fetchExpand3s, 0, 0, 0,
274       (fn_t)fetch3f, 0, 0, 0, 0, 0,
275       (fn_t)fetch3x },
276 };
277 static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
278     { (fn_t)fetch2b, 0,
279       (fn_t)fetch2s, 0, 0, 0,
280       (fn_t)fetch2f, 0, 0, 0, 0, 0,
281       (fn_t)fetch3x },
282     { (fn_t)fetch3b, 0,
283       (fn_t)fetch3s, 0, 0, 0,
284       (fn_t)fetch3f, 0, 0, 0, 0, 0,
285       (fn_t)fetch3x },
286     { (fn_t)fetch4b, 0,
287       (fn_t)fetch4s, 0, 0, 0,
288       (fn_t)fetch4f, 0, 0, 0, 0, 0,
289       (fn_t)fetch4x }
290 };
291 static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
292     { (fn_t)fetch2b, 0,
293       (fn_t)fetch2s, 0, 0, 0,
294       (fn_t)fetch2f, 0, 0, 0, 0, 0,
295       (fn_t)fetch2x },
296     { (fn_t)fetch3b, 0,
297       (fn_t)fetch3s, 0, 0, 0,
298       (fn_t)fetch3f, 0, 0, 0, 0, 0,
299       (fn_t)fetch3x },
300     { (fn_t)fetch4b, 0,
301       (fn_t)fetch4s, 0, 0, 0,
302       (fn_t)fetch4f, 0, 0, 0, 0, 0,
303       (fn_t)fetch4x }
304 };
305 
306 // ----------------------------------------------------------------------------
307 #if 0
308 #pragma mark -
309 #pragma mark array_t
310 #endif
311 
init(GLint size,GLenum type,GLsizei stride,const GLvoid * pointer,const buffer_t * bo,GLsizei count)312 void array_t::init(
313         GLint size, GLenum type, GLsizei stride,
314         const GLvoid *pointer, const buffer_t* bo, GLsizei count)
315 {
316     if (!stride) {
317         stride = size;
318         switch (type) {
319         case GL_SHORT:
320         case GL_UNSIGNED_SHORT:
321             stride *= 2;
322             break;
323         case GL_FLOAT:
324         case GL_FIXED:
325             stride *= 4;
326             break;
327         }
328     }
329     this->size = size;
330     this->type = type;
331     this->stride = stride;
332     this->pointer = pointer;
333     this->bo = bo;
334     this->bounds = count;
335 }
336 
resolve()337 inline void array_t::resolve()
338 {
339     physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
340 }
341 
342 // ----------------------------------------------------------------------------
343 #if 0
344 #pragma mark -
345 #pragma mark vertex_cache_t
346 #endif
347 
init()348 void vertex_cache_t::init()
349 {
350     // make sure the size of vertex_t allows cache-line alignment
351     CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
352 
353     const int align = 32;
354     const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
355     const size_t size = s*sizeof(vertex_t) + align;
356     base = malloc(size);
357     if (base) {
358         memset(base, 0, size);
359         vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1));
360         vCache = vBuffer + VERTEX_BUFFER_SIZE;
361         sequence = 0;
362     }
363 }
364 
uninit()365 void vertex_cache_t::uninit()
366 {
367     free(base);
368     base = vBuffer = vCache = 0;
369 }
370 
clear()371 void vertex_cache_t::clear()
372 {
373 #if VC_CACHE_STATISTICS
374     startTime = systemTime(SYSTEM_TIME_THREAD);
375     total = 0;
376     misses = 0;
377 #endif
378 
379 #if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
380     vertex_t* v = vBuffer;
381     size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
382     do {
383         v->mru = 0;
384         v++;
385     } while (--count);
386 #endif
387 
388     sequence += INDEX_SEQ;
389     if (sequence >= 0x80000000LU) {
390         sequence = INDEX_SEQ;
391         vertex_t* v = vBuffer;
392         size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
393         do {
394             v->index = 0;
395             v++;
396         } while (--count);
397     }
398 }
399 
dump_stats(GLenum mode)400 void vertex_cache_t::dump_stats(GLenum mode)
401 {
402 #if VC_CACHE_STATISTICS
403     nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
404     uint32_t hits = total - misses;
405     uint32_t prim_count;
406     switch (mode) {
407     case GL_POINTS:             prim_count = total;         break;
408     case GL_LINE_STRIP:         prim_count = total - 1;     break;
409     case GL_LINE_LOOP:          prim_count = total - 1;     break;
410     case GL_LINES:              prim_count = total / 2;     break;
411     case GL_TRIANGLE_STRIP:     prim_count = total - 2;     break;
412     case GL_TRIANGLE_FAN:       prim_count = total - 2;     break;
413     case GL_TRIANGLES:          prim_count = total / 3;     break;
414     default:    return;
415     }
416     printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%,"
417             " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n",
418             total, hits, misses, (hits*100)/total,
419             prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
420             float(misses) / prim_count);
421 #endif
422 }
423 
424 // ----------------------------------------------------------------------------
425 #if 0
426 #pragma mark -
427 #endif
428 
429 static __attribute__((noinline))
enableDisableClientState(ogles_context_t * c,GLenum array,bool enable)430 void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
431 {
432     const int tmu = c->arrays.activeTexture;
433     array_t* a;
434     switch (array) {
435     case GL_COLOR_ARRAY:            a = &c->arrays.color;           break;
436     case GL_NORMAL_ARRAY:           a = &c->arrays.normal;          break;
437     case GL_TEXTURE_COORD_ARRAY:    a = &c->arrays.texture[tmu];    break;
438     case GL_VERTEX_ARRAY:           a = &c->arrays.vertex;          break;
439     default:
440         ogles_error(c, GL_INVALID_ENUM);
441         return;
442     }
443     a->enable = enable ? GL_TRUE : GL_FALSE;
444 }
445 
446 // ----------------------------------------------------------------------------
447 #if 0
448 #pragma mark -
449 #pragma mark Vertex Cache
450 #endif
451 
452 static __attribute__((noinline))
cache_vertex(ogles_context_t * c,vertex_t * v,uint32_t index)453 vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
454 {
455     #if VC_CACHE_STATISTICS
456         c->vc.misses++;
457     #endif
458     if (ggl_unlikely(v->locked)) {
459         // we're just looking for an entry in the cache that is not locked.
460         // and we know that there cannot be more than 2 locked entries
461         // because a triangle needs at most 3 vertices.
462         // We never use the first and second entries because they might be in
463         // use by the striper or faner. Any other entry will do as long as
464         // it's not locked.
465         // We compute directly the index of a "free" entry from the locked
466         // state of v[2] and v[3].
467         v = c->vc.vBuffer + 2;
468         v += v[0].locked | (v[1].locked<<1);
469     }
470     // note: compileElement clears v->flags
471     c->arrays.compileElement(c, v, index);
472     v->locked = 1;
473     return v;
474 }
475 
476 static __attribute__((noinline))
fetch_vertex(ogles_context_t * c,size_t index)477 vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
478 {
479     index |= c->vc.sequence;
480 
481 #if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
482 
483     vertex_t* const v = c->vc.vCache +
484             (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
485 
486     if (ggl_likely(v->index == index)) {
487         v->locked = 1;
488         return v;
489     }
490     return cache_vertex(c, v, index);
491 
492 #elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
493 
494     vertex_t* v = c->vc.vCache +
495             (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
496 
497     // always record LRU in v[0]
498     if (ggl_likely(v[0].index == index)) {
499         v[0].locked = 1;
500         v[0].mru = 0;
501         return &v[0];
502     }
503 
504     if (ggl_likely(v[1].index == index)) {
505         v[1].locked = 1;
506         v[0].mru = 1;
507         return &v[1];
508     }
509 
510     const int lru = 1 - v[0].mru;
511     v[0].mru = lru;
512     return cache_vertex(c, &v[lru], index);
513 
514 #elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
515 
516     // just for debugging...
517     vertex_t* v = c->vc.vBuffer + 2;
518     return cache_vertex(c, v, index);
519 
520 #endif
521 }
522 
523 // ----------------------------------------------------------------------------
524 #if 0
525 #pragma mark -
526 #pragma mark Primitive Assembly
527 #endif
528 
drawPrimitivesPoints(ogles_context_t * c,GLint first,GLsizei count)529 void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
530 {
531     if (ggl_unlikely(count < 1))
532         return;
533 
534     // vertex cache size must be multiple of 1
535     const GLsizei vcs =
536             (vertex_cache_t::VERTEX_BUFFER_SIZE +
537              vertex_cache_t::VERTEX_CACHE_SIZE);
538     do {
539         vertex_t* v = c->vc.vBuffer;
540         GLsizei num = count > vcs ? vcs : count;
541         c->arrays.cull = vertex_t::CLIP_ALL;
542         c->arrays.compileElements(c, v, first, num);
543         first += num;
544         count -= num;
545         if (!c->arrays.cull) {
546             // quick/trivial reject of the whole batch
547             do {
548                 const uint32_t cc = v[0].flags;
549                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
550                     c->prims.renderPoint(c, v);
551                 v++;
552                 num--;
553             } while (num);
554         }
555     } while (count);
556 }
557 
558 // ----------------------------------------------------------------------------
559 
drawPrimitivesLineStrip(ogles_context_t * c,GLint first,GLsizei count)560 void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
561 {
562     if (ggl_unlikely(count < 2))
563         return;
564 
565     vertex_t *v, *v0, *v1;
566     c->arrays.cull = vertex_t::CLIP_ALL;
567     c->arrays.compileElement(c, c->vc.vBuffer, first);
568     first += 1;
569     count -= 1;
570 
571     // vertex cache size must be multiple of 1
572     const GLsizei vcs =
573         (vertex_cache_t::VERTEX_BUFFER_SIZE +
574          vertex_cache_t::VERTEX_CACHE_SIZE - 1);
575     do {
576         v0 = c->vc.vBuffer + 0;
577         v  = c->vc.vBuffer + 1;
578         GLsizei num = count > vcs ? vcs : count;
579         c->arrays.compileElements(c, v, first, num);
580         first += num;
581         count -= num;
582         if (!c->arrays.cull) {
583             // quick/trivial reject of the whole batch
584             do {
585                 v1 = v++;
586                 const uint32_t cc = v0->flags & v1->flags;
587                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
588                     c->prims.renderLine(c, v0, v1);
589                 v0 = v1;
590                 num--;
591             } while (num);
592         }
593         // copy back the last processed vertex
594         c->vc.vBuffer[0] = *v0;
595         c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
596     } while (count);
597 }
598 
drawPrimitivesLineLoop(ogles_context_t * c,GLint first,GLsizei count)599 void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
600 {
601     if (ggl_unlikely(count < 2))
602         return;
603     drawPrimitivesLineStrip(c, first, count);
604     if (ggl_likely(count >= 3)) {
605         vertex_t* v0 = c->vc.vBuffer;
606         vertex_t* v1 = c->vc.vBuffer + 1;
607         c->arrays.compileElement(c, v1, first);
608         const uint32_t cc = v0->flags & v1->flags;
609         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
610             c->prims.renderLine(c, v0, v1);
611     }
612 }
613 
drawPrimitivesLines(ogles_context_t * c,GLint first,GLsizei count)614 void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
615 {
616     if (ggl_unlikely(count < 2))
617         return;
618 
619     // vertex cache size must be multiple of 2
620     const GLsizei vcs =
621         ((vertex_cache_t::VERTEX_BUFFER_SIZE +
622         vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
623     do {
624         vertex_t* v = c->vc.vBuffer;
625         GLsizei num = count > vcs ? vcs : count;
626         c->arrays.cull = vertex_t::CLIP_ALL;
627         c->arrays.compileElements(c, v, first, num);
628         first += num;
629         count -= num;
630         if (!c->arrays.cull) {
631             // quick/trivial reject of the whole batch
632             num -= 2;
633             do {
634                 const uint32_t cc = v[0].flags & v[1].flags;
635                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
636                     c->prims.renderLine(c, v, v+1);
637                 v += 2;
638                 num -= 2;
639             } while (num >= 0);
640         }
641     } while (count >= 2);
642 }
643 
644 // ----------------------------------------------------------------------------
645 
drawPrimitivesTriangleFanOrStrip(ogles_context_t * c,GLint first,GLsizei count,int winding)646 static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
647         GLint first, GLsizei count, int winding)
648 {
649     // winding == 2 : fan
650     // winding == 1 : strip
651 
652     if (ggl_unlikely(count < 3))
653         return;
654 
655     vertex_t *v, *v0, *v1, *v2;
656     c->arrays.cull = vertex_t::CLIP_ALL;
657     c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
658     first += 2;
659     count -= 2;
660 
661     // vertex cache size must be multiple of 2. This is extremely important
662     // because it allows us to preserve the same winding when the whole
663     // batch is culled. We also need 2 extra vertices in the array, because
664     // we always keep the two first ones.
665     const GLsizei vcs =
666         ((vertex_cache_t::VERTEX_BUFFER_SIZE +
667           vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
668     do {
669         v0 = c->vc.vBuffer + 0;
670         v1 = c->vc.vBuffer + 1;
671         v  = c->vc.vBuffer + 2;
672         GLsizei num = count > vcs ? vcs : count;
673         c->arrays.compileElements(c, v, first, num);
674         first += num;
675         count -= num;
676         if (!c->arrays.cull) {
677             // quick/trivial reject of the whole batch
678             do {
679                 v2 = v++;
680                 const uint32_t cc = v0->flags & v1->flags & v2->flags;
681                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
682                     c->prims.renderTriangle(c, v0, v1, v2);
683                 swap(((winding^=1) ? v1 : v0), v2);
684                 num--;
685             } while (num);
686         }
687         if (count) {
688             v0 = c->vc.vBuffer + 2 + vcs - 2;
689             v1 = c->vc.vBuffer + 2 + vcs - 1;
690             if ((winding&2) == 0) {
691                 // for strips copy back the two last compiled vertices
692                 c->vc.vBuffer[0] = *v0;
693             }
694             c->vc.vBuffer[1] = *v1;
695             c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
696         }
697     } while (count > 0);
698 }
699 
drawPrimitivesTriangleStrip(ogles_context_t * c,GLint first,GLsizei count)700 void drawPrimitivesTriangleStrip(ogles_context_t* c,
701         GLint first, GLsizei count) {
702     drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
703 }
704 
drawPrimitivesTriangleFan(ogles_context_t * c,GLint first,GLsizei count)705 void drawPrimitivesTriangleFan(ogles_context_t* c,
706         GLint first, GLsizei count) {
707     drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
708 }
709 
drawPrimitivesTriangles(ogles_context_t * c,GLint first,GLsizei count)710 void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
711 {
712     if (ggl_unlikely(count < 3))
713         return;
714 
715     // vertex cache size must be multiple of 3
716     const GLsizei vcs =
717         ((vertex_cache_t::VERTEX_BUFFER_SIZE +
718         vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
719     do {
720         vertex_t* v = c->vc.vBuffer;
721         GLsizei num = count > vcs ? vcs : count;
722         c->arrays.cull = vertex_t::CLIP_ALL;
723         c->arrays.compileElements(c, v, first, num);
724         first += num;
725         count -= num;
726         if (!c->arrays.cull) {
727             // quick/trivial reject of the whole batch
728             num -= 3;
729             do {
730                 const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
731                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
732                     c->prims.renderTriangle(c, v, v+1, v+2);
733                 v += 3;
734                 num -= 3;
735             } while (num >= 0);
736         }
737     } while (count >= 3);
738 }
739 
740 // ----------------------------------------------------------------------------
741 #if 0
742 #pragma mark -
743 #endif
744 
745 // this looks goofy, but gcc does a great job with this...
read_index(int type,const GLvoid * & p)746 static inline unsigned int read_index(int type, const GLvoid*& p) {
747     unsigned int r;
748     if (type) {
749         r = *(const GLubyte*)p;
750         p = (const GLubyte*)p + 1;
751     } else {
752         r = *(const GLushort*)p;
753         p = (const GLushort*)p + 1;
754     }
755     return r;
756 }
757 
758 // ----------------------------------------------------------------------------
759 
drawIndexedPrimitivesPoints(ogles_context_t * c,GLsizei count,const GLvoid * indices)760 void drawIndexedPrimitivesPoints(ogles_context_t* c,
761         GLsizei count, const GLvoid *indices)
762 {
763     if (ggl_unlikely(count < 1))
764         return;
765     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
766     do {
767         vertex_t * v = fetch_vertex(c, read_index(type, indices));
768         if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
769             c->prims.renderPoint(c, v);
770         v->locked = 0;
771         count--;
772     } while(count);
773 }
774 
775 // ----------------------------------------------------------------------------
776 
drawIndexedPrimitivesLineStrip(ogles_context_t * c,GLsizei count,const GLvoid * indices)777 void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
778         GLsizei count, const GLvoid *indices)
779 {
780     if (ggl_unlikely(count < 2))
781         return;
782 
783     vertex_t * const v = c->vc.vBuffer;
784     vertex_t* v0 = v;
785     vertex_t* v1;
786 
787     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
788     c->arrays.compileElement(c, v0, read_index(type, indices));
789     count -= 1;
790     do {
791         v1 = fetch_vertex(c, read_index(type, indices));
792         const uint32_t cc = v0->flags & v1->flags;
793         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
794             c->prims.renderLine(c, v0, v1);
795         v0->locked = 0;
796         v0 = v1;
797         count--;
798     } while (count);
799     v1->locked = 0;
800 }
801 
drawIndexedPrimitivesLineLoop(ogles_context_t * c,GLsizei count,const GLvoid * indices)802 void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
803         GLsizei count, const GLvoid *indices)
804 {
805     if (ggl_unlikely(count <= 2)) {
806         drawIndexedPrimitivesLines(c, count, indices);
807         return;
808     }
809 
810     vertex_t * const v = c->vc.vBuffer;
811     vertex_t* v0 = v;
812     vertex_t* v1;
813 
814     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
815     c->arrays.compileElement(c, v0, read_index(type, indices));
816     count -= 1;
817     do {
818         v1 = fetch_vertex(c, read_index(type, indices));
819         const uint32_t cc = v0->flags & v1->flags;
820         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
821             c->prims.renderLine(c, v0, v1);
822         v0->locked = 0;
823         v0 = v1;
824         count--;
825     } while (count);
826     v1->locked = 0;
827 
828     v1 = c->vc.vBuffer;
829     const uint32_t cc = v0->flags & v1->flags;
830     if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
831         c->prims.renderLine(c, v0, v1);
832 }
833 
drawIndexedPrimitivesLines(ogles_context_t * c,GLsizei count,const GLvoid * indices)834 void drawIndexedPrimitivesLines(ogles_context_t* c,
835         GLsizei count, const GLvoid *indices)
836 {
837     if (ggl_unlikely(count < 2))
838         return;
839 
840     count -= 2;
841     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
842     do {
843         vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
844         vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
845         const uint32_t cc = v0->flags & v1->flags;
846         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
847             c->prims.renderLine(c, v0, v1);
848         v0->locked = 0;
849         v1->locked = 0;
850         count -= 2;
851     } while (count >= 0);
852 }
853 
854 // ----------------------------------------------------------------------------
855 
drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t * c,GLsizei count,const GLvoid * indices,int winding)856 static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
857         GLsizei count, const GLvoid *indices, int winding)
858 {
859     // winding == 2 : fan
860     // winding == 1 : strip
861 
862     if (ggl_unlikely(count < 3))
863         return;
864 
865     vertex_t * const v = c->vc.vBuffer;
866     vertex_t* v0 = v;
867     vertex_t* v1 = v+1;
868     vertex_t* v2;
869 
870     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
871     c->arrays.compileElement(c, v0, read_index(type, indices));
872     c->arrays.compileElement(c, v1, read_index(type, indices));
873     count -= 2;
874 
875     // note: GCC 4.1.1 here makes a prety interesting optimization
876     // where it duplicates the loop below based on c->arrays.indicesType
877 
878     do {
879         v2 = fetch_vertex(c, read_index(type, indices));
880         const uint32_t cc = v0->flags & v1->flags & v2->flags;
881         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
882             c->prims.renderTriangle(c, v0, v1, v2);
883         vertex_t* & consumed = ((winding^=1) ? v1 : v0);
884         consumed->locked = 0;
885         consumed = v2;
886         count--;
887     } while (count);
888     v0->locked = v1->locked = 0;
889     v2->locked = 0;
890 }
891 
drawIndexedPrimitivesTriangleStrip(ogles_context_t * c,GLsizei count,const GLvoid * indices)892 void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
893         GLsizei count, const GLvoid *indices) {
894     drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
895 }
896 
drawIndexedPrimitivesTriangleFan(ogles_context_t * c,GLsizei count,const GLvoid * indices)897 void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
898         GLsizei count, const GLvoid *indices) {
899     drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
900 }
901 
drawIndexedPrimitivesTriangles(ogles_context_t * c,GLsizei count,const GLvoid * indices)902 void drawIndexedPrimitivesTriangles(ogles_context_t* c,
903         GLsizei count, const GLvoid *indices)
904 {
905     if (ggl_unlikely(count < 3))
906         return;
907 
908     count -= 3;
909     if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
910         // This case is probably our most common case...
911         uint16_t const * p = (uint16_t const *)indices;
912         do {
913             vertex_t* const v0 = fetch_vertex(c, *p++);
914             vertex_t* const v1 = fetch_vertex(c, *p++);
915             vertex_t* const v2 = fetch_vertex(c, *p++);
916             const uint32_t cc = v0->flags & v1->flags & v2->flags;
917             if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
918                 c->prims.renderTriangle(c, v0, v1, v2);
919             v0->locked = 0;
920             v1->locked = 0;
921             v2->locked = 0;
922             count -= 3;
923         } while (count >= 0);
924     } else {
925         uint8_t const * p = (uint8_t const *)indices;
926         do {
927             vertex_t* const v0 = fetch_vertex(c, *p++);
928             vertex_t* const v1 = fetch_vertex(c, *p++);
929             vertex_t* const v2 = fetch_vertex(c, *p++);
930             const uint32_t cc = v0->flags & v1->flags & v2->flags;
931             if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
932                 c->prims.renderTriangle(c, v0, v1, v2);
933             v0->locked = 0;
934             v1->locked = 0;
935             v2->locked = 0;
936             count -= 3;
937         } while (count >= 0);
938     }
939 }
940 
941 // ----------------------------------------------------------------------------
942 #if 0
943 #pragma mark -
944 #pragma mark Array compilers
945 #endif
946 
compileElement__generic(ogles_context_t * c,vertex_t * v,GLint first)947 void compileElement__generic(ogles_context_t* c,
948         vertex_t* v, GLint first)
949 {
950     v->flags = 0;
951     v->index = first;
952     first &= vertex_cache_t::INDEX_MASK;
953     const GLubyte* vp = c->arrays.vertex.element(first);
954     v->obj.z = 0;
955     v->obj.w = 0x10000;
956     c->arrays.vertex.fetch(c, v->obj.v, vp);
957     c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
958     c->arrays.perspective(c, v);
959 }
960 
compileElements__generic(ogles_context_t * c,vertex_t * v,GLint first,GLsizei count)961 void compileElements__generic(ogles_context_t* c,
962         vertex_t* v, GLint first, GLsizei count)
963 {
964     const GLubyte* vp = c->arrays.vertex.element(
965             first & vertex_cache_t::INDEX_MASK);
966     const size_t stride = c->arrays.vertex.stride;
967     transform_t const* const mvp = &c->transforms.mvp;
968     do {
969         v->flags = 0;
970         v->index = first++;
971         v->obj.z = 0;
972         v->obj.w = 0x10000;
973         c->arrays.vertex.fetch(c, v->obj.v, vp);
974         c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
975         c->arrays.perspective(c, v);
976         vp += stride;
977         v++;
978     } while (--count);
979 }
980 
981 /*
982 void compileElements__3x_full(ogles_context_t* c,
983         vertex_t* v, GLint first, GLsizei count)
984 {
985     const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
986     const size_t stride = c->arrays.vertex.stride / 4;
987 //    const GLfixed* const& m = c->transforms.mvp.matrix.m;
988 
989     GLfixed m[16];
990     memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
991 
992     do {
993         const GLfixed rx = vp[0];
994         const GLfixed ry = vp[1];
995         const GLfixed rz = vp[2];
996         vp += stride;
997         v->index = first++;
998         v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
999         v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
1000         v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
1001         v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
1002 
1003         const GLfixed w = v->clip.w;
1004         uint32_t clip = 0;
1005         if (v->clip.x < -w)   clip |= vertex_t::CLIP_L;
1006         if (v->clip.x >  w)   clip |= vertex_t::CLIP_R;
1007         if (v->clip.y < -w)   clip |= vertex_t::CLIP_B;
1008         if (v->clip.y >  w)   clip |= vertex_t::CLIP_T;
1009         if (v->clip.z < -w)   clip |= vertex_t::CLIP_N;
1010         if (v->clip.z >  w)   clip |= vertex_t::CLIP_F;
1011         v->flags = clip;
1012         c->arrays.cull &= clip;
1013 
1014         //c->arrays.perspective(c, v);
1015         v++;
1016     } while (--count);
1017 }
1018 */
1019 
1020 // ----------------------------------------------------------------------------
1021 #if 0
1022 #pragma mark -
1023 #pragma mark clippers
1024 #endif
1025 
clipVec4(vec4_t & nv,GLfixed t,const vec4_t & s,const vec4_t & p)1026 static void clipVec4(vec4_t& nv,
1027         GLfixed t, const vec4_t& s, const vec4_t& p)
1028 {
1029     for (int i=0; i<4 ; i++)
1030         nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
1031 }
1032 
clipVertex(ogles_context_t * c,vertex_t * nv,GLfixed t,const vertex_t * s,const vertex_t * p)1033 static void clipVertex(ogles_context_t* c, vertex_t* nv,
1034         GLfixed t, const vertex_t* s, const vertex_t* p)
1035 {
1036     clipVec4(nv->clip, t, s->clip, p->clip);
1037     nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
1038     ogles_vertex_project(c, nv);
1039     nv->flags |=  vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
1040     nv->flags &= ~vertex_t::CLIP_ALL;
1041 }
1042 
clipVertexC(ogles_context_t * c,vertex_t * nv,GLfixed t,const vertex_t * s,const vertex_t * p)1043 static void clipVertexC(ogles_context_t* c, vertex_t* nv,
1044         GLfixed t, const vertex_t* s, const vertex_t* p)
1045 {
1046     clipVec4(nv->color, t, s->color, p->color);
1047     clipVertex(c, nv, t, s, p);
1048 }
1049 
clipVertexT(ogles_context_t * c,vertex_t * nv,GLfixed t,const vertex_t * s,const vertex_t * p)1050 static void clipVertexT(ogles_context_t* c, vertex_t* nv,
1051         GLfixed t, const vertex_t* s, const vertex_t* p)
1052 {
1053     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1054         if (c->rasterizer.state.texture[i].enable)
1055             clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
1056     }
1057     clipVertex(c, nv, t, s, p);
1058 }
1059 
clipVertexAll(ogles_context_t * c,vertex_t * nv,GLfixed t,const vertex_t * s,const vertex_t * p)1060 static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
1061         GLfixed t, const vertex_t* s, const vertex_t* p)
1062 {
1063     clipVec4(nv->color, t, s->color, p->color);
1064     clipVertexT(c, nv, t, s, p);
1065 }
1066 
clipEye(ogles_context_t * c,vertex_t * nv,GLfixed t,const vertex_t * s,const vertex_t * p)1067 static void clipEye(ogles_context_t* c, vertex_t* nv,
1068         GLfixed t, const vertex_t* s, const vertex_t* p)
1069 {
1070     nv->clear();
1071     c->arrays.clipVertex(c, nv, t, p, s);
1072     clipVec4(nv->eye, t, s->eye, p->eye);
1073 }
1074 
1075 // ----------------------------------------------------------------------------
1076 #if 0
1077 #pragma mark -
1078 #endif
1079 
validate_arrays(ogles_context_t * c,GLenum mode)1080 void validate_arrays(ogles_context_t* c, GLenum mode)
1081 {
1082     uint32_t enables = c->rasterizer.state.enables;
1083 
1084     // Perspective correction is not need if Ortho transform, but
1085     // the user can still provide the w coordinate manually, so we can't
1086     // automatically turn it off (in fact we could when the 4th coordinate
1087     // is not spcified in the vertex array).
1088     // W interpolation is never needed for points.
1089     GLboolean perspective =
1090         c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
1091     c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
1092 
1093     // set anti-aliasing
1094     GLboolean smooth = GL_FALSE;
1095     switch (mode) {
1096     case GL_POINTS:
1097         smooth = c->point.smooth;
1098         break;
1099     case GL_LINES:
1100     case GL_LINE_LOOP:
1101     case GL_LINE_STRIP:
1102         smooth = c->line.smooth;
1103         break;
1104     }
1105     if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
1106         c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
1107 
1108     // set the shade model for this primitive
1109     c->rasterizer.procs.shadeModel(c,
1110             (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
1111 
1112     // compute all the matrices we'll need...
1113     uint32_t want =
1114             transform_state_t::MVP |
1115             transform_state_t::VIEWPORT;
1116     if (c->lighting.enable) { // needs normal transforms and eye coords
1117         want |= transform_state_t::MVUI;
1118         want |= transform_state_t::MODELVIEW;
1119     }
1120     if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
1121         want |= transform_state_t::TEXTURE;
1122     }
1123     if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
1124         want |= transform_state_t::MODELVIEW; // needs eye coords
1125     }
1126     ogles_validate_transform(c, want);
1127 
1128     // textures...
1129     if (enables & GGL_ENABLE_TMUS)
1130         ogles_validate_texture(c);
1131 
1132     // vertex compilers
1133     c->arrays.compileElement = compileElement__generic;
1134     c->arrays.compileElements = compileElements__generic;
1135 
1136     // vertex transform
1137     c->arrays.mvp_transform =
1138         c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
1139 
1140     c->arrays.mv_transform =
1141         c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
1142 
1143     /*
1144      * ***********************************************************************
1145      *  pick fetchers
1146      * ***********************************************************************
1147      */
1148 
1149     array_machine_t& am = c->arrays;
1150     am.vertex.fetch = fetchNop;
1151     am.normal.fetch = currentNormal;
1152     am.color.fetch = currentColor;
1153 
1154     if (am.vertex.enable) {
1155         am.vertex.resolve();
1156         if (am.vertex.bo || am.vertex.pointer) {
1157             am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
1158         }
1159     }
1160 
1161     if (am.normal.enable) {
1162         am.normal.resolve();
1163         if (am.normal.bo || am.normal.pointer) {
1164             am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
1165         }
1166     }
1167 
1168     if (am.color.enable) {
1169         am.color.resolve();
1170         if (c->lighting.enable) {
1171             if (am.color.bo || am.color.pointer) {
1172                 am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
1173             }
1174         } else {
1175             if (am.color.bo || am.color.pointer) {
1176                 am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
1177             }
1178         }
1179     }
1180 
1181     int activeTmuCount = 0;
1182     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1183         am.texture[i].fetch = currentTexCoord;
1184         if (c->rasterizer.state.texture[i].enable) {
1185 
1186             // texture fetchers...
1187             if (am.texture[i].enable) {
1188                 am.texture[i].resolve();
1189                 if (am.texture[i].bo || am.texture[i].pointer) {
1190                     am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
1191                 }
1192             }
1193 
1194             // texture transform...
1195             const int index = c->arrays.texture[i].size - 2;
1196             c->arrays.tex_transform[i] =
1197                 c->transforms.texture[i].transform.pointv[index];
1198 
1199             am.tmu = i;
1200             activeTmuCount++;
1201         }
1202     }
1203 
1204     // pick the vertex-clipper
1205     uint32_t clipper = 0;
1206     // we must reload 'enables' here
1207     enables = c->rasterizer.state.enables;
1208     if (enables & GGL_ENABLE_SMOOTH)
1209         clipper |= 1;   // we need to interpolate colors
1210     if (enables & GGL_ENABLE_TMUS)
1211         clipper |= 2;   // we need to interpolate textures
1212     switch (clipper) {
1213     case 0: c->arrays.clipVertex = clipVertex;      break;
1214     case 1: c->arrays.clipVertex = clipVertexC;     break;
1215     case 2: c->arrays.clipVertex = clipVertexT;     break;
1216     case 3: c->arrays.clipVertex = clipVertexAll;   break;
1217     }
1218     c->arrays.clipEye = clipEye;
1219 
1220     // pick the primitive rasterizer
1221     ogles_validate_primitives(c);
1222 }
1223 
1224 // ----------------------------------------------------------------------------
1225 }; // namespace android
1226 // ----------------------------------------------------------------------------
1227 
1228 using namespace android;
1229 
1230 #if 0
1231 #pragma mark -
1232 #pragma mark array API
1233 #endif
1234 
glVertexPointer(GLint size,GLenum type,GLsizei stride,const GLvoid * pointer)1235 void glVertexPointer(
1236     GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1237 {
1238     ogles_context_t* c = ogles_context_t::get();
1239     if (size<2 || size>4 || stride<0) {
1240         ogles_error(c, GL_INVALID_VALUE);
1241         return;
1242     }
1243     switch (type) {
1244     case GL_BYTE:
1245     case GL_SHORT:
1246     case GL_FIXED:
1247     case GL_FLOAT:
1248         break;
1249     default:
1250         ogles_error(c, GL_INVALID_ENUM);
1251         return;
1252     }
1253     c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1254 }
1255 
glColorPointer(GLint size,GLenum type,GLsizei stride,const GLvoid * pointer)1256 void glColorPointer(
1257     GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1258 {
1259     ogles_context_t* c = ogles_context_t::get();
1260     if (size!=4 || stride<0) {
1261         ogles_error(c, GL_INVALID_VALUE);
1262         return;
1263     }
1264     switch (type) {
1265     case GL_UNSIGNED_BYTE:
1266     case GL_FIXED:
1267     case GL_FLOAT:
1268         break;
1269     default:
1270         ogles_error(c, GL_INVALID_ENUM);
1271         return;
1272     }
1273     c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1274 }
1275 
glNormalPointer(GLenum type,GLsizei stride,const GLvoid * pointer)1276 void glNormalPointer(
1277     GLenum type, GLsizei stride, const GLvoid *pointer)
1278 {
1279     ogles_context_t* c = ogles_context_t::get();
1280     if (stride<0) {
1281         ogles_error(c, GL_INVALID_VALUE);
1282         return;
1283     }
1284     switch (type) {
1285     case GL_BYTE:
1286     case GL_SHORT:
1287     case GL_FIXED:
1288     case GL_FLOAT:
1289         break;
1290     default:
1291         ogles_error(c, GL_INVALID_ENUM);
1292         return;
1293     }
1294     c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
1295 }
1296 
glTexCoordPointer(GLint size,GLenum type,GLsizei stride,const GLvoid * pointer)1297 void glTexCoordPointer(
1298     GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1299 {
1300     ogles_context_t* c = ogles_context_t::get();
1301     if (size<2 || size>4 || stride<0) {
1302         ogles_error(c, GL_INVALID_VALUE);
1303         return;
1304     }
1305     switch (type) {
1306     case GL_BYTE:
1307     case GL_SHORT:
1308     case GL_FIXED:
1309     case GL_FLOAT:
1310         break;
1311     default:
1312         ogles_error(c, GL_INVALID_ENUM);
1313         return;
1314     }
1315     const int tmu = c->arrays.activeTexture;
1316     c->arrays.texture[tmu].init(size, type, stride, pointer,
1317             c->arrays.array_buffer, 0);
1318 }
1319 
1320 
glEnableClientState(GLenum array)1321 void glEnableClientState(GLenum array) {
1322     ogles_context_t* c = ogles_context_t::get();
1323     enableDisableClientState(c, array, true);
1324 }
1325 
glDisableClientState(GLenum array)1326 void glDisableClientState(GLenum array) {
1327     ogles_context_t* c = ogles_context_t::get();
1328     enableDisableClientState(c, array, false);
1329 }
1330 
glClientActiveTexture(GLenum texture)1331 void glClientActiveTexture(GLenum texture)
1332 {
1333     ogles_context_t* c = ogles_context_t::get();
1334     if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
1335         ogles_error(c, GL_INVALID_ENUM);
1336         return;
1337     }
1338     c->arrays.activeTexture = texture - GL_TEXTURE0;
1339 }
1340 
glDrawArrays(GLenum mode,GLint first,GLsizei count)1341 void glDrawArrays(GLenum mode, GLint first, GLsizei count)
1342 {
1343     ogles_context_t* c = ogles_context_t::get();
1344     if (count<0) {
1345         ogles_error(c, GL_INVALID_VALUE);
1346         return;
1347     }
1348     switch (mode) {
1349     case GL_POINTS:
1350     case GL_LINE_STRIP:
1351     case GL_LINE_LOOP:
1352     case GL_LINES:
1353     case GL_TRIANGLE_STRIP:
1354     case GL_TRIANGLE_FAN:
1355     case GL_TRIANGLES:
1356         break;
1357     default:
1358         ogles_error(c, GL_INVALID_ENUM);
1359         return;
1360     }
1361 
1362     if (count == 0 || !c->arrays.vertex.enable)
1363         return;
1364     if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1365         return; // all triangles are culled
1366 
1367 
1368     validate_arrays(c, mode);
1369 
1370     const uint32_t enables = c->rasterizer.state.enables;
1371     if (enables & GGL_ENABLE_TMUS)
1372         ogles_lock_textures(c);
1373 
1374     drawArraysPrims[mode](c, first, count);
1375 
1376     if (enables & GGL_ENABLE_TMUS)
1377         ogles_unlock_textures(c);
1378 
1379 #if VC_CACHE_STATISTICS
1380     c->vc.total = count;
1381     c->vc.dump_stats(mode);
1382 #endif
1383 }
1384 
glDrawElements(GLenum mode,GLsizei count,GLenum type,const GLvoid * indices)1385 void glDrawElements(
1386     GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
1387 {
1388     ogles_context_t* c = ogles_context_t::get();
1389     if (count<0) {
1390         ogles_error(c, GL_INVALID_VALUE);
1391         return;
1392     }
1393     switch (mode) {
1394     case GL_POINTS:
1395     case GL_LINE_STRIP:
1396     case GL_LINE_LOOP:
1397     case GL_LINES:
1398     case GL_TRIANGLE_STRIP:
1399     case GL_TRIANGLE_FAN:
1400     case GL_TRIANGLES:
1401         break;
1402     default:
1403         ogles_error(c, GL_INVALID_ENUM);
1404         return;
1405     }
1406     switch (type) {
1407     case GL_UNSIGNED_BYTE:
1408     case GL_UNSIGNED_SHORT:
1409         c->arrays.indicesType = type;
1410         break;
1411     default:
1412         ogles_error(c, GL_INVALID_ENUM);
1413         return;
1414     }
1415     if (count == 0 || !c->arrays.vertex.enable)
1416         return;
1417     if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1418         return; // all triangles are culled
1419 
1420     // clear the vertex-cache
1421     c->vc.clear();
1422     validate_arrays(c, mode);
1423 
1424     // if indices are in a buffer object, the pointer is treated as an
1425     // offset in that buffer.
1426     if (c->arrays.element_array_buffer) {
1427         indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
1428     }
1429 
1430     const uint32_t enables = c->rasterizer.state.enables;
1431     if (enables & GGL_ENABLE_TMUS)
1432         ogles_lock_textures(c);
1433 
1434     drawElementsPrims[mode](c, count, indices);
1435 
1436     if (enables & GGL_ENABLE_TMUS)
1437         ogles_unlock_textures(c);
1438 
1439 
1440 #if VC_CACHE_STATISTICS
1441     c->vc.total = count;
1442     c->vc.dump_stats(mode);
1443 #endif
1444 }
1445 
1446 // ----------------------------------------------------------------------------
1447 // buffers
1448 // ----------------------------------------------------------------------------
1449 
glBindBuffer(GLenum target,GLuint buffer)1450 void glBindBuffer(GLenum target, GLuint buffer)
1451 {
1452     ogles_context_t* c = ogles_context_t::get();
1453     if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1454         ogles_error(c, GL_INVALID_ENUM);
1455         return;
1456     }
1457     // create a buffer object, or bind an existing one
1458     buffer_t const* bo = 0;
1459     if (buffer) {
1460         bo = c->bufferObjectManager->bind(buffer);
1461         if (!bo) {
1462             ogles_error(c, GL_OUT_OF_MEMORY);
1463             return;
1464         }
1465     }
1466     ((target == GL_ARRAY_BUFFER) ?
1467             c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
1468 }
1469 
glBufferData(GLenum target,GLsizeiptr size,const GLvoid * data,GLenum usage)1470 void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
1471 {
1472     ogles_context_t* c = ogles_context_t::get();
1473     if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1474         ogles_error(c, GL_INVALID_ENUM);
1475         return;
1476     }
1477     if (size<0) {
1478         ogles_error(c, GL_INVALID_VALUE);
1479         return;
1480     }
1481     if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
1482         ogles_error(c, GL_INVALID_ENUM);
1483         return;
1484     }
1485     buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
1486             c->arrays.array_buffer : c->arrays.element_array_buffer);
1487 
1488     if (bo == 0) {
1489         // can't modify buffer 0
1490         ogles_error(c, GL_INVALID_OPERATION);
1491         return;
1492     }
1493 
1494     buffer_t* edit_bo = const_cast<buffer_t*>(bo);
1495     if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
1496         ogles_error(c, GL_OUT_OF_MEMORY);
1497         return;
1498     }
1499     if (data) {
1500         memcpy(bo->data, data, size);
1501     }
1502 }
1503 
glBufferSubData(GLenum target,GLintptr offset,GLsizeiptr size,const GLvoid * data)1504 void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
1505 {
1506     ogles_context_t* c = ogles_context_t::get();
1507     if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1508         ogles_error(c, GL_INVALID_ENUM);
1509         return;
1510     }
1511     if (offset<0 || size<0 || data==0) {
1512         ogles_error(c, GL_INVALID_VALUE);
1513         return;
1514     }
1515     buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
1516             c->arrays.array_buffer : c->arrays.element_array_buffer);
1517 
1518     if (bo == 0) {
1519         // can't modify buffer 0
1520         ogles_error(c, GL_INVALID_OPERATION);
1521         return;
1522     }
1523     if (offset+size > bo->size) {
1524         ogles_error(c, GL_INVALID_VALUE);
1525         return;
1526     }
1527     memcpy(bo->data + offset, data, size);
1528 }
1529 
glDeleteBuffers(GLsizei n,const GLuint * buffers)1530 void glDeleteBuffers(GLsizei n, const GLuint* buffers)
1531 {
1532     ogles_context_t* c = ogles_context_t::get();
1533     if (n<0) {
1534         ogles_error(c, GL_INVALID_VALUE);
1535         return;
1536     }
1537 
1538     for (int i=0 ; i<n ; i++) {
1539         GLuint name = buffers[i];
1540         if (name) {
1541             // unbind bound deleted buffers...
1542             if (c->arrays.element_array_buffer) {
1543                 if (c->arrays.element_array_buffer->name == name) {
1544                     c->arrays.element_array_buffer = 0;
1545                 }
1546             }
1547             if (c->arrays.array_buffer) {
1548                 if (c->arrays.array_buffer->name == name) {
1549                     c->arrays.array_buffer = 0;
1550                 }
1551             }
1552             if (c->arrays.vertex.bo) {
1553                 if (c->arrays.vertex.bo->name == name) {
1554                     c->arrays.vertex.bo = 0;
1555                 }
1556             }
1557             if (c->arrays.normal.bo) {
1558                 if (c->arrays.normal.bo->name == name) {
1559                     c->arrays.normal.bo = 0;
1560                 }
1561             }
1562             if (c->arrays.color.bo) {
1563                 if (c->arrays.color.bo->name == name) {
1564                     c->arrays.color.bo = 0;
1565                 }
1566             }
1567             for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
1568                 if (c->arrays.texture[t].bo) {
1569                     if (c->arrays.texture[t].bo->name == name) {
1570                         c->arrays.texture[t].bo = 0;
1571                     }
1572                 }
1573             }
1574         }
1575     }
1576     c->bufferObjectManager->deleteBuffers(n, buffers);
1577     c->bufferObjectManager->recycleTokens(n, buffers);
1578 }
1579 
glGenBuffers(GLsizei n,GLuint * buffers)1580 void glGenBuffers(GLsizei n, GLuint* buffers)
1581 {
1582     ogles_context_t* c = ogles_context_t::get();
1583     if (n<0) {
1584         ogles_error(c, GL_INVALID_VALUE);
1585         return;
1586     }
1587     c->bufferObjectManager->getToken(n, buffers);
1588 }
1589