blob: 06ad2373c35979184c5da5b28ec42418a0687e9e [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/* libs/pixelflinger/trap.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
Mark Salyzyn66ce3e02016-09-28 10:07:20 -07005** 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 Projectdd7bc332009-03-03 19:32:55 -08008**
Mark Salyzyn66ce3e02016-09-28 10:07:20 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080010**
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070011** 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 Projectdd7bc332009-03-03 19:32:55 -080015** limitations under the License.
16*/
17
Mark Salyzyncfd5b082016-10-17 14:28:00 -070018#define LOG_TAG "pixelflinger-trap"
19
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080020#include <assert.h>
21#include <stdio.h>
22#include <stdlib.h>
23
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070024#include <cutils/memory.h>
Mark Salyzyn30f991f2017-01-10 13:19:54 -080025#include <log/log.h>
Mark Salyzyn66ce3e02016-09-28 10:07:20 -070026
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080027#include "trap.h"
28#include "picker.h"
29
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080030namespace android {
31
32// ----------------------------------------------------------------------------
33
34// enable to see triangles edges
35#define DEBUG_TRANGLES 0
36
37// ----------------------------------------------------------------------------
38
39static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r);
40static void pointx(void *con, const GGLcoord* c, GGLcoord r);
41static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r);
42static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r);
43
44static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
45static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
46static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
47
48static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
49static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
50
51static void trianglex_validate(void*,
52 const GGLcoord*, const GGLcoord*, const GGLcoord*);
53static void trianglex_small(void*,
54 const GGLcoord*, const GGLcoord*, const GGLcoord*);
55static void trianglex_big(void*,
56 const GGLcoord*, const GGLcoord*, const GGLcoord*);
57static void aa_trianglex(void*,
58 const GGLcoord*, const GGLcoord*, const GGLcoord*);
59static void trianglex_debug(void* con,
60 const GGLcoord*, const GGLcoord*, const GGLcoord*);
61
62static void aapolyx(void* con,
63 const GGLcoord* pts, int count);
64
65static inline int min(int a, int b) CONST;
66static inline int max(int a, int b) CONST;
67static inline int min(int a, int b, int c) CONST;
68static 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
76inline int min(int a, int b) {
77 return a<b ? a : b;
78}
79inline int max(int a, int b) {
80 return a<b ? b : a;
81}
82inline int min(int a, int b, int c) {
83 return min(a,min(b,c));
84}
85inline int max(int a, int b, int c) {
86 return max(a,max(b,c));
87}
88
89template <typename T>
90static inline void swap(T& a, T& b) {
91 T t(a);
92 a = b;
93 b = t;
94}
95
96static void
97triangle_dump_points( const GGLcoord* v0,
98 const GGLcoord* v1,
Steve Block8d66c492011-12-20 16:07:45 +000099 const GGLcoord* v2 )
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800100{
101 float tri = 1.0f / TRI_ONE;
Steve Block8d66c492011-12-20 16:07:45 +0000102 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 Projectdd7bc332009-03-03 19:32:55 -0800108}
109
110// ----------------------------------------------------------------------------
111#if 0
112#pragma mark -
113#pragma mark Misc
114#endif
115
116void ggl_init_trap(context_t* c)
117{
118 ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE);
119}
120
121void 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
138void 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
154void 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.
179static 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
205void 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
261static 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
270void 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
338void 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
350static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
351{
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800352 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
377static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
378{
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800379 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++) {
Elliott Hughescd6b53f2015-10-21 18:52:17 -0700566 int32_t ex0 = ey0;
567 int32_t ex1 = ey1;
568 int32_t ex2 = ey2;
569 int32_t xl, xr;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800570 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{
Steve Blockfe71a612012-01-04 19:19:03 +0000642 ALOGI( " top=%d (%.3f) bot=%d (%.3f) x=%d (%.3f) ix=%d (%.3f)",
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800643 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{
Steve Blockfe71a612012-01-04 19:19:03 +0000653 ALOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" );
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800654 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;
Steve Block8d66c492011-12-20 16:07:45 +0000838 ALOGD( "x=%08x (%.3f), "
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800839 "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