Ejemplo n.º 1
0
/*
 * 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;
   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;

   output_prims->linear = TRUE;
   output_prims->elts = NULL;
   output_prims->start = 0;
   output_prims->prim = u_assembled_prim(input_prims->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;
}
/**
 * Prepare/validate middle part of the vertex pipeline.
 * NOTE: if you change this function, also look at the non-LLVM
 * function fetch_pipeline_prepare() for similar changes.
 */
static void
llvm_middle_end_prepare( struct draw_pt_middle_end *middle,
                         unsigned in_prim,
                         unsigned opt,
                         unsigned *max_vertices )
{
   struct llvm_middle_end *fpme = llvm_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;
   const unsigned out_prim = gs ? gs->output_primitive :
      u_assembled_prim(in_prim);
   unsigned point_clip = draw->rasterizer->fill_front == PIPE_POLYGON_MODE_POINT ||
                         out_prim == PIPE_PRIM_POINTS;
   unsigned nr;

   fpme->input_prim = in_prim;
   fpme->opt = opt;

   draw_pt_post_vs_prepare( fpme->post_vs,
                            draw->clip_xy,
                            draw->clip_z,
                            draw->clip_user,
                            point_clip ? draw->guard_band_points_xy :
                                         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, gs == NULL );

   if (!(opt & PT_PIPELINE)) {
      draw_pt_emit_prepare( fpme->emit,
			    out_prim,
                            max_vertices );

      *max_vertices = MAX2( *max_vertices, 4096 );
   }
   else {
      /* limit max fetches by limiting max_vertices */
      *max_vertices = 4096;
   }

   /* Get the number of float[4] attributes per vertex.
    * Note: this must be done after draw_pt_emit_prepare() since that
    * can effect the vertex size.
    */
   nr = MAX2(vs->info.num_inputs, draw_total_vs_outputs(draw));

   /* Always leave room for the vertex header whether we need it or
    * not.  It's hard to get rid of it in particular because of the
    * viewport code in draw_pt_post_vs.c.
    */
   fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);

   /* Get the number of float[4] attributes per vertex.
    * Note: this must be done after draw_pt_emit_prepare() since that
    * can effect the vertex size.
    */
   nr = MAX2(vs->info.num_inputs, draw_total_vs_outputs(draw));

   /* Always leave room for the vertex header whether we need it or
    * not.  It's hard to get rid of it in particular because of the
    * viewport code in draw_pt_post_vs.c.
    */
   fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);

   /* return even number */
   *max_vertices = *max_vertices & ~1;

   /* Find/create the vertex shader variant */
   {
      struct draw_llvm_variant_key *key;
      struct draw_llvm_variant *variant = NULL;
      struct draw_llvm_variant_list_item *li;
      struct llvm_vertex_shader *shader = llvm_vertex_shader(vs);
      char store[DRAW_LLVM_MAX_VARIANT_KEY_SIZE];
      unsigned i;

      key = draw_llvm_make_variant_key(fpme->llvm, store);

      /* Search shader's list of variants for the key */
      li = first_elem(&shader->variants);
      while (!at_end(&shader->variants, li)) {
         if (memcmp(&li->base->key, key, shader->variant_key_size) == 0) {
            variant = li->base;
            break;
         }
         li = next_elem(li);
      }

      if (variant) {
         /* found the variant, move to head of global list (for LRU) */
         move_to_head(&fpme->llvm->vs_variants_list,
                      &variant->list_item_global);
      }
      else {
         /* Need to create new variant */

         /* First check if we've created too many variants.  If so, free
          * 25% of the LRU to avoid using too much memory.
          */
         if (fpme->llvm->nr_variants >= DRAW_MAX_SHADER_VARIANTS) {
            /*
             * XXX: should we flush here ?
             */
            for (i = 0; i < DRAW_MAX_SHADER_VARIANTS / 4; i++) {
               struct draw_llvm_variant_list_item *item;
               if (is_empty_list(&fpme->llvm->vs_variants_list)) {
                  break;
               }
               item = last_elem(&fpme->llvm->vs_variants_list);
               assert(item);
               assert(item->base);
               draw_llvm_destroy_variant(item->base);
            }
         }

         variant = draw_llvm_create_variant(fpme->llvm, nr, key);

         if (variant) {
            insert_at_head(&shader->variants, &variant->list_item_local);
            insert_at_head(&fpme->llvm->vs_variants_list,
                           &variant->list_item_global);
            fpme->llvm->nr_variants++;
            shader->variants_cached++;
         }
      }

      fpme->current_variant = variant;
   }

   if (gs) {
      llvm_middle_end_prepare_gs(fpme);
   }
}