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.
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];
}
}
}
}
-
+/*#define DEBUG_OUTPUTS 1*/
static INLINE void
draw_geometry_fetch_outputs(struct draw_geometry_shader *shader,
int num_primitives,
* 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;
}
}
-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;
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];
}
draw_geometry_fetch_outputs(shader, max_primitives,
output, vertex_size);
}
+ return shader->emitted_vertices;
}
void draw_geometry_shader_delete(struct draw_geometry_shader *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);
*/
#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"
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 {
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,
*/
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 );
*/
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 );
static void fetch_emit_prepare( struct draw_pt_middle_end *middle,
unsigned prim,
+ unsigned out_prim,
unsigned opt,
unsigned *max_vertices )
{
ok = draw->render->set_primitive( draw->render,
- prim );
+ out_prim );
if (!ok) {
assert(0);
return;
-
static void fse_prepare( struct draw_pt_middle_end *middle,
- unsigned prim,
+ unsigned in_prim,
+ unsigned out_prim,
unsigned opt,
unsigned *max_vertices )
{
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;
}
/* Must do this after set_primitive() above:
*/
fse->vinfo = vinfo = draw->render->get_vertex_info(draw->render);
-
fse->key.output_stride = vinfo->size * 4;
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 )
{
}
}
- 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
(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,
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) {
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 */
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
- fpme->prim,
+ fpme->output_prim,
pipeline_verts,
fetch_count,
fpme->vertex_size,
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) {
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 */
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run_linear( fpme->draw,
- fpme->prim,
+ fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size);
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
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 */
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
- fpme->prim,
+ fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size,
unsigned vertex_data_offset;
unsigned vertex_size;
- unsigned prim;
+ unsigned input_prim;
+ unsigned output_prim;
unsigned opt;
struct draw_llvm *llvm;
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 )
{
}
}
- 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
(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,
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
- fpme->prim,
+ fpme->output_prim,
pipeline_verts,
fetch_count,
fpme->vertex_size,
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run_linear( fpme->draw,
- fpme->prim,
+ fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size);
*/
if (opt & PT_PIPELINE) {
draw_pipeline_run( fpme->draw,
- fpme->prim,
+ fpme->output_prim,
pipeline_verts,
count,
fpme->vertex_size,
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];
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)
{
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);
unsigned draw_count;
unsigned fetch_count;
unsigned fetch_max;
-
+
struct draw_pt_middle_end *middle;
unsigned input_prim;
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 );
}
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 );
}
-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 )
{
{
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;
* 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 );
}
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);
}
#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
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