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 28namespace android { 29 30// ---------------------------------------------------------------------------- 31 32// enable to see triangles edges 33#define DEBUG_TRANGLES 0 34 35// ---------------------------------------------------------------------------- 36 37static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r); 38static void pointx(void *con, const GGLcoord* c, GGLcoord r); 39static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r); 40static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r); 41 42static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w); 43static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w); 44static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w); 45 46static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b); 47static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b); 48 49static void trianglex_validate(void*, 50 const GGLcoord*, const GGLcoord*, const GGLcoord*); 51static void trianglex_small(void*, 52 const GGLcoord*, const GGLcoord*, const GGLcoord*); 53static void trianglex_big(void*, 54 const GGLcoord*, const GGLcoord*, const GGLcoord*); 55static void aa_trianglex(void*, 56 const GGLcoord*, const GGLcoord*, const GGLcoord*); 57static void trianglex_debug(void* con, 58 const GGLcoord*, const GGLcoord*, const GGLcoord*); 59 60static void aapolyx(void* con, 61 const GGLcoord* pts, int count); 62 63static inline int min(int a, int b) CONST; 64static inline int max(int a, int b) CONST; 65static inline int min(int a, int b, int c) CONST; 66static 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 74inline int min(int a, int b) { 75 return a<b ? a : b; 76} 77inline int max(int a, int b) { 78 return a<b ? b : a; 79} 80inline int min(int a, int b, int c) { 81 return min(a,min(b,c)); 82} 83inline int max(int a, int b, int c) { 84 return max(a,max(b,c)); 85} 86 87template <typename T> 88static inline void swap(T& a, T& b) { 89 T t(a); 90 a = b; 91 b = t; 92} 93 94static void 95triangle_dump_points( const GGLcoord* v0, 96 const GGLcoord* v1, 97 const GGLcoord* v2 ) 98{ 99 float tri = 1.0f / TRI_ONE; 100 LOGD( " 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] ); 106} 107 108// ---------------------------------------------------------------------------- 109#if 0 110#pragma mark - 111#pragma mark Misc 112#endif 113 114void ggl_init_trap(context_t* c) 115{ 116 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE); 117} 118 119void 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 136void 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 152void 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. 177static 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 203void 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 259static 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 268void 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 336void 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 348static 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 376static 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 411void 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 419void 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 449static 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 462static 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 479static 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 492void 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 507void 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++) { 566 register int32_t ex0 = ey0; 567 register int32_t ex1 = ey1; 568 register int32_t ex2 = ey2; 569 register int32_t xl, xr; 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 629const int TRI_ITERATORS_BITS = 16; 630 631struct 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 639static void 640edge_dump( Edge* edge ) 641{ 642 LOGI( " top=%d (%.3f) bot=%d (%.3f) x=%d (%.3f) ix=%d (%.3f)", 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 649static void 650triangle_dump_edges( Edge* edges, 651 int count ) 652{ 653 LOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" ); 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 661static __attribute__((noinline)) 662void 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 718static void 719triangle_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 760void 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 811void 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 823struct 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 833void 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; 838 LOGD( "x=%08x (%.3f), " 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 851static __attribute__((noinline)) 852void 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 907typedef int (*compar_t)(const void*, const void*); 908static 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 918static inline 919void 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 925static inline 926void 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 934static inline 935void SUB_COVERAGE(int16_t*& p, int32_t value) 936{ 937 value = *p - value; 938 value &= ~(value>>31); 939 *p++ = value; 940} 941 942void 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 1174