X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fdraw%2Fdraw_pt_fetch_shade_pipeline.c;h=84f86ae75ee6118e42a7f3dbd96d755d5e55a797;hb=2f13f28120fdfe2f5a64e87b4ec19db94bf63713;hp=df6c265b7ec9026a95cd6383b1d70adb242efcbb;hpb=af09ba96e9e2d783fb0538a82513716c1c9aed3b;p=mesa.git 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 df6c265b7ec..84f86ae75ee 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c @@ -27,12 +27,14 @@ #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_prim.h" #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 "translate/translate.h" +#include "draw/draw_gs.h" struct fetch_pipeline_middle_end { @@ -40,16 +42,22 @@ struct fetch_pipeline_middle_end { struct draw_context *draw; struct pt_emit *emit; + struct pt_so_emit *so_emit; struct pt_fetch *fetch; struct pt_post_vs *post_vs; unsigned vertex_data_offset; unsigned vertex_size; - unsigned prim; + unsigned input_prim; unsigned opt; }; +/** + * Prepare/validate middle part of the vertex pipeline. + * NOTE: if you change this function, also look at the LLVM + * function llvm_middle_end_prepare() for similar changes. + */ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, unsigned prim, unsigned opt, @@ -58,6 +66,12 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_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; + unsigned i; + unsigned instance_id_index = ~0; + + const unsigned gs_out_prim = (gs ? gs->output_primitive : + u_assembled_prim(prim)); /* Add one to num_outputs because the pipeline occasionally tags on * an additional texcoord, eg for AA lines. @@ -65,7 +79,20 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, unsigned nr = MAX2( vs->info.num_inputs, vs->info.num_outputs + 1 ); - fpme->prim = prim; + if (gs) { + nr = MAX2(nr, gs->info.num_outputs + 1); + } + + /* Scan for instanceID system value. + */ + for (i = 0; i < vs->info.num_inputs; i++) { + if (vs->info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) { + instance_id_index = i; + break; + } + } + + fpme->input_prim = prim; fpme->opt = opt; /* Always leave room for the vertex header whether we need it or @@ -78,259 +105,330 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, draw_pt_fetch_prepare( fpme->fetch, vs->info.num_inputs, - fpme->vertex_size ); - /* XXX: it's not really gl rasterization rules we care about here, - * but gl vs dx9 clip spaces. - */ + fpme->vertex_size, + instance_id_index ); draw_pt_post_vs_prepare( fpme->post_vs, - (boolean)draw->bypass_clipping, - (boolean)(draw->identity_viewport || - draw->rasterizer->bypass_vs_clip_and_viewport), - (boolean)draw->rasterizer->gl_rasterization_rules ); - + draw->clip_xy, + draw->clip_z, + draw->clip_user, + draw->guard_band_xy, + draw->identity_viewport, + draw->rasterizer->clip_halfz, + (draw->vs.edgeflag_output ? TRUE : FALSE) ); + + draw_pt_so_emit_prepare( fpme->so_emit, FALSE ); if (!(opt & PT_PIPELINE)) { - draw_pt_emit_prepare( fpme->emit, - prim, + draw_pt_emit_prepare( fpme->emit, + gs_out_prim, max_vertices ); - *max_vertices = MAX2( *max_vertices, - DRAW_PIPE_MAX_VERTICES ); + *max_vertices = MAX2( *max_vertices, 4096 ); } else { - *max_vertices = DRAW_PIPE_MAX_VERTICES; + /* limit max fetches by limiting max_vertices */ + *max_vertices = 4096; } - /* return even number */ - *max_vertices = *max_vertices & ~1; - /* No need to prepare the shader. */ vs->prepare(vs, draw); } - -static void fetch_pipeline_run( struct draw_pt_middle_end *middle, - const unsigned *fetch_elts, - unsigned fetch_count, - const ushort *draw_elts, - unsigned draw_count ) +static void +fetch_pipeline_bind_parameters(struct draw_pt_middle_end *middle) { - struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; - struct draw_context *draw = fpme->draw; - struct draw_vertex_shader *shader = draw->vs.vertex_shader; - unsigned opt = fpme->opt; - unsigned alloc_count = align( fetch_count, 4 ); + /* No-op since the vertex shader executor and drawing pipeline + * just grab the constants, viewport, etc. from the draw context state. + */ +} - struct vertex_header *pipeline_verts = - (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); - if (!pipeline_verts) { - /* Not much we can do here - just skip the rendering. - */ - assert(0); - return; +static void fetch( struct pt_fetch *fetch, + const struct draw_fetch_info *fetch_info, + char *output) +{ + if (fetch_info->linear) { + draw_pt_fetch_run_linear( fetch, + fetch_info->start, + fetch_info->count, + output ); } - - /* Fetch into our vertex buffer - */ - draw_pt_fetch_run( fpme->fetch, - fetch_elts, - fetch_count, - (char *)pipeline_verts ); - - /* Run the shader, note that this overwrites the data[] parts of - * the pipeline verts. If there is no shader, eg if - * bypass_vs_clip_and_viewport, then the inputs == outputs, and are - * already in the correct place. - */ - if (opt & PT_SHADE) - { - shader->run_linear(shader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - (const float (*)[4])draw->pt.user.constants, - fetch_count, - fpme->vertex_size, - fpme->vertex_size); + else { + draw_pt_fetch_run( fetch, + fetch_info->elts, + fetch_info->count, + output ); } +} - if (draw_pt_post_vs_run( fpme->post_vs, - pipeline_verts, - fetch_count, - fpme->vertex_size )) - { - opt |= PT_PIPELINE; - } - /* Do we need to run the pipeline? - */ - if (opt & PT_PIPELINE) { +static void pipeline(struct fetch_pipeline_middle_end *fpme, + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info) +{ + if (prim_info->linear) + draw_pipeline_run_linear( fpme->draw, + vert_info, + prim_info); + else draw_pipeline_run( fpme->draw, - fpme->prim, - pipeline_verts, - fetch_count, - fpme->vertex_size, - draw_elts, - draw_count ); + vert_info, + prim_info ); +} + +static void emit(struct pt_emit *emit, + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info) +{ + if (prim_info->linear) { + draw_pt_emit_linear(emit, vert_info, prim_info); } else { - draw_pt_emit( fpme->emit, - (const float (*)[4])pipeline_verts->data, - fetch_count, - fpme->vertex_size, - draw_elts, - draw_count ); + draw_pt_emit(emit, vert_info, prim_info); } +} - FREE(pipeline_verts); +static void draw_vertex_shader_run(struct draw_vertex_shader *vshader, + const void *constants[PIPE_MAX_CONSTANT_BUFFERS], + unsigned const_size[PIPE_MAX_CONSTANT_BUFFERS], + const struct draw_vertex_info *input_verts, + struct draw_vertex_info *output_verts ) +{ + output_verts->vertex_size = input_verts->vertex_size; + output_verts->stride = input_verts->vertex_size; + output_verts->count = input_verts->count; + output_verts->verts = + (struct vertex_header *)MALLOC(output_verts->vertex_size * + align(output_verts->count, 4)); + + vshader->run_linear(vshader, + (const float (*)[4])input_verts->verts->data, + ( float (*)[4])output_verts->verts->data, + constants, + const_size, + input_verts->count, + input_verts->vertex_size, + input_verts->vertex_size); } - -static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, - unsigned start, - unsigned count) +static void fetch_pipeline_generic( struct draw_pt_middle_end *middle, + const struct draw_fetch_info *fetch_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; - struct draw_vertex_shader *shader = draw->vs.vertex_shader; + struct draw_vertex_shader *vshader = draw->vs.vertex_shader; + struct draw_geometry_shader *gshader = draw->gs.geometry_shader; + struct draw_prim_info gs_prim_info; + struct draw_vertex_info fetched_vert_info; + 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; - unsigned alloc_count = align( count, 4 ); - struct vertex_header *pipeline_verts = - (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); - - if (!pipeline_verts) { - /* Not much we can do here - just skip the rendering. - */ + fetched_vert_info.count = fetch_info->count; + fetched_vert_info.vertex_size = fpme->vertex_size; + fetched_vert_info.stride = fpme->vertex_size; + fetched_vert_info.verts = + (struct vertex_header *)MALLOC(fpme->vertex_size * + align(fetch_info->count, 4)); + if (!fetched_vert_info.verts) { assert(0); return; } + if (draw->collect_statistics) { + draw->statistics.ia_vertices += prim_info->count; + draw->statistics.ia_primitives += + u_decomposed_prims_for_vertices(prim_info->prim, fetch_info->count); + draw->statistics.vs_invocations += fetch_info->count; + } + + /* Fetch into our vertex buffer. + */ + fetch( fpme->fetch, fetch_info, (char *)fetched_vert_info.verts ); - /* Fetch into our vertex buffer + /* Finished with fetch: */ - draw_pt_fetch_run_linear( fpme->fetch, - start, - count, - (char *)pipeline_verts ); + fetch_info = NULL; + vert_info = &fetched_vert_info; /* Run the shader, note that this overwrites the data[] parts of - * the pipeline verts. If there is no shader, ie if - * bypass_vs_clip_and_viewport, then the inputs == outputs, and are - * already in the correct place. + * the pipeline verts. */ - if (opt & PT_SHADE) - { - shader->run_linear(shader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - (const float (*)[4])draw->pt.user.constants, - count, - fpme->vertex_size, - fpme->vertex_size); + if (fpme->opt & PT_SHADE) { + draw_vertex_shader_run(vshader, + draw->pt.user.vs_constants, + draw->pt.user.vs_constants_size, + vert_info, + &vs_vert_info); + + FREE(vert_info->verts); + vert_info = &vs_vert_info; } - if (draw_pt_post_vs_run( fpme->post_vs, - pipeline_verts, - count, - fpme->vertex_size )) - { - opt |= PT_PIPELINE; + if ((fpme->opt & PT_SHADE) && gshader) { + draw_geometry_shader_run(gshader, + draw->pt.user.gs_constants, + draw->pt.user.gs_constants_size, + vert_info, + prim_info, + &vshader->info, + &gs_vert_info, + &gs_prim_info); + + 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; + } + } } + if (prim_info->count == 0) { + debug_printf("GS/IA didn't emit any vertices!\n"); + + FREE(vert_info->verts); + if (free_prim_info) { + FREE(prim_info->primitive_lengths); + } + return; + } + - /* Do we need to run the pipeline? + /* Stream output needs to be done before clipping. + * + * XXX: Stream output surely needs to respect the prim_info->elt + * lists. */ - if (opt & PT_PIPELINE) { - draw_pipeline_run_linear( fpme->draw, - fpme->prim, - pipeline_verts, - count, - fpme->vertex_size); + draw_pt_so_emit( fpme->so_emit, vert_info, prim_info ); + + draw_stats_clipper_primitives(draw, prim_info); + + /* + * if there's no position, need to stop now, or the latter stages + * will try to access non-existent position output. + */ + if (draw_current_shader_position_output(draw) != -1) { + + if (draw_pt_post_vs_run( fpme->post_vs, vert_info, prim_info )) + { + opt |= PT_PIPELINE; + } + + /* Do we need to run the pipeline? + */ + if (opt & PT_PIPELINE) { + pipeline( fpme, vert_info, prim_info ); + } + else { + emit( fpme->emit, vert_info, prim_info ); + } } - else { - draw_pt_emit_linear( fpme->emit, - (const float (*)[4])pipeline_verts->data, - fpme->vertex_size, - count ); + FREE(vert_info->verts); + if (free_prim_info) { + FREE(prim_info->primitive_lengths); } - - FREE(pipeline_verts); } +static void fetch_pipeline_run( struct draw_pt_middle_end *middle, + const unsigned *fetch_elts, + unsigned fetch_count, + const ushort *draw_elts, + unsigned draw_count, + unsigned prim_flags ) +{ + struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; + struct draw_fetch_info fetch_info; + struct draw_prim_info prim_info; + + fetch_info.linear = FALSE; + fetch_info.start = 0; + fetch_info.elts = fetch_elts; + fetch_info.count = fetch_count; + + prim_info.linear = FALSE; + prim_info.start = 0; + prim_info.count = draw_count; + prim_info.elts = draw_elts; + prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; + prim_info.primitive_count = 1; + prim_info.primitive_lengths = &draw_count; + + fetch_pipeline_generic( middle, &fetch_info, &prim_info ); +} -static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle, - unsigned start, - unsigned count, - const ushort *draw_elts, - unsigned draw_count ) +static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, + unsigned start, + unsigned count, + unsigned prim_flags) { struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; - struct draw_context *draw = fpme->draw; - struct draw_vertex_shader *shader = draw->vs.vertex_shader; - unsigned opt = fpme->opt; - unsigned alloc_count = align( count, 4 ); + struct draw_fetch_info fetch_info; + struct draw_prim_info prim_info; + + fetch_info.linear = TRUE; + fetch_info.start = start; + fetch_info.count = count; + fetch_info.elts = NULL; + + prim_info.linear = TRUE; + prim_info.start = 0; + prim_info.count = count; + prim_info.elts = NULL; + prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; + prim_info.primitive_count = 1; + prim_info.primitive_lengths = &count; + + fetch_pipeline_generic( middle, &fetch_info, &prim_info ); +} - struct vertex_header *pipeline_verts = - (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count); - if (!pipeline_verts) - return FALSE; - /* Fetch into our vertex buffer - */ - draw_pt_fetch_run_linear( fpme->fetch, - start, - count, - (char *)pipeline_verts ); +static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle, + unsigned start, + unsigned count, + const ushort *draw_elts, + unsigned draw_count, + unsigned prim_flags ) +{ + struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; + struct draw_fetch_info fetch_info; + struct draw_prim_info prim_info; - /* Run the shader, note that this overwrites the data[] parts of - * the pipeline verts. If there is no shader, ie if - * bypass_vs_clip_and_viewport, then the inputs == outputs, and are - * already in the correct place. - */ - if (opt & PT_SHADE) - { - shader->run_linear(shader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - (const float (*)[4])draw->pt.user.constants, - count, - fpme->vertex_size, - fpme->vertex_size); - } + fetch_info.linear = TRUE; + fetch_info.start = start; + fetch_info.count = count; + fetch_info.elts = NULL; - if (draw_pt_post_vs_run( fpme->post_vs, - pipeline_verts, - count, - fpme->vertex_size )) - { - opt |= PT_PIPELINE; - } + prim_info.linear = FALSE; + prim_info.start = 0; + prim_info.count = draw_count; + prim_info.elts = draw_elts; + prim_info.prim = fpme->input_prim; + prim_info.flags = prim_flags; + prim_info.primitive_count = 1; + prim_info.primitive_lengths = &draw_count; - /* Do we need to run the pipeline? - */ - if (opt & PT_PIPELINE) { - draw_pipeline_run( fpme->draw, - fpme->prim, - pipeline_verts, - count, - fpme->vertex_size, - draw_elts, - draw_count ); - } - else { - draw_pt_emit( fpme->emit, - (const float (*)[4])pipeline_verts->data, - count, - fpme->vertex_size, - draw_elts, - draw_count ); - } + fetch_pipeline_generic( middle, &fetch_info, &prim_info ); - FREE(pipeline_verts); return TRUE; } @@ -351,6 +449,9 @@ static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle ) if (fpme->emit) draw_pt_emit_destroy( fpme->emit ); + if (fpme->so_emit) + draw_pt_so_emit_destroy( fpme->so_emit ); + if (fpme->post_vs) draw_pt_post_vs_destroy( fpme->post_vs ); @@ -365,6 +466,7 @@ struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context * goto fail; fpme->base.prepare = fetch_pipeline_prepare; + fpme->base.bind_parameters = fetch_pipeline_bind_parameters; fpme->base.run = fetch_pipeline_run; fpme->base.run_linear = fetch_pipeline_linear_run; fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts; @@ -382,7 +484,11 @@ struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context * goto fail; fpme->emit = draw_pt_emit_create( draw ); - if (!fpme->emit) + if (!fpme->emit) + goto fail; + + fpme->so_emit = draw_pt_so_emit_create( draw ); + if (!fpme->so_emit) goto fail; return &fpme->base;