| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 1 | /* libs/pixelflinger/trap.cpp | 
 | 2 | ** | 
 | 3 | ** Copyright 2006, The Android Open Source Project | 
 | 4 | ** | 
| Mark Salyzyn | 66ce3e0 | 2016-09-28 10:07:20 -0700 | [diff] [blame] | 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 | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 8 | ** | 
| Mark Salyzyn | 66ce3e0 | 2016-09-28 10:07:20 -0700 | [diff] [blame] | 9 | **     http://www.apache.org/licenses/LICENSE-2.0 | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 10 | ** | 
| Mark Salyzyn | 66ce3e0 | 2016-09-28 10:07:20 -0700 | [diff] [blame] | 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 | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 15 | ** limitations under the License. | 
 | 16 | */ | 
 | 17 |  | 
| Mark Salyzyn | cfd5b08 | 2016-10-17 14:28:00 -0700 | [diff] [blame] | 18 | #define LOG_TAG "pixelflinger-trap" | 
 | 19 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 20 | #include <assert.h> | 
 | 21 | #include <stdio.h> | 
 | 22 | #include <stdlib.h> | 
 | 23 |  | 
| Mark Salyzyn | 66ce3e0 | 2016-09-28 10:07:20 -0700 | [diff] [blame] | 24 | #include <cutils/memory.h> | 
| Mark Salyzyn | 30f991f | 2017-01-10 13:19:54 -0800 | [diff] [blame] | 25 | #include <log/log.h> | 
| Mark Salyzyn | 66ce3e0 | 2016-09-28 10:07:20 -0700 | [diff] [blame] | 26 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 27 | #include "trap.h" | 
 | 28 | #include "picker.h" | 
 | 29 |  | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 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, | 
