From 329a8479b69a800b5fc6485767fb676c3eae26db Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 21 Jan 2008 14:08:20 -0700 Subject: [PATCH] gallium: new 'draw' stage for line stipple Stippled lines are converted into a series of shorter line segments --- src/mesa/pipe/draw/draw_context.c | 2 + src/mesa/pipe/draw/draw_private.h | 2 + src/mesa/pipe/draw/draw_stipple.c | 242 +++++++++++++++++++++++++++++ src/mesa/pipe/draw/draw_validate.c | 5 + src/mesa/sources | 1 + 5 files changed, 252 insertions(+) create mode 100644 src/mesa/pipe/draw/draw_stipple.c diff --git a/src/mesa/pipe/draw/draw_context.c b/src/mesa/pipe/draw/draw_context.c index fd43d690f65..e08873c5e14 100644 --- a/src/mesa/pipe/draw/draw_context.c +++ b/src/mesa/pipe/draw/draw_context.c @@ -49,6 +49,7 @@ struct draw_context *draw_create( void ) /* create pipeline stages */ draw->pipeline.wide = draw_wide_stage( draw ); + draw->pipeline.stipple = draw_stipple_stage( draw ); draw->pipeline.unfilled = draw_unfilled_stage( draw ); draw->pipeline.twoside = draw_twoside_stage( draw ); draw->pipeline.offset = draw_offset_stage( draw ); @@ -93,6 +94,7 @@ struct draw_context *draw_create( void ) void draw_destroy( struct draw_context *draw ) { draw->pipeline.wide->destroy( draw->pipeline.wide ); + draw->pipeline.stipple->destroy( draw->pipeline.stipple ); draw->pipeline.unfilled->destroy( draw->pipeline.unfilled ); draw->pipeline.twoside->destroy( draw->pipeline.twoside ); draw->pipeline.offset->destroy( draw->pipeline.offset ); diff --git a/src/mesa/pipe/draw/draw_private.h b/src/mesa/pipe/draw/draw_private.h index d8832449eab..20503fe158a 100644 --- a/src/mesa/pipe/draw/draw_private.h +++ b/src/mesa/pipe/draw/draw_private.h @@ -158,6 +158,7 @@ struct draw_context struct draw_stage *twoside; struct draw_stage *offset; struct draw_stage *unfilled; + struct draw_stage *stipple; struct draw_stage *wide; struct draw_stage *rasterize; } pipeline; @@ -248,6 +249,7 @@ extern struct draw_stage *draw_offset_stage( struct draw_context *context ); extern struct draw_stage *draw_clip_stage( struct draw_context *context ); extern struct draw_stage *draw_flatshade_stage( struct draw_context *context ); extern struct draw_stage *draw_cull_stage( struct draw_context *context ); +extern struct draw_stage *draw_stipple_stage( struct draw_context *context ); extern struct draw_stage *draw_wide_stage( struct draw_context *context ); extern struct draw_stage *draw_validate_stage( struct draw_context *context ); diff --git a/src/mesa/pipe/draw/draw_stipple.c b/src/mesa/pipe/draw/draw_stipple.c new file mode 100644 index 00000000000..6d5226b1b82 --- /dev/null +++ b/src/mesa/pipe/draw/draw_stipple.c @@ -0,0 +1,242 @@ +/************************************************************************** + * + * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +/* Authors: Keith Whitwell + */ + +/* Implement line stipple by cutting lines up into smaller lines. + * There are hundreds of ways to implement line stipple, this is one + * choice that should work in all situations, requires no state + * manipulations, but with a penalty in terms of large amounts of + * generated geometry. + */ + + +#include "pipe/p_util.h" +#include "pipe/p_defines.h" +#include "pipe/p_shader_tokens.h" +#include "draw_private.h" + + +/** Subclass of draw_stage */ +struct stipple_stage { + struct draw_stage stage; + float counter; + uint pattern; + uint factor; +}; + + +static INLINE struct stipple_stage * +stipple_stage(struct draw_stage *stage) +{ + return (struct stipple_stage *) stage; +} + + +/** + * Compute interpolated vertex attributes for 'dst' at position 't' + * between 'v0' and 'v1'. + */ +static void +screen_interp( struct draw_context *draw, + struct vertex_header *dst, + float t, + const struct vertex_header *v0, + const struct vertex_header *v1 ) +{ + uint attr; + for (attr = 0; attr < draw->vertex_info.num_attribs; attr++) { + switch (draw->vertex_info.interp_mode[attr]) { + case INTERP_NONE: + case INTERP_CONSTANT: + COPY_4FV(dst->data[attr], v0->data[attr]); + break; + case INTERP_PERSPECTIVE: + /* Fall-through */ + /* XXX special-case perspective? */ + case INTERP_LINEAR: + { + const float *val0 = v0->data[attr]; + const float *val1 = v1->data[attr]; + float *newv = dst->data[attr]; + uint i; + for (i = 0; i < 4; i++) { + newv[i] = val0[i] + t * (val1[i] - val0[i]); + } + } + break; + default: + abort(); + } + } +} + + +static void +emit_segment(struct draw_stage *stage, struct prim_header *header, + float t0, float t1) +{ + struct vertex_header *v0new = dup_vert(stage, header->v[0], 0); + struct vertex_header *v1new = dup_vert(stage, header->v[1], 1); + struct prim_header newprim = *header; + + if (t0 > 0.0) { + screen_interp( stage->draw, v0new, t0, header->v[0], header->v[1] ); + newprim.v[0] = v0new; + } + + if (t1 < 1.0) { + screen_interp( stage->draw, v1new, t1, header->v[0], header->v[1] ); + newprim.v[1] = v1new; + } + + stage->next->line( stage->next, &newprim ); +} + + +static INLINE unsigned +stipple_test(int counter, ushort pattern, int factor) +{ + int b = (counter / factor) & 0xf; + return (1 << b) & pattern; +} + + +static void +stipple_line(struct draw_stage *stage, struct prim_header *header) +{ + struct stipple_stage *stipple = stipple_stage(stage); + struct vertex_header *v0 = header->v[0]; + struct vertex_header *v1 = header->v[1]; + const float *pos0 = v0->data[0]; + const float *pos1 = v1->data[0]; + float start = 0; + int state = 0; + + float x0 = pos0[0]; + float x1 = pos1[0]; + float y0 = pos0[1]; + float y1 = pos1[1]; + + float dx = x0 > x1 ? x0 - x1 : x1 - x0; + float dy = y0 > y1 ? y0 - y1 : y1 - y0; + + float length = MAX2(dx, dy); + int i; + + /* XXX ToDo: intead of iterating pixel-by-pixel, use a look-up table. + */ + for (i = 0; i < length; i++) { + int result = stipple_test( stipple->counter+i, + stipple->pattern, stipple->factor ); + if (result != state) { + /* changing from "off" to "on" or vice versa */ + if (state) { + if (start != i) { + /* finishing an "on" segment */ + emit_segment( stage, header, start / length, i / length ); + } + } + else { + /* starting an "on" segment */ + start = i; + } + state = result; + } + } + + if (state && start < length) + emit_segment( stage, header, start / length, 1.0 ); + + stipple->counter += length; +} + + +static void +reset_stipple_counter(struct draw_stage *stage) +{ + struct stipple_stage *stipple = stipple_stage(stage); + stipple->counter = 0; + stage->next->reset_stipple_counter( stage->next ); +} + + +static void +stipple_begin(struct draw_stage *stage) +{ + struct stipple_stage *stipple = stipple_stage(stage); + struct draw_context *draw = stage->draw; + + stipple->pattern = draw->rasterizer->line_stipple_pattern; + stipple->factor = draw->rasterizer->line_stipple_factor + 1; + + stage->next->begin( stage->next ); +} + + +static void +stipple_end(struct draw_stage *stage) +{ + stage->next->end( stage->next ); +} + + +static void +passthrough_point(struct draw_stage *stage, struct prim_header *header) +{ + stage->next->point( stage->next, header ); +} + + +static void +passthrough_tri(struct draw_stage *stage, struct prim_header *header) +{ + stage->next->tri(stage->next, header); +} + + +/** + * Create line stippler stage + */ +struct draw_stage *draw_stipple_stage( struct draw_context *draw ) +{ + struct stipple_stage *stipple = CALLOC_STRUCT(stipple_stage); + + draw_alloc_tmps( &stipple->stage, 2 ); + + stipple->stage.draw = draw; + stipple->stage.next = NULL; + stipple->stage.begin = stipple_begin; + stipple->stage.point = passthrough_point; + stipple->stage.line = stipple_line; + stipple->stage.tri = passthrough_tri; + stipple->stage.reset_stipple_counter = reset_stipple_counter; + stipple->stage.end = stipple_end; + + return &stipple->stage; +} diff --git a/src/mesa/pipe/draw/draw_validate.c b/src/mesa/pipe/draw/draw_validate.c index 58cf340281e..df06e0426c6 100644 --- a/src/mesa/pipe/draw/draw_validate.c +++ b/src/mesa/pipe/draw/draw_validate.c @@ -58,6 +58,11 @@ static void validate_begin( struct draw_stage *stage ) next = draw->pipeline.wide; } + if (draw->rasterizer->line_stipple_enable) { + draw->pipeline.stipple->next = next; + next = draw->pipeline.stipple; + } + if (draw->rasterizer->fill_cw != PIPE_POLYGON_MODE_FILL || draw->rasterizer->fill_ccw != PIPE_POLYGON_MODE_FILL) { draw->pipeline.unfilled->next = next; diff --git a/src/mesa/sources b/src/mesa/sources index d8760ba134e..97ef7e1936d 100644 --- a/src/mesa/sources +++ b/src/mesa/sources @@ -165,6 +165,7 @@ DRAW_SOURCES = \ pipe/draw/draw_flatshade.c \ pipe/draw/draw_offset.c \ pipe/draw/draw_prim.c \ + pipe/draw/draw_stipple.c \ pipe/draw/draw_twoside.c \ pipe/draw/draw_unfilled.c \ pipe/draw/draw_validate.c \ -- 2.30.2