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