| Steve Block | 8d66c49 | 2011-12-20 16:07:45 +0000 | [diff] [blame] | 99 |                       const GGLcoord*  v2 ) | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 100 | { | 
 | 101 |     float tri = 1.0f / TRI_ONE; | 
| Steve Block | 8d66c49 | 2011-12-20 16:07:45 +0000 | [diff] [blame] | 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] ); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 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 | { | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 352 |     GGLcoord v[4][2]; | 
 | 353 |     v[0][0] = v0[0];    v[0][1] = v0[1]; | 
 | 354 |     v[1][0] = v1[0];    v[1][1] = v1[1]; | 
 | 355 |     v0 = v[0]; | 
 | 356 |     v1 = v[1]; | 
 | 357 |     const GGLcoord dx = abs(v0[0] - v1[0]); | 
 | 358 |     const GGLcoord dy = abs(v0[1] - v1[1]); | 
 | 359 |     GGLcoord nx, ny; | 
 | 360 |     nx = ny = 0; | 
 | 361 |  | 
 | 362 |     GGLcoord halfWidth = TRI_ROUND(width) >> 1; | 
 | 363 |     if (halfWidth == 0) | 
 | 364 |         halfWidth = TRI_HALF; | 
 | 365 |  | 
 | 366 |     ((dx > dy) ? ny : nx) = halfWidth; | 
 | 367 |     v[2][0] = v1[0];    v[2][1] = v1[1]; | 
 | 368 |     v[3][0] = v0[0];    v[3][1] = v0[1]; | 
 | 369 |     v[0][0] += nx;      v[0][1] += ny; | 
 | 370 |     v[1][0] += nx;      v[1][1] += ny; | 
 | 371 |     v[2][0] -= nx;      v[2][1] -= ny; | 
 | 372 |     v[3][0] -= nx;      v[3][1] -= ny; | 
 | 373 |     trianglex_big(con, v[0], v[1], v[2]); | 
 | 374 |     trianglex_big(con, v[0], v[2], v[3]); | 
 | 375 | } | 
 | 376 |  | 
 | 377 | static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width) | 
 | 378 | { | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 379 |     GGLcoord v[4][2]; | 
 | 380 |     v[0][0] = v0[0];    v[0][1] = v0[1]; | 
 | 381 |     v[1][0] = v1[0];    v[1][1] = v1[1]; | 
 | 382 |     v0 = v[0]; | 
 | 383 |     v1 = v[1]; | 
 | 384 |      | 
 | 385 |     const GGLcoord dx = v0[0] - v1[0]; | 
 | 386 |     const GGLcoord dy = v0[1] - v1[1]; | 
 | 387 |     GGLcoord nx = -dy; | 
 | 388 |     GGLcoord ny =  dx; | 
 | 389 |  | 
 | 390 |     // generally, this will be well below 1.0 | 
 | 391 |     const GGLfixed norm = gglMulx(width, gglSqrtRecipx(nx*nx+ny*ny), 4); | 
 | 392 |     nx = gglMulx(nx, norm, 21); | 
 | 393 |     ny = gglMulx(ny, norm, 21); | 
 | 394 |      | 
 | 395 |     v[2][0] = v1[0];    v[2][1] = v1[1]; | 
 | 396 |     v[3][0] = v0[0];    v[3][1] = v0[1]; | 
 | 397 |     v[0][0] += nx;      v[0][1] += ny; | 
 | 398 |     v[1][0] += nx;      v[1][1] += ny; | 
 | 399 |     v[2][0] -= nx;      v[2][1] -= ny; | 
 | 400 |     v[3][0] -= nx;      v[3][1] -= ny; | 
 | 401 |     aapolyx(con, v[0], 4);         | 
 | 402 | } | 
 | 403 |  | 
 | 404 |  | 
 | 405 | // ---------------------------------------------------------------------------- | 
 | 406 | #if 0 | 
 | 407 | #pragma mark - | 
 | 408 | #pragma mark Rect | 
 | 409 | #endif | 
 | 410 |  | 
 | 411 | void recti_validate(void *con, GGLint l, GGLint t, GGLint r, GGLint b) | 
 | 412 | { | 
 | 413 |     GGL_CONTEXT(c, con); | 
 | 414 |     ggl_pick(c); | 
 | 415 |     c->procs.recti = recti; | 
 | 416 |     c->procs.recti(con, l, t, r, b); | 
 | 417 | } | 
 | 418 |  | 
 | 419 | void recti(void* con, GGLint l, GGLint t, GGLint r, GGLint b) | 
 | 420 | { | 
 | 421 |     GGL_CONTEXT(c, con); | 
 | 422 |  | 
 | 423 |     // scissor... | 
 | 424 |     if (l < GGLint(c->state.scissor.left)) | 
 | 425 |         l = GGLint(c->state.scissor.left); | 
 | 426 |     if (t < GGLint(c->state.scissor.top)) | 
 | 427 |         t = GGLint(c->state.scissor.top); | 
 | 428 |     if (r > GGLint(c->state.scissor.right)) | 
 | 429 |         r = GGLint(c->state.scissor.right); | 
 | 430 |     if (b > GGLint(c->state.scissor.bottom)) | 
 | 431 |         b = GGLint(c->state.scissor.bottom); | 
 | 432 |  | 
 | 433 |     int xc = r - l; | 
 | 434 |     int yc = b - t; | 
 | 435 |     if (xc>0 && yc>0) { | 
 | 436 |         c->iterators.xl = l; | 
 | 437 |         c->iterators.xr = r; | 
 | 438 |         c->init_y(c, t); | 
 | 439 |         c->rect(c, yc); | 
 | 440 |     } | 
 | 441 | } | 
 | 442 |  | 
 | 443 | // ---------------------------------------------------------------------------- | 
 | 444 | #if 0 | 
 | 445 | #pragma mark - | 
 | 446 | #pragma mark Triangle / Debugging | 
 | 447 | #endif | 
 | 448 |  | 
 | 449 | static void scanline_set(context_t* c) | 
 | 450 | { | 
 | 451 |     int32_t x = c->iterators.xl; | 
 | 452 |     size_t ct = c->iterators.xr - x; | 
 | 453 |     int32_t y = c->iterators.y; | 
 | 454 |     surface_t* cb = &(c->state.buffers.color); | 
 | 455 |     const GGLFormat* fp = &(c->formats[cb->format]); | 
 | 456 |     uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) + | 
 | 457 |                             (x + (cb->stride * y)) * fp->size; | 
 | 458 |     const size_t size = ct * fp->size; | 
 | 459 |     memset(dst, 0xFF, size); | 
 | 460 | } | 
 | 461 |  | 
 | 462 | static void trianglex_debug(void* con, | 
 | 463 |         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2) | 
 | 464 | { | 
 | 465 |     GGL_CONTEXT(c, con); | 
 | 466 |     if (c->state.needs.p & GGL_NEED_MASK(P_AA)) { | 
 | 467 |         aa_trianglex(con,v0,v1,v2); | 
 | 468 |     } else { | 
 | 469 |         trianglex_big(con,v0,v1,v2); | 
 | 470 |     } | 
 | 471 | 	void (*save_scanline)(context_t*)  = c->scanline; | 
 | 472 |     c->scanline = scanline_set; | 
 | 473 |     linex(con, v0, v1, TRI_ONE); | 
 | 474 |     linex(con, v1, v2, TRI_ONE); | 
 | 475 |     linex(con, v2, v0, TRI_ONE); | 
 | 476 |     c->scanline = save_scanline; | 
 | 477 | } | 
 | 478 |  | 
 | 479 | static void trianglex_xor(void* con, | 
 | 480 |         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2) | 
 | 481 | { | 
 | 482 |     trianglex_big(con,v0,v1,v2); | 
 | 483 |     trianglex_small(con,v0,v1,v2); | 
 | 484 | } | 
 | 485 |  | 
 | 486 | // ---------------------------------------------------------------------------- | 
 | 487 | #if 0 | 
 | 488 | #pragma mark - | 
 | 489 | #pragma mark Triangle | 
 | 490 | #endif | 
 | 491 |  | 
 | 492 | void trianglex_validate(void *con, | 
 | 493 |         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2) | 
 | 494 | { | 
 | 495 |     GGL_CONTEXT(c, con); | 
 | 496 |     ggl_pick(c); | 
 | 497 |     if (c->state.needs.p & GGL_NEED_MASK(P_AA)) { | 
 | 498 |         c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : aa_trianglex; | 
 | 499 |     } else { | 
 | 500 |         c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : trianglex_big; | 
 | 501 |     } | 
 | 502 |     c->procs.trianglex(con, v0, v1, v2); | 
 | 503 | } | 
 | 504 |  | 
 | 505 | // ---------------------------------------------------------------------------- | 
 | 506 |  | 
 | 507 | void trianglex_small(void* con, | 
 | 508 |         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2) | 
 | 509 | { | 
 | 510 |     GGL_CONTEXT(c, con); | 
 | 511 |  | 
 | 512 |     // vertices are in 28.4 fixed point, which allows | 
 | 513 |     // us to use 32 bits multiplies below. | 
 | 514 |     int32_t x0 = v0[0]; | 
 | 515 |     int32_t y0 = v0[1]; | 
 | 516 |     int32_t x1 = v1[0]; | 
 | 517 |     int32_t y1 = v1[1]; | 
 | 518 |     int32_t x2 = v2[0]; | 
 | 519 |     int32_t y2 = v2[1]; | 
 | 520 |  | 
 | 521 |     int32_t dx01 = x0 - x1; | 
 | 522 |     int32_t dy20 = y2 - y0; | 
 | 523 |     int32_t dy01 = y0 - y1; | 
 | 524 |     int32_t dx20 = x2 - x0; | 
 | 525 |  | 
 | 526 |     // The code below works only with CCW triangles | 
 | 527 |     // so if we get a CW triangle, we need to swap two of its vertices | 
 | 528 |     if (dx01*dy20 < dy01*dx20) { | 
 | 529 |         swap(x0, x1); | 
 | 530 |         swap(y0, y1); | 
 | 531 |         dx01 = x0 - x1; | 
 | 532 |         dy01 = y0 - y1; | 
 | 533 |         dx20 = x2 - x0; | 
 | 534 |         dy20 = y2 - y0; | 
 | 535 |     } | 
 | 536 |     int32_t dx12 = x1 - x2; | 
 | 537 |     int32_t dy12 = y1 - y2; | 
 | 538 |  | 
 | 539 |     // bounding box & scissor | 
 | 540 |     const int32_t bminx = TRI_FLOOR(min(x0, x1, x2)) >> TRI_FRACTION_BITS; | 
 | 541 |     const int32_t bminy = TRI_FLOOR(min(y0, y1, y2)) >> TRI_FRACTION_BITS; | 
 | 542 |     const int32_t bmaxx = TRI_CEIL( max(x0, x1, x2)) >> TRI_FRACTION_BITS; | 
 | 543 |     const int32_t bmaxy = TRI_CEIL( max(y0, y1, y2)) >> TRI_FRACTION_BITS; | 
 | 544 |     const int32_t minx = max(bminx, c->state.scissor.left); | 
 | 545 |     const int32_t miny = max(bminy, c->state.scissor.top); | 
 | 546 |     const int32_t maxx = min(bmaxx, c->state.scissor.right); | 
 | 547 |     const int32_t maxy = min(bmaxy, c->state.scissor.bottom); | 
 | 548 |     if ((minx >= maxx) || (miny >= maxy)) | 
 | 549 |         return; // too small or clipped out... | 
 | 550 |  | 
 | 551 |     // step equations to the bounding box and snap to pixel center | 
 | 552 |     const int32_t my = (miny << TRI_FRACTION_BITS) + TRI_HALF; | 
 | 553 |     const int32_t mx = (minx << TRI_FRACTION_BITS) + TRI_HALF; | 
 | 554 |     int32_t ey0 = dy01 * (x0 - mx) - dx01 * (y0 - my); | 
 | 555 |     int32_t ey1 = dy12 * (x1 - mx) - dx12 * (y1 - my); | 
 | 556 |     int32_t ey2 = dy20 * (x2 - mx) - dx20 * (y2 - my); | 
 | 557 |  | 
 | 558 |     // right-exclusive fill rule, to avoid rare cases | 
 | 559 |     // of over drawing | 
 | 560 |     if (dy01<0 || (dy01 == 0 && dx01>0)) ey0++; | 
 | 561 |     if (dy12<0 || (dy12 == 0 && dx12>0)) ey1++; | 
 | 562 |     if (dy20<0 || (dy20 == 0 && dx20>0)) ey2++; | 
 | 563 |      | 
 | 564 |     c->init_y(c, miny); | 
 | 565 |     for (int32_t y = miny; y < maxy; y++) { | 
| Elliott Hughes | cd6b53f | 2015-10-21 18:52:17 -0700 | [diff] [blame] | 566 |         int32_t ex0 = ey0; | 
 | 567 |         int32_t ex1 = ey1; | 
 | 568 |         int32_t ex2 = ey2;     | 
 | 569 |         int32_t xl, xr; | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 570 |         for (xl=minx ; xl<maxx ; xl++) { | 
 | 571 |             if (ex0>0 && ex1>0 && ex2>0) | 
 | 572 |                 break; // all strictly positive | 
 | 573 |             ex0 -= dy01 << TRI_FRACTION_BITS; | 
 | 574 |             ex1 -= dy12 << TRI_FRACTION_BITS; | 
 | 575 |             ex2 -= dy20 << TRI_FRACTION_BITS; | 
 | 576 |         } | 
 | 577 |         xr = xl; | 
 | 578 |         for ( ; xr<maxx ; xr++) { | 
 | 579 |             if (!(ex0>0 && ex1>0 && ex2>0)) | 
 | 580 |                 break; // not all strictly positive | 
 | 581 |             ex0 -= dy01 << TRI_FRACTION_BITS; | 
 | 582 |             ex1 -= dy12 << TRI_FRACTION_BITS; | 
 | 583 |             ex2 -= dy20 << TRI_FRACTION_BITS; | 
 | 584 |         } | 
 | 585 |  | 
 | 586 |         if (xl < xr) { | 
 | 587 |             c->iterators.xl = xl; | 
 | 588 |             c->iterators.xr = xr; | 
 | 589 |             c->scanline(c); | 
 | 590 |         } | 
 | 591 |         c->step_y(c); | 
 | 592 |  | 
 | 593 |         ey0 += dx01 << TRI_FRACTION_BITS; | 
 | 594 |         ey1 += dx12 << TRI_FRACTION_BITS; | 
 | 595 |         ey2 += dx20 << TRI_FRACTION_BITS; | 
 | 596 |     } | 
 | 597 | } | 
 | 598 |  | 
 | 599 | // ---------------------------------------------------------------------------- | 
 | 600 | #if 0 | 
 | 601 | #pragma mark - | 
 | 602 | #endif | 
 | 603 |  | 
 | 604 | // the following routine fills a triangle via edge stepping, which | 
 | 605 | // unfortunately requires divisions in the setup phase to get right, | 
 | 606 | // it should probably only be used for relatively large trianges | 
 | 607 |  | 
 | 608 |  | 
 | 609 | // x = y*DX/DY    (ou DX and DY are constants, DY > 0, et y >= 0) | 
 | 610 | //  | 
 | 611 | // for an equation of the type: | 
 | 612 | //      x' = y*K/2^p     (with K and p constants "carefully chosen") | 
 | 613 | //  | 
 | 614 | // We can now do a DDA without precision loss. We define 'e' by: | 
 | 615 | //      x' - x = y*(DX/DY - K/2^p) = y*e | 
 | 616 | //  | 
 | 617 | // If we choose K = round(DX*2^p/DY) then, | 
 | 618 | //      abs(e) <= 1/2^(p+1) by construction | 
 | 619 | //  | 
 | 620 | // therefore abs(x'-x) = y*abs(e) <= y/2^(p+1) <= DY/2^(p+1) <= DMAX/2^(p+1) | 
 | 621 | //  | 
 | 622 | // which means that if DMAX <= 2^p, therefore abs(x-x') <= 1/2, including | 
 | 623 | // at the last line. In fact, it's even a strict inequality except in one | 
 | 624 | // extrem case (DY == DMAX et e = +/- 1/2) | 
 | 625 | //  | 
 | 626 | // Applying that to our coordinates, we need 2^p >= 4096*16 = 65536 | 
 | 627 | // so p = 16 is enough, we're so lucky! | 
 | 628 |  | 
 | 629 | const int TRI_ITERATORS_BITS = 16; | 
 | 630 |  | 
 | 631 | struct Edge | 
 | 632 | { | 
 | 633 |   int32_t  x;      // edge position in 16.16 coordinates | 
 | 634 |   int32_t  x_incr; // on each step, increment x by that amount | 
 | 635 |   int32_t  y_top;  // starting scanline, 16.4 format | 
 | 636 |   int32_t  y_bot; | 
 | 637 | }; | 
 | 638 |  | 
 | 639 | static void | 
 | 640 | edge_dump( Edge*  edge ) | 
 | 641 | { | 
| Steve Block | fe71a61 | 2012-01-04 19:19:03 +0000 | [diff] [blame] | 642 |   ALOGI( "  top=%d (%.3f)  bot=%d (%.3f)  x=%d (%.3f)  ix=%d (%.3f)", | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 643 |         edge->y_top, edge->y_top/float(TRI_ONE), | 
 | 644 | 		edge->y_bot, edge->y_bot/float(TRI_ONE), | 
 | 645 | 		edge->x, edge->x/float(FIXED_ONE), | 
 | 646 | 		edge->x_incr, edge->x_incr/float(FIXED_ONE) ); | 
 | 647 | } | 
 | 648 |  | 
 | 649 | static void | 
 | 650 | triangle_dump_edges( Edge*  edges, | 
 | 651 |                      int            count ) | 
 | 652 | {  | 
| Steve Block | fe71a61 | 2012-01-04 19:19:03 +0000 | [diff] [blame] | 653 |     ALOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" ); | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 654 | 	for ( ; count > 0; count--, edges++ ) | 
 | 655 | 	  edge_dump( edges ); | 
 | 656 | } | 
 | 657 |  | 
 | 658 | // the following function sets up an edge, it assumes | 
 | 659 | // that ymin and ymax are in already in the 'reduced' | 
 | 660 | // format | 
 | 661 | static __attribute__((noinline)) | 
 | 662 | void edge_setup( | 
 | 663 |         Edge*           edges, | 
 | 664 |         int*            pcount, | 
 | 665 |         const GGLcoord* p1, | 
 | 666 |         const GGLcoord* p2, | 
 | 667 |         int32_t         ymin, | 
 | 668 |         int32_t         ymax ) | 
 | 669 | { | 
 | 670 | 	const GGLfixed*  top = p1; | 
 | 671 | 	const GGLfixed*  bot = p2; | 
 | 672 | 	Edge*    edge = edges + *pcount; | 
 | 673 |  | 
 | 674 | 	if (top[1] > bot[1]) { | 
 | 675 |         swap(top, bot); | 
 | 676 | 	} | 
 | 677 |  | 
 | 678 | 	int  y1 = top[1] | 1; | 
 | 679 | 	int  y2 = bot[1] | 1; | 
 | 680 | 	int  dy = y2 - y1; | 
 | 681 |  | 
 | 682 | 	if ( dy == 0 || y1 > ymax || y2 < ymin ) | 
 | 683 | 		return; | 
 | 684 |  | 
 | 685 | 	if ( y1 > ymin ) | 
 | 686 | 		ymin = TRI_SNAP_NEXT_HALF(y1); | 
 | 687 | 	 | 
 | 688 | 	if ( y2 < ymax ) | 
 | 689 | 		ymax = TRI_SNAP_PREV_HALF(y2); | 
 | 690 |  | 
 | 691 | 	if ( ymin > ymax )  // when the edge doesn't cross any scanline | 
 | 692 | 	  return; | 
 | 693 |  | 
 | 694 | 	const int x1 = top[0]; | 
 | 695 | 	const int dx = bot[0] - x1; | 
 | 696 |     const int shift = TRI_ITERATORS_BITS - TRI_FRACTION_BITS; | 
 | 697 |  | 
 | 698 | 	// setup edge fields | 
 | 699 |     // We add 0.5 to edge->x here because it simplifies the rounding | 
 | 700 |     // in triangle_sweep_edges() -- this doesn't change the ordering of 'x' | 
 | 701 | 	edge->x      = (x1 << shift) + (1LU << (TRI_ITERATORS_BITS-1)); | 
 | 702 | 	edge->x_incr = 0; | 
 | 703 | 	edge->y_top  = ymin; | 
 | 704 | 	edge->y_bot  = ymax; | 
 | 705 |  | 
 | 706 | 	if (ggl_likely(ymin <= ymax && dx)) { | 
 | 707 |         edge->x_incr = gglDivQ16(dx, dy); | 
 | 708 |     } | 
 | 709 |     if (ggl_likely(y1 < ymin)) { | 
 | 710 |         int32_t xadjust = (edge->x_incr * (ymin-y1)) >> TRI_FRACTION_BITS; | 
 | 711 |         edge->x += xadjust; | 
 | 712 |     } | 
 | 713 |    | 
 | 714 | 	++*pcount; | 
 | 715 | } | 
 | 716 |  | 
 | 717 |  | 
 | 718 | static void | 
 | 719 | triangle_sweep_edges( Edge*  left, | 
 | 720 |                       Edge*  right, | 
 | 721 | 					  int            ytop, | 
 | 722 | 					  int            ybot, | 
 | 723 | 					  context_t*     c ) | 
 | 724 | { | 
 | 725 |     int count = ((ybot - ytop)>>TRI_FRACTION_BITS) + 1; | 
 | 726 |     if (count<=0) return; | 
 | 727 |  | 
 | 728 |     // sort the edges horizontally | 
 | 729 |     if ((left->x > right->x) ||  | 
 | 730 |         ((left->x == right->x) && (left->x_incr > right->x_incr))) { | 
 | 731 |         swap(left, right); | 
 | 732 |     } | 
 | 733 |  | 
 | 734 |     int left_x = left->x; | 
 | 735 |     int right_x = right->x; | 
 | 736 |     const int left_xi = left->x_incr; | 
 | 737 |     const int right_xi  = right->x_incr; | 
 | 738 |     left->x  += left_xi * count; | 
 | 739 |     right->x += right_xi * count; | 
 | 740 |  | 
 | 741 | 	const int xmin = c->state.scissor.left; | 
 | 742 | 	const int xmax = c->state.scissor.right; | 
 | 743 |     do { | 
 | 744 |         // horizontal scissoring | 
 | 745 |         const int32_t xl = max(left_x  >> TRI_ITERATORS_BITS, xmin); | 
 | 746 |         const int32_t xr = min(right_x >> TRI_ITERATORS_BITS, xmax); | 
 | 747 |         left_x  += left_xi; | 
 | 748 |         right_x += right_xi; | 
 | 749 |         // invoke the scanline rasterizer | 
 | 750 |         if (ggl_likely(xl < xr)) { | 
 | 751 |             c->iterators.xl = xl; | 
 | 752 |             c->iterators.xr = xr; | 
 | 753 |             c->scanline(c); | 
 | 754 |         } | 
 | 755 | 		c->step_y(c); | 
 | 756 | 	} while (--count); | 
 | 757 | } | 
 | 758 |  | 
 | 759 |  | 
 | 760 | void trianglex_big(void* con, | 
 | 761 |         const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2) | 
 | 762 | { | 
 | 763 |     GGL_CONTEXT(c, con); | 
 | 764 |  | 
 | 765 |     Edge edges[3]; | 
 | 766 | 	int num_edges = 0; | 
 | 767 | 	int32_t ymin = TRI_FROM_INT(c->state.scissor.top)    + TRI_HALF; | 
 | 768 | 	int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom) - TRI_HALF; | 
 | 769 | 	     | 
 | 770 | 	edge_setup( edges, &num_edges, v0, v1, ymin, ymax ); | 
 | 771 | 	edge_setup( edges, &num_edges, v0, v2, ymin, ymax ); | 
 | 772 | 	edge_setup( edges, &num_edges, v1, v2, ymin, ymax ); | 
 | 773 |  | 
 | 774 |     if (ggl_unlikely(num_edges<2))  // for really tiny triangles that don't | 
 | 775 | 		return;                     // cross any scanline centers | 
 | 776 |  | 
 | 777 |     Edge* left  = &edges[0]; | 
 | 778 |     Edge* right = &edges[1]; | 
 | 779 |     Edge* other = &edges[2]; | 
 | 780 |     int32_t y_top = min(left->y_top, right->y_top); | 
 | 781 |     int32_t y_bot = max(left->y_bot, right->y_bot); | 
 | 782 |  | 
 | 783 | 	if (ggl_likely(num_edges==3)) { | 
 | 784 |         y_top = min(y_top, edges[2].y_top); | 
 | 785 |         y_bot = max(y_bot, edges[2].y_bot); | 
 | 786 | 		if (edges[0].y_top > y_top) { | 
 | 787 |             other = &edges[0]; | 
 | 788 |             left  = &edges[2]; | 
 | 789 | 		} else if (edges[1].y_top > y_top) { | 
 | 790 |             other = &edges[1]; | 
 | 791 |             right = &edges[2]; | 
 | 792 | 		} | 
 | 793 |     } | 
 | 794 |  | 
 | 795 |     c->init_y(c, y_top >> TRI_FRACTION_BITS); | 
 | 796 |  | 
 | 797 |     int32_t y_mid = min(left->y_bot, right->y_bot); | 
 | 798 |     triangle_sweep_edges( left, right, y_top, y_mid, c ); | 
 | 799 |  | 
 | 800 |     // second scanline sweep loop, if necessary | 
 | 801 |     y_mid += TRI_ONE; | 
 | 802 |     if (y_mid <= y_bot) { | 
 | 803 |         ((left->y_bot == y_bot) ? right : left) = other; | 
 | 804 |         if (other->y_top < y_mid) { | 
 | 805 |             other->x += other->x_incr; | 
 | 806 |         } | 
 | 807 |         triangle_sweep_edges( left, right, y_mid, y_bot, c ); | 
 | 808 |     } | 
 | 809 | } | 
 | 810 |  | 
 | 811 | void aa_trianglex(void* con, | 
 | 812 |         const GGLcoord* a, const GGLcoord* b, const GGLcoord* c) | 
 | 813 | { | 
 | 814 |     GGLcoord pts[6] = { a[0], a[1], b[0], b[1], c[0], c[1] }; | 
 | 815 |     aapolyx(con, pts, 3); | 
 | 816 | } | 
 | 817 |  | 
 | 818 | // ---------------------------------------------------------------------------- | 
 | 819 | #if 0 | 
 | 820 | #pragma mark - | 
 | 821 | #endif | 
 | 822 |  | 
 | 823 | struct AAEdge | 
 | 824 | { | 
 | 825 |     GGLfixed x;         // edge position in 12.16 coordinates | 
 | 826 |     GGLfixed x_incr;    // on each y step, increment x by that amount | 
 | 827 |     GGLfixed y_incr;    // on each x step, increment y by that amount | 
 | 828 |     int16_t y_top;      // starting scanline, 12.4 format | 
 | 829 |     int16_t y_bot;      // starting scanline, 12.4 format | 
 | 830 |     void dump(); | 
 | 831 | }; | 
 | 832 |  | 
 | 833 | void AAEdge::dump() | 
 | 834 | { | 
 | 835 |     float tri  = 1.0f / TRI_ONE; | 
 | 836 |     float iter = 1.0f / (1<<TRI_ITERATORS_BITS); | 
 | 837 |     float fix  = 1.0f / FIXED_ONE; | 
| Steve Block | 8d66c49 | 2011-12-20 16:07:45 +0000 | [diff] [blame] | 838 |     ALOGD(   "x=%08x (%.3f), " | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 839 |             "x_incr=%08x (%.3f), y_incr=%08x (%.3f), " | 
 | 840 |             "y_top=%08x (%.3f), y_bot=%08x (%.3f) ", | 
 | 841 |         x, x*fix, | 
 | 842 |         x_incr, x_incr*iter, | 
 | 843 |         y_incr, y_incr*iter, | 
 | 844 |         y_top, y_top*tri, | 
 | 845 |         y_bot, y_bot*tri ); | 
 | 846 | } | 
 | 847 |  | 
 | 848 | // the following function sets up an edge, it assumes | 
 | 849 | // that ymin and ymax are in already in the 'reduced' | 
 | 850 | // format | 
 | 851 | static __attribute__((noinline)) | 
 | 852 | void aa_edge_setup( | 
 | 853 |         AAEdge*         edges, | 
 | 854 |         int*            pcount, | 
 | 855 |         const GGLcoord* p1, | 
 | 856 |         const GGLcoord* p2, | 
 | 857 |         int32_t         ymin, | 
 | 858 |         int32_t         ymax ) | 
 | 859 | { | 
 | 860 |     const GGLfixed*  top = p1; | 
 | 861 |     const GGLfixed*  bot = p2; | 
 | 862 |     AAEdge* edge = edges + *pcount; | 
 | 863 |  | 
 | 864 |     if (top[1] > bot[1]) | 
 | 865 |         swap(top, bot); | 
 | 866 |  | 
 | 867 |     int  y1 = top[1]; | 
 | 868 |     int  y2 = bot[1]; | 
 | 869 |     int  dy = y2 - y1; | 
 | 870 |  | 
 | 871 |     if (dy==0 || y1>ymax || y2<ymin) | 
 | 872 |         return; | 
 | 873 |  | 
 | 874 |     if (y1 > ymin) | 
 | 875 |         ymin = y1; | 
 | 876 |      | 
 | 877 |     if (y2 < ymax) | 
 | 878 |         ymax = y2; | 
 | 879 |  | 
 | 880 |     const int x1 = top[0]; | 
 | 881 |     const int dx = bot[0] - x1; | 
 | 882 |     const int shift = FIXED_BITS - TRI_FRACTION_BITS; | 
 | 883 |  | 
 | 884 |     // setup edge fields | 
 | 885 |     edge->x      = x1 << shift; | 
 | 886 |     edge->x_incr = 0; | 
 | 887 |     edge->y_top  = ymin; | 
 | 888 |     edge->y_bot  = ymax; | 
 | 889 |     edge->y_incr = 0x7FFFFFFF; | 
 | 890 |  | 
 | 891 |     if (ggl_likely(ymin <= ymax && dx)) { | 
 | 892 |         edge->x_incr = gglDivQ16(dx, dy); | 
 | 893 |         if (dx != 0) { | 
 | 894 |             edge->y_incr = abs(gglDivQ16(dy, dx)); | 
 | 895 |         } | 
 | 896 |     } | 
 | 897 |     if (ggl_likely(y1 < ymin)) { | 
 | 898 |         int32_t xadjust = (edge->x_incr * (ymin-y1)) | 
 | 899 |                 >> (TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS); | 
 | 900 |         edge->x += xadjust; | 
 | 901 |     } | 
 | 902 |    | 
 | 903 |     ++*pcount; | 
 | 904 | } | 
 | 905 |  | 
 | 906 |  | 
 | 907 | typedef int (*compar_t)(const void*, const void*); | 
 | 908 | static int compare_edges(const AAEdge *e0, const AAEdge *e1) { | 
 | 909 |     if (e0->y_top > e1->y_top)      return 1; | 
 | 910 |     if (e0->y_top < e1->y_top)      return -1; | 
 | 911 |     if (e0->x > e1->x)              return 1; | 
 | 912 |     if (e0->x < e1->x)              return -1; | 
 | 913 |     if (e0->x_incr > e1->x_incr)    return 1; | 
 | 914 |     if (e0->x_incr < e1->x_incr)    return -1; | 
 | 915 |     return 0; // same edges, should never happen | 
 | 916 | } | 
 | 917 |  | 
 | 918 | static inline  | 
 | 919 | void SET_COVERAGE(int16_t*& p, int32_t value, ssize_t n) | 
 | 920 | { | 
 | 921 |     android_memset16((uint16_t*)p, value, n*2); | 
 | 922 |     p += n; | 
 | 923 | } | 
 | 924 |  | 
 | 925 | static inline  | 
 | 926 | void ADD_COVERAGE(int16_t*& p, int32_t value) | 
 | 927 | { | 
 | 928 |     value = *p + value; | 
 | 929 |     if (value >= 0x8000) | 
 | 930 |         value = 0x7FFF; | 
 | 931 |     *p++ = value; | 
 | 932 | } | 
 | 933 |  | 
 | 934 | static inline | 
 | 935 | void SUB_COVERAGE(int16_t*& p, int32_t value) | 
 | 936 | { | 
 | 937 |     value = *p - value; | 
 | 938 |     value &= ~(value>>31); | 
 | 939 |     *p++ = value; | 
 | 940 | } | 
 | 941 |  | 
 | 942 | void aapolyx(void* con, | 
 | 943 |         const GGLcoord* pts, int count) | 
 | 944 | { | 
 | 945 |     /* | 
 | 946 |      * NOTE: This routine assumes that the polygon has been clipped to the | 
 | 947 |      * viewport already, that is, no vertex lies outside of the framebuffer. | 
 | 948 |      * If this happens, the code below won't corrupt memory but the  | 
 | 949 |      * coverage values may not be correct. | 
 | 950 |      */ | 
 | 951 |      | 
 | 952 |     GGL_CONTEXT(c, con); | 
 | 953 |  | 
 | 954 |     // we do only quads for now (it's used for thick lines) | 
 | 955 |     if ((count>4) || (count<2)) return; | 
 | 956 |  | 
 | 957 |     // take scissor into account | 
 | 958 |     const int xmin = c->state.scissor.left; | 
 | 959 |     const int xmax = c->state.scissor.right; | 
 | 960 |     if (xmin >= xmax) return; | 
 | 961 |  | 
 | 962 |     // generate edges from the vertices | 
 | 963 |     int32_t ymin = TRI_FROM_INT(c->state.scissor.top); | 
 | 964 |     int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom); | 
 | 965 |     if (ymin >= ymax) return; | 
 | 966 |  | 
 | 967 |     AAEdge edges[4]; | 
 | 968 |     int num_edges = 0; | 
 | 969 |     GGLcoord const * p = pts; | 
 | 970 |     for (int i=0 ; i<count-1 ; i++, p+=2) { | 
 | 971 |         aa_edge_setup(edges, &num_edges, p, p+2, ymin, ymax); | 
 | 972 |     } | 
 | 973 |     aa_edge_setup(edges, &num_edges, p, pts, ymin, ymax ); | 
 | 974 |     if (ggl_unlikely(num_edges<2)) | 
 | 975 |         return; | 
 | 976 |  | 
 | 977 |     // sort the edge list top to bottom, left to right. | 
 | 978 |     qsort(edges, num_edges, sizeof(AAEdge), (compar_t)compare_edges); | 
 | 979 |  | 
 | 980 |     int16_t* const covPtr = c->state.buffers.coverage; | 
 | 981 |     memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr)); | 
 | 982 |  | 
 | 983 |     // now, sweep all edges in order | 
 | 984 |     // start with the 2 first edges. We know that they share their top | 
 | 985 |     // vertex, by construction. | 
 | 986 |     int i = 2; | 
 | 987 |     AAEdge* left  = &edges[0]; | 
 | 988 |     AAEdge* right = &edges[1]; | 
 | 989 |     int32_t yt = left->y_top; | 
 | 990 |     GGLfixed l = left->x; | 
 | 991 |     GGLfixed r = right->x; | 
 | 992 |     int retire = 0; | 
 | 993 |     int16_t* coverage; | 
 | 994 |  | 
 | 995 |     // at this point we can initialize the rasterizer     | 
 | 996 |     c->init_y(c, yt>>TRI_FRACTION_BITS); | 
 | 997 |     c->iterators.xl = xmax; | 
 | 998 |     c->iterators.xr = xmin; | 
 | 999 |  | 
 | 1000 |     do { | 
 | 1001 |         int32_t y = min(min(left->y_bot, right->y_bot), TRI_FLOOR(yt + TRI_ONE)); | 
 | 1002 |         const int32_t shift = TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS; | 
 | 1003 |         const int cf_shift = (1 + TRI_FRACTION_BITS*2 + TRI_ITERATORS_BITS - 15); | 
 | 1004 |  | 
 | 1005 |         // compute xmin and xmax for the left edge | 
 | 1006 |         GGLfixed l_min = gglMulAddx(left->x_incr, y - left->y_top, left->x, shift); | 
 | 1007 |         GGLfixed l_max = l; | 
 | 1008 |         l = l_min; | 
 | 1009 |         if (l_min > l_max) | 
 | 1010 |             swap(l_min, l_max); | 
 | 1011 |  | 
 | 1012 |         // compute xmin and xmax for the right edge | 
 | 1013 |         GGLfixed r_min = gglMulAddx(right->x_incr, y - right->y_top, right->x, shift); | 
 | 1014 |         GGLfixed r_max = r; | 
 | 1015 |         r = r_min; | 
 | 1016 |         if (r_min > r_max) | 
 | 1017 |             swap(r_min, r_max); | 
 | 1018 |  | 
 | 1019 |         // make sure we're not touching coverage values outside of the | 
 | 1020 |         // framebuffer | 
 | 1021 |         l_min &= ~(l_min>>31); | 
 | 1022 |         r_min &= ~(r_min>>31); | 
 | 1023 |         l_max &= ~(l_max>>31); | 
 | 1024 |         r_max &= ~(r_max>>31); | 
 | 1025 |         if (gglFixedToIntFloor(l_min) >= xmax) l_min = gglIntToFixed(xmax)-1; | 
 | 1026 |         if (gglFixedToIntFloor(r_min) >= xmax) r_min = gglIntToFixed(xmax)-1; | 
 | 1027 |         if (gglFixedToIntCeil(l_max) >= xmax)  l_max = gglIntToFixed(xmax)-1; | 
 | 1028 |         if (gglFixedToIntCeil(r_max) >= xmax)  r_max = gglIntToFixed(xmax)-1; | 
 | 1029 |  | 
 | 1030 |         // compute the integer versions of the above | 
 | 1031 |         const GGLfixed l_min_i = gglFloorx(l_min); | 
 | 1032 |         const GGLfixed l_max_i = gglCeilx (l_max); | 
 | 1033 |         const GGLfixed r_min_i = gglFloorx(r_min); | 
 | 1034 |         const GGLfixed r_max_i = gglCeilx (r_max); | 
 | 1035 |  | 
 | 1036 |         // clip horizontally using the scissor | 
 | 1037 |         const int xml = max(xmin, gglFixedToIntFloor(l_min_i)); | 
 | 1038 |         const int xmr = min(xmax, gglFixedToIntFloor(r_max_i)); | 
 | 1039 |  | 
 | 1040 |         // if we just stepped to a new scanline, render the previous one. | 
 | 1041 |         // and clear the coverage buffer | 
 | 1042 |         if (retire) { | 
 | 1043 |             if (c->iterators.xl < c->iterators.xr) | 
 | 1044 |                 c->scanline(c); | 
 | 1045 |             c->step_y(c); | 
 | 1046 |             memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr)); | 
 | 1047 |             c->iterators.xl = xml; | 
 | 1048 |             c->iterators.xr = xmr; | 
 | 1049 |         } else { | 
 | 1050 |             // update the horizontal range of this scanline | 
 | 1051 |             c->iterators.xl = min(c->iterators.xl, xml); | 
 | 1052 |             c->iterators.xr = max(c->iterators.xr, xmr); | 
 | 1053 |         } | 
 | 1054 |  | 
 | 1055 |         coverage = covPtr + gglFixedToIntFloor(l_min_i); | 
 | 1056 |         if (l_min_i == gglFloorx(l_max)) { | 
 | 1057 |              | 
 | 1058 |             /* | 
 | 1059 |              *  fully traverse this pixel vertically | 
 | 1060 |              *       l_max | 
 | 1061 |              *  +-----/--+  yt | 
 | 1062 |              *  |    /   |   | 
 | 1063 |              *  |   /    | | 
 | 1064 |              *  |  /     | | 
 | 1065 |              *  +-/------+  y | 
 | 1066 |              *   l_min  (l_min_i + TRI_ONE) | 
 | 1067 |              */ | 
 | 1068 |                | 
 | 1069 |             GGLfixed dx = l_max - l_min; | 
 | 1070 |             int32_t dy = y - yt; | 
 | 1071 |             int cf = gglMulx((dx >> 1) + (l_min_i + FIXED_ONE - l_max), dy, | 
 | 1072 |                 FIXED_BITS + TRI_FRACTION_BITS - 15); | 
 | 1073 |             ADD_COVERAGE(coverage, cf); | 
 | 1074 |             // all pixels on the right have cf = 1.0 | 
 | 1075 |         } else { | 
 | 1076 |             /* | 
 | 1077 |              *  spans several pixels in one scanline | 
 | 1078 |              *            l_max | 
 | 1079 |              *  +--------+--/-----+  yt | 
 | 1080 |              *  |        |/       | | 
 | 1081 |              *  |       /|        | | 
 | 1082 |              *  |     /  |        | | 
 | 1083 |              *  +---/----+--------+  y | 
 | 1084 |              *   l_min (l_min_i + TRI_ONE) | 
 | 1085 |              */ | 
 | 1086 |  | 
 | 1087 |             // handle the first pixel separately... | 
 | 1088 |             const int32_t y_incr = left->y_incr; | 
 | 1089 |             int32_t dx = TRI_FROM_FIXED(l_min_i - l_min) + TRI_ONE; | 
 | 1090 |             int32_t cf = (dx * dx * y_incr) >> cf_shift; | 
 | 1091 |             ADD_COVERAGE(coverage, cf); | 
 | 1092 |  | 
 | 1093 |             // following pixels get covered by y_incr, but we need | 
 | 1094 |             // to fix-up the cf to account for previous partial pixel | 
 | 1095 |             dx = TRI_FROM_FIXED(l_min - l_min_i); | 
 | 1096 |             cf -= (dx * dx * y_incr) >> cf_shift; | 
 | 1097 |             for (int x = l_min_i+FIXED_ONE ; x < l_max_i-FIXED_ONE ; x += FIXED_ONE) { | 
 | 1098 |                 cf += y_incr >> (TRI_ITERATORS_BITS-15); | 
 | 1099 |                 ADD_COVERAGE(coverage, cf); | 
 | 1100 |             } | 
 | 1101 |              | 
 | 1102 |             // and the last pixel | 
 | 1103 |             dx = TRI_FROM_FIXED(l_max - l_max_i) - TRI_ONE; | 
 | 1104 |             cf += (dx * dx * y_incr) >> cf_shift; | 
 | 1105 |             ADD_COVERAGE(coverage, cf); | 
 | 1106 |         } | 
 | 1107 |          | 
 | 1108 |         // now, fill up all fully covered pixels | 
 | 1109 |         coverage = covPtr + gglFixedToIntFloor(l_max_i); | 
 | 1110 |         int cf = ((y - yt) << (15 - TRI_FRACTION_BITS)); | 
 | 1111 |         if (ggl_likely(cf >= 0x8000)) { | 
 | 1112 |             SET_COVERAGE(coverage, 0x7FFF, ((r_max - l_max_i)>>FIXED_BITS)+1); | 
 | 1113 |         } else { | 
 | 1114 |             for (int x=l_max_i ; x<r_max ; x+=FIXED_ONE) { | 
 | 1115 |                 ADD_COVERAGE(coverage, cf); | 
 | 1116 |             } | 
 | 1117 |         } | 
 | 1118 |          | 
 | 1119 |         // subtract the coverage of the right edge | 
 | 1120 |         coverage = covPtr + gglFixedToIntFloor(r_min_i);  | 
 | 1121 |         if (r_min_i == gglFloorx(r_max)) { | 
 | 1122 |             GGLfixed dx = r_max - r_min; | 
 | 1123 |             int32_t dy = y - yt; | 
 | 1124 |             int cf = gglMulx((dx >> 1) + (r_min_i + FIXED_ONE - r_max), dy, | 
 | 1125 |                 FIXED_BITS + TRI_FRACTION_BITS - 15); | 
 | 1126 |             SUB_COVERAGE(coverage, cf); | 
 | 1127 |             // all pixels on the right have cf = 1.0 | 
 | 1128 |         } else { | 
 | 1129 |             // handle the first pixel separately... | 
 | 1130 |             const int32_t y_incr = right->y_incr; | 
 | 1131 |             int32_t dx = TRI_FROM_FIXED(r_min_i - r_min) + TRI_ONE; | 
 | 1132 |             int32_t cf = (dx * dx * y_incr) >> cf_shift; | 
 | 1133 |             SUB_COVERAGE(coverage, cf); | 
 | 1134 |              | 
 | 1135 |             // following pixels get covered by y_incr, but we need | 
 | 1136 |             // to fix-up the cf to account for previous partial pixel | 
 | 1137 |             dx = TRI_FROM_FIXED(r_min - r_min_i); | 
 | 1138 |             cf -= (dx * dx * y_incr) >> cf_shift; | 
 | 1139 |             for (int x = r_min_i+FIXED_ONE ; x < r_max_i-FIXED_ONE ; x += FIXED_ONE) { | 
 | 1140 |                 cf += y_incr >> (TRI_ITERATORS_BITS-15); | 
 | 1141 |                 SUB_COVERAGE(coverage, cf); | 
 | 1142 |             } | 
 | 1143 |              | 
 | 1144 |             // and the last pixel | 
 | 1145 |             dx = TRI_FROM_FIXED(r_max - r_max_i) - TRI_ONE; | 
 | 1146 |             cf += (dx * dx * y_incr) >> cf_shift; | 
 | 1147 |             SUB_COVERAGE(coverage, cf); | 
 | 1148 |         } | 
 | 1149 |  | 
 | 1150 |         // did we reach the end of an edge? if so, get a new one. | 
 | 1151 |         if (y == left->y_bot || y == right->y_bot) { | 
 | 1152 |             // bail out if we're done | 
 | 1153 |             if (i>=num_edges) | 
 | 1154 |                 break; | 
 | 1155 |             if (y == left->y_bot) | 
 | 1156 |                 left = &edges[i++]; | 
 | 1157 |             if (y == right->y_bot) | 
 | 1158 |                 right = &edges[i++]; | 
 | 1159 |         } | 
 | 1160 |  | 
 | 1161 |         // next scanline | 
 | 1162 |         yt = y; | 
 | 1163 |          | 
 | 1164 |         // did we just finish a scanline?         | 
 | 1165 |         retire = (y << (32-TRI_FRACTION_BITS)) == 0; | 
 | 1166 |     } while (true); | 
 | 1167 |  | 
 | 1168 |     // render the last scanline | 
 | 1169 |     if (c->iterators.xl < c->iterators.xr) | 
 | 1170 |         c->scanline(c); | 
 | 1171 | } | 
 | 1172 |  | 
 | 1173 | }; // namespace android |