Am 18.04.2013 12:16, schrieb Zack Rusin: > Input assembler needs to be able to decompose adjacency primitives > into something that can be understood by the rest of the pipeline. > The specs say that the adjacency primitives are *only* visible > in the geometry shader, for everything else they need to be > decomposed. Which in most of the cases is not an issue, but the > geometry shader always decomposes for us, but without geometry > shader we were passing unchanged adjacency primitives to the > rest of the pipeline and causing crashes everywhere. This > commit introduces a primitive assembler which, if geometry > shader is missing and the input primitive is one of the > adjacency primitives, decomposes them into something > that the rest of the pipeline can understand. > > Signed-off-by: Zack Rusin <za...@vmware.com> > --- > src/gallium/auxiliary/Makefile.sources | 1 + > src/gallium/auxiliary/draw/draw_prim_assembler.c | 202 > ++++++++++++++++++++ > src/gallium/auxiliary/draw/draw_prim_assembler.h | 46 +++++ > .../auxiliary/draw/draw_prim_assembler_tmp.h | 33 ++++ > .../auxiliary/draw/draw_pt_fetch_shade_pipeline.c | 25 ++- > .../draw/draw_pt_fetch_shade_pipeline_llvm.c | 25 ++- > src/gallium/auxiliary/util/u_prim.h | 21 ++ > 7 files changed, 349 insertions(+), 4 deletions(-) > create mode 100644 src/gallium/auxiliary/draw/draw_prim_assembler.c > create mode 100644 src/gallium/auxiliary/draw/draw_prim_assembler.h > create mode 100644 src/gallium/auxiliary/draw/draw_prim_assembler_tmp.h > > diff --git a/src/gallium/auxiliary/Makefile.sources > b/src/gallium/auxiliary/Makefile.sources > index 79def21..20ff5ba 100644 > --- a/src/gallium/auxiliary/Makefile.sources > +++ b/src/gallium/auxiliary/Makefile.sources > @@ -23,6 +23,7 @@ C_SOURCES := \ > draw/draw_pipe_vbuf.c \ > draw/draw_pipe_wide_line.c \ > draw/draw_pipe_wide_point.c \ > + draw/draw_prim_assembler.c \ > draw/draw_pt.c \ > draw/draw_pt_emit.c \ > draw/draw_pt_fetch.c \ > diff --git a/src/gallium/auxiliary/draw/draw_prim_assembler.c > b/src/gallium/auxiliary/draw/draw_prim_assembler.c > new file mode 100644 > index 0000000..9717c32 > --- /dev/null > +++ b/src/gallium/auxiliary/draw/draw_prim_assembler.c > @@ -0,0 +1,202 @@ > +/************************************************************************** > + * > + * Copyright 2013 VMware, Inc. > + * 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 VMWARE 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. > + * > + **************************************************************************/ > + > +#include "draw_prim_assembler.h" > + > +#include "util/u_debug.h" > +#include "util/u_memory.h" > +#include "util/u_prim.h" > + > +#include "pipe/p_defines.h" > + > +struct draw_assembler > +{ > + struct draw_context *draw; > + > + struct draw_prim_info *output_prims; > + struct draw_vertex_info *output_verts; > + > + const struct draw_prim_info *input_prims; > + const struct draw_vertex_info *input_verts; > +}; > + > +boolean > +draw_prim_assembler_is_required(struct draw_context *draw, > + const struct draw_prim_info *prim_info, > + const struct draw_vertex_info *vert_info) > +{ > + switch (prim_info->prim) { > + case PIPE_PRIM_LINES_ADJACENCY: > + case PIPE_PRIM_LINE_STRIP_ADJACENCY: > + case PIPE_PRIM_TRIANGLES_ADJACENCY: > + case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: > + return TRUE; > + default: > + return FALSE; > + } > +} > + > +static void > +copy_verts(struct draw_assembler *asmblr, > + unsigned *indices, unsigned num_indices) > +{ > + unsigned i; > + > + char *output = (char*)asmblr->output_verts->verts; > + const char *input = (const char*)asmblr->input_verts->verts; > + > + for (i = 0; i < num_indices; ++i) { > + unsigned idx = indices[i]; > + unsigned output_offset = > + asmblr->output_verts->count * asmblr->output_verts->stride; > + unsigned input_offset = asmblr->input_verts->stride * idx; > + memcpy(output + output_offset, input + input_offset, > + asmblr->input_verts->vertex_size); > + asmblr->output_verts->count += 1; > + } > +} > + > +static void prim_point(struct draw_assembler *asmblr, > + int idx) > +{ > + unsigned indices[1]; > + > + indices[0] = idx; > + > + copy_verts(asmblr, indices, 1); > +} > + > +static void prim_line(struct draw_assembler *asmblr, > + int i0, int i1) > +{ > + unsigned indices[2]; > + > + indices[0] = i0; > + indices[1] = i1; > + > + copy_verts(asmblr, indices, 2); > +} > + > +static void prim_line_adj(struct draw_assembler *asmblr, > + int i0, int i1, int i2, int i3) > +{ > + unsigned indices[4]; > + > + indices[0] = i1; > + indices[1] = i2; > + > + copy_verts(asmblr, indices, 2); > +} > + > +static void prim_tri(struct draw_assembler *asmblr, > + int i0, int i1, int i2) > +{ > + unsigned indices[3]; > + > + indices[0] = i0; > + indices[1] = i1; > + indices[2] = i2; > + > + copy_verts(asmblr, indices, 3); > +} > + > +static void prim_tri_adj(struct draw_assembler *asmblr, > + int i0, int i1, int i2, > + int i3, int i4, int i5) > +{ > + unsigned indices[6]; > + > + indices[0] = i0; > + indices[1] = i2; > + indices[2] = i4; > + > + copy_verts(asmblr, indices, 3); > +} > + > + > + > +#define FUNC assembler_run_linear > +#define GET_ELT(idx) (start + (idx)) > +#include "draw_prim_assembler_tmp.h" > + > +#define FUNC assembler_run_elts > +#define LOCAL_VARS const ushort *elts = input_prims->elts; > +#define GET_ELT(idx) (elts[start + (idx)]) > +#include "draw_prim_assembler_tmp.h" > + > +void > +draw_prim_assembler_run(struct draw_context *draw, > + const struct draw_prim_info *input_prims, > + const struct draw_vertex_info *input_verts, > + struct draw_prim_info *output_prims, > + struct draw_vertex_info *output_verts) > +{ > + struct draw_assembler asmblr; > + unsigned start, i; > + unsigned assembled_prim = u_assembled_primitive(input_prims->prim); > + unsigned max_primitives = u_decomposed_prims_for_vertices( > + input_prims->prim, input_prims->count); > + unsigned max_verts = u_vertices_per_prim(assembled_prim) * max_primitives; > + > + asmblr.draw = draw; > + asmblr.output_prims = output_prims; > + asmblr.output_verts = output_verts; > + asmblr.input_prims = input_prims; > + asmblr.input_verts = input_verts; > + > + output_prims->linear = TRUE; > + output_prims->elts = NULL; > + output_prims->start = 0; > + output_prims->prim = u_assembled_primitive(input_prims->prim); > + output_prims->flags = 0x0; > + output_prims->primitive_lengths = MALLOC(sizeof(unsigned)); > + output_prims->primitive_lengths[0] = 0; > + output_prims->primitive_count = 1; > + > + output_verts->vertex_size = input_verts->vertex_size; > + output_verts->stride = input_verts->stride; > + output_verts->verts = (struct vertex_header*)MALLOC( > + input_verts->vertex_size * max_verts); > + output_verts->count = 0; > + > + > + for (start = i = 0; i < input_prims->primitive_count; > + start += input_prims->primitive_lengths[i], i++) > + { > + unsigned count = input_prims->primitive_lengths[i]; > + if (input_prims->linear) { > + assembler_run_linear(&asmblr, input_prims, input_verts, > + start, count); > + } else { > + assembler_run_elts(&asmblr, input_prims, input_verts, > + start, count); > + } > + } > + > + output_prims->primitive_lengths[0] = output_verts->count; > + output_prims->count = output_verts->count; > +} > diff --git a/src/gallium/auxiliary/draw/draw_prim_assembler.h > b/src/gallium/auxiliary/draw/draw_prim_assembler.h > new file mode 100644 > index 0000000..b6b6c7c > --- /dev/null > +++ b/src/gallium/auxiliary/draw/draw_prim_assembler.h > @@ -0,0 +1,46 @@ > +/************************************************************************** > + * > + * Copyright 2013 VMware, Inc. > + * 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 VMWARE 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. > + * > + **************************************************************************/ > + > +#ifndef DRAW_PRIM_ASSEMBLER_H > +#define DRAW_PRIM_ASSEMBLER_H > + > +#include "draw/draw_private.h" > + > +boolean > +draw_prim_assembler_is_required(struct draw_context *draw, > + const struct draw_prim_info *prim_info, > + const struct draw_vertex_info *vert_info); > + > +void > +draw_prim_assembler_run(struct draw_context *draw, > + const struct draw_prim_info *in_prim_info, > + const struct draw_vertex_info *in_vert_info, > + struct draw_prim_info *out_prim_info, > + struct draw_vertex_info *out_vert_info); > + > + > +#endif > diff --git a/src/gallium/auxiliary/draw/draw_prim_assembler_tmp.h > b/src/gallium/auxiliary/draw/draw_prim_assembler_tmp.h > new file mode 100644 > index 0000000..fbfa7c6 > --- /dev/null > +++ b/src/gallium/auxiliary/draw/draw_prim_assembler_tmp.h > @@ -0,0 +1,33 @@ > +#define FUNC_VARS \ > + struct draw_assembler *asmblr, \ > + const struct draw_prim_info *input_prims, \ > + const struct draw_vertex_info *input_verts, \ > + unsigned start, \ > + unsigned count > + > +#define FUNC_ENTER \ > + /* declare more local vars */ \ > + const unsigned prim = input_prims->prim; \ > + const unsigned prim_flags = input_prims->flags; \ > + const boolean quads_flatshade_last = FALSE; \ > + const boolean last_vertex_last = > !asmblr->draw->rasterizer->flatshade_first; \ > + do { \ > + switch (prim) { \ > + case PIPE_PRIM_QUADS: \ > + case PIPE_PRIM_QUAD_STRIP: \ > + case PIPE_PRIM_POLYGON: \ > + debug_assert(!"unexpected primitive type in prim assembler"); \ > + return; \ > + default: \ > + break; \ > + } \ > + } while (0) \ > + > + > +#define POINT(i0) prim_point(asmblr, i0) > +#define LINE(flags, i0, i1) prim_line(asmblr, i0, i1) > +#define TRIANGLE(flags, i0, i1, i2) prim_tri(asmblr, i0, i1, i2) > +#define LINE_ADJ(flags, i0, i1, i2, i3) prim_line_adj(asmblr, i0, i1, > i2, i3) > +#define TRIANGLE_ADJ(flags,i0,i1,i2,i3,i4,i5) > prim_tri_adj(asmblr,i0,i1,i2,i3,i4,i5) > + > +#include "draw_decompose_tmp.h" > diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c > b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c > index e17f161..072174d 100644 > --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c > +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c > @@ -31,6 +31,7 @@ > #include "draw/draw_context.h" > #include "draw/draw_vbuf.h" > #include "draw/draw_vertex.h" > +#include "draw/draw_prim_assembler.h" > #include "draw/draw_pt.h" > #include "draw/draw_vs.h" > #include "draw/draw_gs.h" > @@ -69,7 +70,8 @@ static void fetch_pipeline_prepare( struct > draw_pt_middle_end *middle, > unsigned i; > unsigned instance_id_index = ~0; > > - unsigned gs_out_prim = (gs ? gs->output_primitive : prim); > + const unsigned gs_out_prim = (gs ? gs->output_primitive : > + u_assembled_primitive(prim); > > /* Add one to num_outputs because the pipeline occasionally tags on > * an additional texcoord, eg for AA lines. > @@ -217,7 +219,7 @@ static void draw_vertex_shader_run(struct > draw_vertex_shader *vshader, > > static void fetch_pipeline_generic( struct draw_pt_middle_end *middle, > const struct draw_fetch_info *fetch_info, > - const struct draw_prim_info *prim_info ) > + const struct draw_prim_info > *in_prim_info ) > { > struct fetch_pipeline_middle_end *fpme = (struct > fetch_pipeline_middle_end *)middle; > struct draw_context *draw = fpme->draw; > @@ -228,6 +230,10 @@ static void fetch_pipeline_generic( struct > draw_pt_middle_end *middle, > struct draw_vertex_info vs_vert_info; > struct draw_vertex_info gs_vert_info; > struct draw_vertex_info *vert_info; > + struct draw_prim_info ia_prim_info; > + struct draw_vertex_info ia_vert_info; > + const struct draw_prim_info *prim_info = in_prim_info; > + boolean free_prim_info = FALSE; > unsigned opt = fpme->opt; > > fetched_vert_info.count = fetch_info->count; > @@ -283,6 +289,18 @@ static void fetch_pipeline_generic( struct > draw_pt_middle_end *middle, > FREE(vert_info->verts); > vert_info = &gs_vert_info; > prim_info = &gs_prim_info; > + } else { > + if (draw_prim_assembler_is_required(draw, prim_info, vert_info)) { > + draw_prim_assembler_run(draw, prim_info, vert_info, > + &ia_prim_info, &ia_vert_info); > + > + if (ia_vert_info.count) { > + FREE(vert_info->verts); > + vert_info = &ia_vert_info; > + prim_info = &ia_prim_info; > + free_prim_info = TRUE; > + } > + } > } > > > @@ -314,6 +332,9 @@ static void fetch_pipeline_generic( struct > draw_pt_middle_end *middle, > } > } > FREE(vert_info->verts); > + if (free_prim_info) { > + FREE(prim_info->primitive_lengths); > + } > } > > static void fetch_pipeline_run( struct draw_pt_middle_end *middle, > diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c > b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c > index d312dc4..31bd7ce 100644 > --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c > +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c > @@ -33,6 +33,7 @@ > #include "draw/draw_vbuf.h" > #include "draw/draw_vertex.h" > #include "draw/draw_pt.h" > +#include "draw/draw_prim_assembler.h" > #include "draw/draw_vs.h" > #include "draw/draw_llvm.h" > #include "gallivm/lp_bld_init.h" > @@ -138,7 +139,8 @@ llvm_middle_end_prepare( struct draw_pt_middle_end > *middle, > struct draw_context *draw = fpme->draw; > struct draw_vertex_shader *vs = draw->vs.vertex_shader; > struct draw_geometry_shader *gs = draw->gs.geometry_shader; > - const unsigned out_prim = gs ? gs->output_primitive : in_prim; > + const unsigned out_prim = gs ? gs->output_primitive : > + u_assembled_primitive(in_prim); > > /* Add one to num_outputs because the pipeline occasionally tags on > * an additional texcoord, eg for AA lines. > @@ -312,7 +314,7 @@ static void emit(struct pt_emit *emit, > static void > llvm_pipeline_generic( struct draw_pt_middle_end *middle, > const struct draw_fetch_info *fetch_info, > - const struct draw_prim_info *prim_info ) > + const struct draw_prim_info *in_prim_info ) > { > struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; > struct draw_context *draw = fpme->draw; > @@ -321,6 +323,10 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle, > struct draw_vertex_info llvm_vert_info; > struct draw_vertex_info gs_vert_info; > struct draw_vertex_info *vert_info; > + struct draw_prim_info ia_prim_info; > + struct draw_vertex_info ia_vert_info; > + const struct draw_prim_info *prim_info = in_prim_info; > + boolean free_prim_info = FALSE; > unsigned opt = fpme->opt; > unsigned clipped = 0; > > @@ -380,6 +386,18 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle, > FREE(vert_info->verts); > vert_info = &gs_vert_info; > prim_info = &gs_prim_info; > + } else { > + if (draw_prim_assembler_is_required(draw, prim_info, vert_info)) { > + draw_prim_assembler_run(draw, prim_info, vert_info, > + &ia_prim_info, &ia_vert_info); > + > + if (ia_vert_info.count) { > + FREE(vert_info->verts); > + vert_info = &ia_vert_info; > + prim_info = &ia_prim_info; > + free_prim_info = TRUE; > + } > + } > } > > /* stream output needs to be done before clipping */ > @@ -407,6 +425,9 @@ llvm_pipeline_generic( struct draw_pt_middle_end *middle, > } > } > FREE(vert_info->verts); > + if (free_prim_info) { > + FREE(prim_info->primitive_lengths); > + } > } > > > diff --git a/src/gallium/auxiliary/util/u_prim.h > b/src/gallium/auxiliary/util/u_prim.h > index 507d12e..e477444 100644 > --- a/src/gallium/auxiliary/util/u_prim.h > +++ b/src/gallium/auxiliary/util/u_prim.h > @@ -213,6 +213,27 @@ u_decomposed_prims_for_vertices(int primitive, int > vertices) > } > } > > +static INLINE unsigned > +u_assembled_primitive(unsigned prim) > +{ > + switch (prim) { > + case PIPE_PRIM_LINES_ADJACENCY: > + return PIPE_PRIM_LINES; > + case PIPE_PRIM_LINE_STRIP_ADJACENCY: > + return PIPE_PRIM_LINES; > + case PIPE_PRIM_TRIANGLES_ADJACENCY: > + return PIPE_PRIM_TRIANGLES; > + case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: > + return PIPE_PRIM_TRIANGLES; > + default: > + return prim; > + } > + > + return prim; > +} > + > + > + > const char *u_prim_name( unsigned pipe_prim ); > > #endif
Looks good to me though I wonder if it would be an option to do this at vertex fetch time instead after vs? I guess though that way it would have to be done separate for the llvm and non-llvm code as the fetch is integrated into the llvm code. I think that the idea for d3d10 was to do it in the input assembler, so the unneeded vertices don't have to go through the vs. I doubt though it makes much of a difference. Roland _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev