aboutsummaryrefslogtreecommitdiffstats
path: root/libpixelflinger/trap.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:29:04 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 18:29:04 -0800
commite54eebbf1a908d65ee8cf80bab62821c05666d70 (patch)
tree4b825dc642cb6eb9a060e54bf8d69288fbee4904 /libpixelflinger/trap.cpp
parenta1e1c1b106423de09bc918502e7a51d4ffe5a4ae (diff)
downloadsystem_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.gz
system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.tar.bz2
system_core-e54eebbf1a908d65ee8cf80bab62821c05666d70.zip
auto import from //depot/cupcake/@135843
Diffstat (limited to 'libpixelflinger/trap.cpp')
-rw-r--r--libpixelflinger/trap.cpp1173
1 files changed, 0 insertions, 1173 deletions
diff --git a/libpixelflinger/trap.cpp b/libpixelflinger/trap.cpp
deleted file mode 100644
index 30b633f1..00000000
--- a/libpixelflinger/trap.cpp
+++ /dev/null
@@ -1,1173 +0,0 @@
-/* libs/pixelflinger/trap.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "trap.h"
-#include "picker.h"
-
-#include <cutils/log.h>
-#include <cutils/memory.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-// enable to see triangles edges
-#define DEBUG_TRANGLES 0
-
-// ----------------------------------------------------------------------------
-
-static void pointx_validate(void *con, const GGLcoord* c, GGLcoord r);
-static void pointx(void *con, const GGLcoord* c, GGLcoord r);
-static void aa_pointx(void *con, const GGLcoord* c, GGLcoord r);
-static void aa_nice_pointx(void *con, const GGLcoord* c, GGLcoord r);
-
-static void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w);
-
-static void recti_validate(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
-static void recti(void* c, GGLint l, GGLint t, GGLint r, GGLint b);
-
-static void trianglex_validate(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_small(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_big(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void aa_trianglex(void*,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-static void trianglex_debug(void* con,
- const GGLcoord*, const GGLcoord*, const GGLcoord*);
-
-static void aapolyx(void* con,
- const GGLcoord* pts, int count);
-
-static inline int min(int a, int b) CONST;
-static inline int max(int a, int b) CONST;
-static inline int min(int a, int b, int c) CONST;
-static inline int max(int a, int b, int c) CONST;
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Tools
-#endif
-
-inline int min(int a, int b) {
- return a<b ? a : b;
-}
-inline int max(int a, int b) {
- return a<b ? b : a;
-}
-inline int min(int a, int b, int c) {
- return min(a,min(b,c));
-}
-inline int max(int a, int b, int c) {
- return max(a,max(b,c));
-}
-
-template <typename T>
-static inline void swap(T& a, T& b) {
- T t(a);
- a = b;
- b = t;
-}
-
-static void
-triangle_dump_points( const GGLcoord* v0,
- const GGLcoord* v1,
- const GGLcoord* v2 )
-{
- float tri = 1.0f / TRI_ONE;
- LOGD( " P0=(%.3f, %.3f) [%08x, %08x]\n"
- " P1=(%.3f, %.3f) [%08x, %08x]\n"
- " P2=(%.3f, %.3f) [%08x, %08x]\n",
- v0[0]*tri, v0[1]*tri, v0[0], v0[1],
- v1[0]*tri, v1[1]*tri, v1[0], v1[1],
- v2[0]*tri, v2[1]*tri, v2[0], v2[1] );
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Misc
-#endif
-
-void ggl_init_trap(context_t* c)
-{
- ggl_state_changed(c, GGL_PIXEL_PIPELINE_STATE|GGL_TMU_STATE|GGL_CB_STATE);
-}
-
-void ggl_state_changed(context_t* c, int flags)
-{
- if (ggl_likely(!c->dirty)) {
- c->procs.pointx = pointx_validate;
- c->procs.linex = linex_validate;
- c->procs.recti = recti_validate;
- c->procs.trianglex = trianglex_validate;
- }
- c->dirty |= uint32_t(flags);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Point
-#endif
-
-void pointx_validate(void *con, const GGLcoord* v, GGLcoord rad)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- if (c->state.enables & GGL_ENABLE_POINT_AA_NICE) {
- c->procs.pointx = aa_nice_pointx;
- } else {
- c->procs.pointx = aa_pointx;
- }
- } else {
- c->procs.pointx = pointx;
- }
- c->procs.pointx(con, v, rad);
-}
-
-void pointx(void *con, const GGLcoord* v, GGLcoord rad)
-{
- GGL_CONTEXT(c, con);
- GGLcoord halfSize = TRI_ROUND(rad) >> 1;
- if (halfSize == 0)
- halfSize = TRI_HALF;
- GGLcoord xc = v[0];
- GGLcoord yc = v[1];
- if (halfSize & TRI_HALF) { // size odd
- xc = TRI_FLOOR(xc) + TRI_HALF;
- yc = TRI_FLOOR(yc) + TRI_HALF;
- } else { // size even
- xc = TRI_ROUND(xc);
- yc = TRI_ROUND(yc);
- }
- GGLint l = (xc - halfSize) >> TRI_FRACTION_BITS;
- GGLint t = (yc - halfSize) >> TRI_FRACTION_BITS;
- GGLint r = (xc + halfSize) >> TRI_FRACTION_BITS;
- GGLint b = (yc + halfSize) >> TRI_FRACTION_BITS;
- recti(c, l, t, r, b);
-}
-
-// This way of computing the coverage factor, is more accurate and gives
-// better results for small circles, but it is also a lot slower.
-// Here we use super-sampling.
-static int32_t coverageNice(GGLcoord x, GGLcoord y,
- GGLcoord rmin, GGLcoord rmax, GGLcoord rr)
-{
- const GGLcoord d2 = x*x + y*y;
- if (d2 >= rmax) return 0;
- if (d2 < rmin) return 0x7FFF;
-
- const int kSamples = 4;
- const int kInc = 4; // 1/4 = 0.25
- const int kCoverageUnit = 1; // 1/(4^2) = 0.0625
- const GGLcoord kCoordOffset = -6; // -0.375
-
- int hits = 0;
- int x_sample = x + kCoordOffset;
- for (int i=0 ; i<kSamples ; i++, x_sample += kInc) {
- const int xval = rr - (x_sample * x_sample);
- int y_sample = y + kCoordOffset;
- for (int j=0 ; j<kSamples ; j++, y_sample += kInc) {
- if (xval - (y_sample * y_sample) > 0)
- hits += kCoverageUnit;
- }
- }
- return min(0x7FFF, hits << (15 - kSamples));
-}
-
-
-void aa_nice_pointx(void *con, const GGLcoord* v, GGLcoord size)
-{
- GGL_CONTEXT(c, con);
-
- GGLcoord rad = ((size + 1)>>1);
- GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
- GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
- GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
- GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
-
- // scissor...
- if (l < GGLint(c->state.scissor.left)) {
- xstart += TRI_FROM_INT(c->state.scissor.left-l);
- l = GGLint(c->state.scissor.left);
- }
- if (t < GGLint(c->state.scissor.top)) {
- ystart += TRI_FROM_INT(c->state.scissor.top-t);
- t = GGLint(c->state.scissor.top);
- }
- if (r > GGLint(c->state.scissor.right)) {
- r = GGLint(c->state.scissor.right);
- }
- if (b > GGLint(c->state.scissor.bottom)) {
- b = GGLint(c->state.scissor.bottom);
- }
-
- int xc = r - l;
- int yc = b - t;
- if (xc>0 && yc>0) {
- int16_t* covPtr = c->state.buffers.coverage;
- const int32_t sqr2Over2 = 0xC; // rounded up
- GGLcoord rr = rad*rad;
- GGLcoord rmin = (rad - sqr2Over2)*(rad - sqr2Over2);
- GGLcoord rmax = (rad + sqr2Over2)*(rad + sqr2Over2);
- GGLcoord y = ystart;
- c->iterators.xl = l;
- c->iterators.xr = r;
- c->init_y(c, t);
- do {
- // compute coverage factors for each pixel
- GGLcoord x = xstart;
- for (int i=l ; i<r ; i++) {
- covPtr[i] = coverageNice(x, y, rmin, rmax, rr);
- x += TRI_ONE;
- }
- y += TRI_ONE;
- c->scanline(c);
- c->step_y(c);
- } while (--yc);
- }
-}
-
-// This is a cheap way of computing the coverage factor for a circle.
-// We just lerp between the circles of radii r-sqrt(2)/2 and r+sqrt(2)/2
-static inline int32_t coverageFast(GGLcoord x, GGLcoord y,
- GGLcoord rmin, GGLcoord rmax, GGLcoord scale)
-{
- const GGLcoord d2 = x*x + y*y;
- if (d2 >= rmax) return 0;
- if (d2 < rmin) return 0x7FFF;
- return 0x7FFF - (d2-rmin)*scale;
-}
-
-void aa_pointx(void *con, const GGLcoord* v, GGLcoord size)
-{
- GGL_CONTEXT(c, con);
-
- GGLcoord rad = ((size + 1)>>1);
- GGLint l = (v[0] - rad) >> TRI_FRACTION_BITS;
- GGLint t = (v[1] - rad) >> TRI_FRACTION_BITS;
- GGLint r = (v[0] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLint b = (v[1] + rad + (TRI_ONE-1)) >> TRI_FRACTION_BITS;
- GGLcoord xstart = TRI_FROM_INT(l) - v[0] + TRI_HALF;
- GGLcoord ystart = TRI_FROM_INT(t) - v[1] + TRI_HALF;
-
- // scissor...
- if (l < GGLint(c->state.scissor.left)) {
- xstart += TRI_FROM_INT(c->state.scissor.left-l);
- l = GGLint(c->state.scissor.left);
- }
- if (t < GGLint(c->state.scissor.top)) {
- ystart += TRI_FROM_INT(c->state.scissor.top-t);
- t = GGLint(c->state.scissor.top);
- }
- if (r > GGLint(c->state.scissor.right)) {
- r = GGLint(c->state.scissor.right);
- }
- if (b > GGLint(c->state.scissor.bottom)) {
- b = GGLint(c->state.scissor.bottom);
- }
-
- int xc = r - l;
- int yc = b - t;
- if (xc>0 && yc>0) {
- int16_t* covPtr = c->state.buffers.coverage;
- rad <<= 4;
- const int32_t sqr2Over2 = 0xB5; // fixed-point 24.8
- GGLcoord rmin = rad - sqr2Over2;
- GGLcoord rmax = rad + sqr2Over2;
- GGLcoord scale;
- rmin *= rmin;
- rmax *= rmax;
- scale = 0x800000 / (rmax - rmin);
- rmin >>= 8;
- rmax >>= 8;
-
- GGLcoord y = ystart;
- c->iterators.xl = l;
- c->iterators.xr = r;
- c->init_y(c, t);
-
- do {
- // compute coverage factors for each pixel
- GGLcoord x = xstart;
- for (int i=l ; i<r ; i++) {
- covPtr[i] = coverageFast(x, y, rmin, rmax, scale);
- x += TRI_ONE;
- }
- y += TRI_ONE;
- c->scanline(c);
- c->step_y(c);
- } while (--yc);
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Line
-#endif
-
-void linex_validate(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord w)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- c->procs.linex = aa_linex;
- } else {
- c->procs.linex = linex;
- }
- c->procs.linex(con, v0, v1, w);
-}
-
-static void linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
-{
- GGL_CONTEXT(c, con);
- GGLcoord v[4][2];
- v[0][0] = v0[0]; v[0][1] = v0[1];
- v[1][0] = v1[0]; v[1][1] = v1[1];
- v0 = v[0];
- v1 = v[1];
- const GGLcoord dx = abs(v0[0] - v1[0]);
- const GGLcoord dy = abs(v0[1] - v1[1]);
- GGLcoord nx, ny;
- nx = ny = 0;
-
- GGLcoord halfWidth = TRI_ROUND(width) >> 1;
- if (halfWidth == 0)
- halfWidth = TRI_HALF;
-
- ((dx > dy) ? ny : nx) = halfWidth;
- v[2][0] = v1[0]; v[2][1] = v1[1];
- v[3][0] = v0[0]; v[3][1] = v0[1];
- v[0][0] += nx; v[0][1] += ny;
- v[1][0] += nx; v[1][1] += ny;
- v[2][0] -= nx; v[2][1] -= ny;
- v[3][0] -= nx; v[3][1] -= ny;
- trianglex_big(con, v[0], v[1], v[2]);
- trianglex_big(con, v[0], v[2], v[3]);
-}
-
-static void aa_linex(void *con, const GGLcoord* v0, const GGLcoord* v1, GGLcoord width)
-{
- GGL_CONTEXT(c, con);
- GGLcoord v[4][2];
- v[0][0] = v0[0]; v[0][1] = v0[1];
- v[1][0] = v1[0]; v[1][1] = v1[1];
- v0 = v[0];
- v1 = v[1];
-
- const GGLcoord dx = v0[0] - v1[0];
- const GGLcoord dy = v0[1] - v1[1];
- GGLcoord nx = -dy;
- GGLcoord ny = dx;
-
- // generally, this will be well below 1.0
- const GGLfixed norm = gglMulx(width, gglSqrtRecipx(nx*nx+ny*ny), 4);
- nx = gglMulx(nx, norm, 21);
- ny = gglMulx(ny, norm, 21);
-
- v[2][0] = v1[0]; v[2][1] = v1[1];
- v[3][0] = v0[0]; v[3][1] = v0[1];
- v[0][0] += nx; v[0][1] += ny;
- v[1][0] += nx; v[1][1] += ny;
- v[2][0] -= nx; v[2][1] -= ny;
- v[3][0] -= nx; v[3][1] -= ny;
- aapolyx(con, v[0], 4);
-}
-
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Rect
-#endif
-
-void recti_validate(void *con, GGLint l, GGLint t, GGLint r, GGLint b)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- c->procs.recti = recti;
- c->procs.recti(con, l, t, r, b);
-}
-
-void recti(void* con, GGLint l, GGLint t, GGLint r, GGLint b)
-{
- GGL_CONTEXT(c, con);
-
- // scissor...
- if (l < GGLint(c->state.scissor.left))
- l = GGLint(c->state.scissor.left);
- if (t < GGLint(c->state.scissor.top))
- t = GGLint(c->state.scissor.top);
- if (r > GGLint(c->state.scissor.right))
- r = GGLint(c->state.scissor.right);
- if (b > GGLint(c->state.scissor.bottom))
- b = GGLint(c->state.scissor.bottom);
-
- int xc = r - l;
- int yc = b - t;
- if (xc>0 && yc>0) {
- c->iterators.xl = l;
- c->iterators.xr = r;
- c->init_y(c, t);
- c->rect(c, yc);
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Triangle / Debugging
-#endif
-
-static void scanline_set(context_t* c)
-{
- int32_t x = c->iterators.xl;
- size_t ct = c->iterators.xr - x;
- int32_t y = c->iterators.y;
- surface_t* cb = &(c->state.buffers.color);
- const GGLFormat* fp = &(c->formats[cb->format]);
- uint8_t* dst = reinterpret_cast<uint8_t*>(cb->data) +
- (x + (cb->stride * y)) * fp->size;
- const size_t size = ct * fp->size;
- memset(dst, 0xFF, size);
-}
-
-static void trianglex_debug(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- aa_trianglex(con,v0,v1,v2);
- } else {
- trianglex_big(con,v0,v1,v2);
- }
- void (*save_scanline)(context_t*) = c->scanline;
- c->scanline = scanline_set;
- linex(con, v0, v1, TRI_ONE);
- linex(con, v1, v2, TRI_ONE);
- linex(con, v2, v0, TRI_ONE);
- c->scanline = save_scanline;
-}
-
-static void trianglex_xor(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- trianglex_big(con,v0,v1,v2);
- trianglex_small(con,v0,v1,v2);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Triangle
-#endif
-
-void trianglex_validate(void *con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
- ggl_pick(c);
- if (c->state.needs.p & GGL_NEED_MASK(P_AA)) {
- c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : aa_trianglex;
- } else {
- c->procs.trianglex = DEBUG_TRANGLES ? trianglex_debug : trianglex_big;
- }
- c->procs.trianglex(con, v0, v1, v2);
-}
-
-// ----------------------------------------------------------------------------
-
-void trianglex_small(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
-
- // vertices are in 28.4 fixed point, which allows
- // us to use 32 bits multiplies below.
- int32_t x0 = v0[0];
- int32_t y0 = v0[1];
- int32_t x1 = v1[0];
- int32_t y1 = v1[1];
- int32_t x2 = v2[0];
- int32_t y2 = v2[1];
-
- int32_t dx01 = x0 - x1;
- int32_t dy20 = y2 - y0;
- int32_t dy01 = y0 - y1;
- int32_t dx20 = x2 - x0;
-
- // The code below works only with CCW triangles
- // so if we get a CW triangle, we need to swap two of its vertices
- if (dx01*dy20 < dy01*dx20) {
- swap(x0, x1);
- swap(y0, y1);
- dx01 = x0 - x1;
- dy01 = y0 - y1;
- dx20 = x2 - x0;
- dy20 = y2 - y0;
- }
- int32_t dx12 = x1 - x2;
- int32_t dy12 = y1 - y2;
-
- // bounding box & scissor
- const int32_t bminx = TRI_FLOOR(min(x0, x1, x2)) >> TRI_FRACTION_BITS;
- const int32_t bminy = TRI_FLOOR(min(y0, y1, y2)) >> TRI_FRACTION_BITS;
- const int32_t bmaxx = TRI_CEIL( max(x0, x1, x2)) >> TRI_FRACTION_BITS;
- const int32_t bmaxy = TRI_CEIL( max(y0, y1, y2)) >> TRI_FRACTION_BITS;
- const int32_t minx = max(bminx, c->state.scissor.left);
- const int32_t miny = max(bminy, c->state.scissor.top);
- const int32_t maxx = min(bmaxx, c->state.scissor.right);
- const int32_t maxy = min(bmaxy, c->state.scissor.bottom);
- if ((minx >= maxx) || (miny >= maxy))
- return; // too small or clipped out...
-
- // step equations to the bounding box and snap to pixel center
- const int32_t my = (miny << TRI_FRACTION_BITS) + TRI_HALF;
- const int32_t mx = (minx << TRI_FRACTION_BITS) + TRI_HALF;
- int32_t ey0 = dy01 * (x0 - mx) - dx01 * (y0 - my);
- int32_t ey1 = dy12 * (x1 - mx) - dx12 * (y1 - my);
- int32_t ey2 = dy20 * (x2 - mx) - dx20 * (y2 - my);
-
- // right-exclusive fill rule, to avoid rare cases
- // of over drawing
- if (dy01<0 || (dy01 == 0 && dx01>0)) ey0++;
- if (dy12<0 || (dy12 == 0 && dx12>0)) ey1++;
- if (dy20<0 || (dy20 == 0 && dx20>0)) ey2++;
-
- c->init_y(c, miny);
- for (int32_t y = miny; y < maxy; y++) {
- register int32_t ex0 = ey0;
- register int32_t ex1 = ey1;
- register int32_t ex2 = ey2;
- register int32_t xl, xr;
- for (xl=minx ; xl<maxx ; xl++) {
- if (ex0>0 && ex1>0 && ex2>0)
- break; // all strictly positive
- ex0 -= dy01 << TRI_FRACTION_BITS;
- ex1 -= dy12 << TRI_FRACTION_BITS;
- ex2 -= dy20 << TRI_FRACTION_BITS;
- }
- xr = xl;
- for ( ; xr<maxx ; xr++) {
- if (!(ex0>0 && ex1>0 && ex2>0))
- break; // not all strictly positive
- ex0 -= dy01 << TRI_FRACTION_BITS;
- ex1 -= dy12 << TRI_FRACTION_BITS;
- ex2 -= dy20 << TRI_FRACTION_BITS;
- }
-
- if (xl < xr) {
- c->iterators.xl = xl;
- c->iterators.xr = xr;
- c->scanline(c);
- }
- c->step_y(c);
-
- ey0 += dx01 << TRI_FRACTION_BITS;
- ey1 += dx12 << TRI_FRACTION_BITS;
- ey2 += dx20 << TRI_FRACTION_BITS;
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-// the following routine fills a triangle via edge stepping, which
-// unfortunately requires divisions in the setup phase to get right,
-// it should probably only be used for relatively large trianges
-
-
-// x = y*DX/DY (ou DX and DY are constants, DY > 0, et y >= 0)
-//
-// for an equation of the type:
-// x' = y*K/2^p (with K and p constants "carefully chosen")
-//
-// We can now do a DDA without precision loss. We define 'e' by:
-// x' - x = y*(DX/DY - K/2^p) = y*e
-//
-// If we choose K = round(DX*2^p/DY) then,
-// abs(e) <= 1/2^(p+1) by construction
-//
-// therefore abs(x'-x) = y*abs(e) <= y/2^(p+1) <= DY/2^(p+1) <= DMAX/2^(p+1)
-//
-// which means that if DMAX <= 2^p, therefore abs(x-x') <= 1/2, including
-// at the last line. In fact, it's even a strict inequality except in one
-// extrem case (DY == DMAX et e = +/- 1/2)
-//
-// Applying that to our coordinates, we need 2^p >= 4096*16 = 65536
-// so p = 16 is enough, we're so lucky!
-
-const int TRI_ITERATORS_BITS = 16;
-
-struct Edge
-{
- int32_t x; // edge position in 16.16 coordinates
- int32_t x_incr; // on each step, increment x by that amount
- int32_t y_top; // starting scanline, 16.4 format
- int32_t y_bot;
-};
-
-static void
-edge_dump( Edge* edge )
-{
- LOGI( " top=%d (%.3f) bot=%d (%.3f) x=%d (%.3f) ix=%d (%.3f)",
- edge->y_top, edge->y_top/float(TRI_ONE),
- edge->y_bot, edge->y_bot/float(TRI_ONE),
- edge->x, edge->x/float(FIXED_ONE),
- edge->x_incr, edge->x_incr/float(FIXED_ONE) );
-}
-
-static void
-triangle_dump_edges( Edge* edges,
- int count )
-{
- LOGI( "%d edge%s:\n", count, count == 1 ? "" : "s" );
- for ( ; count > 0; count--, edges++ )
- edge_dump( edges );
-}
-
-// the following function sets up an edge, it assumes
-// that ymin and ymax are in already in the 'reduced'
-// format
-static __attribute__((noinline))
-void edge_setup(
- Edge* edges,
- int* pcount,
- const GGLcoord* p1,
- const GGLcoord* p2,
- int32_t ymin,
- int32_t ymax )
-{
- const GGLfixed* top = p1;
- const GGLfixed* bot = p2;
- Edge* edge = edges + *pcount;
-
- if (top[1] > bot[1]) {
- swap(top, bot);
- }
-
- int y1 = top[1] | 1;
- int y2 = bot[1] | 1;
- int dy = y2 - y1;
-
- if ( dy == 0 || y1 > ymax || y2 < ymin )
- return;
-
- if ( y1 > ymin )
- ymin = TRI_SNAP_NEXT_HALF(y1);
-
- if ( y2 < ymax )
- ymax = TRI_SNAP_PREV_HALF(y2);
-
- if ( ymin > ymax ) // when the edge doesn't cross any scanline
- return;
-
- const int x1 = top[0];
- const int dx = bot[0] - x1;
- const int shift = TRI_ITERATORS_BITS - TRI_FRACTION_BITS;
-
- // setup edge fields
- // We add 0.5 to edge->x here because it simplifies the rounding
- // in triangle_sweep_edges() -- this doesn't change the ordering of 'x'
- edge->x = (x1 << shift) + (1LU << (TRI_ITERATORS_BITS-1));
- edge->x_incr = 0;
- edge->y_top = ymin;
- edge->y_bot = ymax;
-
- if (ggl_likely(ymin <= ymax && dx)) {
- edge->x_incr = gglDivQ16(dx, dy);
- }
- if (ggl_likely(y1 < ymin)) {
- int32_t xadjust = (edge->x_incr * (ymin-y1)) >> TRI_FRACTION_BITS;
- edge->x += xadjust;
- }
-
- ++*pcount;
-}
-
-
-static void
-triangle_sweep_edges( Edge* left,
- Edge* right,
- int ytop,
- int ybot,
- context_t* c )
-{
- int count = ((ybot - ytop)>>TRI_FRACTION_BITS) + 1;
- if (count<=0) return;
-
- // sort the edges horizontally
- if ((left->x > right->x) ||
- ((left->x == right->x) && (left->x_incr > right->x_incr))) {
- swap(left, right);
- }
-
- int left_x = left->x;
- int right_x = right->x;
- const int left_xi = left->x_incr;
- const int right_xi = right->x_incr;
- left->x += left_xi * count;
- right->x += right_xi * count;
-
- const int xmin = c->state.scissor.left;
- const int xmax = c->state.scissor.right;
- do {
- // horizontal scissoring
- const int32_t xl = max(left_x >> TRI_ITERATORS_BITS, xmin);
- const int32_t xr = min(right_x >> TRI_ITERATORS_BITS, xmax);
- left_x += left_xi;
- right_x += right_xi;
- // invoke the scanline rasterizer
- if (ggl_likely(xl < xr)) {
- c->iterators.xl = xl;
- c->iterators.xr = xr;
- c->scanline(c);
- }
- c->step_y(c);
- } while (--count);
-}
-
-
-void trianglex_big(void* con,
- const GGLcoord* v0, const GGLcoord* v1, const GGLcoord* v2)
-{
- GGL_CONTEXT(c, con);
-
- Edge edges[3];
- int num_edges = 0;
- int32_t ymin = TRI_FROM_INT(c->state.scissor.top) + TRI_HALF;
- int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom) - TRI_HALF;
-
- edge_setup( edges, &num_edges, v0, v1, ymin, ymax );
- edge_setup( edges, &num_edges, v0, v2, ymin, ymax );
- edge_setup( edges, &num_edges, v1, v2, ymin, ymax );
-
- if (ggl_unlikely(num_edges<2)) // for really tiny triangles that don't
- return; // cross any scanline centers
-
- Edge* left = &edges[0];
- Edge* right = &edges[1];
- Edge* other = &edges[2];
- int32_t y_top = min(left->y_top, right->y_top);
- int32_t y_bot = max(left->y_bot, right->y_bot);
-
- if (ggl_likely(num_edges==3)) {
- y_top = min(y_top, edges[2].y_top);
- y_bot = max(y_bot, edges[2].y_bot);
- if (edges[0].y_top > y_top) {
- other = &edges[0];
- left = &edges[2];
- } else if (edges[1].y_top > y_top) {
- other = &edges[1];
- right = &edges[2];
- }
- }
-
- c->init_y(c, y_top >> TRI_FRACTION_BITS);
-
- int32_t y_mid = min(left->y_bot, right->y_bot);
- triangle_sweep_edges( left, right, y_top, y_mid, c );
-
- // second scanline sweep loop, if necessary
- y_mid += TRI_ONE;
- if (y_mid <= y_bot) {
- ((left->y_bot == y_bot) ? right : left) = other;
- if (other->y_top < y_mid) {
- other->x += other->x_incr;
- }
- triangle_sweep_edges( left, right, y_mid, y_bot, c );
- }
-}
-
-void aa_trianglex(void* con,
- const GGLcoord* a, const GGLcoord* b, const GGLcoord* c)
-{
- GGLcoord pts[6] = { a[0], a[1], b[0], b[1], c[0], c[1] };
- aapolyx(con, pts, 3);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-struct AAEdge
-{
- GGLfixed x; // edge position in 12.16 coordinates
- GGLfixed x_incr; // on each y step, increment x by that amount
- GGLfixed y_incr; // on each x step, increment y by that amount
- int16_t y_top; // starting scanline, 12.4 format
- int16_t y_bot; // starting scanline, 12.4 format
- void dump();
-};
-
-void AAEdge::dump()
-{
- float tri = 1.0f / TRI_ONE;
- float iter = 1.0f / (1<<TRI_ITERATORS_BITS);
- float fix = 1.0f / FIXED_ONE;
- LOGD( "x=%08x (%.3f), "
- "x_incr=%08x (%.3f), y_incr=%08x (%.3f), "
- "y_top=%08x (%.3f), y_bot=%08x (%.3f) ",
- x, x*fix,
- x_incr, x_incr*iter,
- y_incr, y_incr*iter,
- y_top, y_top*tri,
- y_bot, y_bot*tri );
-}
-
-// the following function sets up an edge, it assumes
-// that ymin and ymax are in already in the 'reduced'
-// format
-static __attribute__((noinline))
-void aa_edge_setup(
- AAEdge* edges,
- int* pcount,
- const GGLcoord* p1,
- const GGLcoord* p2,
- int32_t ymin,
- int32_t ymax )
-{
- const GGLfixed* top = p1;
- const GGLfixed* bot = p2;
- AAEdge* edge = edges + *pcount;
-
- if (top[1] > bot[1])
- swap(top, bot);
-
- int y1 = top[1];
- int y2 = bot[1];
- int dy = y2 - y1;
-
- if (dy==0 || y1>ymax || y2<ymin)
- return;
-
- if (y1 > ymin)
- ymin = y1;
-
- if (y2 < ymax)
- ymax = y2;
-
- const int x1 = top[0];
- const int dx = bot[0] - x1;
- const int shift = FIXED_BITS - TRI_FRACTION_BITS;
-
- // setup edge fields
- edge->x = x1 << shift;
- edge->x_incr = 0;
- edge->y_top = ymin;
- edge->y_bot = ymax;
- edge->y_incr = 0x7FFFFFFF;
-
- if (ggl_likely(ymin <= ymax && dx)) {
- edge->x_incr = gglDivQ16(dx, dy);
- if (dx != 0) {
- edge->y_incr = abs(gglDivQ16(dy, dx));
- }
- }
- if (ggl_likely(y1 < ymin)) {
- int32_t xadjust = (edge->x_incr * (ymin-y1))
- >> (TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS);
- edge->x += xadjust;
- }
-
- ++*pcount;
-}
-
-
-typedef int (*compar_t)(const void*, const void*);
-static int compare_edges(const AAEdge *e0, const AAEdge *e1) {
- if (e0->y_top > e1->y_top) return 1;
- if (e0->y_top < e1->y_top) return -1;
- if (e0->x > e1->x) return 1;
- if (e0->x < e1->x) return -1;
- if (e0->x_incr > e1->x_incr) return 1;
- if (e0->x_incr < e1->x_incr) return -1;
- return 0; // same edges, should never happen
-}
-
-static inline
-void SET_COVERAGE(int16_t*& p, int32_t value, ssize_t n)
-{
- android_memset16((uint16_t*)p, value, n*2);
- p += n;
-}
-
-static inline
-void ADD_COVERAGE(int16_t*& p, int32_t value)
-{
- value = *p + value;
- if (value >= 0x8000)
- value = 0x7FFF;
- *p++ = value;
-}
-
-static inline
-void SUB_COVERAGE(int16_t*& p, int32_t value)
-{
- value = *p - value;
- value &= ~(value>>31);
- *p++ = value;
-}
-
-void aapolyx(void* con,
- const GGLcoord* pts, int count)
-{
- /*
- * NOTE: This routine assumes that the polygon has been clipped to the
- * viewport already, that is, no vertex lies outside of the framebuffer.
- * If this happens, the code below won't corrupt memory but the
- * coverage values may not be correct.
- */
-
- GGL_CONTEXT(c, con);
-
- // we do only quads for now (it's used for thick lines)
- if ((count>4) || (count<2)) return;
-
- // take scissor into account
- const int xmin = c->state.scissor.left;
- const int xmax = c->state.scissor.right;
- if (xmin >= xmax) return;
-
- // generate edges from the vertices
- int32_t ymin = TRI_FROM_INT(c->state.scissor.top);
- int32_t ymax = TRI_FROM_INT(c->state.scissor.bottom);
- if (ymin >= ymax) return;
-
- AAEdge edges[4];
- int num_edges = 0;
- GGLcoord const * p = pts;
- for (int i=0 ; i<count-1 ; i++, p+=2) {
- aa_edge_setup(edges, &num_edges, p, p+2, ymin, ymax);
- }
- aa_edge_setup(edges, &num_edges, p, pts, ymin, ymax );
- if (ggl_unlikely(num_edges<2))
- return;
-
- // sort the edge list top to bottom, left to right.
- qsort(edges, num_edges, sizeof(AAEdge), (compar_t)compare_edges);
-
- int16_t* const covPtr = c->state.buffers.coverage;
- memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
-
- // now, sweep all edges in order
- // start with the 2 first edges. We know that they share their top
- // vertex, by construction.
- int i = 2;
- AAEdge* left = &edges[0];
- AAEdge* right = &edges[1];
- int32_t yt = left->y_top;
- GGLfixed l = left->x;
- GGLfixed r = right->x;
- int retire = 0;
- int16_t* coverage;
-
- // at this point we can initialize the rasterizer
- c->init_y(c, yt>>TRI_FRACTION_BITS);
- c->iterators.xl = xmax;
- c->iterators.xr = xmin;
-
- do {
- int32_t y = min(min(left->y_bot, right->y_bot), TRI_FLOOR(yt + TRI_ONE));
- const int32_t shift = TRI_FRACTION_BITS + TRI_ITERATORS_BITS - FIXED_BITS;
- const int cf_shift = (1 + TRI_FRACTION_BITS*2 + TRI_ITERATORS_BITS - 15);
-
- // compute xmin and xmax for the left edge
- GGLfixed l_min = gglMulAddx(left->x_incr, y - left->y_top, left->x, shift);
- GGLfixed l_max = l;
- l = l_min;
- if (l_min > l_max)
- swap(l_min, l_max);
-
- // compute xmin and xmax for the right edge
- GGLfixed r_min = gglMulAddx(right->x_incr, y - right->y_top, right->x, shift);
- GGLfixed r_max = r;
- r = r_min;
- if (r_min > r_max)
- swap(r_min, r_max);
-
- // make sure we're not touching coverage values outside of the
- // framebuffer
- l_min &= ~(l_min>>31);
- r_min &= ~(r_min>>31);
- l_max &= ~(l_max>>31);
- r_max &= ~(r_max>>31);
- if (gglFixedToIntFloor(l_min) >= xmax) l_min = gglIntToFixed(xmax)-1;
- if (gglFixedToIntFloor(r_min) >= xmax) r_min = gglIntToFixed(xmax)-1;
- if (gglFixedToIntCeil(l_max) >= xmax) l_max = gglIntToFixed(xmax)-1;
- if (gglFixedToIntCeil(r_max) >= xmax) r_max = gglIntToFixed(xmax)-1;
-
- // compute the integer versions of the above
- const GGLfixed l_min_i = gglFloorx(l_min);
- const GGLfixed l_max_i = gglCeilx (l_max);
- const GGLfixed r_min_i = gglFloorx(r_min);
- const GGLfixed r_max_i = gglCeilx (r_max);
-
- // clip horizontally using the scissor
- const int xml = max(xmin, gglFixedToIntFloor(l_min_i));
- const int xmr = min(xmax, gglFixedToIntFloor(r_max_i));
-
- // if we just stepped to a new scanline, render the previous one.
- // and clear the coverage buffer
- if (retire) {
- if (c->iterators.xl < c->iterators.xr)
- c->scanline(c);
- c->step_y(c);
- memset(covPtr+xmin, 0, (xmax-xmin)*sizeof(*covPtr));
- c->iterators.xl = xml;
- c->iterators.xr = xmr;
- } else {
- // update the horizontal range of this scanline
- c->iterators.xl = min(c->iterators.xl, xml);
- c->iterators.xr = max(c->iterators.xr, xmr);
- }
-
- coverage = covPtr + gglFixedToIntFloor(l_min_i);
- if (l_min_i == gglFloorx(l_max)) {
-
- /*
- * fully traverse this pixel vertically
- * l_max
- * +-----/--+ yt
- * | / |
- * | / |
- * | / |
- * +-/------+ y
- * l_min (l_min_i + TRI_ONE)
- */
-
- GGLfixed dx = l_max - l_min;
- int32_t dy = y - yt;
- int cf = gglMulx((dx >> 1) + (l_min_i + FIXED_ONE - l_max), dy,
- FIXED_BITS + TRI_FRACTION_BITS - 15);
- ADD_COVERAGE(coverage, cf);
- // all pixels on the right have cf = 1.0
- } else {
- /*
- * spans several pixels in one scanline
- * l_max
- * +--------+--/-----+ yt
- * | |/ |
- * | /| |
- * | / | |
- * +---/----+--------+ y
- * l_min (l_min_i + TRI_ONE)
- */
-
- // handle the first pixel separately...
- const int32_t y_incr = left->y_incr;
- int32_t dx = TRI_FROM_FIXED(l_min_i - l_min) + TRI_ONE;
- int32_t cf = (dx * dx * y_incr) >> cf_shift;
- ADD_COVERAGE(coverage, cf);
-
- // following pixels get covered by y_incr, but we need
- // to fix-up the cf to account for previous partial pixel
- dx = TRI_FROM_FIXED(l_min - l_min_i);
- cf -= (dx * dx * y_incr) >> cf_shift;
- for (int x = l_min_i+FIXED_ONE ; x < l_max_i-FIXED_ONE ; x += FIXED_ONE) {
- cf += y_incr >> (TRI_ITERATORS_BITS-15);
- ADD_COVERAGE(coverage, cf);
- }
-
- // and the last pixel
- dx = TRI_FROM_FIXED(l_max - l_max_i) - TRI_ONE;
- cf += (dx * dx * y_incr) >> cf_shift;
- ADD_COVERAGE(coverage, cf);
- }
-
- // now, fill up all fully covered pixels
- coverage = covPtr + gglFixedToIntFloor(l_max_i);
- int cf = ((y - yt) << (15 - TRI_FRACTION_BITS));
- if (ggl_likely(cf >= 0x8000)) {
- SET_COVERAGE(coverage, 0x7FFF, ((r_max - l_max_i)>>FIXED_BITS)+1);
- } else {
- for (int x=l_max_i ; x<r_max ; x+=FIXED_ONE) {
- ADD_COVERAGE(coverage, cf);
- }
- }
-
- // subtract the coverage of the right edge
- coverage = covPtr + gglFixedToIntFloor(r_min_i);
- if (r_min_i == gglFloorx(r_max)) {
- GGLfixed dx = r_max - r_min;
- int32_t dy = y - yt;
- int cf = gglMulx((dx >> 1) + (r_min_i + FIXED_ONE - r_max), dy,
- FIXED_BITS + TRI_FRACTION_BITS - 15);
- SUB_COVERAGE(coverage, cf);
- // all pixels on the right have cf = 1.0
- } else {
- // handle the first pixel separately...
- const int32_t y_incr = right->y_incr;
- int32_t dx = TRI_FROM_FIXED(r_min_i - r_min) + TRI_ONE;
- int32_t cf = (dx * dx * y_incr) >> cf_shift;
- SUB_COVERAGE(coverage, cf);
-
- // following pixels get covered by y_incr, but we need
- // to fix-up the cf to account for previous partial pixel
- dx = TRI_FROM_FIXED(r_min - r_min_i);
- cf -= (dx * dx * y_incr) >> cf_shift;
- for (int x = r_min_i+FIXED_ONE ; x < r_max_i-FIXED_ONE ; x += FIXED_ONE) {
- cf += y_incr >> (TRI_ITERATORS_BITS-15);
- SUB_COVERAGE(coverage, cf);
- }
-
- // and the last pixel
- dx = TRI_FROM_FIXED(r_max - r_max_i) - TRI_ONE;
- cf += (dx * dx * y_incr) >> cf_shift;
- SUB_COVERAGE(coverage, cf);
- }
-
- // did we reach the end of an edge? if so, get a new one.
- if (y == left->y_bot || y == right->y_bot) {
- // bail out if we're done
- if (i>=num_edges)
- break;
- if (y == left->y_bot)
- left = &edges[i++];
- if (y == right->y_bot)
- right = &edges[i++];
- }
-
- // next scanline
- yt = y;
-
- // did we just finish a scanline?
- retire = (y << (32-TRI_FRACTION_BITS)) == 0;
- } while (true);
-
- // render the last scanline
- if (c->iterators.xl < c->iterators.xr)
- c->scanline(c);
-}
-
-}; // namespace android