summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorHui Qi Tay <[email protected]>2010-08-04 17:13:39 +0100
committerKeith Whitwell <[email protected]>2010-08-27 13:08:54 +0100
commitb91553355f848f2174d53429699b116734781ad7 (patch)
tree9974e195a3e836b31313bbaae487a8c698e36fcd /src
parent5286dd701640976ffc328e8e85fb3830746851a1 (diff)
llvmpipe: native line rasterization with correct pixel rasterization
Line rasterization that follows diamond exit rule. Can still optimize logic for start/endpoints.
Diffstat (limited to 'src')
-rw-r--r--src/gallium/drivers/llvmpipe/lp_setup_line.c242
1 files changed, 213 insertions, 29 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c
index 930207ae33a..15662031178 100644
--- a/src/gallium/drivers/llvmpipe/lp_setup_line.c
+++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c
@@ -243,6 +243,11 @@ print_line(struct lp_setup_context *setup,
}
+static INLINE boolean sign(float x){
+ return x >= 0;
+}
+
+
static void
lp_setup_line( struct lp_setup_context *setup,
const float (*v1)[4],
@@ -251,7 +256,7 @@ lp_setup_line( struct lp_setup_context *setup,
struct lp_scene *scene = lp_setup_get_current_scene(setup);
struct lp_rast_triangle *line;
float oneoverarea;
- float half_width = setup->line_width / 2;
+ float width = MAX2(1.0, setup->line_width);
int minx, maxx, miny, maxy;
int ix0, ix1, iy0, iy1;
unsigned tri_bytes;
@@ -260,7 +265,25 @@ lp_setup_line( struct lp_setup_context *setup,
int i;
int nr_planes = 4;
boolean opaque;
-
+
+ /* linewidth should be interpreted as integer */
+ int fixed_width = subpixel_snap(round(width));
+
+ float xdiamond_offset=0;
+ float ydiamond_offset=0;
+ float xdiamond_offset_end=0;
+ float ydiamond_offset_end=0;
+
+ float x1diff;
+ float y1diff;
+ float x2diff;
+ float y2diff;
+
+ boolean draw_start;
+ boolean draw_end;
+ boolean will_draw_start;
+ boolean will_draw_end;
+
if (0)
print_line(setup, v1, v2);
@@ -278,21 +301,76 @@ lp_setup_line( struct lp_setup_context *setup,
if (!line)
return;
-#ifndef DEBUG
+#ifdef DEBUG
line->v[0][0] = v1[0][0];
line->v[1][0] = v2[0][0];
line->v[0][1] = v1[0][1];
line->v[1][1] = v2[0][1];
#endif
- /* pre-calculation(based on given vertices) to determine if line is
- * more horizontal or more vertical
- */
line->dx = v1[0][0] - v2[0][0];
line->dy = v1[0][1] - v2[0][1];
-
- /* x-major line */
+
+/* X-MAJOR LINE */
if (fabsf(line->dx) >= fabsf(line->dy)) {
+
+ x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5;
+ y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5;
+ x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5;
+ y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5;
+
+ if (y2diff==-0.5 && line->dy<0){
+ y2diff = 0.5;
+ }
+
+ /*
+ * Diamond exit rule test for starting point
+ */
+ if (fabsf(x1diff) + fabsf(y1diff) < 0.5) {
+ draw_start = TRUE;
+ }
+ else if (sign(x1diff) == sign(-line->dx)) {
+ draw_start = FALSE;
+ }
+ else if (sign(-y1diff) != sign(line->dy)) {
+ draw_start = TRUE;
+ }
+ else {
+ /* do intersection test */
+ float yintersect = v1[0][1] + x1diff*((float)line->dy/(float)line->dx);
+ if (yintersect < ceil(v1[0][1]) && yintersect > floor(v1[0][1])){
+ draw_start = TRUE;
+ }
+ else draw_start = FALSE;
+ }
+
+
+ /*
+ * Diamond exit rule test for ending point
+ */
+ if (fabsf(x2diff) + fabsf(y2diff) < 0.5) {
+ draw_end = FALSE;
+ }
+ else if (sign(x2diff) != sign(-line->dx)) {
+ draw_end = FALSE;
+ }
+ else if (sign(-y2diff) == sign(line->dy)) {
+ draw_end = TRUE;
+ }
+ else {
+ /* do intersection test */
+ float yintersect = v2[0][1] + x2diff*((float)line->dy/(float)line->dx);
+ if (yintersect < ceil(v2[0][1]) && yintersect > floor(v2[0][1])){
+ draw_end = TRUE;
+ }
+ else draw_end = FALSE;
+ }
+
+ /* Are we already drawing start/end?
+ */
+ will_draw_start = sign(-x1diff) != sign(line->dx);
+ will_draw_end = (sign(x2diff) == sign(-line->dx)) || x2diff==0;
+
if (line->dx < 0) {
/* if v2 is to the right of v1, swap pointers */
const float (*temp)[4] = v1;
@@ -300,21 +378,102 @@ lp_setup_line( struct lp_setup_context *setup,
v2 = temp;
line->dx = -line->dx;
line->dy = -line->dy;
+ /* Otherwise shift planes appropriately */
+ if (will_draw_start != draw_start) {
+ xdiamond_offset_end = - x1diff - 0.5;
+ ydiamond_offset_end = xdiamond_offset_end*(float)line->dy/(float)line->dx;
+
+ }
+ if (will_draw_end != draw_end) {
+ xdiamond_offset = - x2diff - 0.5;
+ ydiamond_offset = xdiamond_offset*(float)line->dy/(float)line->dx;
+ }
+
}
-
+ else{
+ /* Otherwise shift planes appropriately */
+ if (will_draw_start != draw_start) {
+ xdiamond_offset = - x1diff + 0.5;
+ ydiamond_offset = xdiamond_offset*(float)line->dy/(float)line->dx;
+ }
+ if (will_draw_end != draw_end) {
+ xdiamond_offset_end = - x2diff + 0.5;
+ ydiamond_offset_end = xdiamond_offset_end*(float)line->dy/(float)line->dx;
+ }
+ }
+
/* x/y positions in fixed point */
- x[0] = subpixel_snap(v1[0][0] - setup->pixel_offset);
- x[1] = subpixel_snap(v2[0][0] - setup->pixel_offset);
- x[2] = subpixel_snap(v2[0][0] - setup->pixel_offset);
- x[3] = subpixel_snap(v1[0][0] - setup->pixel_offset);
+ x[0] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset);
+ x[1] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset);
+ x[2] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset);
+ x[3] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset);
+
+ y[0] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset) - fixed_width/2;
+ y[1] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset) - fixed_width/2;
+ y[2] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset) + fixed_width/2;
+ y[3] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset) + fixed_width/2;
- y[0] = subpixel_snap(v1[0][1] - half_width - setup->pixel_offset);
- y[1] = subpixel_snap(v2[0][1] - half_width - setup->pixel_offset);
- y[2] = subpixel_snap(v2[0][1] + half_width - setup->pixel_offset);
- y[3] = subpixel_snap(v1[0][1] + half_width - setup->pixel_offset);
}
+
+
else{
- /* y-major line */
+/* Y-MAJOR LINE */
+ x1diff = v1[0][0] - (float) floor(v1[0][0]) - 0.5;
+ y1diff = v1[0][1] - (float) floor(v1[0][1]) - 0.5;
+ x2diff = v2[0][0] - (float) floor(v2[0][0]) - 0.5;
+ y2diff = v2[0][1] - (float) floor(v2[0][1]) - 0.5;
+
+ if (x2diff==-0.5 && line->dx<0){
+ x2diff = 0.5;
+ }
+
+/*
+ * Diamond exit rule test for starting point
+ */
+ if (fabsf(x1diff) + fabsf(y1diff) < 0.5) {
+ draw_start = TRUE;
+ }
+ else if (sign(-y1diff) == sign(line->dy)) {
+ draw_start = FALSE;
+ }
+ else if (sign(x1diff) != sign(-line->dx)) {
+ draw_start = TRUE;
+ }
+ else {
+ /* do intersection test */
+ float xintersect = v1[0][0] + y1diff*((float)line->dx/(float)line->dy);
+ if (xintersect < ceil(v1[0][0]) && xintersect > floor(v1[0][0])){
+ draw_start = TRUE;
+ }
+ else draw_start = FALSE;
+ }
+
+ /*
+ * Diamond exit rule test for ending point
+ */
+ if (fabsf(x2diff) + fabsf(y2diff) < 0.5) {
+ draw_end = FALSE;
+ }
+ else if (sign(-y2diff) != sign(line->dy) ) {
+ draw_end = FALSE;
+ }
+ else if (sign(x2diff) == sign(-line->dx) ) {
+ draw_end = TRUE;
+ }
+ else {
+ /* do intersection test */
+ float xintersect = v2[0][0] + y2diff*((float)line->dx/(float)line->dy);
+ if (xintersect < ceil(v2[0][0]) && xintersect > floor(v2[0][0])){
+ draw_end = TRUE;
+ }
+ else draw_end = FALSE;
+ }
+
+ /* Are we already drawing start/end?
+ */
+ will_draw_start = sign(y1diff) == sign(line->dy);
+ will_draw_end = (sign(-y2diff) == sign(line->dy)) || y2diff==0;
+
if (line->dy > 0) {
/* if v2 is on top of v1, swap pointers */
const float (*temp)[4] = v1;
@@ -322,19 +481,44 @@ lp_setup_line( struct lp_setup_context *setup,
v2 = temp;
line->dx = -line->dx;
line->dy = -line->dy;
+
+ /* Otherwise shift planes appropriately */
+ if (will_draw_start != draw_start) {
+ ydiamond_offset_end = - y1diff + 0.5;
+ xdiamond_offset_end = ydiamond_offset_end*(float)line->dx/(float)line->dy;
+ }
+ if (will_draw_end != draw_end) {
+ ydiamond_offset = - y2diff + 0.5;
+ xdiamond_offset = ydiamond_offset*(float)line->dx/(float)line->dy;
+ }
+ }
+
+ else{
+ /* Otherwise shift planes appropriately */
+ if (will_draw_start != draw_start) {
+ ydiamond_offset = - y1diff - 0.5;
+ xdiamond_offset = ydiamond_offset*(float)line->dx/(float)line->dy;
+
+ }
+ if (will_draw_end != draw_end) {
+ ydiamond_offset_end = - y2diff - 0.5;
+ xdiamond_offset_end = ydiamond_offset_end*(float)line->dx/(float)line->dy;
+ }
}
- x[0] = subpixel_snap(v1[0][0] - half_width - setup->pixel_offset);
- x[1] = subpixel_snap(v2[0][0] - half_width - setup->pixel_offset);
- x[2] = subpixel_snap(v2[0][0] + half_width - setup->pixel_offset);
- x[3] = subpixel_snap(v1[0][0] + half_width - setup->pixel_offset);
+ /* x/y positions in fixed point */
+ x[0] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset) - fixed_width/2;
+ x[1] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset) - fixed_width/2;
+ x[2] = subpixel_snap(v2[0][0] + xdiamond_offset_end - setup->pixel_offset) + fixed_width/2;
+ x[3] = subpixel_snap(v1[0][0] + xdiamond_offset - setup->pixel_offset) + fixed_width/2;
- y[0] = subpixel_snap(v1[0][1] - setup->pixel_offset);
- y[1] = subpixel_snap(v2[0][1] - setup->pixel_offset);
- y[2] = subpixel_snap(v2[0][1] - setup->pixel_offset);
- y[3] = subpixel_snap(v1[0][1] - setup->pixel_offset);
+ y[0] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset);
+ y[1] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset);
+ y[2] = subpixel_snap(v2[0][1] + ydiamond_offset_end - setup->pixel_offset);
+ y[3] = subpixel_snap(v1[0][1] + ydiamond_offset - setup->pixel_offset);
}
+
/* calculate the deltas */
line->plane[0].dcdy = x[0] - x[1];
line->plane[1].dcdy = x[1] - x[2];
@@ -361,8 +545,8 @@ lp_setup_line( struct lp_setup_context *setup,
minx = (MIN4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER;
maxx = (MAX4(x[0], x[1], x[2], x[3]) + (FIXED_ONE-1)) >> FIXED_ORDER;
- miny = (MIN4(y[0], y[1], y[3], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
- maxy = (MAX4(y[0], y[1], y[3], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
+ miny = (MIN4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
+ maxy = (MAX4(y[0], y[1], y[2], y[3]) + (FIXED_ONE-1) + adj) >> FIXED_ORDER;
}
if (setup->scissor_test) {
@@ -526,7 +710,7 @@ lp_setup_line( struct lp_setup_context *setup,
/*
- * All fields of 'tri' are now set. The remaining code here is
+ * All fields of 'line' are now set. The remaining code here is
* concerned with binning.
*/