/* * Primitive assembler breaks up adjacency primitives and assembles * the base primitives they represent, e.g. vertices forming * PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY * become vertices forming PIPE_PRIM_TRIANGLES * This is needed because specification says that the adjacency * primitives are only visible in the geometry shader so we need * to get rid of them so that the rest of the pipeline can * process the inputs. */ void draw_prim_assembler_run(struct draw_context *draw, const struct draw_prim_info *input_prims, const struct draw_vertex_info *input_verts, struct draw_prim_info *output_prims, struct draw_vertex_info *output_verts) { struct draw_assembler *asmblr = draw->ia; unsigned start, i; unsigned assembled_prim = u_reduced_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->output_prims = output_prims; asmblr->output_verts = output_verts; asmblr->input_prims = input_prims; asmblr->input_verts = input_verts; asmblr->needs_primid = needs_primid(asmblr->draw); asmblr->primid = 0; asmblr->num_prims = 0; output_prims->linear = TRUE; output_prims->elts = NULL; output_prims->start = 0; output_prims->prim = assembled_prim; output_prims->flags = 0x0; output_prims->primitive_lengths = MALLOC(sizeof(unsigned)); output_prims->primitive_lengths[0] = 0; output_prims->primitive_count = 1; output_verts->vertex_size = input_verts->vertex_size; output_verts->stride = input_verts->stride; output_verts->verts = (struct vertex_header*)MALLOC( input_verts->vertex_size * max_verts); output_verts->count = 0; for (start = i = 0; i < input_prims->primitive_count; start += input_prims->primitive_lengths[i], i++) { unsigned count = input_prims->primitive_lengths[i]; if (input_prims->linear) { assembler_run_linear(asmblr, input_prims, input_verts, start, count); } else { assembler_run_elts(asmblr, input_prims, input_verts, start, count); } } output_prims->primitive_lengths[0] = output_verts->count; output_prims->count = output_verts->count; }
/** * Computes clipper invocation statistics. * * Figures out how many primitives would have been * sent to the clipper given the specified * prim info data. */ void draw_stats_clipper_primitives(struct draw_context *draw, const struct draw_prim_info *prim_info) { if (draw->collect_statistics) { unsigned i; for (i = 0; i < prim_info->primitive_count; i++) { draw->statistics.c_invocations += u_decomposed_prims_for_vertices(prim_info->prim, prim_info->primitive_lengths[i]); } } }
/** * Execute geometry shader. */ int draw_geometry_shader_run(struct draw_geometry_shader *shader, const void *constants[PIPE_MAX_CONSTANT_BUFFERS], const unsigned constants_size[PIPE_MAX_CONSTANT_BUFFERS], const struct draw_vertex_info *input_verts, const struct draw_prim_info *input_prim, const struct tgsi_shader_info *input_info, struct draw_vertex_info *output_verts, struct draw_prim_info *output_prims ) { const float (*input)[4] = (const float (*)[4])input_verts->verts->data; unsigned input_stride = input_verts->vertex_size; unsigned num_outputs = draw_total_gs_outputs(shader->draw); unsigned vertex_size = sizeof(struct vertex_header) + num_outputs * 4 * sizeof(float); unsigned num_input_verts = input_prim->linear ? input_verts->count : input_prim->count; unsigned num_in_primitives = align( MAX2(u_decomposed_prims_for_vertices(input_prim->prim, num_input_verts), u_decomposed_prims_for_vertices(shader->input_primitive, num_input_verts)), shader->vector_length); unsigned max_out_prims = u_decomposed_prims_for_vertices(shader->output_primitive, shader->max_output_vertices) * num_in_primitives; //Assume at least one primitive max_out_prims = MAX2(max_out_prims, 1); output_verts->vertex_size = vertex_size; output_verts->stride = output_verts->vertex_size; /* we allocate exactly one extra vertex per primitive to allow the GS to emit * overflown vertices into some area where they won't harm anyone */ output_verts->verts = (struct vertex_header *)MALLOC(output_verts->vertex_size * max_out_prims * shader->primitive_boundary); #if 0 debug_printf("%s count = %d (in prims # = %d)\n", __FUNCTION__, num_input_verts, num_in_primitives); debug_printf("\tlinear = %d, prim_info->count = %d\n", input_prim->linear, input_prim->count); debug_printf("\tprim pipe = %s, shader in = %s, shader out = %s, max out = %d\n", u_prim_name(input_prim->prim), u_prim_name(shader->input_primitive), u_prim_name(shader->output_primitive), shader->max_output_vertices); #endif shader->emitted_vertices = 0; shader->emitted_primitives = 0; shader->vertex_size = vertex_size; shader->tmp_output = (float (*)[4])output_verts->verts->data; shader->fetched_prim_count = 0; shader->input_vertex_stride = input_stride; shader->input = input; shader->input_info = input_info; FREE(shader->primitive_lengths); shader->primitive_lengths = MALLOC(max_out_prims * sizeof(unsigned)); #ifdef HAVE_LLVM if (draw_get_option_use_llvm()) { shader->gs_output = output_verts->verts; if (max_out_prims > shader->max_out_prims) { unsigned i; if (shader->llvm_prim_lengths) { for (i = 0; i < shader->max_out_prims; ++i) { align_free(shader->llvm_prim_lengths[i]); } FREE(shader->llvm_prim_lengths); } shader->llvm_prim_lengths = MALLOC(max_out_prims * sizeof(unsigned*)); for (i = 0; i < max_out_prims; ++i) { int vector_size = shader->vector_length * sizeof(unsigned); shader->llvm_prim_lengths[i] = align_malloc(vector_size, vector_size); } shader->max_out_prims = max_out_prims; } shader->jit_context->prim_lengths = shader->llvm_prim_lengths; shader->jit_context->emitted_vertices = shader->llvm_emitted_vertices; shader->jit_context->emitted_prims = shader->llvm_emitted_primitives; } #endif shader->prepare(shader, constants, constants_size); if (input_prim->linear) gs_run(shader, input_prim, input_verts, output_prims, output_verts); else gs_run_elts(shader, input_prim, input_verts, output_prims, output_verts); /* Flush the remaining primitives. Will happen if * num_input_primitives % 4 != 0 */ if (shader->fetched_prim_count > 0) { gs_flush(shader); } debug_assert(shader->fetched_prim_count == 0); /* Update prim_info: */ output_prims->linear = TRUE; output_prims->elts = NULL; output_prims->start = 0; output_prims->count = shader->emitted_vertices; output_prims->prim = shader->output_primitive; output_prims->flags = 0x0; output_prims->primitive_lengths = shader->primitive_lengths; output_prims->primitive_count = shader->emitted_primitives; output_verts->count = shader->emitted_vertices; if (shader->draw->collect_statistics) { unsigned i; for (i = 0; i < shader->emitted_primitives; ++i) { shader->draw->statistics.gs_primitives += u_decomposed_prims_for_vertices(shader->output_primitive, shader->primitive_lengths[i]); } } #if 0 debug_printf("GS finished, prims = %d, verts = %d\n", output_prims->primitive_count, output_verts->count); #endif return shader->emitted_vertices; }
static void llvm_pipeline_generic(struct draw_pt_middle_end *middle, const struct draw_fetch_info *fetch_info, const struct draw_prim_info *in_prim_info) { struct llvm_middle_end *fpme = llvm_middle_end(middle); struct draw_context *draw = fpme->draw; struct draw_geometry_shader *gshader = draw->gs.geometry_shader; struct draw_prim_info gs_prim_info; struct draw_vertex_info llvm_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 clipped = 0; llvm_vert_info.count = fetch_info->count; llvm_vert_info.vertex_size = fpme->vertex_size; llvm_vert_info.stride = fpme->vertex_size; llvm_vert_info.verts = (struct vertex_header *) MALLOC(fpme->vertex_size * align(fetch_info->count, lp_native_vector_width / 32)); if (!llvm_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, prim_info->count); draw->statistics.vs_invocations += fetch_info->count; } if (fetch_info->linear) clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context, llvm_vert_info.verts, draw->pt.user.vbuffer, fetch_info->start, fetch_info->count, fpme->vertex_size, draw->pt.vertex_buffer, draw->instance_id, draw->start_index, draw->start_instance); else clipped = fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context, llvm_vert_info.verts, draw->pt.user.vbuffer, fetch_info->elts, draw->pt.user.eltMax, fetch_info->count, fpme->vertex_size, draw->pt.vertex_buffer, draw->instance_id, draw->pt.user.eltBias, draw->start_instance); /* Finished with fetch and vs: */ fetch_info = NULL; vert_info = &llvm_vert_info; if ((opt & PT_SHADE) && gshader) { struct draw_vertex_shader *vshader = draw->vs.vertex_shader; 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; } /* stream output needs to be done before clipping */ 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 ((opt & PT_SHADE) && gshader) { clipped = draw_pt_post_vs_run( fpme->post_vs, vert_info, prim_info ); } if (clipped) { opt |= PT_PIPELINE; } /* Do we need to run the pipeline? Now will come here if clipped */ if (opt & PT_PIPELINE) { pipeline( fpme, vert_info, prim_info ); } else { emit( fpme->emit, vert_info, prim_info ); } } FREE(vert_info->verts); if (free_prim_info) { FREE(prim_info->primitive_lengths); } }