OSDN Git Service

add number constraint for samples per MotionEvent am: 5d17838ade
[android-x86/frameworks-native.git] / opengl / libagl / array.cpp
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
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
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
136 static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
137     memcpy(v, c->current.color.v, sizeof(vec4_t));
138 }
139 static void currentColor_clamp(ogles_context_t* c, GLfixed* v, const GLvoid*) {
140     memcpy(v, c->currentColorClamped.v, sizeof(vec4_t));
141 }
142 static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
143     memcpy(v, c->currentNormal.v, sizeof(vec3_t));
144 }
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
150 static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
151 }
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 }
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 }
160 static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
161     memcpy(v, p, 2*sizeof(GLfixed));
162 }
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 }
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 }
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 }
177 static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
178     memcpy(v, p, 3*sizeof(GLfixed));
179 }
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 }
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 }
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 }
197 static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
198     memcpy(v, p, 4*sizeof(GLfixed));
199 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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
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
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
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
365 void vertex_cache_t::uninit()
366 {
367     free(base);
368     base = vBuffer = vCache = 0;
369 }
370
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
400 #if VC_CACHE_STATISTICS
401 void vertex_cache_t::dump_stats(GLenum mode)
402 {
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 }
422 #else
423 void vertex_cache_t::dump_stats(GLenum /*mode*/)
424 {
425 }
426 #endif
427
428 // ----------------------------------------------------------------------------
429 #if 0
430 #pragma mark -
431 #endif
432
433 static __attribute__((noinline))
434 void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
435 {
436     const int tmu = c->arrays.activeTexture;
437     array_t* a;
438     switch (array) {
439     case GL_COLOR_ARRAY:            a = &c->arrays.color;           break;
440     case GL_NORMAL_ARRAY:           a = &c->arrays.normal;          break;
441     case GL_TEXTURE_COORD_ARRAY:    a = &c->arrays.texture[tmu];    break;
442     case GL_VERTEX_ARRAY:           a = &c->arrays.vertex;          break;
443     default:
444         ogles_error(c, GL_INVALID_ENUM);
445         return;
446     }
447     a->enable = enable ? GL_TRUE : GL_FALSE;
448 }
449
450 // ----------------------------------------------------------------------------
451 #if 0
452 #pragma mark -
453 #pragma mark Vertex Cache
454 #endif
455
456 static __attribute__((noinline))
457 vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
458 {
459     #if VC_CACHE_STATISTICS
460         c->vc.misses++;
461     #endif
462     if (ggl_unlikely(v->locked)) {
463         // we're just looking for an entry in the cache that is not locked.
464         // and we know that there cannot be more than 2 locked entries
465         // because a triangle needs at most 3 vertices.
466         // We never use the first and second entries because they might be in
467         // use by the striper or faner. Any other entry will do as long as
468         // it's not locked.
469         // We compute directly the index of a "free" entry from the locked
470         // state of v[2] and v[3].
471         v = c->vc.vBuffer + 2;
472         v += v[0].locked | (v[1].locked<<1);
473     }
474     // note: compileElement clears v->flags
475     c->arrays.compileElement(c, v, index);
476     v->locked = 1;
477     return v;
478 }
479
480 static __attribute__((noinline))
481 vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
482 {
483     index |= c->vc.sequence;
484
485 #if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
486
487     vertex_t* const v = c->vc.vCache +
488             (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
489
490     if (ggl_likely(v->index == index)) {
491         v->locked = 1;
492         return v;
493     }
494     return cache_vertex(c, v, index);
495
496 #elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
497
498     vertex_t* v = c->vc.vCache +
499             (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
500
501     // always record LRU in v[0]
502     if (ggl_likely(v[0].index == index)) {
503         v[0].locked = 1;
504         v[0].mru = 0;
505         return &v[0];
506     }
507
508     if (ggl_likely(v[1].index == index)) {
509         v[1].locked = 1;
510         v[0].mru = 1;
511         return &v[1];
512     }
513
514     const int lru = 1 - v[0].mru;
515     v[0].mru = lru;
516     return cache_vertex(c, &v[lru], index);
517
518 #elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
519
520     // just for debugging...
521     vertex_t* v = c->vc.vBuffer + 2;
522     return cache_vertex(c, v, index);
523
524 #endif
525 }
526
527 // ----------------------------------------------------------------------------
528 #if 0
529 #pragma mark -
530 #pragma mark Primitive Assembly
531 #endif
532
533 void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
534 {
535     if (ggl_unlikely(count < 1))
536         return;
537
538     // vertex cache size must be multiple of 1
539     const GLsizei vcs =
540             (vertex_cache_t::VERTEX_BUFFER_SIZE +
541              vertex_cache_t::VERTEX_CACHE_SIZE);
542     do {
543         vertex_t* v = c->vc.vBuffer;
544         GLsizei num = count > vcs ? vcs : count;
545         c->arrays.cull = vertex_t::CLIP_ALL;
546         c->arrays.compileElements(c, v, first, num);
547         first += num;
548         count -= num;
549         if (!c->arrays.cull) {
550             // quick/trivial reject of the whole batch
551             do {
552                 const uint32_t cc = v[0].flags;
553                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
554                     c->prims.renderPoint(c, v);
555                 v++;
556                 num--;
557             } while (num);
558         }
559     } while (count);
560 }
561
562 // ----------------------------------------------------------------------------
563
564 void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
565 {
566     if (ggl_unlikely(count < 2))
567         return;
568
569     vertex_t *v, *v0, *v1;
570     c->arrays.cull = vertex_t::CLIP_ALL;
571     c->arrays.compileElement(c, c->vc.vBuffer, first);
572     first += 1;
573     count -= 1;
574
575     // vertex cache size must be multiple of 1
576     const GLsizei vcs =
577         (vertex_cache_t::VERTEX_BUFFER_SIZE +
578          vertex_cache_t::VERTEX_CACHE_SIZE - 1);
579     do {
580         v0 = c->vc.vBuffer + 0;
581         v  = c->vc.vBuffer + 1;
582         GLsizei num = count > vcs ? vcs : count;
583         c->arrays.compileElements(c, v, first, num);
584         first += num;
585         count -= num;
586         if (!c->arrays.cull) {
587             // quick/trivial reject of the whole batch
588             do {
589                 v1 = v++;
590                 const uint32_t cc = v0->flags & v1->flags;
591                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
592                     c->prims.renderLine(c, v0, v1);
593                 v0 = v1;
594                 num--;
595             } while (num);
596         }
597         // copy back the last processed vertex
598         c->vc.vBuffer[0] = *v0;
599         c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
600     } while (count);
601 }
602
603 void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
604 {
605     if (ggl_unlikely(count < 2))
606         return;
607     drawPrimitivesLineStrip(c, first, count);
608     if (ggl_likely(count >= 3)) {
609         vertex_t* v0 = c->vc.vBuffer;
610         vertex_t* v1 = c->vc.vBuffer + 1;
611         c->arrays.compileElement(c, v1, first);
612         const uint32_t cc = v0->flags & v1->flags;
613         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
614             c->prims.renderLine(c, v0, v1);
615     }
616 }
617
618 void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
619 {
620     if (ggl_unlikely(count < 2))
621         return;
622
623     // vertex cache size must be multiple of 2
624     const GLsizei vcs =
625         ((vertex_cache_t::VERTEX_BUFFER_SIZE +
626         vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
627     do {
628         vertex_t* v = c->vc.vBuffer;
629         GLsizei num = count > vcs ? vcs : count;
630         c->arrays.cull = vertex_t::CLIP_ALL;
631         c->arrays.compileElements(c, v, first, num);
632         first += num;
633         count -= num;
634         if (!c->arrays.cull) {
635             // quick/trivial reject of the whole batch
636             num -= 2;
637             do {
638                 const uint32_t cc = v[0].flags & v[1].flags;
639                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
640                     c->prims.renderLine(c, v, v+1);
641                 v += 2;
642                 num -= 2;
643             } while (num >= 0);
644         }
645     } while (count >= 2);
646 }
647
648 // ----------------------------------------------------------------------------
649
650 static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
651         GLint first, GLsizei count, int winding)
652 {
653     // winding == 2 : fan
654     // winding == 1 : strip
655
656     if (ggl_unlikely(count < 3))
657         return;
658
659     vertex_t *v, *v0, *v1, *v2;
660     c->arrays.cull = vertex_t::CLIP_ALL;
661     c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
662     first += 2;
663     count -= 2;
664
665     // vertex cache size must be multiple of 2. This is extremely important
666     // because it allows us to preserve the same winding when the whole
667     // batch is culled. We also need 2 extra vertices in the array, because
668     // we always keep the two first ones.
669     const GLsizei vcs =
670         ((vertex_cache_t::VERTEX_BUFFER_SIZE +
671           vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
672     do {
673         v0 = c->vc.vBuffer + 0;
674         v1 = c->vc.vBuffer + 1;
675         v  = c->vc.vBuffer + 2;
676         GLsizei num = count > vcs ? vcs : count;
677         c->arrays.compileElements(c, v, first, num);
678         first += num;
679         count -= num;
680         if (!c->arrays.cull) {
681             // quick/trivial reject of the whole batch
682             do {
683                 v2 = v++;
684                 const uint32_t cc = v0->flags & v1->flags & v2->flags;
685                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
686                     c->prims.renderTriangle(c, v0, v1, v2);
687                 swap(((winding^=1) ? v1 : v0), v2);
688                 num--;
689             } while (num);
690         }
691         if (count) {
692             v0 = c->vc.vBuffer + 2 + vcs - 2;
693             v1 = c->vc.vBuffer + 2 + vcs - 1;
694             if ((winding&2) == 0) {
695                 // for strips copy back the two last compiled vertices
696                 c->vc.vBuffer[0] = *v0;
697             }
698             c->vc.vBuffer[1] = *v1;
699             c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
700         }
701     } while (count > 0);
702 }
703
704 void drawPrimitivesTriangleStrip(ogles_context_t* c,
705         GLint first, GLsizei count) {
706     drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
707 }
708
709 void drawPrimitivesTriangleFan(ogles_context_t* c,
710         GLint first, GLsizei count) {
711     drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
712 }
713
714 void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
715 {
716     if (ggl_unlikely(count < 3))
717         return;
718
719     // vertex cache size must be multiple of 3
720     const GLsizei vcs =
721         ((vertex_cache_t::VERTEX_BUFFER_SIZE +
722         vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
723     do {
724         vertex_t* v = c->vc.vBuffer;
725         GLsizei num = count > vcs ? vcs : count;
726         c->arrays.cull = vertex_t::CLIP_ALL;
727         c->arrays.compileElements(c, v, first, num);
728         first += num;
729         count -= num;
730         if (!c->arrays.cull) {
731             // quick/trivial reject of the whole batch
732             num -= 3;
733             do {
734                 const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
735                 if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
736                     c->prims.renderTriangle(c, v, v+1, v+2);
737                 v += 3;
738                 num -= 3;
739             } while (num >= 0);
740         }
741     } while (count >= 3);
742 }
743
744 // ----------------------------------------------------------------------------
745 #if 0
746 #pragma mark -
747 #endif
748
749 // this looks goofy, but gcc does a great job with this...
750 static inline unsigned int read_index(int type, const GLvoid*& p) {
751     unsigned int r;
752     if (type) {
753         r = *(const GLubyte*)p;
754         p = (const GLubyte*)p + 1;
755     } else {
756         r = *(const GLushort*)p;
757         p = (const GLushort*)p + 1;
758     }
759     return r;
760 }
761
762 // ----------------------------------------------------------------------------
763
764 void drawIndexedPrimitivesPoints(ogles_context_t* c,
765         GLsizei count, const GLvoid *indices)
766 {
767     if (ggl_unlikely(count < 1))
768         return;
769     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
770     do {
771         vertex_t * v = fetch_vertex(c, read_index(type, indices));
772         if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
773             c->prims.renderPoint(c, v);
774         v->locked = 0;
775         count--;
776     } while(count);
777 }
778
779 // ----------------------------------------------------------------------------
780
781 void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
782         GLsizei count, const GLvoid *indices)
783 {
784     if (ggl_unlikely(count < 2))
785         return;
786
787     vertex_t * const v = c->vc.vBuffer;
788     vertex_t* v0 = v;
789     vertex_t* v1;
790
791     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
792     c->arrays.compileElement(c, v0, read_index(type, indices));
793     count -= 1;
794     do {
795         v1 = fetch_vertex(c, read_index(type, indices));
796         const uint32_t cc = v0->flags & v1->flags;
797         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
798             c->prims.renderLine(c, v0, v1);
799         v0->locked = 0;
800         v0 = v1;
801         count--;
802     } while (count);
803     v1->locked = 0;
804 }
805
806 void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
807         GLsizei count, const GLvoid *indices)
808 {
809     if (ggl_unlikely(count <= 2)) {
810         drawIndexedPrimitivesLines(c, count, indices);
811         return;
812     }
813
814     vertex_t * const v = c->vc.vBuffer;
815     vertex_t* v0 = v;
816     vertex_t* v1;
817
818     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
819     c->arrays.compileElement(c, v0, read_index(type, indices));
820     count -= 1;
821     do {
822         v1 = fetch_vertex(c, read_index(type, indices));
823         const uint32_t cc = v0->flags & v1->flags;
824         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
825             c->prims.renderLine(c, v0, v1);
826         v0->locked = 0;
827         v0 = v1;
828         count--;
829     } while (count);
830     v1->locked = 0;
831
832     v1 = c->vc.vBuffer;
833     const uint32_t cc = v0->flags & v1->flags;
834     if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
835         c->prims.renderLine(c, v0, v1);
836 }
837
838 void drawIndexedPrimitivesLines(ogles_context_t* c,
839         GLsizei count, const GLvoid *indices)
840 {
841     if (ggl_unlikely(count < 2))
842         return;
843
844     count -= 2;
845     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
846     do {
847         vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
848         vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
849         const uint32_t cc = v0->flags & v1->flags;
850         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
851             c->prims.renderLine(c, v0, v1);
852         v0->locked = 0;
853         v1->locked = 0;
854         count -= 2;
855     } while (count >= 0);
856 }
857
858 // ----------------------------------------------------------------------------
859
860 static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
861         GLsizei count, const GLvoid *indices, int winding)
862 {
863     // winding == 2 : fan
864     // winding == 1 : strip
865
866     if (ggl_unlikely(count < 3))
867         return;
868
869     vertex_t * const v = c->vc.vBuffer;
870     vertex_t* v0 = v;
871     vertex_t* v1 = v+1;
872     vertex_t* v2;
873
874     const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
875     c->arrays.compileElement(c, v0, read_index(type, indices));
876     c->arrays.compileElement(c, v1, read_index(type, indices));
877     count -= 2;
878
879     // note: GCC 4.1.1 here makes a prety interesting optimization
880     // where it duplicates the loop below based on c->arrays.indicesType
881
882     do {
883         v2 = fetch_vertex(c, read_index(type, indices));
884         const uint32_t cc = v0->flags & v1->flags & v2->flags;
885         if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
886             c->prims.renderTriangle(c, v0, v1, v2);
887         vertex_t* & consumed = ((winding^=1) ? v1 : v0);
888         consumed->locked = 0;
889         consumed = v2;
890         count--;
891     } while (count);
892     v0->locked = v1->locked = 0;
893     v2->locked = 0;
894 }
895
896 void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
897         GLsizei count, const GLvoid *indices) {
898     drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
899 }
900
901 void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
902         GLsizei count, const GLvoid *indices) {
903     drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
904 }
905
906 void drawIndexedPrimitivesTriangles(ogles_context_t* c,
907         GLsizei count, const GLvoid *indices)
908 {
909     if (ggl_unlikely(count < 3))
910         return;
911
912     count -= 3;
913     if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
914         // This case is probably our most common case...
915         uint16_t const * p = (uint16_t const *)indices;
916         do {
917             vertex_t* const v0 = fetch_vertex(c, *p++);
918             vertex_t* const v1 = fetch_vertex(c, *p++);
919             vertex_t* const v2 = fetch_vertex(c, *p++);
920             const uint32_t cc = v0->flags & v1->flags & v2->flags;
921             if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
922                 c->prims.renderTriangle(c, v0, v1, v2);
923             v0->locked = 0;
924             v1->locked = 0;
925             v2->locked = 0;
926             count -= 3;
927         } while (count >= 0);
928     } else {
929         uint8_t const * p = (uint8_t const *)indices;
930         do {
931             vertex_t* const v0 = fetch_vertex(c, *p++);
932             vertex_t* const v1 = fetch_vertex(c, *p++);
933             vertex_t* const v2 = fetch_vertex(c, *p++);
934             const uint32_t cc = v0->flags & v1->flags & v2->flags;
935             if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
936                 c->prims.renderTriangle(c, v0, v1, v2);
937             v0->locked = 0;
938             v1->locked = 0;
939             v2->locked = 0;
940             count -= 3;
941         } while (count >= 0);
942     }
943 }
944
945 // ----------------------------------------------------------------------------
946 #if 0
947 #pragma mark -
948 #pragma mark Array compilers
949 #endif
950
951 void compileElement__generic(ogles_context_t* c,
952         vertex_t* v, GLint first)
953 {
954     v->flags = 0;
955     v->index = first;
956     first &= vertex_cache_t::INDEX_MASK;
957     const GLubyte* vp = c->arrays.vertex.element(first);
958     v->obj.z = 0;
959     v->obj.w = 0x10000;
960     c->arrays.vertex.fetch(c, v->obj.v, vp);
961     c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
962     c->arrays.perspective(c, v);
963 }
964
965 void compileElements__generic(ogles_context_t* c,
966         vertex_t* v, GLint first, GLsizei count)
967 {
968     const GLubyte* vp = c->arrays.vertex.element(
969             first & vertex_cache_t::INDEX_MASK);
970     const size_t stride = c->arrays.vertex.stride;
971     transform_t const* const mvp = &c->transforms.mvp;
972     do {
973         v->flags = 0;
974         v->index = first++;
975         v->obj.z = 0;
976         v->obj.w = 0x10000;
977         c->arrays.vertex.fetch(c, v->obj.v, vp);
978         c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
979         c->arrays.perspective(c, v);
980         vp += stride;
981         v++;
982     } while (--count);
983 }
984
985 /*
986 void compileElements__3x_full(ogles_context_t* c,
987         vertex_t* v, GLint first, GLsizei count)
988 {
989     const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
990     const size_t stride = c->arrays.vertex.stride / 4;
991 //    const GLfixed* const& m = c->transforms.mvp.matrix.m;
992
993     GLfixed m[16];
994     memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
995
996     do {
997         const GLfixed rx = vp[0];
998         const GLfixed ry = vp[1];
999         const GLfixed rz = vp[2];
1000         vp += stride;
1001         v->index = first++;
1002         v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
1003         v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
1004         v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
1005         v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
1006
1007         const GLfixed w = v->clip.w;
1008         uint32_t clip = 0;
1009         if (v->clip.x < -w)   clip |= vertex_t::CLIP_L;
1010         if (v->clip.x >  w)   clip |= vertex_t::CLIP_R;
1011         if (v->clip.y < -w)   clip |= vertex_t::CLIP_B;
1012         if (v->clip.y >  w)   clip |= vertex_t::CLIP_T;
1013         if (v->clip.z < -w)   clip |= vertex_t::CLIP_N;
1014         if (v->clip.z >  w)   clip |= vertex_t::CLIP_F;
1015         v->flags = clip;
1016         c->arrays.cull &= clip;
1017
1018         //c->arrays.perspective(c, v);
1019         v++;
1020     } while (--count);
1021 }
1022 */
1023
1024 // ----------------------------------------------------------------------------
1025 #if 0
1026 #pragma mark -
1027 #pragma mark clippers
1028 #endif
1029
1030 static void clipVec4(vec4_t& nv,
1031         GLfixed t, const vec4_t& s, const vec4_t& p)
1032 {
1033     for (int i=0; i<4 ; i++)
1034         nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
1035 }
1036
1037 static void clipVertex(ogles_context_t* c, vertex_t* nv,
1038         GLfixed t, const vertex_t* s, const vertex_t* p)
1039 {
1040     clipVec4(nv->clip, t, s->clip, p->clip);
1041     nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
1042     ogles_vertex_project(c, nv);
1043     nv->flags |=  vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
1044     nv->flags &= ~vertex_t::CLIP_ALL;
1045 }
1046
1047 static void clipVertexC(ogles_context_t* c, vertex_t* nv,
1048         GLfixed t, const vertex_t* s, const vertex_t* p)
1049 {
1050     clipVec4(nv->color, t, s->color, p->color);
1051     clipVertex(c, nv, t, s, p);
1052 }
1053
1054 static void clipVertexT(ogles_context_t* c, vertex_t* nv,
1055         GLfixed t, const vertex_t* s, const vertex_t* p)
1056 {
1057     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1058         if (c->rasterizer.state.texture[i].enable)
1059             clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
1060     }
1061     clipVertex(c, nv, t, s, p);
1062 }
1063
1064 static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
1065         GLfixed t, const vertex_t* s, const vertex_t* p)
1066 {
1067     clipVec4(nv->color, t, s->color, p->color);
1068     clipVertexT(c, nv, t, s, p);
1069 }
1070
1071 static void clipEye(ogles_context_t* c, vertex_t* nv,
1072         GLfixed t, const vertex_t* s, const vertex_t* p)
1073 {
1074     nv->clear();
1075     c->arrays.clipVertex(c, nv, t, p, s);
1076     clipVec4(nv->eye, t, s->eye, p->eye);
1077 }
1078
1079 // ----------------------------------------------------------------------------
1080 #if 0
1081 #pragma mark -
1082 #endif
1083
1084 void validate_arrays(ogles_context_t* c, GLenum mode)
1085 {
1086     uint32_t enables = c->rasterizer.state.enables;
1087
1088     // Perspective correction is not need if Ortho transform, but
1089     // the user can still provide the w coordinate manually, so we can't
1090     // automatically turn it off (in fact we could when the 4th coordinate
1091     // is not spcified in the vertex array).
1092     // W interpolation is never needed for points.
1093     GLboolean perspective =
1094         c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
1095     c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
1096
1097     // set anti-aliasing
1098     GLboolean smooth = GL_FALSE;
1099     switch (mode) {
1100     case GL_POINTS:
1101         smooth = c->point.smooth;
1102         break;
1103     case GL_LINES:
1104     case GL_LINE_LOOP:
1105     case GL_LINE_STRIP:
1106         smooth = c->line.smooth;
1107         break;
1108     }
1109     if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
1110         c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
1111
1112     // set the shade model for this primitive
1113     c->rasterizer.procs.shadeModel(c,
1114             (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
1115
1116     // compute all the matrices we'll need...
1117     uint32_t want =
1118             transform_state_t::MVP |
1119             transform_state_t::VIEWPORT;
1120     if (c->lighting.enable) { // needs normal transforms and eye coords
1121         want |= transform_state_t::MVUI;
1122         want |= transform_state_t::MODELVIEW;
1123     }
1124     if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
1125         want |= transform_state_t::TEXTURE;
1126     }
1127     if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
1128         want |= transform_state_t::MODELVIEW; // needs eye coords
1129     }
1130     ogles_validate_transform(c, want);
1131
1132     // textures...
1133     if (enables & GGL_ENABLE_TMUS)
1134         ogles_validate_texture(c);
1135
1136     // vertex compilers
1137     c->arrays.compileElement = compileElement__generic;
1138     c->arrays.compileElements = compileElements__generic;
1139
1140     // vertex transform
1141     c->arrays.mvp_transform =
1142         c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
1143
1144     c->arrays.mv_transform =
1145         c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
1146
1147     /*
1148      * ***********************************************************************
1149      *  pick fetchers
1150      * ***********************************************************************
1151      */
1152
1153     array_machine_t& am = c->arrays;
1154     am.vertex.fetch = fetchNop;
1155     am.normal.fetch = currentNormal;
1156     am.color.fetch = currentColor;
1157
1158     if (am.vertex.enable) {
1159         am.vertex.resolve();
1160         if (am.vertex.bo || am.vertex.pointer) {
1161             am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
1162         }
1163     }
1164
1165     if (am.normal.enable) {
1166         am.normal.resolve();
1167         if (am.normal.bo || am.normal.pointer) {
1168             am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
1169         }
1170     }
1171
1172     if (am.color.enable) {
1173         am.color.resolve();
1174         if (c->lighting.enable) {
1175             if (am.color.bo || am.color.pointer) {
1176                 am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
1177             }
1178         } else {
1179             if (am.color.bo || am.color.pointer) {
1180                 am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
1181             }
1182         }
1183     }
1184
1185     int activeTmuCount = 0;
1186     for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
1187         am.texture[i].fetch = currentTexCoord;
1188         if (c->rasterizer.state.texture[i].enable) {
1189
1190             // texture fetchers...
1191             if (am.texture[i].enable) {
1192                 am.texture[i].resolve();
1193                 if (am.texture[i].bo || am.texture[i].pointer) {
1194                     am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
1195                 }
1196             }
1197
1198             // texture transform...
1199             const int index = c->arrays.texture[i].size - 2;
1200             c->arrays.tex_transform[i] =
1201                 c->transforms.texture[i].transform.pointv[index];
1202
1203             am.tmu = i;
1204             activeTmuCount++;
1205         }
1206     }
1207
1208     // pick the vertex-clipper
1209     uint32_t clipper = 0;
1210     // we must reload 'enables' here
1211     enables = c->rasterizer.state.enables;
1212     if (enables & GGL_ENABLE_SMOOTH)
1213         clipper |= 1;   // we need to interpolate colors
1214     if (enables & GGL_ENABLE_TMUS)
1215         clipper |= 2;   // we need to interpolate textures
1216     switch (clipper) {
1217     case 0: c->arrays.clipVertex = clipVertex;      break;
1218     case 1: c->arrays.clipVertex = clipVertexC;     break;
1219     case 2: c->arrays.clipVertex = clipVertexT;     break;
1220     case 3: c->arrays.clipVertex = clipVertexAll;   break;
1221     }
1222     c->arrays.clipEye = clipEye;
1223
1224     // pick the primitive rasterizer
1225     ogles_validate_primitives(c);
1226 }
1227
1228 // ----------------------------------------------------------------------------
1229 }; // namespace android
1230 // ----------------------------------------------------------------------------
1231
1232 using namespace android;
1233
1234 #if 0
1235 #pragma mark -
1236 #pragma mark array API
1237 #endif
1238
1239 void glVertexPointer(
1240     GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1241 {
1242     ogles_context_t* c = ogles_context_t::get();
1243     if (size<2 || size>4 || stride<0) {
1244         ogles_error(c, GL_INVALID_VALUE);
1245         return;
1246     }
1247     switch (type) {
1248     case GL_BYTE:
1249     case GL_SHORT:
1250     case GL_FIXED:
1251     case GL_FLOAT:
1252         break;
1253     default:
1254         ogles_error(c, GL_INVALID_ENUM);
1255         return;
1256     }
1257     c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1258 }
1259
1260 void glColorPointer(
1261     GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1262 {
1263     ogles_context_t* c = ogles_context_t::get();
1264     if (size!=4 || stride<0) {
1265         ogles_error(c, GL_INVALID_VALUE);
1266         return;
1267     }
1268     switch (type) {
1269     case GL_UNSIGNED_BYTE:
1270     case GL_FIXED:
1271     case GL_FLOAT:
1272         break;
1273     default:
1274         ogles_error(c, GL_INVALID_ENUM);
1275         return;
1276     }
1277     c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
1278 }
1279
1280 void glNormalPointer(
1281     GLenum type, GLsizei stride, const GLvoid *pointer)
1282 {
1283     ogles_context_t* c = ogles_context_t::get();
1284     if (stride<0) {
1285         ogles_error(c, GL_INVALID_VALUE);
1286         return;
1287     }
1288     switch (type) {
1289     case GL_BYTE:
1290     case GL_SHORT:
1291     case GL_FIXED:
1292     case GL_FLOAT:
1293         break;
1294     default:
1295         ogles_error(c, GL_INVALID_ENUM);
1296         return;
1297     }
1298     c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
1299 }
1300
1301 void glTexCoordPointer(
1302     GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
1303 {
1304     ogles_context_t* c = ogles_context_t::get();
1305     if (size<2 || size>4 || stride<0) {
1306         ogles_error(c, GL_INVALID_VALUE);
1307         return;
1308     }
1309     switch (type) {
1310     case GL_BYTE:
1311     case GL_SHORT:
1312     case GL_FIXED:
1313     case GL_FLOAT:
1314         break;
1315     default:
1316         ogles_error(c, GL_INVALID_ENUM);
1317         return;
1318     }
1319     const int tmu = c->arrays.activeTexture;
1320     c->arrays.texture[tmu].init(size, type, stride, pointer,
1321             c->arrays.array_buffer, 0);
1322 }
1323
1324
1325 void glEnableClientState(GLenum array) {
1326     ogles_context_t* c = ogles_context_t::get();
1327     enableDisableClientState(c, array, true);
1328 }
1329
1330 void glDisableClientState(GLenum array) {
1331     ogles_context_t* c = ogles_context_t::get();
1332     enableDisableClientState(c, array, false);
1333 }
1334
1335 void glClientActiveTexture(GLenum texture)
1336 {
1337     ogles_context_t* c = ogles_context_t::get();
1338     if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
1339         ogles_error(c, GL_INVALID_ENUM);
1340         return;
1341     }
1342     c->arrays.activeTexture = texture - GL_TEXTURE0;
1343 }
1344
1345 void glDrawArrays(GLenum mode, GLint first, GLsizei count)
1346 {
1347     ogles_context_t* c = ogles_context_t::get();
1348     if (count<0) {
1349         ogles_error(c, GL_INVALID_VALUE);
1350         return;
1351     }
1352     switch (mode) {
1353     case GL_POINTS:
1354     case GL_LINE_STRIP:
1355     case GL_LINE_LOOP:
1356     case GL_LINES:
1357     case GL_TRIANGLE_STRIP:
1358     case GL_TRIANGLE_FAN:
1359     case GL_TRIANGLES:
1360         break;
1361     default:
1362         ogles_error(c, GL_INVALID_ENUM);
1363         return;
1364     }
1365
1366     if (count == 0 || !c->arrays.vertex.enable)
1367         return;
1368     if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1369         return; // all triangles are culled
1370
1371
1372     validate_arrays(c, mode);
1373
1374     const uint32_t enables = c->rasterizer.state.enables;
1375     if (enables & GGL_ENABLE_TMUS)
1376         ogles_lock_textures(c);
1377
1378     drawArraysPrims[mode](c, first, count);
1379
1380     if (enables & GGL_ENABLE_TMUS)
1381         ogles_unlock_textures(c);
1382
1383 #if VC_CACHE_STATISTICS
1384     c->vc.total = count;
1385     c->vc.dump_stats(mode);
1386 #endif
1387 }
1388
1389 void glDrawElements(
1390     GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
1391 {
1392     ogles_context_t* c = ogles_context_t::get();
1393     if (count<0) {
1394         ogles_error(c, GL_INVALID_VALUE);
1395         return;
1396     }
1397     switch (mode) {
1398     case GL_POINTS:
1399     case GL_LINE_STRIP:
1400     case GL_LINE_LOOP:
1401     case GL_LINES:
1402     case GL_TRIANGLE_STRIP:
1403     case GL_TRIANGLE_FAN:
1404     case GL_TRIANGLES:
1405         break;
1406     default:
1407         ogles_error(c, GL_INVALID_ENUM);
1408         return;
1409     }
1410     switch (type) {
1411     case GL_UNSIGNED_BYTE:
1412     case GL_UNSIGNED_SHORT:
1413         c->arrays.indicesType = type;
1414         break;
1415     default:
1416         ogles_error(c, GL_INVALID_ENUM);
1417         return;
1418     }
1419     if (count == 0 || !c->arrays.vertex.enable)
1420         return;
1421     if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
1422         return; // all triangles are culled
1423
1424     // clear the vertex-cache
1425     c->vc.clear();
1426     validate_arrays(c, mode);
1427
1428     // if indices are in a buffer object, the pointer is treated as an
1429     // offset in that buffer.
1430     if (c->arrays.element_array_buffer) {
1431         indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
1432     }
1433
1434     const uint32_t enables = c->rasterizer.state.enables;
1435     if (enables & GGL_ENABLE_TMUS)
1436         ogles_lock_textures(c);
1437
1438     drawElementsPrims[mode](c, count, indices);
1439     
1440     if (enables & GGL_ENABLE_TMUS)
1441         ogles_unlock_textures(c);
1442
1443     
1444 #if VC_CACHE_STATISTICS
1445     c->vc.total = count;
1446     c->vc.dump_stats(mode);
1447 #endif
1448 }
1449
1450 // ----------------------------------------------------------------------------
1451 // buffers
1452 // ----------------------------------------------------------------------------
1453
1454 void glBindBuffer(GLenum target, GLuint buffer)
1455 {
1456     ogles_context_t* c = ogles_context_t::get();
1457     if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1458         ogles_error(c, GL_INVALID_ENUM);
1459         return;
1460     }
1461     // create a buffer object, or bind an existing one
1462     buffer_t const* bo = 0;
1463     if (buffer) {
1464         bo = c->bufferObjectManager->bind(buffer);
1465         if (!bo) {
1466             ogles_error(c, GL_OUT_OF_MEMORY);
1467             return;
1468         }
1469     }
1470     ((target == GL_ARRAY_BUFFER) ?
1471             c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
1472 }
1473
1474 void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
1475 {
1476     ogles_context_t* c = ogles_context_t::get();
1477     if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1478         ogles_error(c, GL_INVALID_ENUM);
1479         return;
1480     }
1481     if (size<0) {
1482         ogles_error(c, GL_INVALID_VALUE);
1483         return;
1484     }
1485     if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
1486         ogles_error(c, GL_INVALID_ENUM);
1487         return;
1488     }
1489     buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
1490             c->arrays.array_buffer : c->arrays.element_array_buffer);
1491
1492     if (bo == 0) {
1493         // can't modify buffer 0
1494         ogles_error(c, GL_INVALID_OPERATION);
1495         return;
1496     }
1497
1498     buffer_t* edit_bo = const_cast<buffer_t*>(bo);
1499     if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
1500         ogles_error(c, GL_OUT_OF_MEMORY);
1501         return;
1502     }
1503     if (data) {
1504         memcpy(bo->data, data, size);
1505     }
1506 }
1507
1508 void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
1509 {
1510     ogles_context_t* c = ogles_context_t::get();
1511     if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
1512         ogles_error(c, GL_INVALID_ENUM);
1513         return;
1514     }
1515     if (offset<0 || size<0 || data==0) {
1516         ogles_error(c, GL_INVALID_VALUE);
1517         return;
1518     }
1519     buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
1520             c->arrays.array_buffer : c->arrays.element_array_buffer);
1521
1522     if (bo == 0) {
1523         // can't modify buffer 0
1524         ogles_error(c, GL_INVALID_OPERATION);
1525         return;
1526     }
1527     if (offset+size > bo->size) {
1528         ogles_error(c, GL_INVALID_VALUE);
1529         return;
1530     }
1531     memcpy(bo->data + offset, data, size);
1532 }
1533
1534 void glDeleteBuffers(GLsizei n, const GLuint* buffers)
1535 {
1536     ogles_context_t* c = ogles_context_t::get();
1537     if (n<0) {
1538         ogles_error(c, GL_INVALID_VALUE);
1539         return;
1540     }
1541
1542     for (int i=0 ; i<n ; i++) {
1543         GLuint name = buffers[i];
1544         if (name) {
1545             // unbind bound deleted buffers...
1546             if (c->arrays.element_array_buffer) {
1547                 if (c->arrays.element_array_buffer->name == name) {
1548                     c->arrays.element_array_buffer = 0;
1549                 }
1550             }
1551             if (c->arrays.array_buffer) {
1552                 if (c->arrays.array_buffer->name == name) {
1553                     c->arrays.array_buffer = 0;
1554                 }
1555             }
1556             if (c->arrays.vertex.bo) {
1557                 if (c->arrays.vertex.bo->name == name) {
1558                     c->arrays.vertex.bo = 0;
1559                 }
1560             }
1561             if (c->arrays.normal.bo) {
1562                 if (c->arrays.normal.bo->name == name) {
1563                     c->arrays.normal.bo = 0;
1564                 }
1565             }
1566             if (c->arrays.color.bo) {
1567                 if (c->arrays.color.bo->name == name) {
1568                     c->arrays.color.bo = 0;
1569                 }
1570             }
1571             for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
1572                 if (c->arrays.texture[t].bo) {
1573                     if (c->arrays.texture[t].bo->name == name) {
1574                         c->arrays.texture[t].bo = 0;
1575                     }
1576                 }
1577             }
1578         }
1579     }
1580     c->bufferObjectManager->deleteBuffers(n, buffers);
1581     c->bufferObjectManager->recycleTokens(n, buffers);
1582 }
1583
1584 void glGenBuffers(GLsizei n, GLuint* buffers)
1585 {
1586     ogles_context_t* c = ogles_context_t::get();
1587     if (n<0) {
1588         ogles_error(c, GL_INVALID_VALUE);
1589         return;
1590     }
1591     c->bufferObjectManager->getToken(n, buffers);
1592 }