| 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 | ** | 
|  | 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 | #include <assert.h> | 
|  | 19 | #include <stdio.h> | 
|  | 20 | #include <stdlib.h> | 
|  | 21 |  | 
|  | 22 | #include "trap.h" | 
|  | 23 | #include "picker.h" | 
|  | 24 |  | 
|  | 25 | #include <cutils/log.h> | 
|  | 26 | #include <cutils/memory.h> | 
|  | 27 |  | 
|  | 28 | namespace android { | 
|  | 29 |  | 
|  | 30 | // ---------------------------------------------------------------------------- | 
|  | 31 |  | 
|  | 32 | // enable to see triangles edges | 
|  | 33 | #define DEBUG_TRANGLES  0 | 
|  | 34 |  | 
|  | 35 | // ---------------------------------------------------------------------------- | 
|  | 36 |  | 
|  | 37 | static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r); | 
|  | 38 | static void pointx(void *con, const GGLcoord* c, GGLcoord r); | 
|  | 39 | static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r); | 
|  | 40 | static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r); | 
|  | 41 |  | 
|  | 42 | static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w); | 
|  | 43 | static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w); | 
|  | 44 | static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w); | 
|  | 45 |  | 
|  | 46 | static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b); | 
|  | 47 | static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b); | 
|  | 48 |  | 
|  | 49 | static void trianglex_validate(void*, | 
|  | 50 | const GGLcoord*, const GGLcoord*, const GGLcoord*); | 
|  | 51 | static void trianglex_small(void*, | 
|  | 52 | const GGLcoord*, const GGLcoord*, const GGLcoord*); | 
|  | 53 | static void trianglex_big(void*, | 
|  | 54 | const GGLcoord*, const GGLcoord*, const GGLcoord*); | 
|  | 55 | static void aa_trianglex(void*, | 
|  | 56 | const GGLcoord*, const GGLcoord*, const GGLcoord*); | 
|  | 57 | static void trianglex_debug(void* con, | 
|  | 58 | const GGLcoord*, const GGLcoord*, const GGLcoord*); | 
|  | 59 |  | 
|  | 60 | static void aapolyx(void* con, | 
|  | 61 | const GGLcoord* pts, int count); | 
|  | 62 |  | 
|  | 63 | static inline int min(int a, int b) CONST; | 
|  | 64 | static inline int max(int a, int b) CONST; | 
|  | 65 | static inline int min(int a, int b, int c) CONST; | 
|  | 66 | static inline int max(int a, int b, int c) CONST; | 
|  | 67 |  | 
|  | 68 | // ---------------------------------------------------------------------------- | 
|  | 69 | #if 0 | 
|  | 70 | #pragma mark - | 
|  | 71 | #pragma mark Tools | 
|  | 72 | #endif | 
|  | 73 |  | 
|  | 74 | inline int min(int a, int b) { | 
|  | 75 | return a<b ? a : b; | 
|  | 76 | } | 
|  | 77 | inline int max(int a, int b) { | 
|  | 78 | return a<b ? b : a; | 
|  | 79 | } | 
|  | 80 | inline int min(int a, int b, int c) { | 
|  | 81 | return min(a,min(b,c)); | 
|  | 82 | } | 
|  | 83 | inline int max(int a, int b, int c) { | 
|  | 84 | return max(a,max(b,c)); | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | template <typename T> | 
|  | 88 | static inline void swap(T& a, T& b) { | 
|  | 89 | T t(a); | 
|  | 90 | a = b; | 
|  | 91 | b = t; | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | static void | 
|  | 95 | triangle_dump_points( const GGLcoord*  v0, | 
|  | 96 | const GGLcoord*  v1, | 
| Steve Block | 8d66c49 | 2011-12-20 16:07:45 +0000 | [diff] [blame] | 97 | const GGLcoord*  v2 ) | 
| The Android Open Source Project | dd7bc33 | 2009-03-03 19:32:55 -0800 | [diff] [blame] | 98 | { | 
|  | 99 | float tri = 1.0f / TRI_ONE; | 
| Steve Block | 8d66c49 | 2011-12-20 16:07:45 +0000 | [diff] [blame] | 100 | ALOGD("  P0=(%.3f, %.3f)  [%08x, %08x]\n" | 
|  | 101 | "  P1=(%.3f, %.3f)  [%08x, %08x]\n" | 
|  | 102 | "  P2=(%.3f, %.3f)  [%08x, %08x]\n", | 
|  | 103 | v0[0]*tri, v0[1]*tri, v0[0], v0[1], | 
|  | 104 | v1[0]*tri, v1[1]*tri, v1[0], v1[1], | 
|  | 105 | 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] | 106 | } | 
|  | 107 |  | 
|  | 108 | // ---------------------------------------------------------------------------- | 
|  | 109 | #if 0 | 
|  | 110 | #pragma mark - | 
|  | 111 | #pragma mark Misc | 
|  | 112 | #endif | 
|  | 113 |  | 
|  | 114 | void ggl_init_trap(context_t* c) | 
|  | 115 | { | 
|  | 116 | ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE); | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | void ggl_state_changed(context_t* c, int flags) | 
|  | 120 | { | 
|  | 121 | if (ggl_likely(!c->dirty)) { | 
|  | 122 | c->procs.pointx     = pointx_validate; | 
|  | 123 | c->procs.linex      = linex_validate; | 
|  | 124 | c->procs.recti      = recti_validate; | 
|  | 125 | c->procs.trianglex  = trianglex_validate; | 
|  | 126 | } | 
|  | 127 | c->dirty |= uint32_t(flags); | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | // ---------------------------------------------------------------------------- | 
|  | 131 | #if 0 | 
|  | 132 | #pragma mark - | 
|  | 133 | #pragma mark Point | 
|  | 134 | #endif | 
|  | 135 |  | 
|  | 136 | void pointx_validate(void *con, const GGLcoord* v, GGLcoord rad) | 
|  | 137 | { | 
|  | 138 | GGL_CONTEXT(c, con); | 
|  | 139 | ggl_pick(c); | 
|  | 140 | if (c->state.needs.p & GGL_NEED_MASK(P_AA)) { | 
|  | 141 | if (c->state.enables & GGL_ENABLE_POINT_AA_NICE) { | 
|  | 142 | c->procs.pointx = aa_nice_pointx; | 
|  | 143 | } else { | 
|  | 144 | c->procs.pointx = aa_pointx; | 
|  | 145 | } | 
|  | 146 | } else { | 
|  | 147 | c->procs.pointx = pointx; | 
|  | 148 | } | 
|  | 149 | c->procs.pointx(con, v, rad); | 
|  | 150 | } | 
|  | 151 |  | 
|  | 152 | void pointx(void *con, const GGLcoord* v, GGLcoord rad) | 
|  | 153 | { | 
|  | 154 | GGL_CONTEXT(c, con); | 
|  | 155 | GGLcoord halfSize = TRI_ROUND(rad) >> 1; | 
|  | 156 | if (halfSize == 0) | 
|  | 157 | halfSize = TRI_HALF; | 
|  | 158 | GGLcoord xc = v[0]; | 
|  | 159 | GGLcoord yc = v[1]; | 
|  | 160 | if (halfSize & TRI_HALF) { // size odd | 
|  | 161 | xc = TRI_FLOOR(xc) + TRI_HALF; | 
|  | 162 | yc = TRI_FLOOR(yc) + TRI_HALF; | 
|  | 163 | } else { // size even | 
|  | 164 | xc = TRI_ROUND(xc); | 
|  | 165 | yc = TRI_ROUND(yc); | 
|  | 166 | } | 
|  | 167 | GGLint l = (xc - halfSize) >> TRI_FRACTION_BITS; | 
|  | 168 | GGLint t = (yc - halfSize) >> TRI_FRACTION_BITS; | 
|  | 169 | GGLint r = (xc + halfSize) >> TRI_FRACTION_BITS; | 
|  | 170 | GGLint b = (yc + halfSize) >> TRI_FRACTION_BITS; | 
|  | 171 | recti(c, l, t, r, b); | 
|  | 172 | } | 
|  | 173 |  | 
|  | 174 | // This way of computing the coverage factor, is more accurate and gives | 
|  | 175 | // better results for small circles, but it is also a lot slower. | 
|  | 176 | // Here we use super-sampling. | 
|  | 177 | static int32_t coverageNice(GGLcoord x, GGLcoord y, | 
|  | 178 | GGLcoord rmin, GGLcoord rmax, GGLcoord rr) | 
|  | 179 | { | 
|  | 180 | const GGLcoord d2 = x*x + y*y; | 
|  | 181 | if (d2 >= rmax) return 0; | 
|  | 182 | if (d2 < rmin)  return 0x7FFF; | 
|  | 183 |  | 
|  | 184 | const int kSamples              =  4; | 
|  | 185 | const int kInc                  =  4;    // 1/4 = 0.25 | 
|  | 186 | const int kCoverageUnit         =  1;    // 1/(4^2) = 0.0625 | 
|  | 187 | const GGLcoord kCoordOffset     = -6;    // -0.375 | 
|  | 188 |  | 
|  | 189 | int hits = 0; | 
|  | 190 | int x_sample = x + kCoordOffset; | 
|  | 191 | for (int i=0 ; i<kSamples ; i++, x_sample += kInc) { | 
|  | 192 | const int xval = rr - (x_sample * x_sample); | 
|  | 193 | int y_sample = y + kCoordOffset; | 
|  | 194 | for (int j=0 ; j<kSamples ; j++, y_sample += kInc) { | 
|  | 195 | if (xval - (y_sample * y_sample) > 0) | 
|  | 196 | hits += kCoverageUnit; | 
|  | 197 | } | 
|  | 198 | } | 
|  | 199 | return min(0x7FFF, hits << (15 - kSamples)); | 
|  | 200 | } | 
|  | 201 |  | 
|  | 202 |  | 
|  | 203 | void aa_nice_pointx(void *con, const GGLcoord* v, GGLcoord size) | 
|  | 204 | { | 
|  | 205 | GGL_CONTEXT(c, con); | 
|  | 206 |  | 
|  | 207 | GGLcoord rad = ((size + 1)>>1); | 
|  | 208 | GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS; | 
|  | 209 | GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS; | 
|  | 210 | GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS; | 
|  | 211 | GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS; | 
|  | 212 | GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF; | 
|  | 213 | GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF; | 
|  | 214 |  | 
|  | 215 | // scissor... | 
|  | 216 | if (l < GGLint(c->state.scissor.left)) { | 
|  | 217 | xstart += TRI_FROM_INT(c->state.scissor.left-l); | 
|  | 218 | l = GGLint(c->state.scissor.left); | 
|  | 219 | } | 
|  | 220 | if (t < GGLint(c->state.scissor.top)) { | 
|  | 221 | ystart += TRI_FROM_INT(c->state.scissor.top-t); | 
|  | 222 | t = GGLint(c->state.scissor.top); | 
|  | 223 | } | 
|  | 224 | if (r > GGLint(c->state.scissor.right)) { | 
|  | 225 | r = GGLint(c->state.scissor.right); | 
|  | 226 | } | 
|  | 227 | if (b > GGLint(c->state.scissor.bottom)) { | 
|  | 228 | b = GGLint(c->state.scissor.bottom); | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | int xc = r - l; | 
|  | 232 | int yc = b - t; | 
|  | 233 | if (xc>0 && yc>0) { | 
|  | 234 | int16_t* covPtr = c->state.buffers.coverage; | 
|  | 235 | const int32_t sqr2Over2 = 0xC; // rounded up | 
|  | 236 | GGLcoord rr = rad*rad; | 
|  | 237 | GGLcoord rmin = (rad - sqr2Over2)*(rad - sqr2Over2); | 
|  | 238 | GGLcoord rmax = (rad + sqr2Over2)*(rad + sqr2Over2); | 
|  | 239 | GGLcoord y = ystart; | 
|  | 240 | c->iterators.xl = l; | 
|  | 241 | c->iterators.xr = r; | 
|  | 242 | c->init_y(c, t); | 
|  | 243 | do { | 
|  | 244 | // compute coverage factors for each pixel | 
|  | 245 | GGLcoord x = xstart; | 
|  | 246 | for (int i=l ; i<r ; i++) { | 
|  | 247 | covPtr[i] = coverageNice(x, y, rmin, rmax, rr); | 
|  | 248 | x += TRI_ONE; | 
|  | 249 | } | 
|  | 250 | y += TRI_ONE; | 
|  | 251 | c->scanline(c); | 
|  | 252 | c->step_y(c); | 
|  | 253 | } while (--yc); | 
|  | 254 | } | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 | // This is a cheap way of computing the coverage factor for a circle. | 
|  | 258 | // We just lerp between the circles of radii r-sqrt(2)/2 and r+sqrt(2)/2 | 
|  | 259 | static inline int32_t coverageFast(GGLcoord x, GGLcoord y, | 
|  | 260 | GGLcoord rmin, GGLcoord rmax, GGLcoord scale) | 
|  | 261 | { | 
|  | 262 | const GGLcoord d2 = x*x + y*y; | 
|  | 263 | if (d2 >= rmax) return 0; | 
|  | 264 | if (d2 < rmin)  return 0x7FFF; | 
|  | 265 | return 0x7FFF - (d2-rmin)*scale; | 
|  | 266 | } | 
|  | 267 |  | 
|  | 268 | void aa_pointx(void *con, const GGLcoord* v, GGLcoord size) | 
|  | 269 | { | 
|  | 270 | GGL_CONTEXT(c, con); | 
|  | 271 |  | 
|  | 272 | GGLcoord rad = ((size + 1)>>1); | 
|  | 273 | GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS; | 
|  | 274 | GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS; | 
|  | 275 | GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS; | 
|  | 276 | GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS; | 
|  | 277 | GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF; | 
|  | 278 | GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF; | 
|  | 279 |  | 
|  | 280 | // scissor... | 
|  | 281 | if (l < GGLint(c->state.scissor.left)) { | 
|  | 282 | xstart += TRI_FROM_INT(c->state.scissor.left-l); | 
|  | 283 | l = GGLint(c->state.scissor.left); | 
|  | 284 | } | 
|  | 285 | if (t < GGLint(c->state.scissor.top)) { | 
|  | 286 | ystart += TRI_FROM_INT(c->state.scissor.top-t); | 
|  | 287 | t = GGLint(c->state.scissor.top); | 
|  | 288 | } | 
|  | 289 | if (r > GGLint(c->state.scissor.right)) { | 
|  | 290 | r = GGLint(c->state.scissor.right); | 
|  | 291 | } | 
|  | 292 | if (b > GGLint(c->state.scissor.bottom)) { | 
|  | 293 | b = GGLint(c->state.scissor.bottom); | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | int xc = r - l; | 
|  | 297 | int yc = b - t; | 
|  | 298 | if (xc>0 && yc>0) { | 
|  | 299 | int16_t* covPtr = c->state.buffers.coverage; | 
|  | 300 | rad <<= 4; | 
|  | 301 | const int32_t sqr2Over2 = 0xB5;    // fixed-point 24.8 | 
|  | 302 | GGLcoord rmin = rad - sqr2Over2; | 
|  | 303 | GGLcoord rmax = rad + sqr2Over2; | 
|  | 304 | GGLcoord scale; | 
|  | 305 | rmin *= rmin; | 
|  | 306 | rmax *= rmax; | 
|  | 307 | scale = 0x800000 / (rmax - rmin); | 
|  | 308 | rmin >>= 8; | 
|  | 309 | rmax >>= 8; | 
|  | 310 |  | 
|  | 311 | GGLcoord y = ystart; | 
|  | 312 | c->iterators.xl = l; | 
|  | 313 | c->iterators.xr = r; | 
|  | 314 | c->init_y(c, t); | 
|  | 315 |  | 
|  | 316 | do { | 
|  | 317 | // compute coverage factors for each pixel | 
|  | 318 | GGLcoord x = xstart; | 
|  | 319 | for (int i=l ; i<r ; i++) { | 
|  | 320 | covPtr[i] = coverageFast(x, y, rmin, rmax, scale); | 
|  | 321 | x += TRI_ONE; | 
|  | 322 | } | 
|  | 323 | y += TRI_ONE; | 
|  | 324 | c->scanline(c); | 
|  | 325 | c->step_y(c); | 
|  | 326 | } while (--yc); | 
|  | 327 | } | 
|  | 328 | } | 
|  | 329 |  | 
|  | 330 | // ---------------------------------------------------------------------------- | 
|  | 331 | #if 0 | 
|  | 332 | #pragma mark - | 
|  | 333 | #pragma mark Line | 
|  | 334 | #endif | 
|  | 335 |  | 
|  | 336 | void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w) | 
|  | 337 | { | 
|  | 338 | GGL_CONTEXT(c, con); | 
|  | 339 | ggl_pick(c); | 
|  | 340 | if (c->state.needs.p & GGL_NEED_MASK(P_AA)) { | 
|  | 341 | c->procs.linex = aa_linex; | 
|  | 342 | } else { | 
|  | 343 | c->procs.linex = linex; | 
|  | 344 | } | 
|  | 345 | c->procs.linex(con, v0, v1, w); | 
|  | 346 | } | 
|  | 347 |  | 
|  | 348 | static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width) | 
|  | 349 | { | 
|  | 350 | GGL_CONTEXT(c, con); | 
|  | 351 | GGLcoord v[4][2]; | 
|  | 352 | v[0][0] = v0[0];    v[0][1] = v0[1]; | 
|  | 353 | v[1][0] = v1[0];    v[1][1] = v1[1]; | 
|  | 354 | v0 = v[0]; | 
|  | 355 | v1 = v[1]; | 
|  | 356 | const GGLcoord dx = abs(v0[0] - v1[0]); | 
|  | 357 | const GGLcoord dy = abs(v0[1] - v1[1]); | 
|  | 358 | GGLcoord nx, ny; | 
|  | 359 | nx = ny = 0; | 
|  | 360 |  | 
|  | 361 | GGLcoord halfWidth = TRI_ROUND(width) >> 1; | 
|  | 362 | if (halfWidth == 0) | 
|  | 363 | halfWidth = TRI_HALF; | 
|  | 364 |  | 
|  | 365 | ((dx > dy) ? ny : nx) = halfWidth; | 
|  | 366 | v[2][0] = v1[0];    v[2][1] = v1[1]; | 
|  | 367 | v[3][0] = v0[0];    v[3][1] = v0[1]; | 
|  | 368 | v[0][0] += nx;      v[0][1] += ny; | 
|  | 369 | v[1][0] += nx;      v[1][1] += ny; | 
|  | 370 | v[2][0] -= nx;      v[2][1] -= ny; | 
|  | 371 | v[3][0] -= nx;      v[3][1] -= ny; | 
|  | 372 | trianglex_big(con, v[0], v[1], v[2]); | 
|  | 373 | trianglex_big(con, v[0], v[2], v[3]); | 
|  | 374 | } | 
|  | 375 |  | 
|  | 376 | static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width) | 
|  | 377 | { | 
|  | 378 | GGL_CONTEXT(c, con); | 
|  | 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 |