Home | History | Annotate | Download | only in libpixelflinger
      1 /* libs/pixelflinger/trap.cpp
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #define LOG_TAG "pixelflinger-trap"
     19 
     20 #include <assert.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 
     24 #include <cutils/memory.h>
     25 #include <log/log.h>
     26 
     27 #include "trap.h"
     28 #include "picker.h"
     29 
     30 namespace android {
     31 
     32 // ----------------------------------------------------------------------------
     33 
     34 // enable to see triangles edges
     35 #define DEBUG_TRANGLES  0
     36 
     37 // ----------------------------------------------------------------------------
     38 
     39 static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r);
     40 static void pointx(void *con, const GGLcoord* c, GGLcoord r);
     41 static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r);
     42 static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r);
     43 
     44 static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
     45 static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
     46 static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
     47 
     48 static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
     49 static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
     50 
     51 static void trianglex_validate(void*,
     52         const GGLcoord*, const GGLcoord*, const GGLcoord*);
     53 static void trianglex_small(void*,
     54         const GGLcoord*, const GGLcoord*, const GGLcoord*);
     55 static void trianglex_big(void*,
     56         const GGLcoord*, const GGLcoord*, const GGLcoord*);
     57 static void aa_trianglex(void*,
     58         const GGLcoord*, const GGLcoord*, const GGLcoord*);
     59 static void trianglex_debug(void* con,
     60         const GGLcoord*, const GGLcoord*, const GGLcoord*);
     61 
     62 static void aapolyx(void* con,
     63         const GGLcoord* pts, int count);
     64 
     65 static inline int min(int a, int b) CONST;
     66 static inline int max(int a, int b) CONST;
     67 static inline int min(int a, int b, int c) CONST;
     68 static inline int max(int a, int b, int c) CONST;
     69 
     70 // ----------------------------------------------------------------------------
     71 #if 0
     72 #pragma mark -
     73 #pragma mark Tools
     74 #endif
     75 
     76 inline int min(int a, int b) {
     77     return a<b ? a : b;
     78 }
     79 inline int max(int a, int b) {
     80     return a<b ? b : a;
     81 }
     82 inline int min(int a, int b, int c) {
     83     return min(a,min(b,c));
     84 }
     85 inline int max(int a, int b, int c) {
     86     return max(a,max(b,c));
     87 }
     88 
     89 template <typename T>
     90 static inline void swap(T& a, T& b) {
     91     T t(a);
     92     a = b;
     93     b = t;
     94 }
     95 
     96 static void
     97 triangle_dump_points( const GGLcoord*  v0,
     98                       const GGLcoord*  v1,
     99                       const GGLcoord*  v2 )
    100 {
    101     float tri = 1.0f / TRI_ONE;
    102     ALOGD("  P0=(%.3f, %.3f)  [%08x, %08x]\n"
    103           "  P1=(%.3f, %.3f)  [%08x, %08x]\n"
    104           "  P2=(%.3f, %.3f)  [%08x, %08x]\n",
    105           v0[0]*tri, v0[1]*tri, v0[0], v0[1],
    106           v1[0]*tri, v1[1]*tri, v1[0], v1[1],
    107           v2[0]*tri, v2[1]*tri, v2[0], v2[1] );
    108 }
    109 
    110 // ----------------------------------------------------------------------------
    111 #if 0
    112 #pragma mark -
    113 #pragma mark Misc
    114 #endif
    115 
    116 void ggl_init_trap(context_t* c)
    117 {
    118     ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE);
    119 }
    120 
    121 void ggl_state_changed(context_t* c, int flags)
    122 {
    123     if (ggl_likely(!c->dirty)) {
    124         c->procs.pointx     = pointx_validate;
    125         c->procs.linex      = linex_validate;
    126         c->procs.recti      = recti_validate;
    127         c->procs.trianglex  = trianglex_validate;
    128     }
    129     c->dirty |= uint32_t(flags);
    130 }
    131 
    132 // ----------------------------------------------------------------------------
    133 #if 0
    134 #pragma mark -
    135 #pragma mark Point
    136 #endif
    137 
    138 void pointx_validate(void *con, const GGLcoord* v, GGLcoord rad)
    139 {
    140     GGL_CONTEXT(c, con);
    141     ggl_pick(c);
    142     if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
    143         if (c->state.enables & GGL_ENABLE_POINT_AA_NICE) {
    144             c->procs.pointx = aa_nice_pointx;
    145         } else {
    146             c->procs.pointx = aa_pointx;
    147         }
    148     } else {
    149         c->procs.pointx = pointx;
    150     }
    151     c->procs.pointx(con, v, rad);
    152 }
    153 
    154 void pointx(void *con, const GGLcoord* v, GGLcoord rad)
    155 {
    156     GGL_CONTEXT(c, con);
    157     GGLcoord halfSize = TRI_ROUND(rad) >> 1;
    158     if (halfSize == 0)
    159         halfSize = TRI_HALF;
    160     GGLcoord xc = v[0];
    161     GGLcoord yc = v[1];
    162     if (halfSize & TRI_HALF) { // size odd
    163         xc = TRI_FLOOR(xc) + TRI_HALF;
    164         yc = TRI_FLOOR(yc) + TRI_HALF;
    165     } else { // size even
    166         xc = TRI_ROUND(xc);
    167         yc = TRI_ROUND(yc);
    168     }
    169     GGLint l = (xc - halfSize) >> TRI_FRACTION_BITS;
    170     GGLint t = (yc - halfSize) >> TRI_FRACTION_BITS;
    171     GGLint r = (xc + halfSize) >> TRI_FRACTION_BITS;
    172     GGLint b = (yc + halfSize) >> TRI_FRACTION_BITS;
    173     recti(c, l, t, r, b);
    174 }
    175 
    176 // This way of computing the coverage factor, is more accurate and gives
    177 // better results for small circles, but it is also a lot slower.
    178 // Here we use super-sampling.
    179 static int32_t coverageNice(GGLcoord x, GGLcoord y,
    180         GGLcoord rmin, GGLcoord rmax, GGLcoord rr)
    181 {
    182     const GGLcoord d2 = x*x + y*y;
    183     if (d2 >= rmax) return 0;
    184     if (d2 < rmin)  return 0x7FFF;
    185 
    186     const int kSamples              =  4;
    187     const int kInc                  =  4;    // 1/4 = 0.25
    188     const int kCoverageUnit         =  1;    // 1/(4^2) = 0.0625
    189     const GGLcoord kCoordOffset     = -6;    // -0.375
    190 
    191     int hits = 0;
    192     int x_sample = x + kCoordOffset;
    193     for (int i=0 ; i<kSamples ; i++, x_sample += kInc) {
    194         const int xval = rr - (x_sample * x_sample);
    195         int y_sample = y + kCoordOffset;
    196         for (int j=0 ; j<kSamples ; j++, y_sample += kInc) {
    197             if (xval - (y_sample * y_sample) > 0)
    198                 hits += kCoverageUnit;
    199         }
    200     }
    201     return min(0x7FFF, hits << (15 - kSamples));
    202 }
    203 
    204 
    205 void aa_nice_pointx(void *con, const GGLcoord* v, GGLcoord size)
    206 {
    207     GGL_CONTEXT(c, con);
    208 
    209     GGLcoord rad = ((size + 1)>>1);
    210     GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
    211     GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
    212     GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
    213     GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
    214     GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
    215     GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
    216 
    217     // scissor...
    218     if (l < GGLint(c->state.scissor.left)) {
    219         xstart += TRI_FROM_INT(c->state.scissor.left-l);
    220         l = GGLint(c->state.scissor.left);
    221     }
    222     if (t < GGLint(c->state.scissor.top)) {
    223         ystart += TRI_FROM_INT(c->state.scissor.top-t);
    224         t = GGLint(c->state.scissor.top);
    225     }
    226     if (r > GGLint(c->state.scissor.right)) {
    227         r = GGLint(c->state.scissor.right);
    228     }
    229     if (b > GGLint(c->state.scissor.bottom)) {
    230         b = GGLint(c->state.scissor.bottom);
    231     }
    232 
    233     int xc = r - l;
    234     int yc = b - t;
    235     if (xc>0 && yc>0) {
    236         int16_t* covPtr = c->state.buffers.coverage;
    237         const int32_t sqr2Over2 = 0xC; // rounded up
    238         GGLcoord rr = rad*rad;
    239         GGLcoord rmin = (rad - sqr2Over2)*(rad - sqr2Over2);
    240         GGLcoord rmax = (rad + sqr2Over2)*(rad + sqr2Over2);
    241         GGLcoord y = ystart;
    242         c->iterators.xl = l;
    243         c->iterators.xr = r;
    244         c->init_y(c, t);
    245         do {
    246             // compute coverage factors for each pixel
    247             GGLcoord x = xstart;
    248             for (int i=l ; i<r ; i++) {
    249                 covPtr[i] = coverageNice(x, y, rmin, rmax, rr);
    250                 x += TRI_ONE;
    251             }
    252             y += TRI_ONE;
    253             c->scanline(c);
    254             c->step_y(c);
    255         } while (--yc);
    256     }
    257 }
    258 
    259 // This is a cheap way of computing the coverage factor for a circle.
    260 // We just lerp between the circles of radii r-sqrt(2)/2 and r+sqrt(2)/2
    261 static inline int32_t coverageFast(GGLcoord x, GGLcoord y,
    262         GGLcoord rmin, GGLcoord rmax, GGLcoord scale)
    263 {
    264     const GGLcoord d2 = x*x + y*y;
    265     if (d2 >= rmax) return 0;
    266     if (d2 < rmin)  return 0x7FFF;
    267     return 0x7FFF - (d2-rmin)*scale;
    268 }
    269 
    270 void aa_pointx(void *con, const GGLcoord* v, GGLcoord size)
    271 {
    272     GGL_CONTEXT(c, con);
    273 
    274     GGLcoord rad = ((size + 1)>>1);
    275     GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
    276     GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
    277     GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
    278     GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
    279     GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
    280     GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
    281 
    282     // scissor...
    283     if (l < GGLint(c->state.scissor.left)) {
    284         xstart += TRI_FROM_INT(c->state.scissor.left-l);
    285         l = GGLint(c->state.scissor.left);
    286     }
    287     if (t < GGLint(c->state.scissor.top)) {
    288         ystart += TRI_FROM_INT(c->state.scissor.top-t);
    289         t = GGLint(c->state.scissor.top);
    290     }
    291     if (r > GGLint(c->state.scissor.right)) {
    292         r = GGLint(c->state.scissor.right);
    293     }
    294     if (b > GGLint(c->state.scissor.bottom)) {
    295         b = GGLint(c->state.scissor.bottom);
    296     }
    297 
    298     int xc = r - l;
    299     int yc = b - t;
    300     if (xc>0 && yc>0) {
    301         int16_t* covPtr = c->state.buffers.coverage;
    302         rad <<= 4;
    303         const int32_t sqr2Over2 = 0xB5;    // fixed-point 24.8
    304         GGLcoord rmin = rad - sqr2Over2;
    305         GGLcoord rmax = rad + sqr2Over2;
    306         GGLcoord scale;
    307         rmin *= rmin;
    308         rmax *= rmax;
    309         scale = 0x800000 / (rmax - rmin);
    310         rmin >>= 8;
    311         rmax >>= 8;
    312 
    313         GGLcoord y = ystart;
    314         c->iterators.xl = l;
    315         c->iterators.xr = r;
    316         c->init_y(c, t);
    317 
    318         do {
    319             // compute coverage factors for each pixel
    320             GGLcoord x = xstart;
    321             for (int i=l ; i<r ; i++) {
    322                 covPtr[i] = coverageFast(x, y, rmin, rmax, scale);
    323                 x += TRI_ONE;
    324             }
    325             y += TRI_ONE;
    326             c->scanline(c);
    327             c->step_y(c);
    328         } while (--yc);
    329     }
    330 }
    331 
    332 // ----------------------------------------------------------------------------
    333 #if 0
    334 #pragma mark -
    335 #pragma mark Line
    336 #endif
    337 
    338 void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w)
    339 {
    340     GGL_CONTEXT(c, con);
    341     ggl_pick(c);
    342     if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
    343         c->procs.linex = aa_linex;
    344     } else {
    345         c->procs.linex = linex;
    346     }
    347     c->procs.linex(con, v0, v1, w);
    348 }
    349 
    350 static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
    351 {
    352     GGL_CONTEXT(c, con);
    353     GGLcoord v[4][2];
    354     v[0][0] = v0[0];    v[0][1] = v0[1];
    355     v[1][0] = v1[0];    v[1][1] = v1[1];
    356     v0 = v[0];
    357     v1 = v[1];
    358     const GGLcoord dx = abs(v0[0] - v1[0]);
    359     const GGLcoord dy = abs(v0[1] - v1[1]);
    360     GGLcoord nx, ny;
    361     nx = ny = 0;
    362 
    363     GGLcoord halfWidth = TRI_ROUND(width) >> 1;
    364     if (halfWidth == 0)
    365         halfWidth = TRI_HALF;
    366 
    367     ((dx > dy) ? ny : nx) = halfWidth;
    368     v[2][0] = v1[0];    v[2][1] = v1[1];
    369     v[3][0] = v0[0];    v[3][1] = v0[1];
    370     v[0][0] += nx;      v[0][1] += ny;
    371     v[1][0] += nx;      v[1][1] += ny;
    372     v[2][0] -= nx;      v[2][1] -= ny;
    373     v[3][0] -= nx;      v[3][1] -= ny;
    374     trianglex_big(con, v[0], v[1], v[2]);
    375     trianglex_big(con, v[0], v[2], v[3]);
    376 }
    377 
    378 static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
    379 {
    380     GGL_CONTEXT(c, con);
    381     GGLcoord v[4][2];
    382     v[0][0] = v0[0];    v[0][1] = v0[1];
    383     v[1][0] = v1[0];    v[1][1] = v1[1];
    384     v0 = v[0];
    385     v1 = v[1];
    386 
    387     const GGLcoord dx = v0[0] - v1[0];
    388     const GGLcoord dy = v0[1] - v1[1];
    389     GGLcoord nx = -dy;
    390     GGLcoord ny =  dx;
    391 
    392     // generally, this will be well below 1.0
    393     const GGLfixed norm = gglMulx(width, gglSqrtRecipx(nx*nx+ny*ny), 4);
    394     nx = gglMulx(nx, norm, 21);
    395     ny = gglMulx(ny, norm, 21);
    396 
    397     v[2][0] = v1[0];    v[2][1] = v1[1];
    398     v[3][0] = v0[0];    v[3][1] = v0[1];
    399     v[0][0] += nx;      v[0][1] += ny;
    400     v[1][0] += nx;      v[1][1] += ny;
    401     v[2][0] -= nx;      v[2][1] -= ny;
    402     v[3][0] -= nx;      v[3][1] -= ny;
    403     aapolyx(con, v[0], 4);
    404 }
    405 
    406 
    407 // ----------------------------------------------------------------------------
    408 #if 0
    409 #pragma mark -
    410 #pragma mark Rect
    411 #endif
    412 
    413 void recti_validate(void *con, GGLint l, GGLint t, GGLint r, GGLint b)
    414 {
    415     GGL_CONTEXT(c, con);
    416     ggl_pick(c);
    417     c->procs.recti = recti;
    418     c->procs.recti(con, l, t, r, b);
    419 }
    420 
    421 void recti(void* con, GGLint l, GGLint t, GGLint r, GGLint b)
    422 {
    423     GGL_CONTEXT(c, con);
    424 
    425     // scissor...
    426     if (l < GGLint(c->state.scissor.left))
    427         l = GGLint(c->state.scissor.left);
    428     if (t < GGLint(c->state.scissor.top))
    429         t = GGLint(c->state.scissor.top);
    430     if (r > GGLint(c->state.scissor.right))
    431         r = GGLint(c->state.scissor.right);
    432     if (b > GGLint(c->state.scissor.bottom))
    433         b = GGLint(c->state.scissor.bottom);
    434 
    435     int xc = r - l;
    436     int yc = b - t;
    437     if (xc>0 && yc>0) {
    438         c->iterators.xl = l;
    439         c->iterators.xr = r;
    440         c->init_y(c, t);
    441         c->rect(c, yc);
    442     }
    443 }
    444 
    445 // ----------------------------------------------------------------------------
    446 #if 0
    447 #pragma mark -
    448 #pragma mark Triangle / Debugging
    449 #endif
    450 
    451 static void scanline_set(context_t* c)
    452 {
    453     int32_t x = c->iterators.xl;
    454     size_t ct = c->iterators.xr - x;
    455     int32_t y = c->iterators.y;
    456     surface_t* cb = &(c->state.buffers.color);
    457     const GGLFormat* fp = &(c->formats[cb->format]);
    458     uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
    459                             (x + (cb->stride * y)) * fp->size;
    460     const size_t size = ct * fp->size;
    461     memset(dst, 0xFF, size);
    462 }
    463 
    464 static void trianglex_debug(void* con,
    465         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
    466 {
    467     GGL_CONTEXT(c, con);
    468     if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
    469         aa_trianglex(con,v0,v1,v2);
    470     } else {
    471         trianglex_big(con,v0,v1,v2);
    472     }
    473 	void (*save_scanline)(context_t*)  = c->scanline;
    474     c->scanline = scanline_set;
    475     linex(con, v0, v1, TRI_ONE);
    476     linex(con, v1, v2, TRI_ONE);
    477     linex(con, v2, v0, TRI_ONE);
    478     c->scanline = save_scanline;
    479 }
    480 
    481 static void trianglex_xor(void* con,
    482         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
    483 {
    484     trianglex_big(con,v0,v1,v2);
    485     trianglex_small(con,v0,v1,v2);
    486 }
    487 
    488 // ----------------------------------------------------------------------------
    489 #if 0
    490 #pragma mark -
    491 #pragma mark Triangle
    492 #endif
    493 
    494 void trianglex_validate(void *con,
    495         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
    496 {
    497     GGL_CONTEXT(c, con);
    498     ggl_pick(c);
    499     if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
    500         c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : aa_trianglex;
    501     } else {
    502         c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : trianglex_big;
    503     }
    504     c->procs.trianglex(con, v0, v1, v2);
    505 }
    506 
    507 // ----------------------------------------------------------------------------
    508 
    509 void trianglex_small(void* con,
    510         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
    511 {
    512     GGL_CONTEXT(c, con);
    513 
    514     // vertices are in 28.4 fixed point, which allows
    515     // us to use 32 bits multiplies below.
    516     int32_t x0 = v0[0];
    517     int32_t y0 = v0[1];
    518     int32_t x1 = v1[0];
    519     int32_t y1 = v1[1];
    520     int32_t x2 = v2[0];
    521     int32_t y2 = v2[1];
    522 
    523     int32_t dx01 = x0 - x1;
    524     int32_t dy20 = y2 - y0;
    525     int32_t dy01 = y0 - y1;
    526     int32_t dx20 = x2 - x0;
    527 
    528     // The code below works only with CCW triangles
    529     // so if we get a CW triangle, we need to swap two of its vertices
    530     if (dx01*dy20 < dy01*dx20) {
    531         swap(x0, x1);
    532         swap(y0, y1);
    533         dx01 = x0 - x1;
    534         dy01 = y0 - y1;
    535         dx20 = x2 - x0;
    536         dy20 = y2 - y0;
    537     }
    538     int32_t dx12 = x1 - x2;
    539     int32_t dy12 = y1 - y2;
    540 
    541     // bounding box & scissor
    542     const int32_t bminx = TRI_FLOOR(min(x0, x1, x2)) >> TRI_FRACTION_BITS;
    543     const int32_t bminy = TRI_FLOOR(min(y0, y1, y2)) >> TRI_FRACTION_BITS;
    544     const int32_t bmaxx = TRI_CEIL( max(x0, x1, x2)) >> TRI_FRACTION_BITS;
    545     const int32_t bmaxy = TRI_CEIL( max(y0, y1, y2)) >> TRI_FRACTION_BITS;
    546     const int32_t minx = max(bminx, c->state.scissor.left);
    547     const int32_t miny = max(bminy, c->state.scissor.top);
    548     const int32_t maxx = min(bmaxx, c->state.scissor.right);
    549     const int32_t maxy = min(bmaxy, c->state.scissor.bottom);
    550     if ((minx >= maxx) || (miny >= maxy))
    551         return; // too small or clipped out...
    552 
    553     // step equations to the bounding box and snap to pixel center
    554     const int32_t my = (miny << TRI_FRACTION_BITS) + TRI_HALF;
    555     const int32_t mx = (minx << TRI_FRACTION_BITS) + TRI_HALF;
    556     int32_t ey0 = dy01 * (x0 - mx) - dx01 * (y0 - my);
    557     int32_t ey1 = dy12 * (x1 - mx) - dx12 * (y1 - my);
    558     int32_t ey2 = dy20 * (x2 - mx) - dx20 * (y2 - my);
    559 
    560     // right-exclusive fill rule, to avoid rare cases
    561     // of over drawing
    562     if (dy01<0 || (dy01 == 0 && dx01>0)) ey0++;
    563     if (dy12<0 || (dy12 == 0 && dx12>0)) ey1++;
    564     if (dy20<0 || (dy20 == 0 && dx20>0)) ey2++;
    565 
    566     c->init_y(c, miny);
    567     for (int32_t y = miny; y < maxy; y++) {
    568         int32_t ex0 = ey0;
    569         int32_t ex1 = ey1;
    570         int32_t ex2 = ey2;
    571         int32_t xl, xr;
    572         for (xl=minx ; xl<maxx ; xl++) {
    573             if (ex0>0 && ex1>0 && ex2>0)
    574                 break; // all strictly positive
    575             ex0 -= dy01 << TRI_FRACTION_BITS;
    576             ex1 -= dy12 << TRI_FRACTION_BITS;
    577             ex2 -= dy20 << TRI_FRACTION_BITS;
    578         }
    579         xr = xl;
    580         for ( ; xr<maxx ; xr++) {
    581             if (!(ex0>0 && ex1>0 && ex2>0))
    582                 break; // not all strictly positive
    583             ex0 -= dy01 << TRI_FRACTION_BITS;
    584             ex1 -= dy12 << TRI_FRACTION_BITS;
    585             ex2 -= dy20 << TRI_FRACTION_BITS;
    586         }
    587 
    588         if (xl < xr) {
    589             c->iterators.xl = xl;
    590             c->iterators.xr = xr;
    591             c->scanline(c);
    592         }
    593         c->step_y(c);
    594 
    595         ey0 += dx01 << TRI_FRACTION_BITS;
    596         ey1 += dx12 << TRI_FRACTION_BITS;
    597         ey2 += dx20 << TRI_FRACTION_BITS;
    598     }
    599 }
    600 
    601 // ----------------------------------------------------------------------------
    602 #if 0
    603 #pragma mark -
    604 #endif
    605 
    606 // the following routine fills a triangle via edge stepping, which
    607 // unfortunately requires divisions in the setup phase to get right,
    608 // it should probably only be used for relatively large trianges
    609 
    610 
    611 // x = y*DX/DY    (ou DX and DY are constants, DY > 0, et y >= 0)
    612 //
    613 // for an equation of the type:
    614 //      x' = y*K/2^p     (with K and p constants "carefully chosen")
    615 //
    616 // We can now do a DDA without precision loss. We define 'e' by:
    617 //      x' - x = y*(DX/DY - K/2^p) = y*e
    618 //
    619 // If we choose K = round(DX*2^p/DY) then,
    620 //      abs(e) <= 1/2^(p+1) by construction
    621 //
    622 // therefore abs(x'-x) = y*abs(e) <= y/2^(p+1) <= DY/2^(p+1) <= DMAX/2^(p+1)
    623 //
    624 // which means that if DMAX <= 2^p, therefore abs(x-x') <= 1/2, including
    625 // at the last line. In fact, it's even a strict inequality except in one
    626 // extrem case (DY == DMAX et e = +/- 1/2)
    627 //
    628 // Applying that to our coordinates, we need 2^p >= 4096*16 = 65536
    629 // so p = 16 is enough, we're so lucky!
    630 
    631 const int TRI_ITERATORS_BITS = 16;
    632 
    633 struct Edge
    634 {
    635   int32_t  x;      // edge position in 16.16 coordinates
    636   int32_t  x_incr; // on each step, increment x by that amount
    637   int32_t  y_top;  // starting scanline, 16.4 format
    638   int32_t  y_bot;
    639 };
    640 
    641 static void
    642 edge_dump( Edge*  edge )
    643 {
    644   ALOGI( "  top=%d (%.3f)  bot=%d (%.3f)  x=%d (%.3f)  ix=%d (%.3f)",
    645         edge->y_top, edge->y_top/float(TRI_ONE),
    646 		edge->y_bot, edge->y_bot/float(TRI_ONE),
    647 		edge->x, edge->x/float(FIXED_ONE),
    648 		edge->x_incr, edge->x_incr/float(FIXED_ONE) );
    649 }
    650 
    651 static void
    652 triangle_dump_edges( Edge*  edges,
    653                      int            count )
    654 {
    655     ALOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" );
    656 	for ( ; count > 0; count--, edges++ )
    657 	  edge_dump( edges );
    658 }
    659 
    660 // the following function sets up an edge, it assumes
    661 // that ymin and ymax are in already in the 'reduced'
    662 // format
    663 static __attribute__((noinline))
    664 void edge_setup(
    665         Edge*           edges,
    666         int*            pcount,
    667         const GGLcoord* p1,
    668         const GGLcoord* p2,
    669         int32_t         ymin,
    670         int32_t         ymax )
    671 {
    672 	const GGLfixed*  top = p1;
    673 	const GGLfixed*  bot = p2;
    674 	Edge*    edge = edges + *pcount;
    675 
    676 	if (top[1] > bot[1]) {
    677         swap(top, bot);
    678 	}
    679 
    680 	int  y1 = top[1] | 1;
    681 	int  y2 = bot[1] | 1;
    682 	int  dy = y2 - y1;
    683 
    684 	if ( dy == 0 || y1 > ymax || y2 < ymin )
    685 		return;
    686 
    687 	if ( y1 > ymin )
    688 		ymin = TRI_SNAP_NEXT_HALF(y1);
    689 
    690 	if ( y2 < ymax )
    691 		ymax = TRI_SNAP_PREV_HALF(y2);
    692 
    693 	if ( ymin > ymax )  // when the edge doesn't cross any scanline
    694 	  return;
    695 
    696 	const int x1 = top[0];
    697 	const int dx = bot[0] - x1;
    698     const int shift = TRI_ITERATORS_BITS - TRI_FRACTION_BITS;
    699 
    700 	// setup edge fields
    701     // We add 0.5 to edge->x here because it simplifies the rounding
    702     // in triangle_sweep_edges() -- this doesn't change the ordering of 'x'
    703 	edge->x      = (x1 << shift) + (1LU << (TRI_ITERATORS_BITS-1));
    704 	edge->x_incr = 0;
    705 	edge->y_top  = ymin;
    706 	edge->y_bot  = ymax;
    707 
    708 	if (ggl_likely(ymin <= ymax && dx)) {
    709         edge->x_incr = gglDivQ16(dx, dy);
    710     }
    711     if (ggl_likely(y1 < ymin)) {
    712         int32_t xadjust = (edge->x_incr * (ymin-y1)) >> TRI_FRACTION_BITS;
    713         edge->x += xadjust;
    714     }
    715 
    716 	++*pcount;
    717 }
    718 
    719 
    720 static void
    721 triangle_sweep_edges( Edge*  left,
    722                       Edge*  right,
    723 					  int            ytop,
    724 					  int            ybot,
    725 					  context_t*     c )
    726 {
    727     int count = ((ybot - ytop)>>TRI_FRACTION_BITS) + 1;
    728     if (count<=0) return;
    729 
    730     // sort the edges horizontally
    731     if ((left->x > right->x) ||
    732         ((left->x == right->x) && (left->x_incr > right->x_incr))) {
    733         swap(left, right);
    734     }
    735 
    736     int left_x = left->x;
    737     int right_x = right->x;
    738     const int left_xi = left->x_incr;
    739     const int right_xi  = right->x_incr;
    740     left->x  += left_xi * count;
    741     right->x += right_xi * count;
    742 
    743 	const int xmin = c->state.scissor.left;
    744 	const int xmax = c->state.scissor.right;
    745     do {
    746         // horizontal scissoring
    747         const int32_t xl = max(left_x  >> TRI_ITERATORS_BITS, xmin);
    748         const int32_t xr = min(right_x >> TRI_ITERATORS_BITS, xmax);
    749         left_x  += left_xi;
    750         right_x += right_xi;
    751         // invoke the scanline rasterizer
    752         if (ggl_likely(xl < xr)) {
    753             c->iterators.xl = xl;
    754             c->iterators.xr = xr;
    755             c->scanline(c);
    756         }
    757 		c->step_y(c);
    758 	} while (--count);
    759 }
    760 
    761 
    762 void trianglex_big(void* con,
    763         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
    764 {
    765     GGL_CONTEXT(c, con);
    766 
    767     Edge edges[3];
    768 	int num_edges = 0;
    769 	int32_t ymin = TRI_FROM_INT(c->state.scissor.top)    + TRI_HALF;
    770 	int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom) - TRI_HALF;
    771 
    772 	edge_setup( edges, &num_edges, v0, v1, ymin, ymax );
    773 	edge_setup( edges, &num_edges, v0, v2, ymin, ymax );
    774 	edge_setup( edges, &num_edges, v1, v2, ymin, ymax );
    775 
    776     if (ggl_unlikely(num_edges<2))  // for really tiny triangles that don't
    777 		return;                     // cross any scanline centers
    778 
    779     Edge* left  = &edges[0];
    780     Edge* right = &edges[1];
    781     Edge* other = &edges[2];
    782     int32_t y_top = min(left->y_top, right->y_top);
    783     int32_t y_bot = max(left->y_bot, right->y_bot);
    784 
    785 	if (ggl_likely(num_edges==3)) {
    786         y_top = min(y_top, edges[2].y_top);
    787         y_bot = max(y_bot, edges[2].y_bot);
    788 		if (edges[0].y_top > y_top) {
    789             other = &edges[0];
    790             left  = &edges[2];
    791 		} else if (edges[1].y_top > y_top) {
    792             other = &edges[1];
    793             right = &edges[2];
    794 		}
    795     }
    796 
    797     c->init_y(c, y_top >> TRI_FRACTION_BITS);
    798 
    799     int32_t y_mid = min(left->y_bot, right->y_bot);
    800     triangle_sweep_edges( left, right, y_top, y_mid, c );
    801 
    802     // second scanline sweep loop, if necessary
    803     y_mid += TRI_ONE;
    804     if (y_mid <= y_bot) {
    805         ((left->y_bot == y_bot) ? right : left) = other;
    806         if (other->y_top < y_mid) {
    807             other->x += other->x_incr;
    808         }
    809         triangle_sweep_edges( left, right, y_mid, y_bot, c );
    810     }
    811 }
    812 
    813 void aa_trianglex(void* con,
    814         const GGLcoord* a, const GGLcoord* b, const GGLcoord* c)
    815 {
    816     GGLcoord pts[6] = { a[0], a[1], b[0], b[1], c[0], c[1] };
    817     aapolyx(con, pts, 3);
    818 }
    819 
    820 // ----------------------------------------------------------------------------
    821 #if 0
    822 #pragma mark -
    823 #endif
    824 
    825 struct AAEdge
    826 {
    827     GGLfixed x;         // edge position in 12.16 coordinates
    828     GGLfixed x_incr;    // on each y step, increment x by that amount
    829     GGLfixed y_incr;    // on each x step, increment y by that amount
    830     int16_t y_top;      // starting scanline, 12.4 format
    831     int16_t y_bot;      // starting scanline, 12.4 format
    832     void dump();
    833 };
    834 
    835 void AAEdge::dump()
    836 {
    837     float tri  = 1.0f / TRI_ONE;
    838     float iter = 1.0f / (1<<TRI_ITERATORS_BITS);
    839     float fix  = 1.0f / FIXED_ONE;
    840     ALOGD(   "x=%08x (%.3f), "
    841             "x_incr=%08x (%.3f), y_incr=%08x (%.3f), "
    842             "y_top=%08x (%.3f), y_bot=%08x (%.3f) ",
    843         x, x*fix,
    844         x_incr, x_incr*iter,
    845         y_incr, y_incr*iter,
    846         y_top, y_top*tri,
    847         y_bot, y_bot*tri );
    848 }
    849 
    850 // the following function sets up an edge, it assumes
    851 // that ymin and ymax are in already in the 'reduced'
    852 // format
    853 static __attribute__((noinline))
    854 void aa_edge_setup(
    855         AAEdge*         edges,
    856         int*            pcount,
    857         const GGLcoord* p1,
    858         const GGLcoord* p2,
    859         int32_t         ymin,
    860         int32_t         ymax )
    861 {
    862     const GGLfixed*  top = p1;
    863     const GGLfixed*  bot = p2;
    864     AAEdge* edge = edges + *pcount;
    865 
    866     if (top[1] > bot[1])
    867         swap(top, bot);
    868 
    869     int  y1 = top[1];
    870     int  y2 = bot[1];
    871     int  dy = y2 - y1;
    872 
    873     if (dy==0 || y1>ymax || y2<ymin)
    874         return;
    875 
    876     if (y1 > ymin)
    877         ymin = y1;
    878 
    879     if (y2 < ymax)
    880         ymax = y2;
    881 
    882     const int x1 = top[0];
    883     const int dx = bot[0] - x1;
    884     const int shift = FIXED_BITS - TRI_FRACTION_BITS;
    885 
    886     // setup edge fields
    887     edge->x      = x1 << shift;
    888     edge->x_incr = 0;
    889     edge->y_top  = ymin;
    890     edge->y_bot  = ymax;
    891     edge->y_incr = 0x7FFFFFFF;
    892 
    893     if (ggl_likely(ymin <= ymax && dx)) {
    894         edge->x_incr = gglDivQ16(dx, dy);
    895         if (dx != 0) {
    896             edge->y_incr = abs(gglDivQ16(dy, dx));
    897         }
    898     }
    899     if (ggl_likely(y1 < ymin)) {
    900         int32_t xadjust = (edge->x_incr * (ymin-y1))
    901                 >> (TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS);
    902         edge->x += xadjust;
    903     }
    904 
    905     ++*pcount;
    906 }
    907 
    908 
    909 typedef int (*compar_t)(const void*, const void*);
    910 static int compare_edges(const AAEdge *e0, const AAEdge *e1) {
    911     if (e0->y_top > e1->y_top)      return 1;
    912     if (e0->y_top < e1->y_top)      return -1;
    913     if (e0->x > e1->x)              return 1;
    914     if (e0->x < e1->x)              return -1;
    915     if (e0->x_incr > e1->x_incr)    return 1;
    916     if (e0->x_incr < e1->x_incr)    return -1;
    917     return 0; // same edges, should never happen
    918 }
    919 
    920 static inline
    921 void SET_COVERAGE(int16_t*& p, int32_t value, ssize_t n)
    922 {
    923     android_memset16((uint16_t*)p, value, n*2);
    924     p += n;
    925 }
    926 
    927 static inline
    928 void ADD_COVERAGE(int16_t*& p, int32_t value)
    929 {
    930     value = *p + value;
    931     if (value >= 0x8000)
    932         value = 0x7FFF;
    933     *p++ = value;
    934 }
    935 
    936 static inline
    937 void SUB_COVERAGE(int16_t*& p, int32_t value)
    938 {
    939     value = *p - value;
    940     value &= ~(value>>31);
    941     *p++ = value;
    942 }
    943 
    944 void aapolyx(void* con,
    945         const GGLcoord* pts, int count)
    946 {
    947     /*
    948      * NOTE: This routine assumes that the polygon has been clipped to the
    949      * viewport already, that is, no vertex lies outside of the framebuffer.
    950      * If this happens, the code below won't corrupt memory but the
    951      * coverage values may not be correct.
    952      */
    953 
    954     GGL_CONTEXT(c, con);
    955 
    956     // we do only quads for now (it's used for thick lines)
    957     if ((count>4) || (count<2)) return;
    958 
    959     // take scissor into account
    960     const int xmin = c->state.scissor.left;
    961     const int xmax = c->state.scissor.right;
    962     if (xmin >= xmax) return;
    963 
    964     // generate edges from the vertices
    965     int32_t ymin = TRI_FROM_INT(c->state.scissor.top);
    966     int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom);
    967     if (ymin >= ymax) return;
    968 
    969     AAEdge edges[4];
    970     int num_edges = 0;
    971     GGLcoord const * p = pts;
    972     for (int i=0 ; i<count-1 ; i++, p+=2) {
    973         aa_edge_setup(edges, &num_edges, p, p+2, ymin, ymax);
    974     }
    975     aa_edge_setup(edges, &num_edges, p, pts, ymin, ymax );
    976     if (ggl_unlikely(num_edges<2))
    977         return;
    978 
    979     // sort the edge list top to bottom, left to right.
    980     qsort(edges, num_edges, sizeof(AAEdge), (compar_t)compare_edges);
    981 
    982     int16_t* const covPtr = c->state.buffers.coverage;
    983     memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
    984 
    985     // now, sweep all edges in order
    986     // start with the 2 first edges. We know that they share their top
    987     // vertex, by construction.
    988     int i = 2;
    989     AAEdge* left  = &edges[0];
    990     AAEdge* right = &edges[1];
    991     int32_t yt = left->y_top;
    992     GGLfixed l = left->x;
    993     GGLfixed r = right->x;
    994     int retire = 0;
    995     int16_t* coverage;
    996 
    997     // at this point we can initialize the rasterizer
    998     c->init_y(c, yt>>TRI_FRACTION_BITS);
    999     c->iterators.xl = xmax;
   1000     c->iterators.xr = xmin;
   1001 
   1002     do {
   1003         int32_t y = min(min(left->y_bot, right->y_bot), TRI_FLOOR(yt + TRI_ONE));
   1004         const int32_t shift = TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS;
   1005         const int cf_shift = (1 + TRI_FRACTION_BITS*2 + TRI_ITERATORS_BITS - 15);
   1006 
   1007         // compute xmin and xmax for the left edge
   1008         GGLfixed l_min = gglMulAddx(left->x_incr, y - left->y_top, left->x, shift);
   1009         GGLfixed l_max = l;
   1010         l = l_min;
   1011         if (l_min > l_max)
   1012             swap(l_min, l_max);
   1013 
   1014         // compute xmin and xmax for the right edge
   1015         GGLfixed r_min = gglMulAddx(right->x_incr, y - right->y_top, right->x, shift);
   1016         GGLfixed r_max = r;
   1017         r = r_min;
   1018         if (r_min > r_max)
   1019             swap(r_min, r_max);
   1020 
   1021         // make sure we're not touching coverage values outside of the
   1022         // framebuffer
   1023         l_min &= ~(l_min>>31);
   1024         r_min &= ~(r_min>>31);
   1025         l_max &= ~(l_max>>31);
   1026         r_max &= ~(r_max>>31);
   1027         if (gglFixedToIntFloor(l_min) >= xmax) l_min = gglIntToFixed(xmax)-1;
   1028         if (gglFixedToIntFloor(r_min) >= xmax) r_min = gglIntToFixed(xmax)-1;
   1029         if (gglFixedToIntCeil(l_max) >= xmax)  l_max = gglIntToFixed(xmax)-1;
   1030         if (gglFixedToIntCeil(r_max) >= xmax)  r_max = gglIntToFixed(xmax)-1;
   1031 
   1032         // compute the integer versions of the above
   1033         const GGLfixed l_min_i = gglFloorx(l_min);
   1034         const GGLfixed l_max_i = gglCeilx (l_max);
   1035         const GGLfixed r_min_i = gglFloorx(r_min);
   1036         const GGLfixed r_max_i = gglCeilx (r_max);
   1037 
   1038         // clip horizontally using the scissor
   1039         const int xml = max(xmin, gglFixedToIntFloor(l_min_i));
   1040         const int xmr = min(xmax, gglFixedToIntFloor(r_max_i));
   1041 
   1042         // if we just stepped to a new scanline, render the previous one.
   1043         // and clear the coverage buffer
   1044         if (retire) {
   1045             if (c->iterators.xl < c->iterators.xr)
   1046                 c->scanline(c);
   1047             c->step_y(c);
   1048             memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
   1049             c->iterators.xl = xml;
   1050             c->iterators.xr = xmr;
   1051         } else {
   1052             // update the horizontal range of this scanline
   1053             c->iterators.xl = min(c->iterators.xl, xml);
   1054             c->iterators.xr = max(c->iterators.xr, xmr);
   1055         }
   1056 
   1057         coverage = covPtr + gglFixedToIntFloor(l_min_i);
   1058         if (l_min_i == gglFloorx(l_max)) {
   1059 
   1060             /*
   1061              *  fully traverse this pixel vertically
   1062              *       l_max
   1063              *  +-----/--+  yt
   1064              *  |    /   |
   1065              *  |   /    |
   1066              *  |  /     |
   1067              *  +-/------+  y
   1068              *   l_min  (l_min_i + TRI_ONE)
   1069              */
   1070 
   1071             GGLfixed dx = l_max - l_min;
   1072             int32_t dy = y - yt;
   1073             int cf = gglMulx((dx >> 1) + (l_min_i + FIXED_ONE - l_max), dy,
   1074                 FIXED_BITS + TRI_FRACTION_BITS - 15);
   1075             ADD_COVERAGE(coverage, cf);
   1076             // all pixels on the right have cf = 1.0
   1077         } else {
   1078             /*
   1079              *  spans several pixels in one scanline
   1080              *            l_max
   1081              *  +--------+--/-----+  yt
   1082              *  |        |/       |
   1083              *  |       /|        |
   1084              *  |     /  |        |
   1085              *  +---/----+--------+  y
   1086              *   l_min (l_min_i + TRI_ONE)
   1087              */
   1088 
   1089             // handle the first pixel separately...
   1090             const int32_t y_incr = left->y_incr;
   1091             int32_t dx = TRI_FROM_FIXED(l_min_i - l_min) + TRI_ONE;
   1092             int32_t cf = (dx * dx * y_incr) >> cf_shift;
   1093             ADD_COVERAGE(coverage, cf);
   1094 
   1095             // following pixels get covered by y_incr, but we need
   1096             // to fix-up the cf to account for previous partial pixel
   1097             dx = TRI_FROM_FIXED(l_min - l_min_i);
   1098             cf -= (dx * dx * y_incr) >> cf_shift;
   1099             for (int x = l_min_i+FIXED_ONE ; x < l_max_i-FIXED_ONE ; x += FIXED_ONE) {
   1100                 cf += y_incr >> (TRI_ITERATORS_BITS-15);
   1101                 ADD_COVERAGE(coverage, cf);
   1102             }
   1103 
   1104             // and the last pixel
   1105             dx = TRI_FROM_FIXED(l_max - l_max_i) - TRI_ONE;
   1106             cf += (dx * dx * y_incr) >> cf_shift;
   1107             ADD_COVERAGE(coverage, cf);
   1108         }
   1109 
   1110         // now, fill up all fully covered pixels
   1111         coverage = covPtr + gglFixedToIntFloor(l_max_i);
   1112         int cf = ((y - yt) << (15 - TRI_FRACTION_BITS));
   1113         if (ggl_likely(cf >= 0x8000)) {
   1114             SET_COVERAGE(coverage, 0x7FFF, ((r_max - l_max_i)>>FIXED_BITS)+1);
   1115         } else {
   1116             for (int x=l_max_i ; x<r_max ; x+=FIXED_ONE) {
   1117                 ADD_COVERAGE(coverage, cf);
   1118             }
   1119         }
   1120 
   1121         // subtract the coverage of the right edge
   1122         coverage = covPtr + gglFixedToIntFloor(r_min_i);
   1123         if (r_min_i == gglFloorx(r_max)) {
   1124             GGLfixed dx = r_max - r_min;
   1125             int32_t dy = y - yt;
   1126             int cf = gglMulx((dx >> 1) + (r_min_i + FIXED_ONE - r_max), dy,
   1127                 FIXED_BITS + TRI_FRACTION_BITS - 15);
   1128             SUB_COVERAGE(coverage, cf);
   1129             // all pixels on the right have cf = 1.0
   1130         } else {
   1131             // handle the first pixel separately...
   1132             const int32_t y_incr = right->y_incr;
   1133             int32_t dx = TRI_FROM_FIXED(r_min_i - r_min) + TRI_ONE;
   1134             int32_t cf = (dx * dx * y_incr) >> cf_shift;
   1135             SUB_COVERAGE(coverage, cf);
   1136 
   1137             // following pixels get covered by y_incr, but we need
   1138             // to fix-up the cf to account for previous partial pixel
   1139             dx = TRI_FROM_FIXED(r_min - r_min_i);
   1140             cf -= (dx * dx * y_incr) >> cf_shift;
   1141             for (int x = r_min_i+FIXED_ONE ; x < r_max_i-FIXED_ONE ; x += FIXED_ONE) {
   1142                 cf += y_incr >> (TRI_ITERATORS_BITS-15);
   1143                 SUB_COVERAGE(coverage, cf);
   1144             }
   1145 
   1146             // and the last pixel
   1147             dx = TRI_FROM_FIXED(r_max - r_max_i) - TRI_ONE;
   1148             cf += (dx * dx * y_incr) >> cf_shift;
   1149             SUB_COVERAGE(coverage, cf);
   1150         }
   1151 
   1152         // did we reach the end of an edge? if so, get a new one.
   1153         if (y == left->y_bot || y == right->y_bot) {
   1154             // bail out if we're done
   1155             if (i>=num_edges)
   1156                 break;
   1157             if (y == left->y_bot)
   1158                 left = &edges[i++];
   1159             if (y == right->y_bot)
   1160                 right = &edges[i++];
   1161         }
   1162 
   1163         // next scanline
   1164         yt = y;
   1165 
   1166         // did we just finish a scanline?
   1167         retire = (y << (32-TRI_FRACTION_BITS)) == 0;
   1168     } while (true);
   1169 
   1170     // render the last scanline
   1171     if (c->iterators.xl < c->iterators.xr)
   1172         c->scanline(c);
   1173 }
   1174 
   1175 }; // namespace android
   1176