From: Keith Whitwell Date: Thu, 3 Apr 2008 11:21:30 +0000 (+0100) Subject: draw: add passthrough path to the pipeline X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d2cb4ba0bb2388c784f145c59f3798f914dc7f39;p=mesa.git draw: add passthrough path to the pipeline This handles the case where bypass_vs is set, but vertices need to go through the pipeline for some reason - eg unfilled polygon mode. Demonstrates how to drive the pipeline from inside one of these things. --- diff --git a/src/gallium/auxiliary/draw/Makefile b/src/gallium/auxiliary/draw/Makefile index a0db2e4555e..b28e516396e 100644 --- a/src/gallium/auxiliary/draw/Makefile +++ b/src/gallium/auxiliary/draw/Makefile @@ -18,6 +18,7 @@ C_SOURCES = \ draw_pt.c \ draw_pt_vcache.c \ draw_pt_fetch_emit.c \ + draw_pt_fetch_pipeline.c \ draw_pt_elts.c \ draw_prim.c \ draw_pstipple.c \ diff --git a/src/gallium/auxiliary/draw/SConscript b/src/gallium/auxiliary/draw/SConscript index 981225a8c2c..9ca41974412 100644 --- a/src/gallium/auxiliary/draw/SConscript +++ b/src/gallium/auxiliary/draw/SConscript @@ -17,6 +17,7 @@ draw = env.ConvenienceLibrary( 'draw_pt.c', 'draw_pt_vcache.c', 'draw_pt_fetch_emit.c', + 'draw_pt_fetch_pipeline.c', 'draw_pt_elts.c', 'draw_prim.c', 'draw_pstipple.c', diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index 9a9b25297f1..0c9f9c2e036 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -160,6 +160,11 @@ struct draw_vertex_shader { /* Internal function for vertex fetch. */ typedef void (*fetch_func)(const void *ptr, float *attrib); + +fetch_func draw_get_fetch_func( enum pipe_format format ); + + + typedef void (*full_fetch_func)( struct draw_context *draw, struct tgsi_exec_machine *machine, const unsigned *elts, @@ -211,6 +216,7 @@ struct draw_context struct { struct draw_pt_middle_end *fetch_emit; + struct draw_pt_middle_end *fetch_pipeline; struct draw_pt_middle_end *fetch_shade_emit; struct draw_pt_middle_end *fetch_shade_cliptest_pipeline_or_emit; } middle; diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index c3baf5b7da7..f59fb86f781 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -73,7 +73,6 @@ draw_pt_arrays(struct draw_context *draw, */ -#if 0 if (!cliptest && !pipeline && !shading) { /* This is the 'passthrough' path: */ @@ -81,6 +80,14 @@ draw_pt_arrays(struct draw_context *draw, */ middle = draw->pt.middle.fetch_emit; } + else if (!cliptest && !shading) { + /* This is the 'passthrough' path targetting the pipeline backend. + */ + /* Fetch user verts, emit pipeline verts, run pipeline: + */ + middle = draw->pt.middle.fetch_pipeline; + } +#if 0 else if (!cliptest && !pipeline) { /* Fetch user verts, run vertex shader, emit hw verts: */ @@ -117,10 +124,9 @@ draw_pt_arrays(struct draw_context *draw, middle = draw->pt.middle.fetch_shade_cliptest_pipeline; } #else - if (cliptest || pipeline || shading) + else { return FALSE; - - middle = draw->pt.middle.fetch_emit; + } #endif @@ -190,6 +196,10 @@ boolean draw_pt_init( struct draw_context *draw ) if (!draw->pt.middle.fetch_emit) return FALSE; + draw->pt.middle.fetch_pipeline = draw_pt_fetch_pipeline( draw ); + if (!draw->pt.middle.fetch_pipeline) + return FALSE; + draw->pt.front.vcache = draw_pt_vcache( draw ); if (!draw->pt.front.vcache) return FALSE; @@ -205,6 +215,11 @@ void draw_pt_destroy( struct draw_context *draw ) draw->pt.middle.fetch_emit = NULL; } + if (draw->pt.middle.fetch_pipeline) { + draw->pt.middle.fetch_pipeline->destroy( draw->pt.middle.fetch_pipeline ); + draw->pt.middle.fetch_pipeline = NULL; + } + if (draw->pt.front.vcache) { draw->pt.front.vcache->destroy( draw->pt.front.vcache ); draw->pt.front.vcache = NULL; diff --git a/src/gallium/auxiliary/draw/draw_pt.h b/src/gallium/auxiliary/draw/draw_pt.h index 428b1e0e6bc..800072c5115 100644 --- a/src/gallium/auxiliary/draw/draw_pt.h +++ b/src/gallium/auxiliary/draw/draw_pt.h @@ -112,6 +112,7 @@ const void *draw_pt_elt_ptr( struct draw_context *draw, */ struct draw_pt_front_end *draw_pt_vcache( struct draw_context *draw ); struct draw_pt_middle_end *draw_pt_fetch_emit( struct draw_context *draw ); +struct draw_pt_middle_end *draw_pt_fetch_pipeline( struct draw_context *draw ); diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c index f863a46d9cc..39f0b40838f 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c @@ -85,45 +85,6 @@ struct fetch_emit_middle_end { }; -static void fetch_B8G8R8A8_UNORM( const void *from, - float *attrib ) -{ - ubyte *ub = (ubyte *) from; - attrib[2] = UBYTE_TO_FLOAT(ub[0]); - attrib[1] = UBYTE_TO_FLOAT(ub[1]); - attrib[0] = UBYTE_TO_FLOAT(ub[2]); - attrib[3] = UBYTE_TO_FLOAT(ub[3]); -} - -static void fetch_R32G32B32A32_FLOAT( const void *from, - float *attrib ) -{ - float *f = (float *) from; - attrib[0] = f[0]; - attrib[1] = f[1]; - attrib[2] = f[2]; - attrib[3] = f[3]; -} - -static void fetch_R32G32B32_FLOAT( const void *from, - float *attrib ) -{ - float *f = (float *) from; - attrib[0] = f[0]; - attrib[1] = f[1]; - attrib[2] = f[2]; - attrib[3] = 1.0; -} - -static void fetch_R32G32_FLOAT( const void *from, - float *attrib ) -{ - float *f = (float *) from; - attrib[0] = f[0]; - attrib[1] = f[1]; - attrib[2] = 0.0; - attrib[3] = 1.0; -} static void fetch_R32_FLOAT( const void *from, float *attrib ) @@ -235,28 +196,9 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle, feme->fetch[i].pitch = draw->vertex_buffer[src_buffer].pitch; - switch (draw->vertex_element[src_element].src_format) { - case PIPE_FORMAT_B8G8R8A8_UNORM: - feme->fetch[i].fetch = fetch_B8G8R8A8_UNORM; - break; - case PIPE_FORMAT_R32G32B32A32_FLOAT: - feme->fetch[i].fetch = fetch_R32G32B32A32_FLOAT; - break; - case PIPE_FORMAT_R32G32B32_FLOAT: - feme->fetch[i].fetch = fetch_R32G32B32_FLOAT; - break; - case PIPE_FORMAT_R32G32_FLOAT: - feme->fetch[i].fetch = fetch_R32G32_FLOAT; - break; - case PIPE_FORMAT_R32_FLOAT: - feme->fetch[i].fetch = fetch_R32_FLOAT; - break; - default: - assert(0); - feme->fetch[i].fetch = NULL; - break; - } - + feme->fetch[i].fetch = draw_get_fetch_func(draw->vertex_element[src_element].src_format); + + switch (vinfo->emit[i]) { case EMIT_4F: feme->fetch[i].emit = emit_R32G32B32A32_FLOAT; diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c b/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c new file mode 100644 index 00000000000..94e7d01be4b --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_pipeline.c @@ -0,0 +1,391 @@ +/************************************************************************** + * + * 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 + */ + +#include "pipe/p_util.h" +#include "draw/draw_context.h" +#include "draw/draw_private.h" +#include "draw/draw_vertex.h" +#include "draw/draw_pt.h" + +/* The simplest 'middle end' in the new vertex code. + * + * The responsibilities of a middle end are to: + * - perform vertex fetch using + * - draw vertex element/buffer state + * - a list of fetch indices we received as an input + * - run the vertex shader + * - cliptest, + * - clip coord calculation + * - viewport transformation + * - if necessary, run the primitive pipeline, passing it: + * - a linear array of vertex_header vertices constructed here + * - a set of draw indices we received as an input + * - otherwise, drive the hw backend, + * - allocate space for hardware format vertices + * - translate the vertex-shader output vertices to hw format + * - calling the backend draw functions. + * + * For convenience, we provide a helper function to drive the hardware + * backend given similar inputs to those required to run the pipeline. + * + * In the case of passthrough mode, many of these actions are disabled + * or noops, so we end up doing: + * + * - perform vertex fetch + * - drive the hw backend + * + * IE, basically just vertex fetch to post-vs-format vertices, + * followed by a call to the backend helper function. + */ + + +struct fetch_pipeline_middle_end { + struct draw_pt_middle_end base; + struct draw_context *draw; + + struct { + const ubyte *ptr; + unsigned pitch; + void (*fetch)( const void *from, float *attrib); + void (*emit)( const float *attrib, float **out ); + } fetch[PIPE_MAX_ATTRIBS]; + + unsigned nr_fetch; + unsigned pipeline_vertex_size; + unsigned prim; +}; + + +static void fetch_NULL( const void *from, + float *attrib ) +{ +} + + + +static void emit_R32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out) += 1; +} + +static void emit_R32G32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out)[1] = attrib[1]; + (*out) += 2; +} + +static void emit_R32G32B32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out)[1] = attrib[1]; + (*out)[2] = attrib[2]; + (*out) += 3; +} + +static void emit_R32G32B32A32_FLOAT( const float *attrib, + float **out ) +{ + (*out)[0] = attrib[0]; + (*out)[1] = attrib[1]; + (*out)[2] = attrib[2]; + (*out)[3] = attrib[3]; + (*out) += 4; +} + +static void emit_header( const float *attrib, + float **out ) +{ + (*out)[0] = 0; + (*out)[1] = 0; + (*out)[2] = 0; + (*out)[3] = 0; + (*out)[3] = 1; + (*out) += 5; +} + +/** + * General-purpose fetch from user's vertex arrays, emit to driver's + * vertex buffer. + * + * XXX this is totally temporary. + */ +static void +fetch_store_general( struct fetch_pipeline_middle_end *fpme, + void *out_ptr, + const unsigned *fetch_elts, + unsigned count ) +{ + float *out = (float *)out_ptr; + uint i, j; + + for (i = 0; i < count; i++) { + unsigned elt = fetch_elts[i]; + + for (j = 0; j < fpme->nr_fetch; j++) { + float attrib[4]; + const ubyte *from = (fpme->fetch[j].ptr + + fpme->fetch[j].pitch * elt); + + fpme->fetch[j].fetch( from, attrib ); + fpme->fetch[j].emit( attrib, &out ); + } + } +} + + +/* We aren't running a vertex shader, but are running the pipeline. + * That means the vertices we need to build look like: + * + * dw0: vertex header (zero?) + * dw1: clip coord 0 + * dw2: clip coord 1 + * dw3: clip coord 2 + * dw4: clip coord 4 + * dw5: screen coord 0 + * dw6: screen coord 0 + * dw7: screen coord 0 + * dw8: screen coord 0 + * dw9: other attribs... + * + */ +static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, + unsigned prim ) +{ + static const float zero = 0; + struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; + struct draw_context *draw = fpme->draw; + unsigned i, nr = 0; + + fpme->prim = prim; + + /* Emit the vertex header and empty clipspace coord field: + */ + { + fpme->fetch[nr].ptr = NULL; + fpme->fetch[nr].pitch = 0; + fpme->fetch[nr].fetch = fetch_NULL; + fpme->fetch[nr].emit = emit_header; + nr++; + } + + + /* Need to look at vertex shader inputs (we know it is a + * passthrough shader, so these define the outputs too). If we + * were running a shader, we'd still be looking at the inputs at + * this point. + */ + for (i = 0; i < draw->vertex_shader->info.num_inputs; i++) { + unsigned buf = draw->vertex_element[i].vertex_buffer_index; + enum pipe_format format = draw->vertex_element[i].src_format; + + fpme->fetch[nr].ptr = ((const ubyte *) draw->user.vbuffer[buf] + + draw->vertex_buffer[buf].buffer_offset + + draw->vertex_element[i].src_offset); + + fpme->fetch[nr].pitch = draw->vertex_buffer[buf].pitch; + fpme->fetch[nr].fetch = draw_get_fetch_func( format ); + + /* Always do this -- somewhat redundant... + */ + fpme->fetch[nr].emit = emit_R32G32B32A32_FLOAT; + nr++; + } + + fpme->nr_fetch = nr; + fpme->pipeline_vertex_size = (5 + (nr-1) * 4) * sizeof(float); +} + + + +/** + * Add a point to the primitive queue. + * \param i0 index into user's vertex arrays + */ +static void do_point( struct draw_context *draw, + const char *v0 ) +{ + struct prim_header prim; + + prim.reset_line_stipple = 0; + prim.edgeflags = 1; + prim.pad = 0; + prim.v[0] = (struct vertex_header *)v0; + + draw->pipeline.first->point( draw->pipeline.first, &prim ); +} + + +/** + * Add a line to the primitive queue. + * \param i0 index into user's vertex arrays + * \param i1 index into user's vertex arrays + */ +static void do_line( struct draw_context *draw, + const char *v0, + const char *v1 ) +{ + struct prim_header prim; + + prim.reset_line_stipple = 1; /* fixme */ + prim.edgeflags = 1; + prim.pad = 0; + prim.v[0] = (struct vertex_header *)v0; + prim.v[1] = (struct vertex_header *)v1; + + draw->pipeline.first->line( draw->pipeline.first, &prim ); +} + +/** + * Add a triangle to the primitive queue. + */ +static void do_triangle( struct draw_context *draw, + char *v0, + char *v1, + char *v2 ) +{ + struct prim_header prim; + +// _mesa_printf("tri %d %d %d\n", i0, i1, i2); + prim.reset_line_stipple = 1; + prim.edgeflags = ~0; + prim.pad = 0; + prim.v[0] = (struct vertex_header *)v0; + prim.v[1] = (struct vertex_header *)v1; + prim.v[2] = (struct vertex_header *)v2; + + draw->pipeline.first->tri( draw->pipeline.first, &prim ); +} + + +static void run_pipeline( struct fetch_pipeline_middle_end *fpme, + char *verts, + const ushort *elts, + unsigned count ) +{ + struct draw_context *draw = fpme->draw; + unsigned stride = fpme->pipeline_vertex_size; + unsigned i; + + switch (fpme->prim) { + case PIPE_PRIM_POINTS: + for (i = 0; i < count; i++) + do_point( draw, + verts + stride * elts[i] ); + break; + case PIPE_PRIM_LINES: + for (i = 0; i+1 < count; i += 2) + do_line( draw, + verts + stride * elts[i+0], + verts + stride * elts[i+1]); + break; + case PIPE_PRIM_TRIANGLES: + for (i = 0; i+2 < count; i += 3) + do_triangle( draw, + verts + stride * elts[i+0], + verts + stride * elts[i+1], + verts + stride * elts[i+2]); + break; + } +} + + + + +static void fetch_pipeline_run( struct draw_pt_middle_end *middle, + const unsigned *fetch_elts, + unsigned fetch_count, + const ushort *draw_elts, + unsigned draw_count ) +{ + struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; + struct draw_context *draw = fpme->draw; + char *pipeline_verts; + + pipeline_verts = MALLOC( fpme->pipeline_vertex_size * + fetch_count ); + if (!pipeline_verts) { + assert(0); + return; + } + + + /* Single routine to fetch vertices and emit pipeline verts. + */ + fetch_store_general( fpme, + pipeline_verts, + fetch_elts, + fetch_count ); + + + run_pipeline( fpme, + pipeline_verts, + draw_elts, + draw_count ); + + + /* Done -- that was easy, wasn't it: + */ + FREE( pipeline_verts ); +} + + + +static void fetch_pipeline_finish( struct draw_pt_middle_end *middle ) +{ + /* nothing to do */ +} + +static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle ) +{ + FREE(middle); +} + + +struct draw_pt_middle_end *draw_pt_fetch_pipeline( struct draw_context *draw ) +{ + struct fetch_pipeline_middle_end *fetch_pipeline = CALLOC_STRUCT( fetch_pipeline_middle_end ); + + fetch_pipeline->base.prepare = fetch_pipeline_prepare; + fetch_pipeline->base.run = fetch_pipeline_run; + fetch_pipeline->base.finish = fetch_pipeline_finish; + fetch_pipeline->base.destroy = fetch_pipeline_destroy; + + fetch_pipeline->draw = draw; + + return &fetch_pipeline->base; +} + diff --git a/src/gallium/auxiliary/draw/draw_vertex_fetch.c b/src/gallium/auxiliary/draw/draw_vertex_fetch.c index 11f99babf65..9041041006e 100644 --- a/src/gallium/auxiliary/draw/draw_vertex_fetch.c +++ b/src/gallium/auxiliary/draw/draw_vertex_fetch.c @@ -166,7 +166,7 @@ fetch_B8G8R8A8_UNORM(const void *ptr, float *attrib) } -static fetch_func get_fetch_func( enum pipe_format format ) +fetch_func draw_get_fetch_func( enum pipe_format format ) { #if 0 { @@ -502,7 +502,7 @@ void draw_update_vertex_fetch( struct draw_context *draw ) draw->vertex_element[i].src_offset; draw->vertex_fetch.pitch[i] = draw->vertex_buffer[buf].pitch; - draw->vertex_fetch.fetch[i] = get_fetch_func( format ); + draw->vertex_fetch.fetch[i] = draw_get_fetch_func( format ); } draw->vertex_fetch.nr_attrs = nr_attrs;