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