/** * Update fragment state. This is called just prior to drawing * something when some fragment-related state has changed. */ void llvmpipe_update_fs(struct llvmpipe_context *lp) { struct lp_fragment_shader *shader = lp->fs; struct lp_fragment_shader_variant_key key; struct lp_fragment_shader_variant *variant = NULL; struct lp_fs_variant_list_item *li; make_variant_key(lp, shader, &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) { move_to_head(&lp->fs_variants_list, &variant->list_item_global); } else { int64_t t0, t1; int64_t dt; unsigned i; if (lp->nr_fs_variants >= LP_MAX_SHADER_VARIANTS) { struct pipe_context *pipe = &lp->pipe; /* * XXX: we need to flush the context until we have some sort of reference * counting in fragment shaders as they may still be binned * Flushing alone might not be sufficient we need to wait on it too. */ llvmpipe_finish(pipe, __FUNCTION__); for (i = 0; i < LP_MAX_SHADER_VARIANTS / 4; i++) { struct lp_fs_variant_list_item *item = last_elem(&lp->fs_variants_list); remove_shader_variant(lp, item->base); } } t0 = os_time_get(); variant = generate_variant(lp, shader, &key); t1 = os_time_get(); dt = t1 - t0; LP_COUNT_ADD(llvm_compile_time, dt); LP_COUNT_ADD(nr_llvm_compiles, 2); /* emit vs. omit in/out test */ if (variant) { insert_at_head(&shader->variants, &variant->list_item_local); insert_at_head(&lp->fs_variants_list, &variant->list_item_global); lp->nr_fs_variants++; shader->variants_cached++; } } lp_setup_set_fs_variant(lp->setup, variant); }
static void llvm_middle_end_prepare_gs(struct llvm_middle_end *fpme) { struct draw_context *draw = fpme->draw; struct draw_geometry_shader *gs = draw->gs.geometry_shader; struct draw_gs_llvm_variant_key *key; struct draw_gs_llvm_variant *variant = NULL; struct draw_gs_llvm_variant_list_item *li; struct llvm_geometry_shader *shader = llvm_geometry_shader(gs); char store[DRAW_GS_LLVM_MAX_VARIANT_KEY_SIZE]; unsigned i; key = draw_gs_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->gs_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_gs_variants >= DRAW_MAX_SHADER_VARIANTS) { /* * XXX: should we flush here ? */ for (i = 0; i < DRAW_MAX_SHADER_VARIANTS / 4; i++) { struct draw_gs_llvm_variant_list_item *item; if (is_empty_list(&fpme->llvm->gs_variants_list)) { break; } item = last_elem(&fpme->llvm->gs_variants_list); assert(item); assert(item->base); draw_gs_llvm_destroy_variant(item->base); } } variant = draw_gs_llvm_create_variant(fpme->llvm, gs->info.num_outputs, key); if (variant) { insert_at_head(&shader->variants, &variant->list_item_local); insert_at_head(&fpme->llvm->gs_variants_list, &variant->list_item_global); fpme->llvm->nr_gs_variants++; shader->variants_cached++; } } gs->current_variant = variant; }
/** * 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); } }
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 = (struct llvm_middle_end *)middle; struct draw_context *draw = fpme->draw; struct llvm_vertex_shader *shader = llvm_vertex_shader(draw->vs.vertex_shader); char store[DRAW_LLVM_MAX_VARIANT_KEY_SIZE]; struct draw_llvm_variant_key *key; struct draw_llvm_variant *variant = NULL; struct draw_llvm_variant_list_item *li; unsigned i; unsigned instance_id_index = ~0; const unsigned out_prim = (draw->gs.geometry_shader ? draw->gs.geometry_shader->output_primitive : in_prim); /* Add one to num_outputs because the pipeline occasionally tags on * an additional texcoord, eg for AA lines. */ const unsigned nr = MAX2( shader->base.info.num_inputs, shader->base.info.num_outputs + 1 ); /* Scan for instanceID system value. * XXX but we never use instance_id_index?! */ for (i = 0; i < shader->base.info.num_inputs; i++) { if (shader->base.info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) { instance_id_index = i; break; } } fpme->input_prim = in_prim; fpme->opt = opt; /* 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); /* XXX: it's not really gl rasterization rules we care about here, * but gl vs dx9 clip spaces. */ draw_pt_post_vs_prepare( fpme->post_vs, draw->clip_xy, draw->clip_z, draw->clip_user, draw->identity_viewport, (boolean)draw->rasterizer->gl_rasterization_rules, (draw->vs.edgeflag_output ? TRUE : FALSE) ); draw_pt_so_emit_prepare( fpme->so_emit ); 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; } /* return even number */ *max_vertices = *max_vertices & ~1; 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 */ unsigned i; /* 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 = last_elem(&fpme->llvm->vs_variants_list); 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; /*XXX we only support one constant buffer */ fpme->llvm->jit_context.vs_constants = draw->pt.user.vs_constants[0]; fpme->llvm->jit_context.gs_constants = draw->pt.user.gs_constants[0]; fpme->llvm->jit_context.planes = (float (*) [12][4]) draw->pt.user.planes[0]; fpme->llvm->jit_context.viewport = (float *)draw->viewport.scale; }