diff options
author | Keith Whitwell <keith@tungstengraphics.com> | 2007-09-25 13:20:53 +0100 |
---|---|---|
committer | Keith Whitwell <keith@tungstengraphics.com> | 2007-09-25 13:23:20 +0100 |
commit | a37e0daeb97bb36ba10038b12a909e22e08b52c4 (patch) | |
tree | 6c8a10ceb9a7764a63db627f0602f552709631d2 /src/mesa/pipe/softpipe | |
parent | 45b37dc078130b64e110d1a965960c60c56f0e60 (diff) |
First attempt at building vertex buffers post-clip.
Build a buffer of contigous vertices and indices at the backend of our
software transformation/clipping path. This will become the mechanism
for emitting buffers of vertices to rasterization hardware.
This is similar to but not the same as the post-transform vertex cache.
In particular, these vertices are subject to clipping, culling, poly offset,
etc. The vertices emitted will all be used by hardware.
TODOs include the actual transformation to hardware vertex formats, moving
this out of softpipe to somewhere more useful and allowing >1 primitive to
share the generated VB.
Diffstat (limited to 'src/mesa/pipe/softpipe')
-rw-r--r-- | src/mesa/pipe/softpipe/Makefile | 1 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_context.c | 14 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_context.h | 2 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_prim_setup.c | 96 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_prim_setup.h | 34 | ||||
-rw-r--r-- | src/mesa/pipe/softpipe/sp_prim_vbuf.c | 305 |
6 files changed, 444 insertions, 8 deletions
diff --git a/src/mesa/pipe/softpipe/Makefile b/src/mesa/pipe/softpipe/Makefile index 0335f56b99..63eb6b5761 100644 --- a/src/mesa/pipe/softpipe/Makefile +++ b/src/mesa/pipe/softpipe/Makefile @@ -10,6 +10,7 @@ DRIVER_SOURCES = \ sp_context.c \ sp_draw_arrays.c \ sp_prim_setup.c \ + sp_prim_vbuf.c \ sp_quad.c \ sp_quad_alpha_test.c \ sp_quad_blend.c \ diff --git a/src/mesa/pipe/softpipe/sp_context.c b/src/mesa/pipe/softpipe/sp_context.c index a6ab45314c..e415966dae 100644 --- a/src/mesa/pipe/softpipe/sp_context.c +++ b/src/mesa/pipe/softpipe/sp_context.c @@ -334,7 +334,19 @@ struct pipe_context *softpipe_create( struct pipe_winsys *pipe_winsys, */ softpipe->draw = draw_create(); assert(softpipe->draw); - draw_set_rasterize_stage(softpipe->draw, sp_draw_render_stage(softpipe)); + softpipe->setup = sp_draw_render_stage(softpipe); + + if (getenv("SP_VBUF")) { + softpipe->vbuf = sp_draw_vbuf_stage(softpipe->draw, + &softpipe->pipe, + sp_vbuf_setup_draw); + + draw_set_rasterize_stage(softpipe->draw, softpipe->vbuf); + } + else { + draw_set_rasterize_stage(softpipe->draw, softpipe->setup); + } + sp_init_region_functions(softpipe); sp_init_surface_functions(softpipe); diff --git a/src/mesa/pipe/softpipe/sp_context.h b/src/mesa/pipe/softpipe/sp_context.h index 7b1518cfac..c0a681f3d6 100644 --- a/src/mesa/pipe/softpipe/sp_context.h +++ b/src/mesa/pipe/softpipe/sp_context.h @@ -146,6 +146,8 @@ struct softpipe_context { /** The primitive drawing context */ struct draw_context *draw; + struct draw_stage *setup; + struct draw_stage *vbuf; struct pipe_surface *cbuf; /**< current color buffer (one of cbufs) */ }; diff --git a/src/mesa/pipe/softpipe/sp_prim_setup.c b/src/mesa/pipe/softpipe/sp_prim_setup.c index 6d63cc9412..2e27d00acf 100644 --- a/src/mesa/pipe/softpipe/sp_prim_setup.c +++ b/src/mesa/pipe/softpipe/sp_prim_setup.c @@ -41,7 +41,7 @@ #include "pipe/draw/draw_vertex.h" #include "pipe/p_util.h" - +#define DEBUG_VERTS 0 /** * Triangle edge info @@ -241,15 +241,15 @@ static void flush_spans( struct setup_stage *setup ) setup->span.right[1] = 0; } -#if 0 +#if DEBUG_VERTS static void print_vertex(const struct setup_stage *setup, const struct vertex_header *v) { int i; - printf("Vertex:\n"); + fprintf(stderr, "Vertex: (%p)\n", v); for (i = 0; i < setup->quad.nr_attrs; i++) { - printf(" %d: %f %f %f\n", i, - v->data[i][0], v->data[i][1], v->data[i][2]); + fprintf(stderr, " %d: %f %f %f %f\n", i, + v->data[i][0], v->data[i][1], v->data[i][2], v->data[i][3]); } } #endif @@ -261,8 +261,8 @@ static boolean setup_sort_vertices( struct setup_stage *setup, const struct vertex_header *v1 = prim->v[1]; const struct vertex_header *v2 = prim->v[2]; -#if 0 - printf("Triangle:\n"); +#if DEBUG_VERTS + fprintf(stderr, "Triangle:\n"); print_vertex(setup, v0); print_vertex(setup, v1); print_vertex(setup, v2); @@ -1096,3 +1096,85 @@ struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe ) return &setup->stage; } + + +/* Recalculate det. This is only used in the test harness below: + */ +static void calc_det( struct prim_header *header ) +{ + /* Window coords: */ + const float *v0 = header->v[0]->data[0]; + const float *v1 = header->v[1]->data[0]; + const float *v2 = header->v[2]->data[0]; + + /* edge vectors e = v0 - v2, f = v1 - v2 */ + const float ex = v0[0] - v2[0]; + const float ey = v0[1] - v2[1]; + const float fx = v1[0] - v2[0]; + const float fy = v1[1] - v2[1]; + + /* det = cross(e,f).z */ + header->det = ex * fy - ey * fx; +} + + + +/* Test harness - feed vertex buffer back into prim pipeline. + * + * The big issue at this point is that reset_stipple doesn't make it + * through the interface. Probably need to split primitives at reset + * stipple, perhaps using the ~0 index marker. + */ +void sp_vbuf_setup_draw( struct pipe_context *pipe, + unsigned primitive, + const ushort *elements, + unsigned nr_elements, + const void *vertex_buffer, + unsigned nr_vertices ) +{ + struct softpipe_context *softpipe = softpipe_context( pipe ); + struct setup_stage *setup = setup_stage( softpipe->setup ); + struct prim_header prim; + unsigned vertex_size = setup->stage.draw->vertex_info.size * sizeof(float); + int i, j; + + prim.det = 0; + prim.reset_line_stipple = 0; + prim.edgeflags = 0; + prim.pad = 0; + + setup->stage.begin( &setup->stage ); + + switch (primitive) { + case PIPE_PRIM_TRIANGLES: + for (i = 0; i < nr_elements; i += 3) { + for (j = 0; j < 3; j++) + prim.v[j] = (struct vertex_header *)((char *)vertex_buffer + + elements[i+j] * vertex_size); + + calc_det(&prim); + setup->stage.tri( &setup->stage, &prim ); + } + break; + + case PIPE_PRIM_LINES: + for (i = 0; i < nr_elements; i += 2) { + for (j = 0; j < 2; j++) + prim.v[j] = (struct vertex_header *)((char *)vertex_buffer + + elements[i+j] * vertex_size); + + setup->stage.line( &setup->stage, &prim ); + } + break; + + case PIPE_PRIM_POINTS: + for (i = 0; i < nr_elements; i += 2) { + prim.v[i] = (struct vertex_header *)((char *)vertex_buffer + + elements[i] * vertex_size); + setup->stage.point( &setup->stage, &prim ); + } + break; + } + + setup->stage.end( &setup->stage ); +} diff --git a/src/mesa/pipe/softpipe/sp_prim_setup.h b/src/mesa/pipe/softpipe/sp_prim_setup.h index dece42fe45..598394f73e 100644 --- a/src/mesa/pipe/softpipe/sp_prim_setup.h +++ b/src/mesa/pipe/softpipe/sp_prim_setup.h @@ -44,5 +44,39 @@ struct softpipe_context; extern struct draw_stage *sp_draw_render_stage( struct softpipe_context *softpipe ); +/* A special stage to gather the stream of triangles, lines, points + * together and reconstruct vertex buffers for hardware upload. + * + * First attempt, work in progress. + * + * TODO: + * - separate out vertex buffer building and primitive emit, ie >1 draw per vb. + * - tell vbuf stage how to build hw vertices directly + * - pass vbuf stage a buffer pointer for direct emit to agp/vram. + */ +typedef void (*vbuf_draw_func)( struct pipe_context *pipe, + unsigned prim, + const ushort *elements, + unsigned nr_elements, + const void *vertex_buffer, + unsigned nr_vertices ); + + +extern struct draw_stage *sp_draw_vbuf_stage( struct draw_context *draw_context, + struct pipe_context *pipe, + vbuf_draw_func draw ); + + + +/* Test harness + */ +void sp_vbuf_setup_draw( struct pipe_context *pipe, + unsigned prim, + const ushort *elements, + unsigned nr_elements, + const void *vertex_buffer, + unsigned nr_vertices ); + + #endif /* SP_PRIM_SETUP_H */ diff --git a/src/mesa/pipe/softpipe/sp_prim_vbuf.c b/src/mesa/pipe/softpipe/sp_prim_vbuf.c new file mode 100644 index 0000000000..235903ca6d --- /dev/null +++ b/src/mesa/pipe/softpipe/sp_prim_vbuf.c @@ -0,0 +1,305 @@ +/************************************************************************** + * + * 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. + * + **************************************************************************/ + +/** + * Build post-transformation, post-clipping vertex buffers and element + * lists by hooking into the end of the primitive pipeline and + * manipulating the vertex_id field in the vertex headers. + * + * Keith Whitwell <keith@tungstengraphics.com> + */ + + +#include "sp_context.h" +#include "sp_headers.h" +#include "sp_quad.h" +#include "sp_prim_setup.h" +#include "pipe/draw/draw_private.h" +#include "pipe/draw/draw_vertex.h" +#include "pipe/p_util.h" + +static void vbuf_flush_elements( struct draw_stage *stage ); + + +#define VBUF_SIZE (64*1024) +#define IBUF_SIZE (16*1024) + + +/** + * Vertex buffer emit stage. + */ +struct vbuf_stage { + struct draw_stage stage; /**< This must be first (base class) */ + + struct draw_context *draw_context; + struct pipe_context *pipe; + vbuf_draw_func draw; + + /* Vertices are passed in as an array of floats making up each + * attribute in turn. Will eventually convert to hardware format + * in this stage. + */ + char *vertex_map; + char *vertex_ptr; + unsigned vertex_size; + unsigned nr_vertices; + + unsigned max_vertices; + + ushort *element_map; + unsigned nr_elements; + + unsigned prim; + +}; + +/** + * Basically a cast wrapper. + */ +static INLINE struct vbuf_stage *vbuf_stage( struct draw_stage *stage ) +{ + return (struct vbuf_stage *)stage; +} + + + + +static boolean overflow( void *map, void *ptr, unsigned bytes, unsigned bufsz ) +{ + unsigned long used = (char *)ptr - (char *)map; + return (used + bytes) > bufsz; +} + + +static boolean check_space( struct vbuf_stage *vbuf ) +{ + if (overflow( vbuf->vertex_map, + vbuf->vertex_ptr, + 4 * vbuf->vertex_size, + VBUF_SIZE )) + return FALSE; + + + if (vbuf->nr_elements + 4 > IBUF_SIZE / sizeof(ushort) ) + return FALSE; + + return TRUE; +} + + +static void emit_vertex( struct vbuf_stage *vbuf, + struct vertex_header *vertex ) +{ + fprintf(stderr, "emit vertex %d to %p\n", + vbuf->nr_vertices, vbuf->vertex_ptr); + + vertex->vertex_id = vbuf->nr_vertices++; + + //vbuf->emit_vertex( vbuf->vertex_ptr, vertex ); + memcpy(vbuf->vertex_ptr, vertex, vbuf->vertex_size); + + vbuf->vertex_ptr += vbuf->vertex_size; +} + + + +/** + * + */ +static void vbuf_tri( struct draw_stage *stage, + struct prim_header *prim ) +{ + struct vbuf_stage *vbuf = vbuf_stage( stage ); + unsigned i; + + if (!check_space( vbuf )) + vbuf_flush_elements( stage ); + + for (i = 0; i < 3; i++) { + if (prim->v[i]->vertex_id == 0xffff) + emit_vertex( vbuf, prim->v[i] ); + + vbuf->element_map[vbuf->nr_elements++] = prim->v[i]->vertex_id; + } +} + + +static void vbuf_line(struct draw_stage *stage, + struct prim_header *prim) +{ + struct vbuf_stage *vbuf = vbuf_stage( stage ); + unsigned i; + + if (!check_space( vbuf )) + vbuf_flush_elements( stage ); + + for (i = 0; i < 2; i++) { + if (prim->v[i]->vertex_id == 0xffff) + emit_vertex( vbuf, prim->v[i] ); + + vbuf->element_map[vbuf->nr_elements++] = prim->v[i]->vertex_id; + } +} + + +static void vbuf_point(struct draw_stage *stage, + struct prim_header *prim) +{ + struct vbuf_stage *vbuf = vbuf_stage( stage ); + + if (!check_space( vbuf )) + vbuf_flush_elements( stage ); + + if (prim->v[0]->vertex_id == 0xffff) + emit_vertex( vbuf, prim->v[0] ); + + vbuf->element_map[vbuf->nr_elements++] = prim->v[0]->vertex_id; +} + + +static void vbuf_first_tri( struct draw_stage *stage, + struct prim_header *prim ) +{ + struct vbuf_stage *vbuf = vbuf_stage( stage ); + + vbuf_flush_elements( stage ); + stage->tri = vbuf_tri; + stage->tri( stage, prim ); + vbuf->prim = PIPE_PRIM_TRIANGLES; +} + +static void vbuf_first_line( struct draw_stage *stage, + struct prim_header *prim ) +{ + struct vbuf_stage *vbuf = vbuf_stage( stage ); + + vbuf_flush_elements( stage ); + stage->line = vbuf_line; + stage->line( stage, prim ); + vbuf->prim = PIPE_PRIM_LINES; +} + +static void vbuf_first_point( struct draw_stage *stage, + struct prim_header *prim ) +{ + struct vbuf_stage *vbuf = vbuf_stage( stage ); + + vbuf_flush_elements( stage ); + stage->point = vbuf_point; + stage->point( stage, prim ); + vbuf->prim = PIPE_PRIM_POINTS; +} + + + +static void vbuf_flush_elements( struct draw_stage *stage ) +{ + struct vbuf_stage *vbuf = vbuf_stage( stage ); + + if (vbuf->nr_elements) { + fprintf(stderr, "%s (%d elts)\n", __FUNCTION__, vbuf->nr_elements); + + /* Draw now or add to list of primitives??? + */ + vbuf->draw( vbuf->pipe, + vbuf->prim, + vbuf->element_map, + vbuf->nr_elements, + vbuf->vertex_map, + (vbuf->vertex_ptr - vbuf->vertex_map) / vbuf->vertex_size ); + + vbuf->nr_elements = 0; + + vbuf->vertex_ptr = vbuf->vertex_map; + vbuf->nr_vertices = 0; + + /* Reset vertex ids? Actually, want to not do that unless our + * vertex buffer is full. Would like separate + * flush-on-index-full and flush-on-vb-full, but may raise + * issues uploading vertices if the hardware wants to flush when + * we flush. + */ + draw_vertex_cache_reset_vertex_ids( vbuf->draw_context ); + } + + stage->tri = vbuf_first_tri; + stage->line = vbuf_first_line; + stage->point = vbuf_first_point; +} + + +static void vbuf_begin( struct draw_stage *stage ) +{ + struct vbuf_stage *vbuf = vbuf_stage(stage); + + vbuf->vertex_size = vbuf->draw_context->vertex_info.size * sizeof(float); +} + + +static void vbuf_end( struct draw_stage *stage ) +{ + /* Overkill. + */ + vbuf_flush_elements( stage ); +} + + +static void reset_stipple_counter( struct draw_stage *stage ) +{ + /* XXX: This doesn't work. + */ +} + + +/** + * Create a new primitive vbuf/render stage. + */ +struct draw_stage *sp_draw_vbuf_stage( struct draw_context *draw_context, + struct pipe_context *pipe, + vbuf_draw_func draw ) +{ + struct vbuf_stage *vbuf = CALLOC_STRUCT(vbuf_stage); + + vbuf->stage.begin = vbuf_begin; + vbuf->stage.point = vbuf_first_point; + vbuf->stage.line = vbuf_first_line; + vbuf->stage.tri = vbuf_first_tri; + vbuf->stage.end = vbuf_end; + vbuf->stage.reset_stipple_counter = reset_stipple_counter; + + vbuf->pipe = pipe; + vbuf->draw = draw; + vbuf->draw_context = draw_context; + + vbuf->element_map = malloc( IBUF_SIZE ); + vbuf->vertex_map = malloc( VBUF_SIZE ); + + vbuf->vertex_ptr = vbuf->vertex_map; + + + return &vbuf->stage; +} |