From: Zack Rusin Date: Thu, 8 Aug 2013 19:44:10 +0000 (-0400) Subject: draw: rewrite primitive assembler X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=662a4d4a120cb0a07023f00e3c5e4a0809428a53;p=mesa.git draw: rewrite primitive assembler We can't be injecting the primitive id's in the pipeline because by that time the primitives have already been decomposed. To properly number the primitives we need to handle the adjacency primitives by hand. This patch moves the prim id injection into the original primitive assembler and completely removes the useless pipeline stage. Signed-off-by: Zack Rusin Reviewed-by: Roland Scheidegger --- diff --git a/src/gallium/auxiliary/Makefile.sources b/src/gallium/auxiliary/Makefile.sources index b0172de5270..acbcef7e2ed 100644 --- a/src/gallium/auxiliary/Makefile.sources +++ b/src/gallium/auxiliary/Makefile.sources @@ -13,7 +13,6 @@ C_SOURCES := \ draw/draw_pipe_clip.c \ draw/draw_pipe_cull.c \ draw/draw_pipe_flatshade.c \ - draw/draw_pipe_ia.c \ draw/draw_pipe_offset.c \ draw/draw_pipe_pstipple.c \ draw/draw_pipe_stipple.c \ diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 2dc6772e7fb..2d4843ebe25 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -40,6 +40,7 @@ #include "util/u_prim.h" #include "draw_context.h" #include "draw_pipe.h" +#include "draw_prim_assembler.h" #include "draw_vs.h" #include "draw_gs.h" @@ -95,6 +96,10 @@ draw_create_context(struct pipe_context *pipe, boolean try_llvm) if (!draw_init(draw)) goto err_destroy; + draw->ia = draw_prim_assembler_create(draw); + if (!draw->ia) + goto err_destroy; + return draw; err_destroy: @@ -206,6 +211,7 @@ void draw_destroy( struct draw_context *draw ) draw->render->destroy( draw->render ); */ + draw_prim_assembler_destroy(draw->ia); draw_pipeline_destroy( draw ); draw_pt_destroy( draw ); draw_vs_destroy( draw ); @@ -556,7 +562,7 @@ void draw_prepare_shader_outputs(struct draw_context *draw) { draw_remove_extra_vertex_attribs(draw); - draw_ia_prepare_outputs(draw, draw->pipeline.ia); + draw_prim_assembler_prepare_outputs(draw->ia); draw_unfilled_prepare_outputs(draw, draw->pipeline.unfilled); } diff --git a/src/gallium/auxiliary/draw/draw_pipe.c b/src/gallium/auxiliary/draw/draw_pipe.c index 81402997f82..f1ee6cb1b0a 100644 --- a/src/gallium/auxiliary/draw/draw_pipe.c +++ b/src/gallium/auxiliary/draw/draw_pipe.c @@ -49,7 +49,6 @@ boolean draw_pipeline_init( struct draw_context *draw ) draw->pipeline.clip = draw_clip_stage( draw ); draw->pipeline.flatshade = draw_flatshade_stage( draw ); draw->pipeline.cull = draw_cull_stage( draw ); - draw->pipeline.ia = draw_ia_stage( draw ); draw->pipeline.validate = draw_validate_stage( draw ); draw->pipeline.first = draw->pipeline.validate; @@ -62,7 +61,6 @@ boolean draw_pipeline_init( struct draw_context *draw ) !draw->pipeline.clip || !draw->pipeline.flatshade || !draw->pipeline.cull || - !draw->pipeline.ia || !draw->pipeline.validate) return FALSE; @@ -97,8 +95,6 @@ void draw_pipeline_destroy( struct draw_context *draw ) draw->pipeline.flatshade->destroy( draw->pipeline.flatshade ); if (draw->pipeline.cull) draw->pipeline.cull->destroy( draw->pipeline.cull ); - if (draw->pipeline.ia) - draw->pipeline.ia->destroy( draw->pipeline.ia ); if (draw->pipeline.validate) draw->pipeline.validate->destroy( draw->pipeline.validate ); if (draw->pipeline.aaline) diff --git a/src/gallium/auxiliary/draw/draw_pipe.h b/src/gallium/auxiliary/draw/draw_pipe.h index 70822a41901..7c9ed6c31d9 100644 --- a/src/gallium/auxiliary/draw/draw_pipe.h +++ b/src/gallium/auxiliary/draw/draw_pipe.h @@ -91,10 +91,6 @@ extern struct draw_stage *draw_stipple_stage( struct draw_context *context ); extern struct draw_stage *draw_wide_line_stage( struct draw_context *context ); extern struct draw_stage *draw_wide_point_stage( struct draw_context *context ); extern struct draw_stage *draw_validate_stage( struct draw_context *context ); -extern struct draw_stage *draw_ia_stage(struct draw_context *context); - -boolean draw_ia_stage_required(const struct draw_context *context, - unsigned prim); extern void draw_free_temp_verts( struct draw_stage *stage ); extern boolean draw_alloc_temp_verts( struct draw_stage *stage, unsigned nr ); @@ -108,9 +104,6 @@ void draw_pipe_passthrough_point(struct draw_stage *stage, struct prim_header *h void draw_unfilled_prepare_outputs(struct draw_context *context, struct draw_stage *stage); -void draw_ia_prepare_outputs(struct draw_context *context, - struct draw_stage *stage); - /** * Get a writeable copy of a vertex. diff --git a/src/gallium/auxiliary/draw/draw_pipe_ia.c b/src/gallium/auxiliary/draw/draw_pipe_ia.c deleted file mode 100644 index d64f19b38cb..00000000000 --- a/src/gallium/auxiliary/draw/draw_pipe_ia.c +++ /dev/null @@ -1,259 +0,0 @@ -/************************************************************************** - * - * Copyright 2013 VMware - * 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. - * - **************************************************************************/ - -/** - * \brief Used to decompose adjacency primitives and inject the prim id - */ - -#include "util/u_math.h" -#include "util/u_memory.h" -#include "pipe/p_defines.h" -#include "draw_pipe.h" -#include "draw_fs.h" -#include "draw_gs.h" - - -struct ia_stage { - struct draw_stage stage; - int primid_slot; - unsigned primid; -}; - - -static INLINE struct ia_stage * -ia_stage(struct draw_stage *stage) -{ - return (struct ia_stage *)stage; -} - - -static void -inject_primid(struct draw_stage *stage, - struct prim_header *header, - unsigned num_verts) -{ - struct ia_stage *ia = ia_stage(stage); - unsigned slot = ia->primid_slot; - unsigned i; - unsigned primid = ia->primid; - - /* In case the backend doesn't care about it */ - if (slot < 0) { - return; - } - - for (i = 0; i < num_verts; ++i) { - struct vertex_header *v = header->v[i]; - /* We have to reset the vertex_id because it's used by - * vbuf to figure out if the vertex had already been - * emitted. For line/tri strips the first vertex of - * subsequent primitives would already be emitted, - * but since we're changing the primitive id on the vertex - * we want to make sure it's reemitted with the correct - * data. - */ - v->vertex_id = UNDEFINED_VERTEX_ID; - memcpy(&v->data[slot][0], &primid, sizeof(primid)); - memcpy(&v->data[slot][1], &primid, sizeof(primid)); - memcpy(&v->data[slot][2], &primid, sizeof(primid)); - memcpy(&v->data[slot][3], &primid, sizeof(primid)); - } - ++ia->primid; -} - - -static void -ia_point(struct draw_stage *stage, - struct prim_header *header) -{ - inject_primid(stage, header, 1); - stage->next->point(stage->next, header); -} - -static void -ia_line(struct draw_stage *stage, - struct prim_header *header) -{ - inject_primid(stage, header, 2); - stage->next->line(stage->next, header); -} - -static void -ia_tri(struct draw_stage *stage, - struct prim_header *header) -{ - inject_primid(stage, header, 3); - stage->next->tri(stage->next, header); -} - -static void -ia_first_point(struct draw_stage *stage, - struct prim_header *header) -{ - struct ia_stage *ia = ia_stage(stage); - - if (ia->primid_slot >= 0) { - stage->point = ia_point; - } else { - stage->point = draw_pipe_passthrough_point; - } - - stage->point(stage, header); -} - -static void -ia_first_line(struct draw_stage *stage, - struct prim_header *header) -{ - struct ia_stage *ia = ia_stage(stage); - - if (ia->primid_slot >= 0) { - stage->line = ia_line; - } else { - stage->line = draw_pipe_passthrough_line; - } - - stage->line(stage, header); -} - -static void -ia_first_tri(struct draw_stage *stage, - struct prim_header *header) -{ - struct ia_stage *ia = ia_stage(stage); - - if (ia->primid_slot >= 0) { - stage->tri = ia_tri; - } else { - stage->tri = draw_pipe_passthrough_tri; - } - - stage->tri(stage, header); -} - - -static void -ia_flush(struct draw_stage *stage, unsigned flags) -{ - stage->point = ia_first_point; - stage->line = ia_first_line; - stage->tri = ia_first_tri; - stage->next->flush(stage->next, flags); -} - - -static void -ia_reset_stipple_counter(struct draw_stage *stage) -{ - stage->next->reset_stipple_counter(stage->next); -} - - -static void -ia_destroy(struct draw_stage *stage) -{ - draw_free_temp_verts(stage); - FREE(stage); -} - - -static boolean -needs_primid(const struct draw_context *draw) -{ - const struct draw_fragment_shader *fs = draw->fs.fragment_shader; - const struct draw_geometry_shader *gs = draw->gs.geometry_shader; - if (fs && fs->info.uses_primid) { - return !gs || !gs->info.uses_primid; - } - return FALSE; -} - -boolean -draw_ia_stage_required(const struct draw_context *draw, unsigned prim) -{ - const struct draw_geometry_shader *gs = draw->gs.geometry_shader; - if (needs_primid(draw)) { - return TRUE; - } - - if (gs) { - return FALSE; - } - - switch (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; - } -} - -void -draw_ia_prepare_outputs(struct draw_context *draw, - struct draw_stage *stage) -{ - struct ia_stage *ia = ia_stage(stage); - if (needs_primid(draw)) { - ia->primid_slot = draw_alloc_extra_vertex_attrib( - stage->draw, TGSI_SEMANTIC_PRIMID, 0); - } else { - ia->primid_slot = -1; - } - ia->primid = 0; -} - -struct draw_stage * -draw_ia_stage(struct draw_context *draw) -{ - struct ia_stage *ia = CALLOC_STRUCT(ia_stage); - if (ia == NULL) - goto fail; - - ia->stage.draw = draw; - ia->stage.name = "ia"; - ia->stage.next = NULL; - ia->stage.point = ia_first_point; - ia->stage.line = ia_first_line; - ia->stage.tri = ia_first_tri; - ia->stage.flush = ia_flush; - ia->stage.reset_stipple_counter = ia_reset_stipple_counter; - ia->stage.destroy = ia_destroy; - - if (!draw_alloc_temp_verts(&ia->stage, 0)) - goto fail; - - return &ia->stage; - -fail: - if (ia) - ia->stage.destroy(&ia->stage); - - return NULL; -} diff --git a/src/gallium/auxiliary/draw/draw_pipe_validate.c b/src/gallium/auxiliary/draw/draw_pipe_validate.c index 9b2f5845e09..3562acdbcdc 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_validate.c +++ b/src/gallium/auxiliary/draw/draw_pipe_validate.c @@ -76,14 +76,6 @@ draw_need_pipeline(const struct draw_context *draw, prim ); } - /* If we need to decompose the primitives or inject - * primitive id information then we have to run - * the pipeline. - */ - if (draw_ia_stage_required(draw, prim)) { - return TRUE; - } - /* Don't have to worry about triangles turning into lines/points * and triggering the pipeline, because we have to trigger the * pipeline *anyway* if unfilled mode is active. @@ -288,12 +280,6 @@ static struct draw_stage *validate_pipeline( struct draw_stage *stage ) next = draw->pipeline.clip; } - /* Input assembler */ - if (draw_ia_stage_required(draw, draw->pt.prim)) { - draw->pipeline.ia->next = next; - next = draw->pipeline.ia; - } - draw->pipeline.first = next; if (0) { diff --git a/src/gallium/auxiliary/draw/draw_prim_assembler.c b/src/gallium/auxiliary/draw/draw_prim_assembler.c index 9bedeeadb44..eba441c17ad 100644 --- a/src/gallium/auxiliary/draw/draw_prim_assembler.c +++ b/src/gallium/auxiliary/draw/draw_prim_assembler.c @@ -27,6 +27,9 @@ #include "draw_prim_assembler.h" +#include "draw_fs.h" +#include "draw_gs.h" + #include "util/u_debug.h" #include "util/u_memory.h" #include "util/u_prim.h" @@ -42,8 +45,28 @@ struct draw_assembler const struct draw_prim_info *input_prims; const struct draw_vertex_info *input_verts; + + boolean needs_primid; + int primid_slot; + unsigned primid; + + boolean is_strip; + boolean is_first_prim; + unsigned num_prims; }; + +static boolean +needs_primid(const struct draw_context *draw) +{ + const struct draw_fragment_shader *fs = draw->fs.fragment_shader; + const struct draw_geometry_shader *gs = draw->gs.geometry_shader; + if (fs && fs->info.uses_primid) { + return !gs || !gs->info.uses_primid; + } + return FALSE; +} + boolean draw_prim_assembler_is_required(const struct draw_context *draw, const struct draw_prim_info *prim_info, @@ -56,7 +79,7 @@ draw_prim_assembler_is_required(const struct draw_context *draw, case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: return TRUE; default: - return FALSE; + return needs_primid(draw); } } @@ -84,16 +107,43 @@ copy_verts(struct draw_assembler *asmblr, asmblr->input_verts->vertex_size); asmblr->output_verts->count += 1; } + ++asmblr->num_prims; +} + + +static void +inject_primid(struct draw_assembler *asmblr, + unsigned idx, + unsigned primid) +{ + int slot = asmblr->primid_slot; + char *input = (char*)asmblr->input_verts->verts; + unsigned input_offset = asmblr->input_verts->stride * idx; + struct vertex_header *v = (struct vertex_header*)(input + input_offset); + + /* In case the backend doesn't care about it */ + if (slot < 0) { + return; + } + + memcpy(&v->data[slot][0], &primid, sizeof(primid)); + memcpy(&v->data[slot][1], &primid, sizeof(primid)); + memcpy(&v->data[slot][2], &primid, sizeof(primid)); + memcpy(&v->data[slot][3], &primid, sizeof(primid)); } + static void prim_point(struct draw_assembler *asmblr, unsigned idx) { unsigned indices[1]; + if (asmblr->needs_primid) { + inject_primid(asmblr, idx, asmblr->primid++); + } indices[0] = idx; - + copy_verts(asmblr, indices, 1); } @@ -103,6 +153,18 @@ prim_line(struct draw_assembler *asmblr, { unsigned indices[2]; + if (asmblr->needs_primid) { + if (asmblr->is_strip && asmblr->is_first_prim) { + inject_primid(asmblr, i0, asmblr->primid++); + inject_primid(asmblr, i1, asmblr->primid++); + asmblr->is_first_prim = FALSE; + } else if (asmblr->is_strip) { + inject_primid(asmblr, i1, asmblr->primid++); + } else { + inject_primid(asmblr, i0, asmblr->primid); + inject_primid(asmblr, i1, asmblr->primid++); + } + } indices[0] = i0; indices[1] = i1; @@ -115,6 +177,19 @@ prim_line_adj(struct draw_assembler *asmblr, { unsigned indices[2]; + if (asmblr->needs_primid) { + if (asmblr->is_strip && asmblr->is_first_prim) { + inject_primid(asmblr, i1, asmblr->primid++); + inject_primid(asmblr, i2, asmblr->primid++); + asmblr->is_first_prim = FALSE; + } else if (asmblr->is_strip) { + inject_primid(asmblr, i2, asmblr->primid++); + } else { + inject_primid(asmblr, i1, asmblr->primid); + inject_primid(asmblr, i2, asmblr->primid++); + } + } + indices[0] = i1; indices[1] = i2; @@ -127,6 +202,24 @@ prim_tri(struct draw_assembler *asmblr, { unsigned indices[3]; + if (asmblr->needs_primid) { + if (asmblr->is_strip && asmblr->is_first_prim) { + inject_primid(asmblr, i0, asmblr->primid++); + inject_primid(asmblr, i1, asmblr->primid++); + inject_primid(asmblr, i2, asmblr->primid++); + asmblr->is_first_prim = FALSE; + } else if (asmblr->is_strip) { + if (asmblr->num_prims & 1) { + inject_primid(asmblr, i1, asmblr->primid++); + } else { + inject_primid(asmblr, i2, asmblr->primid++); + } + } else { + inject_primid(asmblr, i0, asmblr->primid); + inject_primid(asmblr, i1, asmblr->primid); + inject_primid(asmblr, i2, asmblr->primid++); + } + } indices[0] = i0; indices[1] = i1; indices[2] = i2; @@ -141,6 +234,25 @@ prim_tri_adj(struct draw_assembler *asmblr, { unsigned indices[3]; + if (asmblr->needs_primid) { + if (asmblr->is_strip && asmblr->is_first_prim) { + inject_primid(asmblr, i0, asmblr->primid++); + inject_primid(asmblr, i2, asmblr->primid++); + inject_primid(asmblr, i4, asmblr->primid++); + asmblr->is_first_prim = FALSE; + } else if (asmblr->is_strip) { + if (asmblr->num_prims & 1) { + inject_primid(asmblr, i2, asmblr->primid++); + } else { + inject_primid(asmblr, i4, asmblr->primid++); + } + } else { + inject_primid(asmblr, i0, asmblr->primid); + inject_primid(asmblr, i2, asmblr->primid); + inject_primid(asmblr, i4, asmblr->primid); + asmblr->primid++; + } + } indices[0] = i0; indices[1] = i2; indices[2] = i4; @@ -148,6 +260,18 @@ prim_tri_adj(struct draw_assembler *asmblr, copy_verts(asmblr, indices, 3); } +void +draw_prim_assembler_prepare_outputs(struct draw_assembler *ia) +{ + struct draw_context *draw = ia->draw; + if (needs_primid(draw)) { + ia->primid_slot = draw_alloc_extra_vertex_attrib( + ia->draw, TGSI_SEMANTIC_PRIMID, 0); + } else { + ia->primid_slot = -1; + } + ia->primid = 0; +} #define FUNC assembler_run_linear @@ -178,18 +302,26 @@ draw_prim_assembler_run(struct draw_context *draw, struct draw_prim_info *output_prims, struct draw_vertex_info *output_verts) { - struct draw_assembler asmblr; + struct draw_assembler *asmblr = draw->ia; unsigned start, i; unsigned assembled_prim = u_assembled_prim(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; + asmblr->output_prims = output_prims; + asmblr->output_verts = output_verts; + asmblr->input_prims = input_prims; + asmblr->input_verts = input_verts; + asmblr->is_strip = + (input_prims->prim == PIPE_PRIM_TRIANGLE_STRIP || + input_prims->prim == PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY) || + (input_prims->prim == PIPE_PRIM_LINE_STRIP || + input_prims->prim == PIPE_PRIM_LINE_STRIP_ADJACENCY); + asmblr->needs_primid = needs_primid(asmblr->draw); + asmblr->is_first_prim = asmblr->is_strip; + asmblr->primid = 0; + asmblr->num_prims = 0; output_prims->linear = TRUE; output_prims->elts = NULL; @@ -212,10 +344,10 @@ draw_prim_assembler_run(struct draw_context *draw, { unsigned count = input_prims->primitive_lengths[i]; if (input_prims->linear) { - assembler_run_linear(&asmblr, input_prims, input_verts, + assembler_run_linear(asmblr, input_prims, input_verts, start, count); } else { - assembler_run_elts(&asmblr, input_prims, input_verts, + assembler_run_elts(asmblr, input_prims, input_verts, start, count); } } @@ -223,3 +355,19 @@ draw_prim_assembler_run(struct draw_context *draw, output_prims->primitive_lengths[0] = output_verts->count; output_prims->count = output_verts->count; } + +struct draw_assembler * +draw_prim_assembler_create(struct draw_context *draw) +{ + struct draw_assembler *ia = CALLOC_STRUCT( draw_assembler ); + + ia->draw = draw; + + return ia; +} + +void +draw_prim_assembler_destroy(struct draw_assembler *ia) +{ + FREE(ia); +} diff --git a/src/gallium/auxiliary/draw/draw_prim_assembler.h b/src/gallium/auxiliary/draw/draw_prim_assembler.h index 2ef7c518063..5ba715b8135 100644 --- a/src/gallium/auxiliary/draw/draw_prim_assembler.h +++ b/src/gallium/auxiliary/draw/draw_prim_assembler.h @@ -46,6 +46,14 @@ #include "draw/draw_private.h" +struct draw_assembler; + +struct draw_assembler * +draw_prim_assembler_create(struct draw_context *draw); + +void +draw_prim_assembler_destroy(struct draw_assembler *ia); + boolean draw_prim_assembler_is_required(const struct draw_context *draw, const struct draw_prim_info *prim_info, @@ -59,4 +67,8 @@ draw_prim_assembler_run(struct draw_context *draw, struct draw_vertex_info *out_vert_info); +void +draw_prim_assembler_prepare_outputs(struct draw_assembler *ia); + + #endif diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index b21e7956845..ba93b093377 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -68,6 +68,7 @@ struct vbuf_render; struct tgsi_exec_machine; struct tgsi_sampler; struct draw_pt_front_end; +struct draw_assembler; /** @@ -130,7 +131,6 @@ struct draw_context struct draw_stage *wide_line; struct draw_stage *wide_point; struct draw_stage *rasterize; - struct draw_stage *ia; float wide_point_threshold; /**< convert pnts to tris if larger than this */ float wide_line_threshold; /**< convert lines to tris if wider than this */ @@ -331,6 +331,8 @@ struct draw_context struct pipe_query_data_pipeline_statistics statistics; boolean collect_statistics; + struct draw_assembler *ia; + void *driver_private; };