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 <zackr@vmware.com>
Reviewed-by: Roland Scheidegger <sroland@vmware.com>
This commit is contained in:
Zack Rusin 2013-08-08 15:44:10 -04:00
parent 1d425c4c6d
commit 662a4d4a12
9 changed files with 180 additions and 297 deletions

View file

@ -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 \

View file

@ -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);
}

View file

@ -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)

View file

@ -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.

View file

@ -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;
}

View file

@ -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) {

View file

@ -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);
}

View file

@ -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

View file

@ -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;
};