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