diff options
Diffstat (limited to 'src/gallium/auxiliary/draw')
38 files changed, 1956 insertions, 779 deletions
diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 61980c3e4f..dab95e5051 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -435,13 +435,18 @@ draw_num_shader_outputs(const struct draw_context *draw) */ void draw_texture_samplers(struct draw_context *draw, + uint shader, uint num_samplers, struct tgsi_sampler **samplers) { - draw->vs.num_samplers = num_samplers; - draw->vs.samplers = samplers; - draw->gs.num_samplers = num_samplers; - draw->gs.samplers = samplers; + if (shader == PIPE_SHADER_VERTEX) { + draw->vs.num_samplers = num_samplers; + draw->vs.samplers = samplers; + } else { + debug_assert(shader == PIPE_SHADER_GEOMETRY); + draw->gs.num_samplers = num_samplers; + draw->gs.samplers = samplers; + } } @@ -574,3 +579,25 @@ draw_get_rasterizer_no_cull( struct draw_context *draw, } return draw->rasterizer_no_cull[scissor][flatshade]; } + +void +draw_set_mapped_so_buffers(struct draw_context *draw, + void *buffers[PIPE_MAX_SO_BUFFERS], + unsigned num_buffers) +{ + int i; + + for (i = 0; i < num_buffers; ++i) { + draw->so.buffers[i] = buffers[i]; + } + draw->so.num_buffers = num_buffers; +} + +void +draw_set_so_state(struct draw_context *draw, + struct pipe_stream_output_state *state) +{ + memcpy(&draw->so.state, + state, + sizeof(struct pipe_stream_output_state)); +} diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h index b905c2f2da..c0122f2aca 100644 --- a/src/gallium/auxiliary/draw/draw_context.h +++ b/src/gallium/auxiliary/draw/draw_context.h @@ -97,6 +97,7 @@ draw_num_shader_outputs(const struct draw_context *draw); void draw_texture_samplers(struct draw_context *draw, + uint shader_type, uint num_samplers, struct tgsi_sampler **samplers); @@ -162,6 +163,14 @@ draw_set_mapped_constant_buffer(struct draw_context *draw, const void *buffer, unsigned size); +void +draw_set_mapped_so_buffers(struct draw_context *draw, + void *buffers[PIPE_MAX_SO_BUFFERS], + unsigned num_buffers); +void +draw_set_so_state(struct draw_context *draw, + struct pipe_stream_output_state *state); + /*********************************************************************** * draw_prim.c diff --git a/src/gallium/auxiliary/draw/draw_gs.c b/src/gallium/auxiliary/draw/draw_gs.c index 131deed43e..79a57a67f3 100644 --- a/src/gallium/auxiliary/draw/draw_gs.c +++ b/src/gallium/auxiliary/draw/draw_gs.c @@ -37,8 +37,8 @@ #include "util/u_math.h" #include "util/u_memory.h" +#include "util/u_prim.h" -#define MAX_PRIM_VERTICES 6 /* fixme: move it from here */ #define MAX_PRIMITIVES 64 @@ -75,6 +75,7 @@ draw_gs_set_constants(struct draw_context *draw, const void *constants, unsigned size) { + /* noop */ } @@ -90,6 +91,7 @@ draw_create_geometry_shader(struct draw_context *draw, if (!gs) return NULL; + gs->draw = draw; gs->state = *state; gs->state.tokens = tgsi_dup_tokens(state->tokens); if (!gs->state.tokens) { @@ -112,7 +114,7 @@ draw_create_geometry_shader(struct draw_context *draw, 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_VERTICES) + TGSI_PROPERTY_GS_MAX_OUTPUT_VERTICES) gs->max_output_vertices = gs->info.properties[i].data[0]; } @@ -154,128 +156,37 @@ void draw_delete_geometry_shader(struct draw_context *draw, FREE(dgs); } -static INLINE int num_vertices_for_prim(int prim) -{ - switch(prim) { - case PIPE_PRIM_POINTS: - return 1; - case PIPE_PRIM_LINES: - return 2; - case PIPE_PRIM_LINE_LOOP: - return 2; - case PIPE_PRIM_LINE_STRIP: - return 2; - case PIPE_PRIM_TRIANGLES: - return 3; - case PIPE_PRIM_TRIANGLE_STRIP: - return 3; - case PIPE_PRIM_TRIANGLE_FAN: - return 3; - case PIPE_PRIM_LINES_ADJACENCY: - case PIPE_PRIM_LINE_STRIP_ADJACENCY: - return 4; - case PIPE_PRIM_TRIANGLES_ADJACENCY: - case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: - return 6; - default: - assert(!"Bad geometry shader input"); - return 0; - } -} - -static void draw_fetch_geometry_input(struct draw_geometry_shader *shader, - int start_primitive, - int num_primitives, - const float (*input_ptr)[4], - unsigned input_vertex_stride, - unsigned inputs_from_vs) -{ - struct tgsi_exec_machine *machine = shader->machine; - unsigned slot, vs_slot, k, j; - unsigned num_vertices = num_vertices_for_prim(shader->input_primitive); - int idx = 0; - - for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; slot++) { - /*debug_printf("Slot = %d (semantic = %d)\n", slot, - shader->info.input_semantic_name[slot]);*/ - if (shader->info.input_semantic_name[slot] == - TGSI_SEMANTIC_PRIMID) { - for (j = 0; j < num_primitives; ++j) { - machine->Inputs[idx].xyzw[0].f[j] = (float)start_primitive + j; - machine->Inputs[idx].xyzw[1].f[j] = (float)start_primitive + j; - machine->Inputs[idx].xyzw[2].f[j] = (float)start_primitive + j; - machine->Inputs[idx].xyzw[3].f[j] = (float)start_primitive + j; - } - ++idx; - } else { - for (j = 0; j < num_primitives; ++j) { - int vidx = idx; - const float (*prim_ptr)[4]; - /*debug_printf(" %d) Prim (num_verts = %d)\n", start_primitive + j, - num_vertices);*/ - prim_ptr = (const float (*)[4])( - (const char *)input_ptr + - (j * num_vertices * input_vertex_stride)); - - for (k = 0; k < num_vertices; ++k, ++vidx) { - const float (*input)[4]; - input = (const float (*)[4])( - (const char *)prim_ptr + (k * input_vertex_stride)); - vidx = k * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot; - /*debug_printf("\t%d)(%d) Input vert:\n", vidx, k);*/ -#if 1 - assert(!util_is_inf_or_nan(input[vs_slot][0])); - assert(!util_is_inf_or_nan(input[vs_slot][1])); - assert(!util_is_inf_or_nan(input[vs_slot][2])); - assert(!util_is_inf_or_nan(input[vs_slot][3])); -#endif - machine->Inputs[vidx].xyzw[0].f[j] = input[vs_slot][0]; - machine->Inputs[vidx].xyzw[1].f[j] = input[vs_slot][1]; - machine->Inputs[vidx].xyzw[2].f[j] = input[vs_slot][2]; - machine->Inputs[vidx].xyzw[3].f[j] = input[vs_slot][3]; -#if 0 - debug_printf("\t\t%d %f %f %f %f\n", slot, - machine->Inputs[vidx].xyzw[0].f[j], - machine->Inputs[vidx].xyzw[1].f[j], - machine->Inputs[vidx].xyzw[2].f[j], - machine->Inputs[vidx].xyzw[3].f[j]); -#endif - } - } - ++vs_slot; - idx += num_vertices; - } - } -} - +/*#define DEBUG_OUTPUTS 1*/ static INLINE void draw_geometry_fetch_outputs(struct draw_geometry_shader *shader, int num_primitives, - float (*output)[4], - unsigned vertex_size) + float (**p_output)[4]) { struct tgsi_exec_machine *machine = shader->machine; unsigned prim_idx, j, slot; + float (*output)[4]; + + output = *p_output; /* Unswizzle all output results. */ - /* FIXME: handle all the primitives produced by the gs, not just - * the first one - unsigned prim_count = - mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0];*/ + for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) { - unsigned num_verts_per_prim = machine->Primitives[0]; + unsigned num_verts_per_prim = machine->Primitives[prim_idx]; + shader->primitive_lengths[prim_idx + shader->emitted_primitives] = + machine->Primitives[prim_idx]; + shader->emitted_vertices += num_verts_per_prim; for (j = 0; j < num_verts_per_prim; j++) { int idx = (prim_idx * num_verts_per_prim + j) * shader->info.num_outputs; #ifdef DEBUG_OUTPUTS - debug_printf("%d) Output vert:\n", idx); + debug_printf("%d) Output vert:\n", idx / shader->info.num_outputs); #endif for (slot = 0; slot < shader->info.num_outputs; slot++) { - output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[prim_idx]; - output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[prim_idx]; - output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[prim_idx]; - output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[prim_idx]; + output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[0]; + output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[0]; + output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[0]; + output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[0]; #ifdef DEBUG_OUTPUTS debug_printf("\t%d: %f %f %f %f\n", slot, output[slot][0], @@ -285,52 +196,286 @@ draw_geometry_fetch_outputs(struct draw_geometry_shader *shader, #endif debug_assert(!util_is_inf_or_nan(output[slot][0])); } - output = (float (*)[4])((char *)output + vertex_size); + output = (float (*)[4])((char *)output + shader->vertex_size); } } + *p_output = output; + shader->emitted_primitives += num_primitives; } -void draw_geometry_shader_run(struct draw_geometry_shader *shader, - const float (*input)[4], - float (*output)[4], - const void *constants[PIPE_MAX_CONSTANT_BUFFERS], - unsigned count, - unsigned input_stride, - unsigned vertex_size) +/*#define DEBUG_INPUTS 1*/ +static void draw_fetch_gs_input(struct draw_geometry_shader *shader, + unsigned *indices, + unsigned num_vertices, + unsigned prim_idx) { struct tgsi_exec_machine *machine = shader->machine; - unsigned int i; - unsigned num_vertices = num_vertices_for_prim(shader->input_primitive); - unsigned num_primitives = count/num_vertices; - unsigned inputs_from_vs = 0; + unsigned slot, vs_slot, i; + unsigned input_vertex_stride = shader->input_vertex_stride; + const float (*input_ptr)[4]; - for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { - machine->Consts[i] = constants[i]; - } + input_ptr = shader->input; - for (i = 0; i < shader->info.num_inputs; ++i) { - if (shader->info.input_semantic_name[i] != TGSI_SEMANTIC_PRIMID) - ++inputs_from_vs; + for (i = 0; i < num_vertices; ++i) { + const float (*input)[4]; +#if DEBUG_INPUTS + debug_printf("%d) vertex index = %d (prim idx = %d)\n", + i, indices[i], prim_idx); +#endif + input = (const float (*)[4])( + (const char *)input_ptr + (indices[i] * input_vertex_stride)); + for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; ++slot) { + unsigned idx = i * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot; + if (shader->info.input_semantic_name[slot] == TGSI_SEMANTIC_PRIMID) { + machine->Inputs[idx].xyzw[0].f[prim_idx] = + (float)shader->in_prim_idx; + machine->Inputs[idx].xyzw[1].f[prim_idx] = + (float)shader->in_prim_idx; + machine->Inputs[idx].xyzw[2].f[prim_idx] = + (float)shader->in_prim_idx; + machine->Inputs[idx].xyzw[3].f[prim_idx] = + (float)shader->in_prim_idx; + } else { +#if DEBUG_INPUTS + debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n", + slot, vs_slot, idx); +#endif +#if 1 + assert(!util_is_inf_or_nan(input[vs_slot][0])); + assert(!util_is_inf_or_nan(input[vs_slot][1])); + assert(!util_is_inf_or_nan(input[vs_slot][2])); + assert(!util_is_inf_or_nan(input[vs_slot][3])); +#endif + machine->Inputs[idx].xyzw[0].f[prim_idx] = input[vs_slot][0]; + machine->Inputs[idx].xyzw[1].f[prim_idx] = input[vs_slot][1]; + machine->Inputs[idx].xyzw[2].f[prim_idx] = input[vs_slot][2]; + machine->Inputs[idx].xyzw[3].f[prim_idx] = input[vs_slot][3]; +#if DEBUG_INPUTS + debug_printf("\t\t%f %f %f %f\n", + machine->Inputs[idx].xyzw[0].f[prim_idx], + machine->Inputs[idx].xyzw[1].f[prim_idx], + machine->Inputs[idx].xyzw[2].f[prim_idx], + machine->Inputs[idx].xyzw[3].f[prim_idx]); +#endif + ++vs_slot; + } + } } +} + +static void gs_flush(struct draw_geometry_shader *shader, + unsigned input_primitives) +{ + unsigned out_prim_count; + struct tgsi_exec_machine *machine = shader->machine; + + debug_assert(input_primitives > 0 && + input_primitives < 4); + + tgsi_set_exec_mask(machine, + 1, + input_primitives > 1, + input_primitives > 2, + input_primitives > 3); + + /* run interpreter */ + tgsi_exec_machine_run(machine); + + out_prim_count = + machine->Temps[TGSI_EXEC_TEMP_PRIMITIVE_I].xyzw[TGSI_EXEC_TEMP_PRIMITIVE_C].u[0]; + +#if 0 + debug_printf("PRIM emitted prims = %d (verts=%d), cur prim count = %d\n", + shader->emitted_primitives, shader->emitted_vertices, + out_prim_count); +#endif + draw_geometry_fetch_outputs(shader, out_prim_count, + &shader->tmp_output); +} + +static void gs_point(struct draw_geometry_shader *shader, + int idx) +{ + unsigned indices[1]; - for (i = 0; i < num_primitives; ++i) { - unsigned int max_primitives = 1; + indices[0] = idx; - draw_fetch_geometry_input(shader, i, max_primitives, input, - input_stride, inputs_from_vs); + draw_fetch_gs_input(shader, indices, 1, 0); + ++shader->in_prim_idx; - tgsi_set_exec_mask(machine, - 1, - max_primitives > 1, - max_primitives > 2, - max_primitives > 3); + gs_flush(shader, 1); +} + +static void gs_line(struct draw_geometry_shader *shader, + int i0, int i1) +{ + unsigned indices[2]; + + indices[0] = i0; + indices[1] = i1; + + draw_fetch_gs_input(shader, indices, 2, 0); + ++shader->in_prim_idx; + + gs_flush(shader, 1); +} + +static void gs_line_adj(struct draw_geometry_shader *shader, + int i0, int i1, int i2, int i3) +{ + unsigned indices[4]; + + indices[0] = i0; + indices[1] = i1; + indices[2] = i2; + indices[3] = i3; + + draw_fetch_gs_input(shader, indices, 4, 0); + ++shader->in_prim_idx; + + gs_flush(shader, 1); +} + +static void gs_tri(struct draw_geometry_shader *shader, + int i0, int i1, int i2) +{ + unsigned indices[3]; + + indices[0] = i0; + indices[1] = i1; + indices[2] = i2; + + draw_fetch_gs_input(shader, indices, 3, 0); + ++shader->in_prim_idx; + + gs_flush(shader, 1); +} + +static void gs_tri_adj(struct draw_geometry_shader *shader, + int i0, int i1, int i2, + int i3, int i4, int i5) +{ + unsigned indices[6]; + + indices[0] = i0; + indices[1] = i1; + indices[2] = i2; + indices[3] = i3; + indices[4] = i4; + indices[5] = i5; - /* run interpreter */ - tgsi_exec_machine_run(machine); + draw_fetch_gs_input(shader, indices, 6, 0); + ++shader->in_prim_idx; - draw_geometry_fetch_outputs(shader, max_primitives, - output, vertex_size); + gs_flush(shader, 1); +} + +#define TRIANGLE(gs,i0,i1,i2) gs_tri(gs,i0,i1,i2) +#define TRI_ADJ(gs,i0,i1,i2,i3,i4,i5) gs_tri_adj(gs,i0,i1,i2,i3,i4,i5) +#define LINE(gs,i0,i1) gs_line(gs,i0,i1) +#define LINE_ADJ(gs,i0,i1,i2,i3) gs_line_adj(gs,i0,i1,i2,i3) +#define POINT(gs,i0) gs_point(gs,i0) +#define FUNC gs_run +#define LOCAL_VARS +#include "draw_gs_tmp.h" + + +#define TRIANGLE(gs,i0,i1,i2) gs_tri(gs,elts[i0],elts[i1],elts[i2]) +#define TRI_ADJ(gs,i0,i1,i2,i3,i4,i5) \ + gs_tri_adj(gs,elts[i0],elts[i1],elts[i2],elts[i3], \ + elts[i4],elts[i5]) +#define LINE(gs,i0,i1) gs_line(gs,elts[i0],elts[i1]) +#define LINE_ADJ(gs,i0,i1,i2,i3) gs_line_adj(gs,elts[i0], \ + elts[i1], \ + elts[i2],elts[i3]) +#define POINT(gs,i0) gs_point(gs,elts[i0]) +#define FUNC gs_run_elts +#define LOCAL_VARS \ + const ushort *elts = input_prims->elts; +#include "draw_gs_tmp.h" + +int draw_geometry_shader_run(struct draw_geometry_shader *shader, + const void *constants[PIPE_MAX_CONSTANT_BUFFERS], + const struct draw_vertex_info *input_verts, + const struct draw_prim_info *input_prim, + 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 vertex_size = input_verts->vertex_size; + struct tgsi_exec_machine *machine = shader->machine; + unsigned int i; + unsigned num_input_verts = input_prim->linear ? + input_verts->count : + input_prim->count; + unsigned num_in_primitives = + MAX2(u_gs_prims_for_vertices(input_prim->prim, num_input_verts), + u_gs_prims_for_vertices(shader->input_primitive, num_input_verts)); + unsigned max_out_prims = u_gs_prims_for_vertices(shader->output_primitive, + shader->max_output_vertices) + * num_in_primitives; + + output_verts->vertex_size = input_verts->vertex_size; + output_verts->stride = input_verts->vertex_size; + output_verts->verts = + (struct vertex_header *)MALLOC(input_verts->vertex_size * + num_in_primitives * + shader->max_output_vertices); + + +#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("\tprimt pipe = %d, shader in = %d, shader out = %d, max out = %d\n", + input_prim->prim, shader->input_primitive, + 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->in_prim_idx = 0; + shader->input_vertex_stride = input_stride; + shader->input = input; + if (shader->primitive_lengths) { + FREE(shader->primitive_lengths); } + shader->primitive_lengths = MALLOC(max_out_prims * sizeof(unsigned)); + + for (i = 0; i < PIPE_MAX_CONSTANT_BUFFERS; i++) { + machine->Consts[i] = constants[i]; + } + + 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); + + /* 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->primitive_lengths = shader->primitive_lengths; + output_prims->primitive_count = shader->emitted_primitives; + output_verts->count = shader->emitted_vertices; + +#if 0 + debug_printf("GS finished, prims = %d, verts = %d\n", + output_prims->primitive_count, + output_verts->count); +#endif + + return shader->emitted_vertices; } void draw_geometry_shader_delete(struct draw_geometry_shader *shader) diff --git a/src/gallium/auxiliary/draw/draw_gs.h b/src/gallium/auxiliary/draw/draw_gs.h index d8eb210343..2cb634818c 100644 --- a/src/gallium/auxiliary/draw/draw_gs.h +++ b/src/gallium/auxiliary/draw/draw_gs.h @@ -54,23 +54,36 @@ struct draw_geometry_shader { unsigned input_primitive; unsigned output_primitive; - /* Extracted from shader: - */ - const float (*immediates)[4]; + unsigned *primitive_lengths; + unsigned emitted_vertices; + unsigned emitted_primitives; + + float (*tmp_output)[4]; + unsigned vertex_size; + + unsigned in_prim_idx; + unsigned input_vertex_stride; + const float (*input)[4]; }; -void draw_geometry_shader_run(struct draw_geometry_shader *shader, - const float (*input)[4], - float (*output)[4], - const void *constants[PIPE_MAX_CONSTANT_BUFFERS], - unsigned count, - unsigned input_stride, - unsigned output_stride); +/* + * Returns the number of vertices emitted. + * The vertex shader can emit any number of vertices as long as it's + * smaller than the GS_MAX_OUTPUT_VERTICES shader property. + */ +int draw_geometry_shader_run(struct draw_geometry_shader *shader, + const void *constants[PIPE_MAX_CONSTANT_BUFFERS], + const struct draw_vertex_info *input_verts, + const struct draw_prim_info *input_prim, + struct draw_vertex_info *output_verts, + struct draw_prim_info *output_prims ); void draw_geometry_shader_prepare(struct draw_geometry_shader *shader, struct draw_context *draw); void draw_geometry_shader_delete(struct draw_geometry_shader *shader); +int draw_gs_max_output_vertices(struct draw_geometry_shader *shader, + unsigned pipe_prim); #endif diff --git a/src/gallium/auxiliary/draw/draw_gs_tmp.h b/src/gallium/auxiliary/draw/draw_gs_tmp.h new file mode 100644 index 0000000000..7a8683cf7c --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_gs_tmp.h @@ -0,0 +1,152 @@ + +static void FUNC( struct draw_geometry_shader *shader, + 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_context *draw = shader->draw; + + boolean flatfirst = (draw->rasterizer->flatshade && + draw->rasterizer->flatshade_first); + unsigned i, j; + unsigned count = input_prims->count; + LOCAL_VARS + + if (0) debug_printf("%s %d\n", __FUNCTION__, count); + + debug_assert(input_prims->primitive_count == 1); + + switch (input_prims->prim) { + case PIPE_PRIM_POINTS: + for (i = 0; i < count; i++) { + POINT( shader, i + 0 ); + } + break; + + case PIPE_PRIM_LINES: + for (i = 0; i+1 < count; i += 2) { + LINE( shader , i + 0 , i + 1 ); + } + break; + + case PIPE_PRIM_LINE_LOOP: + if (count >= 2) { + + for (i = 1; i < count; i++) { + LINE( shader, i - 1, i ); + } + + LINE( shader, i - 1, 0 ); + } + break; + + case PIPE_PRIM_LINE_STRIP: + for (i = 1; i < count; i++) { + LINE( shader, i - 1, i ); + } + break; + + case PIPE_PRIM_TRIANGLES: + for (i = 0; i+2 < count; i += 3) { + TRIANGLE( shader, i + 0, i + 1, i + 2 ); + } + break; + + case PIPE_PRIM_TRIANGLE_STRIP: + if (flatfirst) { + for (i = 0; i+2 < count; i++) { + TRIANGLE( shader, + i + 0, + i + 1 + (i&1), + i + 2 - (i&1) ); + } + } + else { + for (i = 0; i+2 < count; i++) { + TRIANGLE( shader, + i + 0 + (i&1), + i + 1 - (i&1), + i + 2 ); + } + } + break; + + case PIPE_PRIM_TRIANGLE_FAN: + if (count >= 3) { + if (flatfirst) { + for (i = 0; i+2 < count; i++) { + TRIANGLE( shader, + i + 1, + i + 2, + 0 ); + } + } + else { + for (i = 0; i+2 < count; i++) { + TRIANGLE( shader, + 0, + i + 1, + i + 2 ); + } + } + } + break; + + case PIPE_PRIM_POLYGON: + { + for (i = 0; i+2 < count; i++) { + + if (flatfirst) { + TRIANGLE( shader, 0, i + 1, i + 2 ); + } + else { + TRIANGLE( shader, i + 1, i + 2, 0 ); + } + } + } + break; + + case PIPE_PRIM_LINES_ADJACENCY: + for (i = 0; i+3 < count; i += 4) { + LINE_ADJ( shader , i + 0 , i + 1, i + 2, i + 3 ); + } + break; + case PIPE_PRIM_LINE_STRIP_ADJACENCY: + for (i = 1; i + 2 < count; i++) { + LINE_ADJ( shader, i - 1, i, i + 1, i + 2 ); + } + break; + + case PIPE_PRIM_TRIANGLES_ADJACENCY: + for (i = 0; i+5 < count; i += 5) { + TRI_ADJ( shader, i + 0, i + 1, i + 2, + i + 3, i + 4, i + 5); + } + break; + case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY: + for (i = 0, j = 0; i+5 < count; i += 2, ++j) { + TRI_ADJ( shader, + i + 0, + i + 1 + 2*(j&1), + i + 2 + 2*(j&1), + i + 3 - 2*(j&1), + i + 4 - 2*(j&1), + i + 5); + } + break; + + default: + debug_assert(!"Unsupported primitive in geometry shader"); + break; + } +} + + +#undef TRIANGLE +#undef TRI_ADJ +#undef POINT +#undef LINE +#undef LINE_ADJ +#undef FUNC +#undef LOCAL_VARS diff --git a/src/gallium/auxiliary/draw/draw_llvm.c b/src/gallium/auxiliary/draw/draw_llvm.c index bd5d8853cf..f521669fcd 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.c +++ b/src/gallium/auxiliary/draw/draw_llvm.c @@ -1,3 +1,30 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #include "draw_llvm.h" #include "draw_context.h" @@ -173,6 +200,8 @@ draw_llvm_create(struct draw_context *draw) #endif llvm = CALLOC_STRUCT( draw_llvm ); + if (!llvm) + return NULL; llvm->draw = draw; llvm->engine = draw->engine; @@ -217,6 +246,9 @@ draw_llvm_create(struct draw_context *draw) LLVMDumpModule(llvm->module); } + llvm->nr_variants = 0; + make_empty_list(&llvm->vs_variants_list); + return llvm; } @@ -229,9 +261,13 @@ draw_llvm_destroy(struct draw_llvm *llvm) } struct draw_llvm_variant * -draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs) +draw_llvm_create_variant(struct draw_llvm *llvm, int num_inputs) { struct draw_llvm_variant *variant = MALLOC(sizeof(struct draw_llvm_variant)); + struct llvm_vertex_shader *shader = + llvm_vertex_shader(llvm->draw->vs.vertex_shader); + + variant->llvm = llvm; draw_llvm_make_variant_key(llvm, &variant->key); @@ -240,6 +276,12 @@ draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs) draw_llvm_generate(llvm, variant); draw_llvm_generate_elts(llvm, variant); + variant->shader = shader; + variant->list_item_global.base = variant; + variant->list_item_local.base = variant; + /*variant->no = */shader->variants_created++; + variant->list_item_global.base = variant; + return variant; } @@ -895,3 +937,30 @@ draw_llvm_make_variant_key(struct draw_llvm *llvm, &llvm->draw->vs.vertex_shader->state, sizeof(struct pipe_shader_state)); } + +void +draw_llvm_destroy_variant(struct draw_llvm_variant *variant) +{ + struct draw_llvm *llvm = variant->llvm; + struct draw_context *draw = llvm->draw; + + if (variant->function_elts) { + if (variant->function_elts) + LLVMFreeMachineCodeForFunction(draw->engine, + variant->function_elts); + LLVMDeleteFunction(variant->function_elts); + } + + if (variant->function) { + if (variant->function) + LLVMFreeMachineCodeForFunction(draw->engine, + variant->function); + LLVMDeleteFunction(variant->function); + } + + remove_from_list(&variant->list_item_local); + variant->shader->variants_cached--; + remove_from_list(&variant->list_item_global); + llvm->nr_variants--; + FREE(variant); +} diff --git a/src/gallium/auxiliary/draw/draw_llvm.h b/src/gallium/auxiliary/draw/draw_llvm.h index 58fee7f9d6..c98d7fb393 100644 --- a/src/gallium/auxiliary/draw/draw_llvm.h +++ b/src/gallium/auxiliary/draw/draw_llvm.h @@ -1,15 +1,48 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + #ifndef HAVE_LLVM_H #define HAVE_LLVM_H #include "draw/draw_private.h" +#include "draw/draw_vs.h" + #include "pipe/p_context.h" +#include "util/u_simple_list.h" #include <llvm-c/Core.h> #include <llvm-c/Analysis.h> #include <llvm-c/Target.h> #include <llvm-c/ExecutionEngine.h> +struct draw_llvm; +struct llvm_vertex_shader; + struct draw_jit_texture { uint32_t width; @@ -104,11 +137,50 @@ typedef void unsigned stride, struct pipe_vertex_buffer *vertex_buffers); +struct draw_llvm_variant_key +{ + struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS]; + unsigned nr_vertex_elements; + struct pipe_shader_state vs; +}; + +struct draw_llvm_variant_list_item +{ + struct draw_llvm_variant *base; + struct draw_llvm_variant_list_item *next, *prev; +}; + +struct draw_llvm_variant +{ + struct draw_llvm_variant_key key; + LLVMValueRef function; + LLVMValueRef function_elts; + draw_jit_vert_func jit_func; + draw_jit_vert_func_elts jit_func_elts; + + struct llvm_vertex_shader *shader; + + struct draw_llvm *llvm; + struct draw_llvm_variant_list_item list_item_global; + struct draw_llvm_variant_list_item list_item_local; +}; + +struct llvm_vertex_shader { + struct draw_vertex_shader base; + + struct draw_llvm_variant_list_item variants; + unsigned variants_created; + unsigned variants_cached; +}; + struct draw_llvm { struct draw_context *draw; struct draw_jit_context jit_context; + struct draw_llvm_variant_list_item vs_variants_list; + int nr_variants; + LLVMModuleRef module; LLVMExecutionEngineRef engine; LLVMModuleProviderRef provider; @@ -121,23 +193,12 @@ struct draw_llvm { LLVMTypeRef vb_ptr_type; }; -struct draw_llvm_variant_key +static struct llvm_vertex_shader * +llvm_vertex_shader(struct draw_vertex_shader *vs) { - struct pipe_vertex_element vertex_element[PIPE_MAX_ATTRIBS]; - unsigned nr_vertex_elements; - struct pipe_shader_state vs; -}; + return (struct llvm_vertex_shader *)vs; +} -struct draw_llvm_variant -{ - struct draw_llvm_variant_key key; - LLVMValueRef function; - LLVMValueRef function_elts; - draw_jit_vert_func jit_func; - draw_jit_vert_func_elts jit_func_elts; - - struct draw_llvm_variant *next; -}; struct draw_llvm * draw_llvm_create(struct draw_context *draw); @@ -146,7 +207,10 @@ void draw_llvm_destroy(struct draw_llvm *llvm); struct draw_llvm_variant * -draw_llvm_prepare(struct draw_llvm *llvm, int num_inputs); +draw_llvm_create_variant(struct draw_llvm *llvm, int num_inputs); + +void +draw_llvm_destroy_variant(struct draw_llvm_variant *variant); void draw_llvm_make_variant_key(struct draw_llvm *llvm, @@ -156,4 +220,5 @@ LLVMValueRef draw_llvm_translate_from(LLVMBuilderRef builder, LLVMValueRef vbuffer, enum pipe_format from_format); + #endif diff --git a/src/gallium/auxiliary/draw/draw_pipe.c b/src/gallium/auxiliary/draw/draw_pipe.c index 7ea04e3819..8cd75ecf9a 100644 --- a/src/gallium/auxiliary/draw/draw_pipe.c +++ b/src/gallium/auxiliary/draw/draw_pipe.c @@ -177,15 +177,15 @@ static void do_triangle( struct draw_context *draw, ( DRAW_PIPE_RESET_STIPPLE | \ DRAW_PIPE_EDGE_FLAG_0 | \ DRAW_PIPE_EDGE_FLAG_1 ), \ - verts + stride * elts[i0], \ - verts + stride * elts[i1], \ - verts + stride * elts[i2]); \ + verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i2] & ~DRAW_PIPE_FLAG_MASK)); \ do_triangle( draw, \ ( DRAW_PIPE_EDGE_FLAG_1 | \ DRAW_PIPE_EDGE_FLAG_2 ), \ - verts + stride * elts[i0], \ - verts + stride * elts[i2], \ - verts + stride * elts[i3]) + verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i2] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i3] & ~DRAW_PIPE_FLAG_MASK)) /* emit last quad vertex as last vertex in triangles */ #define QUAD_LAST_PV(i0,i1,i2,i3) \ @@ -193,15 +193,15 @@ static void do_triangle( struct draw_context *draw, ( DRAW_PIPE_RESET_STIPPLE | \ DRAW_PIPE_EDGE_FLAG_0 | \ DRAW_PIPE_EDGE_FLAG_2 ), \ - verts + stride * elts[i0], \ - verts + stride * elts[i1], \ - verts + stride * elts[i3]); \ + verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i3] & ~DRAW_PIPE_FLAG_MASK)); \ do_triangle( draw, \ ( DRAW_PIPE_EDGE_FLAG_0 | \ DRAW_PIPE_EDGE_FLAG_1 ), \ - verts + stride * elts[i1], \ - verts + stride * elts[i2], \ - verts + stride * elts[i3]) + verts + stride * (elts[i1] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i2] & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * (elts[i3] & ~DRAW_PIPE_FLAG_MASK)) #define TRIANGLE(flags,i0,i1,i2) \ do_triangle( draw, \ @@ -218,7 +218,7 @@ static void do_triangle( struct draw_context *draw, #define POINT(i0) \ do_point( draw, \ - verts + stride * elts[i0] ) + verts + stride * (elts[i0] & ~DRAW_PIPE_FLAG_MASK) ) #define FUNC pipe_run #define ARGS \ @@ -256,27 +256,34 @@ static void do_triangle( struct draw_context *draw, * draw_vbuf.c code uses when it has to perform a flush. */ void draw_pipeline_run( struct draw_context *draw, - unsigned prim, - struct vertex_header *vertices, - unsigned vertex_count, - unsigned stride, - const ushort *elts, - unsigned count ) + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info) { - char *verts = (char *)vertices; + unsigned i, start; + + draw->pipeline.verts = (char *)vert_info->verts; + draw->pipeline.vertex_stride = vert_info->stride; + draw->pipeline.vertex_count = vert_info->count; + + for (start = i = 0; + i < prim_info->primitive_count; + start += prim_info->primitive_lengths[i], i++) + { + unsigned count = prim_info->primitive_lengths[i]; + + pipe_run(draw, + prim_info->prim, + vert_info->verts, + vert_info->stride, + prim_info->elts + start, + count); + } - draw->pipeline.verts = verts; - draw->pipeline.vertex_stride = stride; - draw->pipeline.vertex_count = vertex_count; - - pipe_run(draw, prim, vertices, stride, elts, count); - draw->pipeline.verts = NULL; draw->pipeline.vertex_count = 0; } - /* * Set up macros for draw_pt_decompose.h template code. * This code is for non-indexed (aka linear) rendering (no elts). @@ -289,14 +296,14 @@ void draw_pipeline_run( struct draw_context *draw, DRAW_PIPE_EDGE_FLAG_0 | \ DRAW_PIPE_EDGE_FLAG_1 ), \ verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK), \ - verts + stride * (i1), \ - verts + stride * (i2)); \ + verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK)); \ do_triangle( draw, \ ( DRAW_PIPE_EDGE_FLAG_1 | \ DRAW_PIPE_EDGE_FLAG_2 ), \ verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK), \ - verts + stride * (i2), \ - verts + stride * (i3)) + verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * ((i3) & ~DRAW_PIPE_FLAG_MASK)) /* emit last quad vertex as last vertex in triangles */ #define QUAD_LAST_PV(i0,i1,i2,i3) \ @@ -305,31 +312,31 @@ void draw_pipeline_run( struct draw_context *draw, DRAW_PIPE_EDGE_FLAG_0 | \ DRAW_PIPE_EDGE_FLAG_2 ), \ verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK), \ - verts + stride * (i1), \ - verts + stride * (i3)); \ + verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * ((i3) & ~DRAW_PIPE_FLAG_MASK)); \ do_triangle( draw, \ ( DRAW_PIPE_EDGE_FLAG_0 | \ DRAW_PIPE_EDGE_FLAG_1 ), \ verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK), \ - verts + stride * (i2), \ - verts + stride * (i3)) + verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * ((i3) & ~DRAW_PIPE_FLAG_MASK)) #define TRIANGLE(flags,i0,i1,i2) \ do_triangle( draw, \ flags, /* flags */ \ verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK), \ - verts + stride * (i1), \ - verts + stride * (i2)) + verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK), \ + verts + stride * ((i2) & ~DRAW_PIPE_FLAG_MASK)) #define LINE(flags,i0,i1) \ do_line( draw, \ flags, \ verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK), \ - verts + stride * (i1)) + verts + stride * ((i1) & ~DRAW_PIPE_FLAG_MASK)) #define POINT(i0) \ do_point( draw, \ - verts + stride * i0 ) + verts + stride * ((i0) & ~DRAW_PIPE_FLAG_MASK) ) #define FUNC pipe_run_linear #define ARGS \ @@ -354,17 +361,29 @@ void draw_pipeline_run( struct draw_context *draw, * For drawing non-indexed primitives. */ void draw_pipeline_run_linear( struct draw_context *draw, - unsigned prim, - struct vertex_header *vertices, - unsigned count, - unsigned stride ) + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info) { - char *verts = (char *)vertices; - draw->pipeline.verts = verts; - draw->pipeline.vertex_stride = stride; - draw->pipeline.vertex_count = count; - - pipe_run_linear(draw, prim, vertices, stride, count); + unsigned i, start; + + for (start = i = 0; + i < prim_info->primitive_count; + start += prim_info->primitive_lengths[i], i++) + { + unsigned count = prim_info->primitive_lengths[i]; + char *verts = ((char*)vert_info->verts) + + (start * vert_info->stride); + + draw->pipeline.verts = verts; + draw->pipeline.vertex_stride = vert_info->stride; + draw->pipeline.vertex_count = count; + + pipe_run_linear(draw, + prim_info->prim, + (struct vertex_header*)verts, + vert_info->stride, + count); + } draw->pipeline.verts = NULL; draw->pipeline.vertex_count = 0; diff --git a/src/gallium/auxiliary/draw/draw_pipe_aaline.c b/src/gallium/auxiliary/draw/draw_pipe_aaline.c index 4faf0a779c..debd17fd74 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_aaline.c +++ b/src/gallium/auxiliary/draw/draw_pipe_aaline.c @@ -788,9 +788,6 @@ draw_aaline_stage(struct draw_context *draw) if (aaline == NULL) return NULL; - if (!draw_alloc_temp_verts( &aaline->stage, 8 )) - goto fail; - aaline->stage.draw = draw; aaline->stage.name = "aaline"; aaline->stage.next = NULL; @@ -801,11 +798,14 @@ draw_aaline_stage(struct draw_context *draw) aaline->stage.reset_stipple_counter = aaline_reset_stipple_counter; aaline->stage.destroy = aaline_destroy; + if (!draw_alloc_temp_verts( &aaline->stage, 8 )) + goto fail; + return aaline; fail: if (aaline) - aaline_destroy(&aaline->stage); + aaline->stage.destroy(&aaline->stage); return NULL; } diff --git a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c index bba6f50c02..d406a86ccb 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_aapoint.c +++ b/src/gallium/auxiliary/draw/draw_pipe_aapoint.c @@ -780,9 +780,6 @@ draw_aapoint_stage(struct draw_context *draw) if (aapoint == NULL) goto fail; - if (!draw_alloc_temp_verts( &aapoint->stage, 4 )) - goto fail; - aapoint->stage.draw = draw; aapoint->stage.name = "aapoint"; aapoint->stage.next = NULL; @@ -793,11 +790,14 @@ draw_aapoint_stage(struct draw_context *draw) aapoint->stage.reset_stipple_counter = aapoint_reset_stipple_counter; aapoint->stage.destroy = aapoint_destroy; + if (!draw_alloc_temp_verts( &aapoint->stage, 4 )) + goto fail; + return aapoint; fail: if (aapoint) - aapoint_destroy(&aapoint->stage); + aapoint->stage.destroy(&aapoint->stage); return NULL; diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c index df8d82e367..122b1c7968 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_clip.c +++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c @@ -522,9 +522,6 @@ struct draw_stage *draw_clip_stage( struct draw_context *draw ) if (clipper == NULL) goto fail; - if (!draw_alloc_temp_verts( &clipper->stage, MAX_CLIPPED_VERTICES+1 )) - goto fail; - clipper->stage.draw = draw; clipper->stage.name = "clipper"; clipper->stage.point = clip_point; @@ -536,6 +533,9 @@ struct draw_stage *draw_clip_stage( struct draw_context *draw ) clipper->plane = draw->plane; + if (!draw_alloc_temp_verts( &clipper->stage, MAX_CLIPPED_VERTICES+1 )) + goto fail; + return &clipper->stage; fail: diff --git a/src/gallium/auxiliary/draw/draw_pipe_cull.c b/src/gallium/auxiliary/draw/draw_pipe_cull.c index bf84ce30ed..2f4d01d23a 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_cull.c +++ b/src/gallium/auxiliary/draw/draw_pipe_cull.c @@ -129,9 +129,6 @@ struct draw_stage *draw_cull_stage( struct draw_context *draw ) if (cull == NULL) goto fail; - if (!draw_alloc_temp_verts( &cull->stage, 0 )) - goto fail; - cull->stage.draw = draw; cull->stage.name = "cull"; cull->stage.next = NULL; @@ -142,6 +139,9 @@ struct draw_stage *draw_cull_stage( struct draw_context *draw ) cull->stage.reset_stipple_counter = cull_reset_stipple_counter; cull->stage.destroy = cull_destroy; + if (!draw_alloc_temp_verts( &cull->stage, 0 )) + goto fail; + return &cull->stage; fail: diff --git a/src/gallium/auxiliary/draw/draw_pipe_flatshade.c b/src/gallium/auxiliary/draw/draw_pipe_flatshade.c index 34afb1a0b6..693f2895aa 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_flatshade.c +++ b/src/gallium/auxiliary/draw/draw_pipe_flatshade.c @@ -257,9 +257,6 @@ struct draw_stage *draw_flatshade_stage( struct draw_context *draw ) if (flatshade == NULL) goto fail; - if (!draw_alloc_temp_verts( &flatshade->stage, 2 )) - goto fail; - flatshade->stage.draw = draw; flatshade->stage.name = "flatshade"; flatshade->stage.next = NULL; @@ -270,6 +267,9 @@ struct draw_stage *draw_flatshade_stage( struct draw_context *draw ) flatshade->stage.reset_stipple_counter = flatshade_reset_stipple_counter; flatshade->stage.destroy = flatshade_destroy; + if (!draw_alloc_temp_verts( &flatshade->stage, 2 )) + goto fail; + return &flatshade->stage; fail: diff --git a/src/gallium/auxiliary/draw/draw_pipe_offset.c b/src/gallium/auxiliary/draw/draw_pipe_offset.c index 8e321946ce..8afbbfa156 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_offset.c +++ b/src/gallium/auxiliary/draw/draw_pipe_offset.c @@ -161,9 +161,7 @@ struct draw_stage *draw_offset_stage( struct draw_context *draw ) { struct offset_stage *offset = CALLOC_STRUCT(offset_stage); if (offset == NULL) - return NULL; - - draw_alloc_temp_verts( &offset->stage, 3 ); + goto fail; offset->stage.draw = draw; offset->stage.name = "offset"; @@ -175,5 +173,14 @@ struct draw_stage *draw_offset_stage( struct draw_context *draw ) offset->stage.reset_stipple_counter = offset_reset_stipple_counter; offset->stage.destroy = offset_destroy; + if (!draw_alloc_temp_verts( &offset->stage, 3 )) + goto fail; + return &offset->stage; + +fail: + if (offset) + offset->stage.destroy( &offset->stage ); + + return NULL; } diff --git a/src/gallium/auxiliary/draw/draw_pipe_pstipple.c b/src/gallium/auxiliary/draw/draw_pipe_pstipple.c index ef30db094f..fff960c7eb 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_pstipple.c +++ b/src/gallium/auxiliary/draw/draw_pipe_pstipple.c @@ -607,8 +607,8 @@ static struct pstip_stage * draw_pstip_stage(struct draw_context *draw) { struct pstip_stage *pstip = CALLOC_STRUCT(pstip_stage); - - draw_alloc_temp_verts( &pstip->stage, 8 ); + if (pstip == NULL) + goto fail; pstip->stage.draw = draw; pstip->stage.name = "pstip"; @@ -620,7 +620,16 @@ draw_pstip_stage(struct draw_context *draw) pstip->stage.reset_stipple_counter = pstip_reset_stipple_counter; pstip->stage.destroy = pstip_destroy; + if (!draw_alloc_temp_verts( &pstip->stage, 8 )) + goto fail; + return pstip; + +fail: + if (pstip) + pstip->stage.destroy( &pstip->stage ); + + return NULL; } diff --git a/src/gallium/auxiliary/draw/draw_pipe_stipple.c b/src/gallium/auxiliary/draw/draw_pipe_stipple.c index 70fbab9ea7..4b3f4e7ae1 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_stipple.c +++ b/src/gallium/auxiliary/draw/draw_pipe_stipple.c @@ -235,8 +235,8 @@ stipple_destroy( struct draw_stage *stage ) struct draw_stage *draw_stipple_stage( struct draw_context *draw ) { struct stipple_stage *stipple = CALLOC_STRUCT(stipple_stage); - - draw_alloc_temp_verts( &stipple->stage, 2 ); + if (stipple == NULL) + goto fail; stipple->stage.draw = draw; stipple->stage.name = "stipple"; @@ -248,5 +248,14 @@ struct draw_stage *draw_stipple_stage( struct draw_context *draw ) stipple->stage.flush = stipple_flush; stipple->stage.destroy = stipple_destroy; + if (!draw_alloc_temp_verts( &stipple->stage, 2 )) + goto fail; + return &stipple->stage; + +fail: + if (stipple) + stipple->stage.destroy( &stipple->stage ); + + return NULL; } diff --git a/src/gallium/auxiliary/draw/draw_pipe_twoside.c b/src/gallium/auxiliary/draw/draw_pipe_twoside.c index 808b2fb0b5..9a3f3fee62 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_twoside.c +++ b/src/gallium/auxiliary/draw/draw_pipe_twoside.c @@ -177,9 +177,6 @@ struct draw_stage *draw_twoside_stage( struct draw_context *draw ) if (twoside == NULL) goto fail; - if (!draw_alloc_temp_verts( &twoside->stage, 3 )) - goto fail; - twoside->stage.draw = draw; twoside->stage.name = "twoside"; twoside->stage.next = NULL; @@ -190,6 +187,9 @@ struct draw_stage *draw_twoside_stage( struct draw_context *draw ) twoside->stage.reset_stipple_counter = twoside_reset_stipple_counter; twoside->stage.destroy = twoside_destroy; + if (!draw_alloc_temp_verts( &twoside->stage, 3 )) + goto fail; + return &twoside->stage; fail: diff --git a/src/gallium/auxiliary/draw/draw_pipe_unfilled.c b/src/gallium/auxiliary/draw/draw_pipe_unfilled.c index e333d26a93..d87741b91e 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_unfilled.c +++ b/src/gallium/auxiliary/draw/draw_pipe_unfilled.c @@ -202,9 +202,6 @@ struct draw_stage *draw_unfilled_stage( struct draw_context *draw ) if (unfilled == NULL) goto fail; - if (!draw_alloc_temp_verts( &unfilled->stage, 0 )) - goto fail; - unfilled->stage.draw = draw; unfilled->stage.name = "unfilled"; unfilled->stage.next = NULL; @@ -216,6 +213,9 @@ struct draw_stage *draw_unfilled_stage( struct draw_context *draw ) unfilled->stage.reset_stipple_counter = unfilled_reset_stipple_counter; unfilled->stage.destroy = unfilled_destroy; + if (!draw_alloc_temp_verts( &unfilled->stage, 0 )) + goto fail; + return &unfilled->stage; fail: diff --git a/src/gallium/auxiliary/draw/draw_pipe_wide_line.c b/src/gallium/auxiliary/draw/draw_pipe_wide_line.c index d7ac95b740..98da9cfb99 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_wide_line.c +++ b/src/gallium/auxiliary/draw/draw_pipe_wide_line.c @@ -202,8 +202,8 @@ static void wideline_destroy( struct draw_stage *stage ) struct draw_stage *draw_wide_line_stage( struct draw_context *draw ) { struct wideline_stage *wide = CALLOC_STRUCT(wideline_stage); - - draw_alloc_temp_verts( &wide->stage, 4 ); + if (wide == NULL) + goto fail; wide->stage.draw = draw; wide->stage.name = "wide-line"; @@ -215,5 +215,14 @@ struct draw_stage *draw_wide_line_stage( struct draw_context *draw ) wide->stage.reset_stipple_counter = wideline_reset_stipple_counter; wide->stage.destroy = wideline_destroy; + if (!draw_alloc_temp_verts( &wide->stage, 4 )) + goto fail; + return &wide->stage; + +fail: + if (wide) + wide->stage.destroy( &wide->stage ); + + return NULL; } diff --git a/src/gallium/auxiliary/draw/draw_pipe_wide_point.c b/src/gallium/auxiliary/draw/draw_pipe_wide_point.c index a86fe19586..3e6e538995 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_wide_point.c +++ b/src/gallium/auxiliary/draw/draw_pipe_wide_point.c @@ -324,9 +324,6 @@ struct draw_stage *draw_wide_point_stage( struct draw_context *draw ) if (wide == NULL) goto fail; - if (!draw_alloc_temp_verts( &wide->stage, 4 )) - goto fail; - wide->stage.draw = draw; wide->stage.name = "wide-point"; wide->stage.next = NULL; @@ -337,6 +334,9 @@ struct draw_stage *draw_wide_point_stage( struct draw_context *draw ) wide->stage.reset_stipple_counter = widepoint_reset_stipple_counter; wide->stage.destroy = widepoint_destroy; + if (!draw_alloc_temp_verts( &wide->stage, 4 )) + goto fail; + return &wide->stage; fail: diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index a2bfb693c0..54944a7c67 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -81,6 +81,9 @@ struct vertex_header { #define UNDEFINED_VERTEX_ID 0xffff +/* maximum number of shader variants we can cache */ +#define DRAW_MAX_SHADER_VARIANTS 1024 + /** * Private context for the drawing module. */ @@ -235,6 +238,12 @@ struct draw_context struct tgsi_sampler **samplers; } gs; + struct { + struct pipe_stream_output_state state; + void *buffers[PIPE_MAX_SO_BUFFERS]; + uint num_buffers; + } so; + /* Clip derived state: */ float plane[12][4]; @@ -259,6 +268,34 @@ struct draw_context void *driver_private; }; + +struct draw_fetch_info { + boolean linear; + unsigned start; + const unsigned *elts; + unsigned count; +}; + +struct draw_vertex_info { + struct vertex_header *verts; + unsigned vertex_size; + unsigned stride; + unsigned count; +}; + +struct draw_prim_info { + boolean linear; + unsigned start; + + const ushort *elts; + unsigned count; + + unsigned prim; + unsigned *primitive_lengths; + unsigned primitive_count; +}; + + /******************************************************************************* * Draw common initialization code */ @@ -336,18 +373,13 @@ void draw_pipeline_destroy( struct draw_context *draw ); #define DRAW_PIPE_FLAG_MASK (0xf<<12) void draw_pipeline_run( struct draw_context *draw, - unsigned prim, - struct vertex_header *vertices, - unsigned vertex_count, - unsigned stride, - const ushort *elts, - unsigned count ); + const struct draw_vertex_info *vert, + const struct draw_prim_info *prim); void draw_pipeline_run_linear( struct draw_context *draw, - unsigned prim, - struct vertex_header *vertices, - unsigned count, - unsigned stride ); + const struct draw_vertex_info *vert, + const struct draw_prim_info *prim); + diff --git a/src/gallium/auxiliary/draw/draw_pt.c b/src/gallium/auxiliary/draw/draw_pt.c index b853f3a89f..6234272d6c 100644 --- a/src/gallium/auxiliary/draw/draw_pt.c +++ b/src/gallium/auxiliary/draw/draw_pt.c @@ -31,6 +31,7 @@ */ #include "draw/draw_context.h" +#include "draw/draw_gs.h" #include "draw/draw_private.h" #include "draw/draw_pt.h" #include "tgsi/tgsi_dump.h" @@ -74,30 +75,34 @@ draw_pt_arrays(struct draw_context *draw, { unsigned first, incr; draw_pt_split_prim(prim, &first, &incr); - count = trim(count, first, incr); + count = trim(count, first, incr); if (count < first) return TRUE; } if (!draw->force_passthrough) { + unsigned gs_out_prim = (draw->gs.geometry_shader ? + draw->gs.geometry_shader->output_primitive : + prim); + if (!draw->render) { opt |= PT_PIPELINE; } - + if (draw_need_pipeline(draw, draw->rasterizer, - prim)) { + gs_out_prim)) { opt |= PT_PIPELINE; } if (!draw->bypass_clipping && !draw->pt.test_fse) { opt |= PT_CLIPTEST; } - + opt |= PT_SHADE; } - - if (draw->pt.middle.llvm) { + + if (draw->pt.middle.llvm && !draw->gs.geometry_shader) { middle = draw->pt.middle.llvm; } else { if (opt == 0) @@ -119,7 +124,7 @@ draw_pt_arrays(struct draw_context *draw, frontend->prepare( frontend, prim, middle, opt ); - frontend->run(frontend, + frontend->run(frontend, draw_pt_elt_func(draw), draw_pt_elt_ptr(draw, start), draw->pt.user.eltBias, diff --git a/src/gallium/auxiliary/draw/draw_pt.h b/src/gallium/auxiliary/draw/draw_pt.h index 3e3ea320cc..44356fba4c 100644 --- a/src/gallium/auxiliary/draw/draw_pt.h +++ b/src/gallium/auxiliary/draw/draw_pt.h @@ -39,6 +39,8 @@ typedef unsigned (*pt_elt_func)( const void *elts, unsigned idx ); struct draw_pt_middle_end; struct draw_context; +struct draw_prim_info; +struct draw_vertex_info; #define PT_SHADE 0x1 @@ -162,21 +164,31 @@ void draw_pt_emit_prepare( struct pt_emit *emit, unsigned *max_vertices ); void draw_pt_emit( struct pt_emit *emit, - const float (*vertex_data)[4], - unsigned vertex_count, - unsigned stride, - const ushort *elts, - unsigned count ); + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info); void draw_pt_emit_linear( struct pt_emit *emit, - const float (*vertex_data)[4], - unsigned stride, - unsigned count ); + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info); void draw_pt_emit_destroy( struct pt_emit *emit ); struct pt_emit *draw_pt_emit_create( struct draw_context *draw ); +/******************************************************************************* + * HW stream output emit: + */ +struct pt_so_emit; + +void draw_pt_so_emit_prepare( struct pt_so_emit *emit ); + +void draw_pt_so_emit( struct pt_so_emit *emit, + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info ); + +void draw_pt_so_emit_destroy( struct pt_so_emit *emit ); + +struct pt_so_emit *draw_pt_so_emit_create( struct draw_context *draw ); /******************************************************************************* * API vertex fetch: @@ -208,9 +220,7 @@ struct pt_fetch *draw_pt_fetch_create( struct draw_context *draw ); struct pt_post_vs; boolean draw_pt_post_vs_run( struct pt_post_vs *pvs, - struct vertex_header *pipeline_verts, - unsigned stride, - unsigned count ); + struct draw_vertex_info *info ); void draw_pt_post_vs_prepare( struct pt_post_vs *pvs, boolean bypass_clipping, diff --git a/src/gallium/auxiliary/draw/draw_pt_emit.c b/src/gallium/auxiliary/draw/draw_pt_emit.c index f623c0743d..0229bcc7fe 100644 --- a/src/gallium/auxiliary/draw/draw_pt_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_emit.c @@ -127,15 +127,17 @@ void draw_pt_emit_prepare( struct pt_emit *emit, void draw_pt_emit( struct pt_emit *emit, - const float (*vertex_data)[4], - unsigned vertex_count, - unsigned stride, - const ushort *elts, - unsigned count ) + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info) { + const float (*vertex_data)[4] = (const float (*)[4])vert_info->verts->data; + unsigned vertex_count = vert_info->count; + unsigned stride = vert_info->stride; + const ushort *elts = prim_info->elts; struct draw_context *draw = emit->draw; struct translate *translate = emit->translate; struct vbuf_render *render = draw->render; + unsigned start, i; void *hw_verts; /* XXX: need to flush to get prim_vbuf.c to release its allocation?? @@ -190,23 +192,31 @@ void draw_pt_emit( struct pt_emit *emit, 0, vertex_count - 1 ); - render->draw_elements(render, - elts, - count); + for (start = i = 0; + i < prim_info->primitive_count; + start += prim_info->primitive_lengths[i], i++) + { + render->draw_elements(render, + elts + start, + prim_info->primitive_lengths[i]); + } render->release_vertices(render); } void draw_pt_emit_linear(struct pt_emit *emit, - const float (*vertex_data)[4], - unsigned stride, - unsigned count) + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info) { + const float (*vertex_data)[4] = (const float (*)[4])vert_info->verts->data; + unsigned stride = vert_info->stride; + unsigned count = vert_info->count; struct draw_context *draw = emit->draw; struct translate *translate = emit->translate; struct vbuf_render *render = draw->render; void *hw_verts; + unsigned start, i; #if 0 debug_printf("Linear emit\n"); @@ -258,7 +268,14 @@ void draw_pt_emit_linear(struct pt_emit *emit, render->unmap_vertices( render, 0, count - 1 ); - render->draw_arrays(render, 0, count); + for (start = i = 0; + i < prim_info->primitive_count; + start += prim_info->primitive_lengths[i], i++) + { + render->draw_arrays(render, + start, + prim_info->primitive_lengths[i]); + } render->release_vertices(render); diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch.c b/src/gallium/auxiliary/draw/draw_pt_fetch.c index a1347221b5..ae12ee24bd 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch.c @@ -29,7 +29,6 @@ #include "util/u_math.h" #include "draw/draw_context.h" #include "draw/draw_private.h" -#include "draw/draw_vbuf.h" #include "draw/draw_pt.h" #include "translate/translate.h" #include "translate/translate_cache.h" @@ -69,31 +68,12 @@ void draw_pt_fetch_prepare( struct pt_fetch *fetch, fetch->vertex_size = vertex_size; - /* Always emit/leave space for a vertex header. - * - * It's worth considering whether the vertex headers should contain - * a pointer to the 'data', rather than having it inline. - * Something to look at after we've fully switched over to the pt - * paths. + /* Leave the clipmask/edgeflags/pad/vertex_id untouched */ - { - /* Need to set header->vertex_id = 0xffff somehow. - */ - key.element[nr].type = TRANSLATE_ELEMENT_NORMAL; - key.element[nr].input_format = PIPE_FORMAT_R32_FLOAT; - key.element[nr].input_buffer = draw->pt.nr_vertex_buffers; - key.element[nr].input_offset = 0; - key.element[nr].instance_divisor = 0; - key.element[nr].output_format = PIPE_FORMAT_R32_FLOAT; - key.element[nr].output_offset = dst_offset; - dst_offset += 1 * sizeof(float); - nr++; - - - /* Just leave the clip[] array untouched. - */ - dst_offset += 4 * sizeof(float); - } + dst_offset += 1 * sizeof(float); + /* Just leave the clip[] array untouched. + */ + dst_offset += 4 * sizeof(float); if (instance_id_index != ~0) { num_extra_inputs++; @@ -132,26 +112,11 @@ void draw_pt_fetch_prepare( struct pt_fetch *fetch, key.nr_elements = nr; key.output_stride = vertex_size; - if (!fetch->translate || translate_key_compare(&fetch->translate->key, &key) != 0) { translate_key_sanitize(&key); fetch->translate = translate_cache_find(fetch->cache, &key); - - { - static struct vertex_header vh = { 0, - 1, - 0, - UNDEFINED_VERTEX_ID, - { .0f, .0f, .0f, .0f } }; - - fetch->translate->set_buffer(fetch->translate, - draw->pt.nr_vertex_buffers, - &vh, - 0, - ~0); - } } } diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c index 5158c6341c..5c8af17c8e 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_emit.c @@ -36,6 +36,7 @@ #include "draw/draw_vbuf.h" #include "draw/draw_vertex.h" #include "draw/draw_pt.h" +#include "draw/draw_gs.h" #include "translate/translate.h" #include "translate/translate_cache.h" @@ -100,9 +101,14 @@ static void fetch_emit_prepare( struct draw_pt_middle_end *middle, boolean ok; struct translate_key key; + unsigned gs_out_prim = (draw->gs.geometry_shader ? + draw->gs.geometry_shader->output_primitive : + prim); + + ok = draw->render->set_primitive( draw->render, - prim ); + gs_out_prim ); if (!ok) { assert(0); return; diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c index f0fc591bf5..b8270280b6 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_emit.c @@ -67,9 +67,8 @@ struct fetch_shade_emit { - static void fse_prepare( struct draw_pt_middle_end *middle, - unsigned prim, + unsigned prim, unsigned opt, unsigned *max_vertices ) { @@ -79,9 +78,12 @@ static void fse_prepare( struct draw_pt_middle_end *middle, const struct vertex_info *vinfo; unsigned i; unsigned nr_vbs = 0; - - if (!draw->render->set_primitive( draw->render, + /* Can't support geometry shader on this path. + */ + assert(!draw->gs.geometry_shader); + + if (!draw->render->set_primitive( draw->render, prim )) { assert(0); return; @@ -90,7 +92,6 @@ static void fse_prepare( struct draw_pt_middle_end *middle, /* Must do this after set_primitive() above: */ fse->vinfo = vinfo = draw->render->get_vertex_info(draw->render); - fse->key.output_stride = vinfo->size * 4; 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 da5106463a..121dfc414a 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c @@ -27,6 +27,7 @@ #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" @@ -40,16 +41,16 @@ 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; }; - static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, unsigned prim, unsigned opt, @@ -61,6 +62,10 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, unsigned i; unsigned instance_id_index = ~0; + unsigned gs_out_prim = (draw->gs.geometry_shader ? + draw->gs.geometry_shader->output_primitive : + prim); + /* Add one to num_outputs because the pipeline occasionally tags on * an additional texcoord, eg for AA lines. */ @@ -76,7 +81,7 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, } } - fpme->prim = prim; + fpme->input_prim = prim; fpme->opt = opt; /* Always leave room for the vertex header whether we need it or @@ -98,11 +103,13 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, (boolean)draw->bypass_clipping, (boolean)draw->identity_viewport, (boolean)draw->rasterizer->gl_rasterization_rules, - (draw->vs.edgeflag_output ? true : false) ); + (draw->vs.edgeflag_output ? TRUE : FALSE) ); + + draw_pt_so_emit_prepare( fpme->so_emit ); 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, @@ -121,147 +128,146 @@ static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle, } - -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( struct pt_fetch *fetch, + const struct draw_fetch_info *fetch_info, + char *output) { - struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle; - struct draw_context *draw = fpme->draw; - struct draw_vertex_shader *vshader = draw->vs.vertex_shader; - struct draw_geometry_shader *gshader = draw->gs.geometry_shader; - unsigned opt = fpme->opt; - unsigned alloc_count = align( fetch_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. - */ - assert(0); - return; + 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 (opt & PT_SHADE) - { - vshader->run_linear(vshader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - draw->pt.user.vs_constants, - fetch_count, - fpme->vertex_size, - fpme->vertex_size); - if (gshader) - draw_geometry_shader_run(gshader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - draw->pt.user.gs_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], + 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, + 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 *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_geometry_shader *geometry_shader = draw->gs.geometry_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; 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; } - /* Fetch into our vertex buffer + /* Fetch into our vertex buffer. */ - draw_pt_fetch_run_linear( fpme->fetch, - start, - count, - (char *)pipeline_verts ); + fetch( fpme->fetch, fetch_info, (char *)fetched_vert_info.verts ); + + /* Finished with fetch: + */ + fetch_info = NULL; + vert_info = &fetched_vert_info; /* Run the shader, note that this overwrites the data[] parts of * the pipeline verts. */ - if (opt & PT_SHADE) - { - shader->run_linear(shader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - draw->pt.user.vs_constants, - count, - fpme->vertex_size, - fpme->vertex_size); - - if (geometry_shader) - draw_geometry_shader_run(geometry_shader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - draw->pt.user.gs_constants, - count, - fpme->vertex_size, - fpme->vertex_size); + if (fpme->opt & PT_SHADE) { + draw_vertex_shader_run(vshader, + draw->pt.user.vs_constants, + vert_info, + &vs_vert_info); + + FREE(vert_info->verts); + vert_info = &vs_vert_info; } + if ((fpme->opt & PT_SHADE) && gshader) { + draw_geometry_shader_run(gshader, + draw->pt.user.gs_constants, + vert_info, + prim_info, + &gs_vert_info, + &gs_prim_info); + + FREE(vert_info->verts); + vert_info = &gs_vert_info; + prim_info = &gs_prim_info; + } + + + /* Stream output needs to be done before clipping. + * + * XXX: Stream output surely needs to respect the prim_info->elt + * lists. + */ + draw_pt_so_emit( fpme->so_emit, + vert_info, + prim_info ); + if (draw_pt_post_vs_run( fpme->post_vs, - pipeline_verts, - count, - fpme->vertex_size )) + vert_info )) { opt |= PT_PIPELINE; } @@ -269,102 +275,96 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle, /* Do we need to run the pipeline? */ if (opt & PT_PIPELINE) { - draw_pipeline_run_linear( fpme->draw, - fpme->prim, - pipeline_verts, - count, - fpme->vertex_size); + pipeline( fpme, + vert_info, + prim_info ); } else { - draw_pt_emit_linear( fpme->emit, - (const float (*)[4])pipeline_verts->data, - fpme->vertex_size, - count ); + emit( fpme->emit, + vert_info, + prim_info ); } - - FREE(pipeline_verts); + FREE(vert_info->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 ) +{ + 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.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) { 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_geometry_shader *geometry_shader = draw->gs.geometry_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.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 ) +{ + 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 (opt & PT_SHADE) - { - shader->run_linear(shader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - draw->pt.user.vs_constants, - count, - fpme->vertex_size, - fpme->vertex_size); - - if (geometry_shader) - draw_geometry_shader_run(geometry_shader, - (const float (*)[4])pipeline_verts->data, - ( float (*)[4])pipeline_verts->data, - draw->pt.user.gs_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.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; } @@ -385,6 +385,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 ); @@ -416,7 +419,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; diff --git a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c index d56889b5f6..d33969ac70 100644 --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c @@ -28,6 +28,7 @@ #include "util/u_math.h" #include "util/u_memory.h" #include "draw/draw_context.h" +#include "draw/draw_gs.h" #include "draw/draw_vbuf.h" #include "draw/draw_vertex.h" #include "draw/draw_pt.h" @@ -40,52 +41,58 @@ struct llvm_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; struct draw_llvm *llvm; - struct draw_llvm_variant *variants; struct draw_llvm_variant *current_variant; - int nr_variants; }; static void llvm_middle_end_prepare( struct draw_pt_middle_end *middle, - unsigned prim, + 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 draw_vertex_shader *vs = draw->vs.vertex_shader; + struct llvm_vertex_shader *shader = + llvm_vertex_shader(draw->vs.vertex_shader); 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; + + 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. */ - unsigned nr = MAX2( vs->info.num_inputs, - vs->info.num_outputs + 1 ); + unsigned nr = MAX2( shader->base.info.num_inputs, + shader->base.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) { + 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->prim = prim; + fpme->input_prim = in_prim; fpme->opt = opt; /* Always leave room for the vertex header whether we need it or @@ -102,11 +109,13 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle, (boolean)draw->bypass_clipping, (boolean)(draw->identity_viewport), (boolean)draw->rasterizer->gl_rasterization_rules, - (draw->vs.edgeflag_output ? true : false) ); + (draw->vs.edgeflag_output ? TRUE : FALSE) ); + + draw_pt_so_emit_prepare( fpme->so_emit ); if (!(opt & PT_PIPELINE)) { draw_pt_emit_prepare( fpme->emit, - prim, + out_prim, max_vertices ); *max_vertices = MAX2( *max_vertices, @@ -121,20 +130,41 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle, draw_llvm_make_variant_key(fpme->llvm, &key); - variant = fpme->variants; - while(variant) { - if(memcmp(&variant->key, &key, sizeof key) == 0) + li = first_elem(&shader->variants); + while(!at_end(&shader->variants, li)) { + if(memcmp(&li->base->key, &key, sizeof key) == 0) { + variant = li->base; break; + } + li = next_elem(li); + } - variant = variant->next; + if (variant) { + move_to_head(&fpme->llvm->vs_variants_list, &variant->list_item_global); } + else { + unsigned i; + 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); - if (!variant) { - variant = draw_llvm_prepare(fpme->llvm, nr); - variant->next = fpme->variants; - fpme->variants = variant; - ++fpme->nr_variants; + 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 */ @@ -145,66 +175,142 @@ llvm_middle_end_prepare( struct draw_pt_middle_end *middle, } +static void pipeline(struct llvm_middle_end *llvm, + const struct draw_vertex_info *vert_info, + const struct draw_prim_info *prim_info) +{ + if (prim_info->linear) + draw_pipeline_run_linear( llvm->draw, + vert_info, + prim_info); + else + draw_pipeline_run( llvm->draw, + vert_info, + prim_info ); +} -static void llvm_middle_end_run( struct draw_pt_middle_end *middle, - const unsigned *fetch_elts, - unsigned fetch_count, - const ushort *draw_elts, - unsigned draw_count ) +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(emit, vert_info, prim_info); + } +} + +static void +llvm_pipeline_generic( struct draw_pt_middle_end *middle, + const struct draw_fetch_info *fetch_info, + const struct draw_prim_info *prim_info ) { struct llvm_middle_end *fpme = (struct 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; unsigned opt = fpme->opt; - unsigned alloc_count = align( fetch_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. - */ + 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, 4)); + if (!llvm_vert_info.verts) { assert(0); return; } - fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context, - pipeline_verts, - (const char **)draw->pt.user.vbuffer, - fetch_elts, - fetch_count, - fpme->vertex_size, - draw->pt.vertex_buffer ); - - if (draw_pt_post_vs_run( fpme->post_vs, - pipeline_verts, - fetch_count, - fpme->vertex_size )) - { + if (fetch_info->linear) + fpme->current_variant->jit_func( &fpme->llvm->jit_context, + llvm_vert_info.verts, + (const char **)draw->pt.user.vbuffer, + fetch_info->start, + fetch_info->count, + fpme->vertex_size, + draw->pt.vertex_buffer ); + else + fpme->current_variant->jit_func_elts( &fpme->llvm->jit_context, + llvm_vert_info.verts, + (const char **)draw->pt.user.vbuffer, + fetch_info->elts, + fetch_info->count, + fpme->vertex_size, + draw->pt.vertex_buffer); + + /* Finished with fetch and vs: + */ + fetch_info = NULL; + vert_info = &llvm_vert_info; + + + if ((opt & PT_SHADE) && gshader) { + draw_geometry_shader_run(gshader, + draw->pt.user.gs_constants, + vert_info, + prim_info, + &gs_vert_info, + &gs_prim_info); + + FREE(vert_info->verts); + vert_info = &gs_vert_info; + prim_info = &gs_prim_info; + } + + /* stream output needs to be done before clipping */ + draw_pt_so_emit( fpme->so_emit, + vert_info, + prim_info ); + + if (draw_pt_post_vs_run( fpme->post_vs, vert_info )) { opt |= PT_PIPELINE; } /* Do we need to run the pipeline? */ if (opt & PT_PIPELINE) { - draw_pipeline_run( fpme->draw, - fpme->prim, - pipeline_verts, - fetch_count, - fpme->vertex_size, - draw_elts, - draw_count ); + pipeline( fpme, + 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 ); + emit( fpme->emit, + vert_info, + prim_info ); } + FREE(vert_info->verts); +} - FREE(pipeline_verts); +static void llvm_middle_end_run( struct draw_pt_middle_end *middle, + const unsigned *fetch_elts, + unsigned fetch_count, + const ushort *draw_elts, + unsigned draw_count ) +{ + struct llvm_middle_end *fpme = (struct llvm_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.primitive_count = 1; + prim_info.primitive_lengths = &draw_count; + + llvm_pipeline_generic( middle, &fetch_info, &prim_info ); } @@ -213,57 +319,23 @@ static void llvm_middle_end_linear_run( struct draw_pt_middle_end *middle, unsigned count) { struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; - struct draw_context *draw = fpme->draw; - 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. - */ - assert(0); - return; - } - -#if 0 - debug_printf("#### Pipeline = %p (data = %p)\n", - pipeline_verts, pipeline_verts->data); -#endif - fpme->current_variant->jit_func( &fpme->llvm->jit_context, - pipeline_verts, - (const char **)draw->pt.user.vbuffer, - start, - count, - fpme->vertex_size, - draw->pt.vertex_buffer ); - - if (draw_pt_post_vs_run( fpme->post_vs, - pipeline_verts, - count, - fpme->vertex_size )) - { - opt |= PT_PIPELINE; - } - - /* Do we need to run the pipeline? - */ - if (opt & PT_PIPELINE) { - draw_pipeline_run_linear( fpme->draw, - fpme->prim, - pipeline_verts, - count, - fpme->vertex_size); - } - else { - draw_pt_emit_linear( fpme->emit, - (const float (*)[4])pipeline_verts->data, - fpme->vertex_size, - count ); - } - - FREE(pipeline_verts); + 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.primitive_count = 1; + prim_info.primitive_lengths = &count; + + llvm_pipeline_generic( middle, &fetch_info, &prim_info ); } @@ -276,53 +348,24 @@ llvm_middle_end_linear_run_elts( struct draw_pt_middle_end *middle, unsigned draw_count ) { struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; - struct draw_context *draw = fpme->draw; - 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) - return FALSE; - - fpme->current_variant->jit_func( &fpme->llvm->jit_context, - pipeline_verts, - (const char **)draw->pt.user.vbuffer, - start, - count, - fpme->vertex_size, - draw->pt.vertex_buffer ); - - if (draw_pt_post_vs_run( fpme->post_vs, - pipeline_verts, - count, - fpme->vertex_size )) - { - opt |= PT_PIPELINE; - } + struct draw_fetch_info fetch_info; + struct draw_prim_info prim_info; - /* 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_info.linear = TRUE; + fetch_info.start = start; + fetch_info.count = count; + fetch_info.elts = NULL; + + 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.primitive_count = 1; + prim_info.primitive_lengths = &draw_count; + + llvm_pipeline_generic( middle, &fetch_info, &prim_info ); - FREE(pipeline_verts); return TRUE; } @@ -336,37 +379,16 @@ static void llvm_middle_end_finish( struct draw_pt_middle_end *middle ) static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle ) { struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle; - struct draw_context *draw = fpme->draw; - struct draw_llvm_variant *variant = NULL; - variant = fpme->variants; - while(variant) { - struct draw_llvm_variant *next = variant->next; - - if (variant->function_elts) { - if (variant->function_elts) - LLVMFreeMachineCodeForFunction(draw->engine, - variant->function_elts); - LLVMDeleteFunction(variant->function_elts); - } - - if (variant->function) { - if (variant->function) - LLVMFreeMachineCodeForFunction(draw->engine, - variant->function); - LLVMDeleteFunction(variant->function); - } - - FREE(variant); - - variant = next; - } if (fpme->fetch) draw_pt_fetch_destroy( fpme->fetch ); 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 ); @@ -377,7 +399,8 @@ static void llvm_middle_end_destroy( struct draw_pt_middle_end *middle ) } -struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit_llvm( struct draw_context *draw ) +struct draw_pt_middle_end * +draw_pt_fetch_pipeline_or_emit_llvm(struct draw_context *draw) { struct llvm_middle_end *fpme = 0; @@ -409,13 +432,15 @@ struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit_llvm( struct draw_cont if (!fpme->emit) goto fail; + fpme->so_emit = draw_pt_so_emit_create( draw ); + if (!fpme->so_emit) + goto fail; + fpme->llvm = draw_llvm_create(draw); if (!fpme->llvm) goto fail; - fpme->variants = NULL; fpme->current_variant = NULL; - fpme->nr_variants = 0; return &fpme->base; diff --git a/src/gallium/auxiliary/draw/draw_pt_post_vs.c b/src/gallium/auxiliary/draw/draw_pt_post_vs.c index 5525dfc748..e850cc2edd 100644 --- a/src/gallium/auxiliary/draw/draw_pt_post_vs.c +++ b/src/gallium/auxiliary/draw/draw_pt_post_vs.c @@ -29,19 +29,23 @@ #include "pipe/p_context.h" #include "draw/draw_context.h" #include "draw/draw_private.h" -#include "draw/draw_vbuf.h" #include "draw/draw_pt.h" struct pt_post_vs { struct draw_context *draw; boolean (*run)( struct pt_post_vs *pvs, - struct vertex_header *vertices, - unsigned count, - unsigned stride ); + struct draw_vertex_info *info ); }; - +static INLINE void +initialize_vertex_header(struct vertex_header *header) +{ + header->clipmask = 0; + header->edgeflag = 1; + header->pad = 0; + header->vertex_id = UNDEFINED_VERTEX_ID; +} static INLINE float dot4(const float *a, const float *b) @@ -52,8 +56,6 @@ dot4(const float *a, const float *b) a[3]*b[3]); } - - static INLINE unsigned compute_clipmask_gl(const float *clip, /*const*/ float plane[][4], unsigned nr) { @@ -92,22 +94,21 @@ compute_clipmask_gl(const float *clip, /*const*/ float plane[][4], unsigned nr) * instructions */ static boolean post_vs_cliptest_viewport_gl( struct pt_post_vs *pvs, - struct vertex_header *vertices, - unsigned count, - unsigned stride ) + struct draw_vertex_info *info ) { - struct vertex_header *out = vertices; + struct vertex_header *out = info->verts; const float *scale = pvs->draw->viewport.scale; const float *trans = pvs->draw->viewport.translate; const unsigned pos = draw_current_shader_position_output(pvs->draw); unsigned clipped = 0; unsigned j; - if (0) debug_printf("%s\n", __FUNCTION__); + if (0) debug_printf("%s count, %d\n", __FUNCTION__, info->count); - for (j = 0; j < count; j++) { + for (j = 0; j < info->count; j++) { float *position = out->data[pos]; + initialize_vertex_header(out); #if 0 debug_printf("%d) io = %p, data = %p = [%f, %f, %f, %f]\n", j, out, position, position[0], position[1], position[2], position[3]); @@ -143,7 +144,7 @@ static boolean post_vs_cliptest_viewport_gl( struct pt_post_vs *pvs, #endif } - out = (struct vertex_header *)( (char *)out + stride ); + out = (struct vertex_header *)( (char *)out + info->stride ); } return clipped != 0; @@ -153,29 +154,27 @@ static boolean post_vs_cliptest_viewport_gl( struct pt_post_vs *pvs, /* As above plus edgeflags */ -static boolean +static boolean post_vs_cliptest_viewport_gl_edgeflag(struct pt_post_vs *pvs, - struct vertex_header *vertices, - unsigned count, - unsigned stride ) + struct draw_vertex_info *info) { unsigned j; boolean needpipe; - needpipe = post_vs_cliptest_viewport_gl( pvs, vertices, count, stride); + needpipe = post_vs_cliptest_viewport_gl(pvs, info); /* If present, copy edgeflag VS output into vertex header. * Otherwise, leave header as is. */ if (pvs->draw->vs.edgeflag_output) { - struct vertex_header *out = vertices; + struct vertex_header *out = info->verts; int ef = pvs->draw->vs.edgeflag_output; - for (j = 0; j < count; j++) { + for (j = 0; j < info->count; j++) { const float *edgeflag = out->data[ef]; out->edgeflag = !(edgeflag[0] != 1.0f); needpipe |= !out->edgeflag; - out = (struct vertex_header *)( (char *)out + stride ); + out = (struct vertex_header *)( (char *)out + info->stride ); } } return needpipe; @@ -187,29 +186,28 @@ post_vs_cliptest_viewport_gl_edgeflag(struct pt_post_vs *pvs, /* If bypass_clipping is set, skip cliptest and rhw divide. */ static boolean post_vs_viewport( struct pt_post_vs *pvs, - struct vertex_header *vertices, - unsigned count, - unsigned stride ) + struct draw_vertex_info *info ) { - struct vertex_header *out = vertices; + struct vertex_header *out = info->verts; const float *scale = pvs->draw->viewport.scale; const float *trans = pvs->draw->viewport.translate; const unsigned pos = draw_current_shader_position_output(pvs->draw); unsigned j; if (0) debug_printf("%s\n", __FUNCTION__); - for (j = 0; j < count; j++) { + for (j = 0; j < info->count; j++) { float *position = out->data[pos]; + initialize_vertex_header(out); /* Viewport mapping only, no cliptest/rhw divide */ position[0] = position[0] * scale[0] + trans[0]; position[1] = position[1] * scale[1] + trans[1]; position[2] = position[2] * scale[2] + trans[2]; - out = (struct vertex_header *)((char *)out + stride); + out = (struct vertex_header *)((char *)out + info->stride); } - + return FALSE; } @@ -218,20 +216,25 @@ static boolean post_vs_viewport( struct pt_post_vs *pvs, * to do. */ static boolean post_vs_none( struct pt_post_vs *pvs, - struct vertex_header *vertices, - unsigned count, - unsigned stride ) + struct draw_vertex_info *info ) { + struct vertex_header *out = info->verts; + unsigned j; + if (0) debug_printf("%s\n", __FUNCTION__); + /* just initialize the vertex_id in all headers */ + for (j = 0; j < info->count; j++) { + initialize_vertex_header(out); + + out = (struct vertex_header *)((char *)out + info->stride); + } return FALSE; } boolean draw_pt_post_vs_run( struct pt_post_vs *pvs, - struct vertex_header *pipeline_verts, - unsigned count, - unsigned stride ) + struct draw_vertex_info *info ) { - return pvs->run( pvs, pipeline_verts, count, stride ); + return pvs->run( pvs, info ); } @@ -272,7 +275,7 @@ struct pt_post_vs *draw_pt_post_vs_create( struct draw_context *draw ) return NULL; pvs->draw = draw; - + return pvs; } diff --git a/src/gallium/auxiliary/draw/draw_pt_so_emit.c b/src/gallium/auxiliary/draw/draw_pt_so_emit.c new file mode 100644 index 0000000000..5d82934889 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_pt_so_emit.c @@ -0,0 +1,303 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "draw/draw_context.h" +#include "draw/draw_private.h" +#include "draw/draw_vbuf.h" +#include "draw/draw_vertex.h" +#include "draw/draw_pt.h" + +#include "util/u_math.h" +#include "util/u_memory.h" + +struct pt_so_emit { + struct draw_context *draw; + + void *buffers[PIPE_MAX_SO_BUFFERS]; + + unsigned input_vertex_stride; + const float (*inputs)[4]; + + boolean has_so; + + boolean single_buffer; + + unsigned emitted_primitives; + unsigned emitted_vertices; +}; + + +void draw_pt_so_emit_prepare(struct pt_so_emit *emit) +{ + struct draw_context *draw = emit->draw; + + emit->has_so = (draw->so.state.num_outputs > 0); + + /* if we have a state with outputs make sure we have + * buffers to output to */ + if (emit->has_so) { + boolean has_valid_buffer = FALSE; + unsigned i; + for (i = 0; i < draw->so.num_buffers; ++i) { + if (draw->so.buffers[i]) { + has_valid_buffer = TRUE; + break; + } + } + emit->has_so = has_valid_buffer; + } + + if (!emit->has_so) + return; + + /* XXX: need to flush to get prim_vbuf.c to release its allocation?? + */ + draw_do_flush( draw, DRAW_FLUSH_BACKEND ); +} + +static boolean +is_component_writable(unsigned mask, + unsigned compo) +{ + switch (mask) { + case TGSI_WRITEMASK_NONE: + return FALSE; + case TGSI_WRITEMASK_X: + return compo == 0; + case TGSI_WRITEMASK_Y: + return compo == 1; + case TGSI_WRITEMASK_XY: + return compo == 0 || compo == 1; + case TGSI_WRITEMASK_Z: + return compo == 2; + case TGSI_WRITEMASK_XZ: + return compo == 0 || compo == 2; + case TGSI_WRITEMASK_YZ: + return compo == 1 || compo == 2; + case TGSI_WRITEMASK_XYZ: + return compo == 0 || compo == 1 || compo == 2; + case TGSI_WRITEMASK_W: + return compo == 3; + case TGSI_WRITEMASK_XW: + return compo == 0 || compo == 3; + case TGSI_WRITEMASK_YW: + return compo == 1 || compo == 3; + case TGSI_WRITEMASK_XYW: + return compo == 0 || compo == 1 || compo == 3; + case TGSI_WRITEMASK_ZW: + return compo == 2 || compo == 3; + case TGSI_WRITEMASK_XZW: + return compo == 0 || compo == 1 || compo == 3; + case TGSI_WRITEMASK_YZW: + return compo == 1 || compo == 2 || compo == 4; + case TGSI_WRITEMASK_XYZW: + return compo < 4; + default: + debug_assert(!"Unknown writemask in stream out"); + return compo < 4; + } +} + +static void so_emit_prim(struct pt_so_emit *so, + unsigned *indices, + unsigned num_vertices) +{ + unsigned slot, i; + unsigned input_vertex_stride = so->input_vertex_stride; + struct draw_context *draw = so->draw; + const float (*input_ptr)[4]; + const struct pipe_stream_output_state *state = + &draw->so.state; + float **buffer = 0; + + input_ptr = so->inputs; + + for (i = 0; i < num_vertices; ++i) { + const float (*input)[4]; + unsigned total_written_compos = 0; + /*debug_printf("%d) vertex index = %d (prim idx = %d)\n", i, indices[i], prim_idx);*/ + input = (const float (*)[4])( + (const char *)input_ptr + (indices[i] * input_vertex_stride)); + for (slot = 0; slot < state->num_outputs; ++slot) { + unsigned idx = state->register_index[slot]; + unsigned writemask = state->register_mask[slot]; + unsigned written_compos = 0; + unsigned compo; + + buffer = (float**)&so->buffers[state->output_buffer[slot]]; + + /*debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n", + slot, vs_slot, idx);*/ +#if 1 + assert(!util_is_inf_or_nan(input[idx][0])); + assert(!util_is_inf_or_nan(input[idx][1])); + assert(!util_is_inf_or_nan(input[idx][2])); + assert(!util_is_inf_or_nan(input[idx][3])); +#endif + for (compo = 0; compo < 4; ++compo) { + if (is_component_writable(writemask, compo)) { + float *buf = *buffer; + buf[written_compos++] = input[idx][compo]; + } + } +#if 0 + debug_printf("\t\t(writemask = %d)%f %f %f %f\n", + writemask, + input[idx][0], + input[idx][1], + input[idx][2], + input[idx][3]); +#endif + *buffer += written_compos; + total_written_compos += written_compos; + } + if (so->single_buffer) { + int stride = (int)state->stride - + sizeof(float) * total_written_compos; + + debug_assert(stride >= 0); + *buffer = (float*) (((char*)*buffer) + stride); + } + } + so->emitted_vertices += num_vertices; + ++so->emitted_primitives; +} + +static void so_point(struct pt_so_emit *so, int idx) +{ + unsigned indices[1]; + + indices[0] = idx; + + so_emit_prim(so, indices, 1); +} + +static void so_line(struct pt_so_emit *so, int i0, int i1) +{ + unsigned indices[2]; + + indices[0] = i0; + indices[1] = i1; + + so_emit_prim(so, indices, 2); +} + +static void so_tri(struct pt_so_emit *so, int i0, int i1, int i2) +{ + unsigned indices[3]; + + indices[0] = i0; + indices[1] = i1; + indices[2] = i2; + + so_emit_prim(so, indices, 3); +} + + +#define TRIANGLE(gs,i0,i1,i2) so_tri(so,i0,i1,i2) +#define LINE(gs,i0,i1) so_line(so,i0,i1) +#define POINT(gs,i0) so_point(so,i0) +#define FUNC so_run_linear +#define LOCAL_VARS +#include "draw_so_emit_tmp.h" +#undef LOCAL_VARS +#undef FUNC + + +#define TRIANGLE(gs,i0,i1,i2) so_tri(gs,elts[i0],elts[i1],elts[i2]) +#define LINE(gs,i0,i1) so_line(gs,elts[i0],elts[i1]) +#define POINT(gs,i0) so_point(gs,elts[i0]) +#define FUNC so_run_elts +#define LOCAL_VARS \ + const ushort *elts = input_prims->elts; +#include "draw_so_emit_tmp.h" +#undef LOCAL_VARS +#undef FUNC + + +void draw_pt_so_emit( struct pt_so_emit *emit, + const struct draw_vertex_info *input_verts, + const struct draw_prim_info *input_prims ) +{ + struct draw_context *draw = emit->draw; + struct vbuf_render *render = draw->render; + unsigned start, i; + + if (!emit->has_so) + return; + + emit->emitted_vertices = 0; + emit->emitted_primitives = 0; + emit->input_vertex_stride = input_verts->stride; + emit->inputs = (const float (*)[4])input_verts->verts->data; + for (i = 0; i < draw->so.num_buffers; ++i) { + emit->buffers[i] = draw->so.buffers[i]; + } + emit->single_buffer = TRUE; + for (i = 0; i < draw->so.state.num_outputs; ++i) { + if (draw->so.state.output_buffer[i] != 0) + emit->single_buffer = FALSE; + } + + /* XXX: need to flush to get prim_vbuf.c to release its allocation??*/ + draw_do_flush( draw, DRAW_FLUSH_BACKEND ); + + 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) { + so_run_linear(emit, input_prims, input_verts, + start, count); + } else { + so_run_elts(emit, input_prims, input_verts, + start, count); + } + } + + render->set_stream_output_info(render, + emit->emitted_primitives, + emit->emitted_vertices); +} + + +struct pt_so_emit *draw_pt_so_emit_create( struct draw_context *draw ) +{ + struct pt_so_emit *emit = CALLOC_STRUCT(pt_so_emit); + if (!emit) + return NULL; + + emit->draw = draw; + + return emit; +} + +void draw_pt_so_emit_destroy( struct pt_so_emit *emit ) +{ + FREE(emit); +} diff --git a/src/gallium/auxiliary/draw/draw_pt_varray.c b/src/gallium/auxiliary/draw/draw_pt_varray.c index d0e16c9bc3..d89d5cd20f 100644 --- a/src/gallium/auxiliary/draw/draw_pt_varray.c +++ b/src/gallium/auxiliary/draw/draw_pt_varray.c @@ -136,7 +136,7 @@ static unsigned decompose_prim[PIPE_PRIM_POLYGON + 1] = { static void varray_prepare(struct draw_pt_front_end *frontend, - unsigned prim, + unsigned in_prim, struct draw_pt_middle_end *middle, unsigned opt) { @@ -144,11 +144,13 @@ static void varray_prepare(struct draw_pt_front_end *frontend, varray->base.run = varray_run; - varray->input_prim = prim; - varray->output_prim = decompose_prim[prim]; + varray->input_prim = in_prim; + varray->output_prim = decompose_prim[in_prim]; varray->middle = middle; - middle->prepare(middle, varray->output_prim, opt, &varray->driver_fetch_max ); + middle->prepare(middle, + varray->output_prim, + opt, &varray->driver_fetch_max ); /* check that the max is even */ assert((varray->driver_fetch_max & 1) == 0); diff --git a/src/gallium/auxiliary/draw/draw_pt_vcache.c b/src/gallium/auxiliary/draw/draw_pt_vcache.c index 6a48e61e62..b7e0da7d44 100644 --- a/src/gallium/auxiliary/draw/draw_pt_vcache.c +++ b/src/gallium/auxiliary/draw/draw_pt_vcache.c @@ -54,7 +54,7 @@ struct vcache_frontend { unsigned draw_count; unsigned fetch_count; unsigned fetch_max; - + struct draw_pt_middle_end *middle; unsigned input_prim; @@ -64,14 +64,14 @@ struct vcache_frontend { unsigned opt; }; -static INLINE void +static INLINE void vcache_flush( struct vcache_frontend *vcache ) { if (vcache->middle_prim != vcache->output_prim) { vcache->middle_prim = vcache->output_prim; - vcache->middle->prepare( vcache->middle, - vcache->middle_prim, - vcache->opt, + vcache->middle->prepare( vcache->middle, + vcache->middle_prim, + vcache->opt, &vcache->fetch_max ); } @@ -356,19 +356,19 @@ vcache_check_run( struct draw_pt_front_end *frontend, if (0) debug_printf("fetch_count %d fetch_max %d draw_count %d\n", fetch_count, vcache->fetch_max, draw_count); - + if (elt_bias + max_index >= DRAW_PIPE_MAX_VERTICES || fetch_count >= UNDEFINED_VERTEX_ID || fetch_count > draw_count) { if (0) debug_printf("fail\n"); goto fail; } - + if (vcache->middle_prim != vcache->input_prim) { vcache->middle_prim = vcache->input_prim; - vcache->middle->prepare( vcache->middle, - vcache->middle_prim, - vcache->opt, + vcache->middle->prepare( vcache->middle, + vcache->middle_prim, + vcache->opt, &vcache->fetch_max ); } @@ -467,9 +467,9 @@ vcache_check_run( struct draw_pt_front_end *frontend, -static void +static void vcache_prepare( struct draw_pt_front_end *frontend, - unsigned prim, + unsigned in_prim, struct draw_pt_middle_end *middle, unsigned opt ) { @@ -479,13 +479,19 @@ vcache_prepare( struct draw_pt_front_end *frontend, { vcache->base.run = vcache_run_extras; } - else + else { vcache->base.run = vcache_check_run; } - vcache->input_prim = prim; - vcache->output_prim = u_reduced_prim(prim); + /* VCache will always emit the reduced version of its input + * primitive, ie STRIP/FANS become TRIS, etc. + * + * This is not to be confused with what the GS might be up to, + * which is a separate issue. + */ + vcache->input_prim = in_prim; + vcache->output_prim = u_reduced_prim(in_prim); vcache->middle = middle; vcache->opt = opt; @@ -494,7 +500,9 @@ vcache_prepare( struct draw_pt_front_end *frontend, * doing so: */ vcache->middle_prim = (opt & PT_PIPELINE) ? vcache->output_prim : vcache->input_prim; - middle->prepare( middle, vcache->middle_prim, opt, &vcache->fetch_max ); + middle->prepare( middle, + vcache->middle_prim, + opt, &vcache->fetch_max ); } diff --git a/src/gallium/auxiliary/draw/draw_so_emit_tmp.h b/src/gallium/auxiliary/draw/draw_so_emit_tmp.h new file mode 100644 index 0000000000..01212a8e53 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_so_emit_tmp.h @@ -0,0 +1,123 @@ + +static void FUNC( struct pt_so_emit *so, + const struct draw_prim_info *input_prims, + const struct draw_vertex_info *input_verts, + unsigned start, + unsigned count) +{ + struct draw_context *draw = so->draw; + + boolean flatfirst = (draw->rasterizer->flatshade && + draw->rasterizer->flatshade_first); + unsigned i; + LOCAL_VARS + + if (0) debug_printf("%s %d\n", __FUNCTION__, count); + + debug_assert(input_prims->primitive_count == 1); + + switch (input_prims->prim) { + case PIPE_PRIM_POINTS: + for (i = 0; i < count; i++) { + POINT( so, start + i + 0 ); + } + break; + + case PIPE_PRIM_LINES: + for (i = 0; i+1 < count; i += 2) { + LINE( so , start + i + 0 , start + i + 1 ); + } + break; + + case PIPE_PRIM_LINE_LOOP: + if (count >= 2) { + + for (i = 1; i < count; i++) { + LINE( so, start + i - 1, start + i ); + } + + LINE( so, start + i - 1, start ); + } + break; + + case PIPE_PRIM_LINE_STRIP: + for (i = 1; i < count; i++) { + LINE( so, start + i - 1, start + i ); + } + break; + + case PIPE_PRIM_TRIANGLES: + for (i = 0; i+2 < count; i += 3) { + TRIANGLE( so, start + i + 0, start + i + 1, start + i + 2 ); + } + break; + + case PIPE_PRIM_TRIANGLE_STRIP: + if (flatfirst) { + for (i = 0; i+2 < count; i++) { + TRIANGLE( so, + start + i + 0, + start + i + 1 + (i&1), + start + i + 2 - (i&1) ); + } + } + else { + for (i = 0; i+2 < count; i++) { + TRIANGLE( so, + start + i + 0 + (i&1), + start + i + 1 - (i&1), + start + i + 2 ); + } + } + break; + + case PIPE_PRIM_TRIANGLE_FAN: + if (count >= 3) { + if (flatfirst) { + for (i = 0; i+2 < count; i++) { + TRIANGLE( so, + start + i + 1, + start + i + 2, + start ); + } + } + else { + for (i = 0; i+2 < count; i++) { + TRIANGLE( so, + start, + start + i + 1, + start + i + 2 ); + } + } + } + break; + + case PIPE_PRIM_POLYGON: + { + /* These bitflags look a little odd because we submit the + * vertices as (1,2,0) to satisfy flatshade requirements. + */ + + for (i = 0; i+2 < count; i++) { + + if (flatfirst) { + TRIANGLE( so, start + 0, start + i + 1, start + i + 2 ); + } + else { + TRIANGLE( so, start + i + 1, start + i + 2, start + 0 ); + } + } + } + break; + + default: + debug_assert(!"Unsupported primitive in stream output"); + break; + } +} + + +#undef TRIANGLE +#undef POINT +#undef LINE +#undef FUNC diff --git a/src/gallium/auxiliary/draw/draw_vbuf.h b/src/gallium/auxiliary/draw/draw_vbuf.h index 83ae26a9c2..e32803c072 100644 --- a/src/gallium/auxiliary/draw/draw_vbuf.h +++ b/src/gallium/auxiliary/draw/draw_vbuf.h @@ -117,6 +117,14 @@ struct vbuf_render { void (*release_vertices)( struct vbuf_render * ); void (*destroy)( struct vbuf_render * ); + + + /** + * Called after writing data to the stream out buffers + */ + void (*set_stream_output_info)( struct vbuf_render *vbufr, + unsigned primitive_count, + unsigned vertices_count ); }; diff --git a/src/gallium/auxiliary/draw/draw_vs.c b/src/gallium/auxiliary/draw/draw_vs.c index b9db886a24..57ea63fc06 100644 --- a/src/gallium/auxiliary/draw/draw_vs.c +++ b/src/gallium/auxiliary/draw/draw_vs.c @@ -98,6 +98,11 @@ draw_create_vertex_shader(struct draw_context *draw, vs = draw_create_vs_ppc( draw, shader ); #endif } +#if HAVE_LLVM + else { + vs = draw_create_vs_llvm(draw, shader); + } +#endif if (!vs) { vs = draw_create_vs_exec( draw, shader ); diff --git a/src/gallium/auxiliary/draw/draw_vs.h b/src/gallium/auxiliary/draw/draw_vs.h index 6c7e94db43..a731994523 100644 --- a/src/gallium/auxiliary/draw/draw_vs.h +++ b/src/gallium/auxiliary/draw/draw_vs.h @@ -165,7 +165,6 @@ draw_create_vs_ppc(struct draw_context *draw, const struct pipe_shader_state *templ); - struct draw_vs_varient_key; struct draw_vertex_shader; @@ -173,6 +172,11 @@ struct draw_vs_varient * draw_vs_create_varient_aos_sse( struct draw_vertex_shader *vs, const struct draw_vs_varient_key *key ); +#if HAVE_LLVM +struct draw_vertex_shader * +draw_create_vs_llvm(struct draw_context *draw, + const struct pipe_shader_state *state); +#endif /******************************************************************************** diff --git a/src/gallium/auxiliary/draw/draw_vs_llvm.c b/src/gallium/auxiliary/draw/draw_vs_llvm.c new file mode 100644 index 0000000000..6c13df7913 --- /dev/null +++ b/src/gallium/auxiliary/draw/draw_vs_llvm.c @@ -0,0 +1,120 @@ +/************************************************************************** + * + * Copyright 2010 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include "util/u_math.h" +#include "util/u_memory.h" +#include "pipe/p_shader_tokens.h" + +#include "draw_private.h" +#include "draw_context.h" +#include "draw_vs.h" +#include "draw_llvm.h" + +#include "tgsi/tgsi_parse.h" +#include "tgsi/tgsi_scan.h" + +static void +vs_llvm_prepare(struct draw_vertex_shader *shader, + struct draw_context *draw) +{ + /*struct llvm_vertex_shader *evs = llvm_vertex_shader(shader);*/ +} + +static void +vs_llvm_run_linear( struct draw_vertex_shader *shader, + const float (*input)[4], + float (*output)[4], + const void *constants[PIPE_MAX_CONSTANT_BUFFERS], + unsigned count, + unsigned input_stride, + unsigned output_stride ) +{ + /* we should never get here since the entire pipeline is + * generated in draw_pt_fetch_shade_pipeline_llvm.c */ + debug_assert(0); +} + + +static void +vs_llvm_delete( struct draw_vertex_shader *dvs ) +{ + struct llvm_vertex_shader *shader = llvm_vertex_shader(dvs); + struct pipe_fence_handle *fence = NULL; + struct draw_llvm_variant_list_item *li; + struct pipe_context *pipe = dvs->draw->pipe; + + /* + * XXX: This might be not neccessary at all. + */ + pipe->flush(pipe, 0, &fence); + if (fence) { + pipe->screen->fence_finish(pipe->screen, fence, 0); + pipe->screen->fence_reference(pipe->screen, &fence, NULL); + } + + + li = first_elem(&shader->variants); + while(!at_end(&shader->variants, li)) { + struct draw_llvm_variant_list_item *next = next_elem(li); + draw_llvm_destroy_variant(li->base); + li = next; + } + + assert(shader->variants_cached == 0); + FREE((void*) dvs->state.tokens); + FREE( dvs ); +} + + +struct draw_vertex_shader * +draw_create_vs_llvm(struct draw_context *draw, + const struct pipe_shader_state *state) +{ + struct llvm_vertex_shader *vs = CALLOC_STRUCT( llvm_vertex_shader ); + + if (vs == NULL) + return NULL; + + /* we make a private copy of the tokens */ + vs->base.state.tokens = tgsi_dup_tokens(state->tokens); + if (!vs->base.state.tokens) { + FREE(vs); + return NULL; + } + + tgsi_scan_shader(state->tokens, &vs->base.info); + + vs->base.draw = draw; + vs->base.prepare = vs_llvm_prepare; + vs->base.run_linear = vs_llvm_run_linear; + vs->base.delete = vs_llvm_delete; + vs->base.create_varient = draw_vs_create_varient_generic; + + make_empty_list(&vs->variants); + + return &vs->base; +} |