geometry shaders: make gs work with changable primitives and variable number of vertices

lots and lots of fixes for geometry shaders. in particular now we work when the gs
emits a different primitive than the one the pipeline was started with and also
we work when gs emits more vertices than would fit in the original buffer.
This commit is contained in:
Zack Rusin 2010-06-09 11:13:34 -04:00
parent cec9955acc
commit d4ef0f6c67
14 changed files with 152 additions and 99 deletions

View file

@ -112,7 +112,7 @@ draw_create_geometry_shader(struct draw_context *draw,
TGSI_PROPERTY_GS_OUTPUT_PRIM)
gs->output_primitive = gs->info.properties[i].data[0];
else if (gs->info.properties[i].name ==
TGSI_PROPERTY_GS_MAX_VERTICES)
TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES)
gs->max_output_vertices = gs->info.properties[i].data[0];
}
@ -247,7 +247,7 @@ static void draw_fetch_geometry_input(struct draw_geometry_shader *shader,
}
}
}
/*#define DEBUG_OUTPUTS 1*/
static INLINE void
draw_geometry_fetch_outputs(struct draw_geometry_shader *shader,
int num_primitives,
@ -263,8 +263,11 @@ draw_geometry_fetch_outputs(struct draw_geometry_shader *shader,
* the first one
unsigned prim_count =
mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0];*/
shader->emitted_primitives += num_primitives;
for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) {
unsigned num_verts_per_prim = machine->Primitives[0];
shader->emitted_vertices += num_verts_per_prim;
for (j = 0; j < num_verts_per_prim; j++) {
int idx = (prim_idx * num_verts_per_prim + j) *
shader->info.num_outputs;
@ -290,13 +293,13 @@ draw_geometry_fetch_outputs(struct draw_geometry_shader *shader,
}
}
void draw_geometry_shader_run(struct draw_geometry_shader *shader,
const float (*input)[4],
float (*output)[4],
const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
unsigned count,
unsigned input_stride,
unsigned vertex_size)
int draw_geometry_shader_run(struct draw_geometry_shader *shader,
const float (*input)[4],
float (*output)[4],
const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
unsigned count,
unsigned input_stride,
unsigned vertex_size)
{
struct tgsi_exec_machine *machine = shader->machine;
unsigned int i;
@ -304,6 +307,9 @@ void draw_geometry_shader_run(struct draw_geometry_shader *shader,
unsigned num_primitives = count/num_vertices;
unsigned inputs_from_vs = 0;
shader->emitted_vertices = 0;
shader->emitted_primitives = 0;
for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) {
machine->Consts[i] = constants[i];
}
@ -331,6 +337,7 @@ void draw_geometry_shader_run(struct draw_geometry_shader *shader,
draw_geometry_fetch_outputs(shader, max_primitives,
output, vertex_size);
}
return shader->emitted_vertices;
}
void draw_geometry_shader_delete(struct draw_geometry_shader *shader)

View file

@ -54,18 +54,26 @@ struct draw_geometry_shader {
unsigned input_primitive;
unsigned output_primitive;
unsigned emitted_vertices;
unsigned emitted_primitives;
/* Extracted from shader:
*/
const float (*immediates)[4];
};
void draw_geometry_shader_run(struct draw_geometry_shader *shader,
const float (*input)[4],
float (*output)[4],
const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
unsigned count,
unsigned input_stride,
unsigned output_stride);
/*
* Returns the number of vertices emitted.
* The vertex shader can emit any number of vertices as long as it's
* smaller than the GS_MAX_OUTPUT_VERTICES shader property.
*/
int draw_geometry_shader_run(struct draw_geometry_shader *shader,
const float (*input)[4],
float (*output)[4],
const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
unsigned count,
unsigned input_stride,
unsigned output_stride);
void draw_geometry_shader_prepare(struct draw_geometry_shader *shader,
struct draw_context *draw);

View file

@ -31,6 +31,7 @@
*/
#include "draw/draw_context.h"
#include "draw/draw_gs.h"
#include "draw/draw_private.h"
#include "draw/draw_pt.h"
#include "tgsi/tgsi_dump.h"
@ -68,35 +69,39 @@ draw_pt_arrays(struct draw_context *draw,
struct draw_pt_front_end *frontend = NULL;
struct draw_pt_middle_end *middle = NULL;
unsigned opt = 0;
unsigned out_prim = prim;
/* Sanitize primitive length:
*/
{
unsigned first, incr;
draw_pt_split_prim(prim, &first, &incr);
count = trim(count, first, incr);
count = trim(count, first, incr);
if (count < first)
return TRUE;
}
if (draw->gs.geometry_shader) {
out_prim = draw->gs.geometry_shader->output_primitive;
}
if (!draw->force_passthrough) {
if (!draw->render) {
opt |= PT_PIPELINE;
}
if (draw_need_pipeline(draw,
draw->rasterizer,
prim)) {
out_prim)) {
opt |= PT_PIPELINE;
}
if (!draw->bypass_clipping && !draw->pt.test_fse) {
opt |= PT_CLIPTEST;
}
opt |= PT_SHADE;
}
if (draw->pt.middle.llvm && !draw->gs.geometry_shader) {
middle = draw->pt.middle.llvm;
} else {
@ -117,9 +122,9 @@ draw_pt_arrays(struct draw_context *draw,
frontend = draw->pt.front.varray;
}
frontend->prepare( frontend, prim, middle, opt );
frontend->prepare( frontend, prim, out_prim, middle, opt );
frontend->run(frontend,
frontend->run(frontend,
draw_pt_elt_func(draw),
draw_pt_elt_ptr(draw, start),
draw->pt.user.eltBias,

View file

@ -60,7 +60,8 @@ struct draw_context;
*/
struct draw_pt_front_end {
void (*prepare)( struct draw_pt_front_end *,
unsigned prim,
unsigned input_prim,
unsigned output_prim,
struct draw_pt_middle_end *,
unsigned opt );
@ -84,7 +85,8 @@ struct draw_pt_front_end {
*/
struct draw_pt_middle_end {
void (*prepare)( struct draw_pt_middle_end *,
unsigned prim,
unsigned input_prim,
unsigned output_prim,
unsigned opt,
unsigned *max_vertices );

View file

@ -90,6 +90,7 @@ struct fetch_emit_middle_end {
static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
unsigned prim,
unsigned out_prim,
unsigned opt,
unsigned *max_vertices )
{
@ -102,7 +103,7 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
ok = draw->render->set_primitive( draw->render,
prim );
out_prim );
if (!ok) {
assert(0);
return;

View file

@ -67,9 +67,9 @@ struct fetch_shade_emit {
static void fse_prepare( struct draw_pt_middle_end *middle,
unsigned prim,
unsigned in_prim,
unsigned out_prim,
unsigned opt,
unsigned *max_vertices )
{
@ -79,10 +79,10 @@ static void fse_prepare( struct draw_pt_middle_end *middle,
const struct vertex_info *vinfo;
unsigned i;
unsigned nr_vbs = 0;
if (!draw->render->set_primitive( draw->render,
prim )) {
if (!draw->render->set_primitive( draw->render,
out_prim )) {
assert(0);
return;
}
@ -90,7 +90,6 @@ static void fse_prepare( struct draw_pt_middle_end *middle,
/* Must do this after set_primitive() above:
*/
fse->vinfo = vinfo = draw->render->get_vertex_info(draw->render);
fse->key.output_stride = vinfo->size * 4;

View file

@ -46,13 +46,15 @@ struct fetch_pipeline_middle_end {
unsigned vertex_data_offset;
unsigned vertex_size;
unsigned prim;
unsigned input_prim;
unsigned output_prim;
unsigned opt;
};
static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
unsigned prim,
unsigned in_prim,
unsigned out_prim,
unsigned opt,
unsigned *max_vertices )
{
@ -77,7 +79,8 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
}
}
fpme->prim = prim;
fpme->input_prim = in_prim;
fpme->output_prim = out_prim;
fpme->opt = opt;
/* Always leave room for the vertex header whether we need it or
@ -99,13 +102,13 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
(boolean)draw->bypass_clipping,
(boolean)draw->identity_viewport,
(boolean)draw->rasterizer->gl_rasterization_rules,
(draw->vs.edgeflag_output ? true : false) );
(draw->vs.edgeflag_output ? true : false) );
draw_pt_so_emit_prepare( fpme->so_emit, prim );
draw_pt_so_emit_prepare( fpme->so_emit, out_prim );
if (!(opt & PT_PIPELINE)) {
draw_pt_emit_prepare( fpme->emit,
prim,
draw_pt_emit_prepare( fpme->emit,
out_prim,
max_vertices );
*max_vertices = MAX2( *max_vertices,
@ -136,9 +139,15 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
unsigned opt = fpme->opt;
struct vertex_header *pipeline_verts;
unsigned alloc_count = align( fetch_count, 4 );
struct vertex_header *pipeline_verts =
if (draw->gs.geometry_shader &&
draw->gs.geometry_shader->max_output_vertices > fetch_count) {
alloc_count = align(draw->gs.geometry_shader->max_output_vertices, 4);
}
pipeline_verts =
(struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
if (!pipeline_verts) {
@ -168,13 +177,14 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
fpme->vertex_size,
fpme->vertex_size);
if (gshader)
draw_geometry_shader_run(gshader,
(const float (*)[4])pipeline_verts->data,
( float (*)[4])pipeline_verts->data,
draw->pt.user.gs_constants,
fetch_count,
fpme->vertex_size,
fpme->vertex_size);
fetch_count =
draw_geometry_shader_run(gshader,
(const float (*)[4])pipeline_verts->data,
( float (*)[4])pipeline_verts->data,
draw->pt.user.gs_constants,
fetch_count,
fpme->vertex_size,
fpme->vertex_size);
}
/* stream output needs to be done before clipping */
@ -195,7 +205,7 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
fpme->prim,
fpme->output_prim,
pipeline_verts,
fetch_count,
fpme->vertex_size,
@ -225,9 +235,14 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
struct draw_vertex_shader *shader = draw->vs.vertex_shader;
struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
unsigned opt = fpme->opt;
struct vertex_header *pipeline_verts;
unsigned alloc_count = align( count, 4 );
struct vertex_header *pipeline_verts =
if (geometry_shader && geometry_shader->max_output_vertices > count) {
alloc_count = align(geometry_shader->max_output_vertices, 4);
}
pipeline_verts =
(struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
if (!pipeline_verts) {
@ -258,13 +273,13 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
fpme->vertex_size);
if (geometry_shader)
draw_geometry_shader_run(geometry_shader,
(const float (*)[4])pipeline_verts->data,
( float (*)[4])pipeline_verts->data,
draw->pt.user.gs_constants,
count,
fpme->vertex_size,
fpme->vertex_size);
count = draw_geometry_shader_run(geometry_shader,
(const float (*)[4])pipeline_verts->data,
( float (*)[4])pipeline_verts->data,
draw->pt.user.gs_constants,
count,
fpme->vertex_size,
fpme->vertex_size);
}
/* stream output needs to be done before clipping */
@ -285,7 +300,7 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run_linear( fpme->draw,
fpme->prim,
fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size);
@ -313,12 +328,18 @@ static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle
struct draw_vertex_shader *shader = draw->vs.vertex_shader;
struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
unsigned opt = fpme->opt;
struct vertex_header *pipeline_verts;
unsigned alloc_count = align( count, 4 );
struct vertex_header *pipeline_verts =
if (draw->gs.geometry_shader &&
draw->gs.geometry_shader->max_output_vertices > count) {
alloc_count = align(draw->gs.geometry_shader->max_output_vertices, 4);
}
pipeline_verts =
(struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
if (!pipeline_verts)
if (!pipeline_verts)
return FALSE;
/* Fetch into our vertex buffer
@ -342,13 +363,13 @@ static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle
fpme->vertex_size);
if (geometry_shader)
draw_geometry_shader_run(geometry_shader,
(const float (*)[4])pipeline_verts->data,
( float (*)[4])pipeline_verts->data,
draw->pt.user.gs_constants,
count,
fpme->vertex_size,
fpme->vertex_size);
count = draw_geometry_shader_run(geometry_shader,
(const float (*)[4])pipeline_verts->data,
( float (*)[4])pipeline_verts->data,
draw->pt.user.gs_constants,
count,
fpme->vertex_size,
fpme->vertex_size);
}
/* stream output needs to be done before clipping */
@ -369,7 +390,7 @@ static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
fpme->prim,
fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size,

View file

@ -47,7 +47,8 @@ struct llvm_middle_end {
unsigned vertex_data_offset;
unsigned vertex_size;
unsigned prim;
unsigned input_prim;
unsigned output_prim;
unsigned opt;
struct draw_llvm *llvm;
@ -59,7 +60,8 @@ struct llvm_middle_end {
static void
llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
unsigned prim,
unsigned in_prim,
unsigned out_prim,
unsigned opt,
unsigned *max_vertices )
{
@ -86,7 +88,8 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
}
}
fpme->prim = prim;
fpme->input_prim = in_prim;
fpme->output_prim = out_prim;
fpme->opt = opt;
/* Always leave room for the vertex header whether we need it or
@ -105,10 +108,10 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
(boolean)draw->rasterizer->gl_rasterization_rules,
(draw->vs.edgeflag_output ? true : false) );
draw_pt_so_emit_prepare( fpme->so_emit, prim );
draw_pt_so_emit_prepare( fpme->so_emit, out_prim );
if (!(opt & PT_PIPELINE)) {
draw_pt_emit_prepare( fpme->emit,
prim,
out_prim,
max_vertices );
*max_vertices = MAX2( *max_vertices,
@ -195,7 +198,7 @@ static void llvm_middle_end_run( struct draw_pt_middle_end *middle,
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
fpme->prim,
fpme->output_prim,
pipeline_verts,
fetch_count,
fpme->vertex_size,
@ -265,7 +268,7 @@ static void llvm_middle_end_linear_run( struct draw_pt_middle_end *middle,
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run_linear( fpme->draw,
fpme->prim,
fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size);
@ -326,7 +329,7 @@ llvm_middle_end_linear_run_elts( struct draw_pt_middle_end *middle,
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
fpme->prim,
fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size,

View file

@ -103,7 +103,7 @@ static boolean post_vs_cliptest_viewport_gl( struct pt_post_vs *pvs,
unsigned clipped = 0;
unsigned j;
if (0) debug_printf("%s\n", __FUNCTION__);
if (0) debug_printf("%s count, %d\n", __FUNCTION__, count);
for (j = 0; j < count; j++) {
float *position = out->data[pos];

View file

@ -136,7 +136,8 @@ static unsigned decompose_prim[PIPE_PRIM_POLYGON + 1] = {
static void varray_prepare(struct draw_pt_front_end *frontend,
unsigned prim,
unsigned in_prim,
unsigned out_prim,
struct draw_pt_middle_end *middle,
unsigned opt)
{
@ -144,11 +145,12 @@ static void varray_prepare(struct draw_pt_front_end *frontend,
varray->base.run = varray_run;
varray->input_prim = prim;
varray->output_prim = decompose_prim[prim];
varray->input_prim = in_prim;
varray->output_prim = decompose_prim[out_prim];
varray->middle = middle;
middle->prepare(middle, varray->output_prim, opt, &varray->driver_fetch_max );
middle->prepare(middle, varray->input_prim,
varray->output_prim, opt, &varray->driver_fetch_max );
/* check that the max is even */
assert((varray->driver_fetch_max & 1) == 0);

View file

@ -54,7 +54,7 @@ struct vcache_frontend {
unsigned draw_count;
unsigned fetch_count;
unsigned fetch_max;
struct draw_pt_middle_end *middle;
unsigned input_prim;
@ -64,14 +64,15 @@ struct vcache_frontend {
unsigned opt;
};
static INLINE void
static INLINE void
vcache_flush( struct vcache_frontend *vcache )
{
if (vcache->middle_prim != vcache->output_prim) {
vcache->middle_prim = vcache->output_prim;
vcache->middle->prepare( vcache->middle,
vcache->middle_prim,
vcache->opt,
vcache->middle->prepare( vcache->middle,
vcache->input_prim,
vcache->middle_prim,
vcache->opt,
&vcache->fetch_max );
}
@ -356,19 +357,20 @@ vcache_check_run( struct draw_pt_front_end *frontend,
if (0) debug_printf("fetch_count %d fetch_max %d draw_count %d\n", fetch_count,
vcache->fetch_max,
draw_count);
if (elt_bias + max_index >= DRAW_PIPE_MAX_VERTICES ||
fetch_count >= UNDEFINED_VERTEX_ID ||
fetch_count > draw_count) {
if (0) debug_printf("fail\n");
goto fail;
}
if (vcache->middle_prim != vcache->input_prim) {
vcache->middle_prim = vcache->input_prim;
vcache->middle->prepare( vcache->middle,
vcache->middle_prim,
vcache->opt,
vcache->middle->prepare( vcache->middle,
vcache->input_prim,
vcache->middle_prim,
vcache->opt,
&vcache->fetch_max );
}
@ -467,9 +469,10 @@ vcache_check_run( struct draw_pt_front_end *frontend,
static void
static void
vcache_prepare( struct draw_pt_front_end *frontend,
unsigned prim,
unsigned in_prim,
unsigned out_prim,
struct draw_pt_middle_end *middle,
unsigned opt )
{
@ -479,13 +482,13 @@ vcache_prepare( struct draw_pt_front_end *frontend,
{
vcache->base.run = vcache_run_extras;
}
else
else
{
vcache->base.run = vcache_check_run;
}
vcache->input_prim = prim;
vcache->output_prim = u_reduced_prim(prim);
vcache->input_prim = in_prim;
vcache->output_prim = u_reduced_prim(out_prim);
vcache->middle = middle;
vcache->opt = opt;
@ -494,7 +497,8 @@ vcache_prepare( struct draw_pt_front_end *frontend,
* doing so:
*/
vcache->middle_prim = (opt & PT_PIPELINE) ? vcache->output_prim : vcache->input_prim;
middle->prepare( middle, vcache->middle_prim, opt, &vcache->fetch_max );
middle->prepare( middle, vcache->input_prim,
vcache->middle_prim, opt, &vcache->fetch_max );
}

View file

@ -1236,7 +1236,7 @@ static void emit_decls( struct ureg_program *ureg )
assert(ureg->processor == TGSI_PROCESSOR_GEOMETRY);
emit_property(ureg,
TGSI_PROPERTY_GS_MAX_VERTICES,
TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES,
ureg->property_gs_max_vertices);
}

View file

@ -173,7 +173,7 @@ union tgsi_immediate_data
#define TGSI_PROPERTY_GS_INPUT_PRIM 0
#define TGSI_PROPERTY_GS_OUTPUT_PRIM 1
#define TGSI_PROPERTY_GS_MAX_VERTICES 2
#define TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES 2
#define TGSI_PROPERTY_FS_COORD_ORIGIN 3
#define TGSI_PROPERTY_FS_COORD_PIXEL_CENTER 4
#define TGSI_PROPERTY_COUNT 5

View file

@ -1,6 +1,7 @@
GEOM
PROPERTY GS_INPUT_PRIMITIVE TRIANGLES
PROPERTY GS_OUTPUT_PRIMITIVE LINES
PROPERTY GS_OUTPUT_PRIMITIVE LINE_STRIP
PROPERTY GS_MAX_OUTPUT_VERTICES 4
DCL IN[][0], POSITION, CONSTANT
DCL IN[][1], COLOR, CONSTANT
DCL OUT[0], POSITION, CONSTANT