/** * Create new draw module context with gallivm state for LLVM JIT. */ struct draw_context * draw_create_gallivm(struct pipe_context *pipe, struct gallivm_state *gallivm) { struct draw_context *draw = CALLOC_STRUCT( draw_context ); if (draw == NULL) goto fail; #if HAVE_LLVM if (draw_get_option_use_llvm()) { if (!gallivm) { gallivm = gallivm_create(); draw->own_gallivm = gallivm; } if (gallivm) draw->llvm = draw_llvm_create(draw, gallivm); } #endif if (!draw_init(draw)) goto fail; draw->pipe = pipe; return draw; fail: draw_destroy( draw ); return NULL; }
/** * Create new draw module context with gallivm state for LLVM JIT. */ static struct draw_context * draw_create_context(struct pipe_context *pipe, boolean try_llvm) { struct draw_context *draw = CALLOC_STRUCT( draw_context ); if (draw == NULL) goto err_out; #if HAVE_LLVM if (try_llvm && draw_get_option_use_llvm()) { draw->llvm = draw_llvm_create(draw); if (!draw->llvm) goto err_destroy; } #endif draw->pipe = pipe; if (!draw_init(draw)) goto err_destroy; return draw; err_destroy: draw_destroy( draw ); err_out: return NULL; }
/** * Create new draw module context with gallivm state for LLVM JIT. */ static struct draw_context * draw_create_context(struct pipe_context *pipe, void *context, boolean try_llvm) { struct draw_context *draw = CALLOC_STRUCT( draw_context ); if (!draw) goto err_out; /* we need correct cpu caps for disabling denorms in draw_vbo() */ util_cpu_detect(); #if HAVE_LLVM if (try_llvm && draw_get_option_use_llvm()) { draw->llvm = draw_llvm_create(draw, (LLVMContextRef)context); } #endif draw->pipe = pipe; if (!draw_init(draw)) goto err_destroy; draw->ia = draw_prim_assembler_create(draw); if (!draw->ia) goto err_destroy; return draw; err_destroy: draw_destroy( draw ); err_out: return NULL; }
void draw_geometry_shader_prepare(struct draw_geometry_shader *shader, struct draw_context *draw) { #ifdef HAVE_LLVM boolean use_llvm = draw_get_option_use_llvm(); #else boolean use_llvm = FALSE; #endif if (!use_llvm && shader && shader->machine->Tokens != shader->state.tokens) { tgsi_exec_machine_bind_shader(shader->machine, shader->state.tokens, draw->gs.tgsi.sampler); } }
/** * XXX: Results for PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS because there are two * different ways of setting textures, and drivers typically only support one. */ int draw_get_shader_param(unsigned shader, enum pipe_shader_cap param) { #ifdef HAVE_LLVM if (draw_get_option_use_llvm()) { switch(shader) { case PIPE_SHADER_VERTEX: case PIPE_SHADER_GEOMETRY: return gallivm_get_shader_param(param); default: return 0; } } #endif return draw_get_shader_param_no_llvm(shader, param); }
void draw_delete_geometry_shader(struct draw_context *draw, struct draw_geometry_shader *dgs) { if (!dgs) { return; } #ifdef HAVE_LLVM if (draw_get_option_use_llvm()) { struct llvm_geometry_shader *shader = llvm_geometry_shader(dgs); struct draw_gs_llvm_variant_list_item *li; li = first_elem(&shader->variants); while(!at_end(&shader->variants, li)) { struct draw_gs_llvm_variant_list_item *next = next_elem(li); draw_gs_llvm_destroy_variant(li->base); li = next; } assert(shader->variants_cached == 0); if (dgs->llvm_prim_lengths) { unsigned i; for (i = 0; i < dgs->max_out_prims; ++i) { align_free(dgs->llvm_prim_lengths[i]); } FREE(dgs->llvm_prim_lengths); } align_free(dgs->llvm_emitted_primitives); align_free(dgs->llvm_emitted_vertices); align_free(dgs->llvm_prim_ids); align_free(dgs->gs_input); } #endif FREE(dgs->primitive_lengths); FREE((void*) dgs->state.tokens); FREE(dgs); }
struct draw_geometry_shader * draw_create_geometry_shader(struct draw_context *draw, const struct pipe_shader_state *state) { #ifdef HAVE_LLVM boolean use_llvm = draw_get_option_use_llvm(); struct llvm_geometry_shader *llvm_gs; #endif struct draw_geometry_shader *gs; unsigned i; #ifdef HAVE_LLVM if (use_llvm) { llvm_gs = CALLOC_STRUCT(llvm_geometry_shader); if (llvm_gs == NULL) return NULL; gs = &llvm_gs->base; make_empty_list(&llvm_gs->variants); } else #endif { gs = CALLOC_STRUCT(draw_geometry_shader); } if (!gs) return NULL; gs->draw = draw; gs->state = *state; gs->state.tokens = tgsi_dup_tokens(state->tokens); if (!gs->state.tokens) { FREE(gs); return NULL; } tgsi_scan_shader(state->tokens, &gs->info); /* setup the defaults */ gs->input_primitive = PIPE_PRIM_TRIANGLES; gs->output_primitive = PIPE_PRIM_TRIANGLE_STRIP; gs->max_output_vertices = 32; gs->max_out_prims = 0; #ifdef HAVE_LLVM if (use_llvm) { /* TODO: change the input array to handle the following vector length, instead of the currently hardcoded TGSI_NUM_CHANNELS gs->vector_length = lp_native_vector_width / 32;*/ gs->vector_length = TGSI_NUM_CHANNELS; } else #endif { gs->vector_length = 1; } for (i = 0; i < gs->info.num_properties; ++i) { if (gs->info.properties[i].name == TGSI_PROPERTY_GS_INPUT_PRIM) gs->input_primitive = gs->info.properties[i].data[0]; else if (gs->info.properties[i].name == 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_OUTPUT_VERTICES) gs->max_output_vertices = gs->info.properties[i].data[0]; } /* Primitive boundary is bigger than max_output_vertices by one, because * the specification says that the geometry shader should exit if the * number of emitted vertices is bigger or equal to max_output_vertices and * we can't do that because we're running in the SoA mode, which means that * our storing routines will keep getting called on channels that have * overflown. * So we need some scratch area where we can keep writing the overflown * vertices without overwriting anything important or crashing. */ gs->primitive_boundary = gs->max_output_vertices + 1; for (i = 0; i < gs->info.num_outputs; i++) { if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION && gs->info.output_semantic_index[i] == 0) gs->position_output = i; if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_VIEWPORT_INDEX) gs->viewport_index_output = i; if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPDIST) { debug_assert(gs->info.output_semantic_index[i] < PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT); gs->clipdistance_output[gs->info.output_semantic_index[i]] = i; } if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_CULLDIST) { debug_assert(gs->info.output_semantic_index[i] < PIPE_MAX_CLIP_OR_CULL_DISTANCE_ELEMENT_COUNT); gs->culldistance_output[gs->info.output_semantic_index[i]] = i; } } gs->machine = draw->gs.tgsi.machine; #ifdef HAVE_LLVM if (use_llvm) { int vector_size = gs->vector_length * sizeof(float); gs->gs_input = align_malloc(sizeof(struct draw_gs_inputs), 16); memset(gs->gs_input, 0, sizeof(struct draw_gs_inputs)); gs->llvm_prim_lengths = 0; gs->llvm_emitted_primitives = align_malloc(vector_size, vector_size); gs->llvm_emitted_vertices = align_malloc(vector_size, vector_size); gs->llvm_prim_ids = align_malloc(vector_size, vector_size); gs->fetch_outputs = llvm_fetch_gs_outputs; gs->fetch_inputs = llvm_fetch_gs_input; gs->prepare = llvm_gs_prepare; gs->run = llvm_gs_run; gs->jit_context = &draw->llvm->gs_jit_context; llvm_gs->variant_key_size = draw_gs_llvm_variant_key_size( MAX2(gs->info.file_max[TGSI_FILE_SAMPLER]+1, gs->info.file_max[TGSI_FILE_SAMPLER_VIEW]+1)); } else #endif { gs->fetch_outputs = tgsi_fetch_gs_outputs; gs->fetch_inputs = tgsi_fetch_gs_input; gs->prepare = tgsi_gs_prepare; gs->run = tgsi_gs_run; } return gs; }
/** * 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; }