+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;
+
+ shader->fetch_inputs(shader, indices, 3,
+ shader->fetched_prim_count);
+ ++shader->in_prim_idx;
+ ++shader->fetched_prim_count;
+
+ if (draw_gs_should_flush(shader))
+ gs_flush(shader);
+}
+
+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;
+
+ shader->fetch_inputs(shader, indices, 6,
+ shader->fetched_prim_count);
+ ++shader->in_prim_idx;
+ ++shader->fetched_prim_count;
+
+ if (draw_gs_should_flush(shader))
+ gs_flush(shader);
+}
+
+#define FUNC gs_run
+#define GET_ELT(idx) (idx)
+#include "draw_gs_tmp.h"
+
+
+#define FUNC gs_run_elts
+#define LOCAL_VARS const ushort *elts = input_prims->elts;
+#define GET_ELT(idx) (elts[idx])
+#include "draw_gs_tmp.h"
+
+
+/**
+ * Execute geometry shader.
+ */
+int draw_geometry_shader_run(struct draw_geometry_shader *shader,
+ const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
+ const unsigned constants_size[PIPE_MAX_CONSTANT_BUFFERS],
+ const struct draw_vertex_info *input_verts,
+ const struct draw_prim_info *input_prim,
+ const struct tgsi_shader_info *input_info,
+ struct draw_vertex_info *output_verts,
+ struct draw_prim_info *output_prims )
+{
+ const float (*input)[4] = (const float (*)[4])input_verts->verts->data;
+ unsigned input_stride = input_verts->vertex_size;
+ unsigned num_outputs = draw_total_gs_outputs(shader->draw);
+ unsigned vertex_size = sizeof(struct vertex_header) + num_outputs * 4 * sizeof(float);
+ unsigned num_input_verts = input_prim->linear ?
+ input_verts->count :
+ input_prim->count;
+ unsigned num_in_primitives =
+ align(
+ MAX2(u_decomposed_prims_for_vertices(input_prim->prim,
+ num_input_verts),
+ u_decomposed_prims_for_vertices(shader->input_primitive,
+ num_input_verts)),
+ shader->vector_length);
+ unsigned max_out_prims =
+ u_decomposed_prims_for_vertices(shader->output_primitive,
+ shader->max_output_vertices)
+ * num_in_primitives;
+ /* we allocate exactly one extra vertex per primitive to allow the GS to emit
+ * overflown vertices into some area where they won't harm anyone */
+ unsigned total_verts_per_buffer = shader->primitive_boundary *
+ num_in_primitives;
+ unsigned invocation;
+ //Assume at least one primitive
+ max_out_prims = MAX2(max_out_prims, 1);
+
+
+ output_verts->vertex_size = vertex_size;
+ output_verts->stride = output_verts->vertex_size;
+ output_verts->verts =
+ (struct vertex_header *)MALLOC(output_verts->vertex_size *
+ total_verts_per_buffer * shader->num_invocations);
+ debug_assert(output_verts->verts);
+
+#if 0
+ debug_printf("%s count = %d (in prims # = %d)\n",
+ __FUNCTION__, num_input_verts, num_in_primitives);
+ debug_printf("\tlinear = %d, prim_info->count = %d\n",
+ input_prim->linear, input_prim->count);
+ debug_printf("\tprim pipe = %s, shader in = %s, shader out = %s\n"
+ u_prim_name(input_prim->prim),
+ u_prim_name(shader->input_primitive),
+ u_prim_name(shader->output_primitive));
+ debug_printf("\tmaxv = %d, maxp = %d, primitive_boundary = %d, "
+ "vertex_size = %d, tverts = %d\n",
+ shader->max_output_vertices, max_out_prims,
+ shader->primitive_boundary, output_verts->vertex_size,
+ total_verts_per_buffer);
+#endif
+
+ shader->emitted_vertices = 0;
+ shader->emitted_primitives = 0;
+ shader->vertex_size = vertex_size;
+ shader->tmp_output = (float (*)[4])output_verts->verts->data;
+ shader->fetched_prim_count = 0;
+ shader->input_vertex_stride = input_stride;
+ shader->input = input;
+ shader->input_info = input_info;
+ FREE(shader->primitive_lengths);
+ shader->primitive_lengths = MALLOC(max_out_prims * sizeof(unsigned) * shader->num_invocations);
+
+
+#ifdef HAVE_LLVM
+ if (shader->draw->llvm) {
+ shader->gs_output = output_verts->verts;
+ if (max_out_prims > shader->max_out_prims) {
+ unsigned i;
+ if (shader->llvm_prim_lengths) {
+ for (i = 0; i < shader->max_out_prims; ++i) {
+ align_free(shader->llvm_prim_lengths[i]);
+ }
+ FREE(shader->llvm_prim_lengths);
+ }
+
+ shader->llvm_prim_lengths = MALLOC(max_out_prims * sizeof(unsigned*));
+ for (i = 0; i < max_out_prims; ++i) {
+ int vector_size = shader->vector_length * sizeof(unsigned);
+ shader->llvm_prim_lengths[i] =
+ align_malloc(vector_size, vector_size);
+ }
+
+ shader->max_out_prims = max_out_prims;
+ }
+ shader->jit_context->prim_lengths = shader->llvm_prim_lengths;
+ shader->jit_context->emitted_vertices = shader->llvm_emitted_vertices;
+ shader->jit_context->emitted_prims = shader->llvm_emitted_primitives;
+ }
+#endif
+
+ for (invocation = 0; invocation < shader->num_invocations; invocation++) {
+ shader->invocation_id = invocation;
+
+ shader->prepare(shader, constants, constants_size);
+
+ if (input_prim->linear)
+ gs_run(shader, input_prim, input_verts,
+ output_prims, output_verts);
+ else
+ gs_run_elts(shader, input_prim, input_verts,
+ output_prims, output_verts);
+
+ /* Flush the remaining primitives. Will happen if
+ * num_input_primitives % 4 != 0
+ */
+ if (shader->fetched_prim_count > 0) {
+ gs_flush(shader);
+ }
+ debug_assert(shader->fetched_prim_count == 0);
+ }
+
+ /* Update prim_info:
+ */
+ output_prims->linear = TRUE;
+ output_prims->elts = NULL;
+ output_prims->start = 0;
+ output_prims->count = shader->emitted_vertices;
+ output_prims->prim = shader->output_primitive;
+ output_prims->flags = 0x0;
+ output_prims->primitive_lengths = shader->primitive_lengths;
+ output_prims->primitive_count = shader->emitted_primitives;
+ output_verts->count = shader->emitted_vertices;
+
+ if (shader->draw->collect_statistics) {
+ unsigned i;
+ for (i = 0; i < shader->emitted_primitives; ++i) {
+ shader->draw->statistics.gs_primitives +=
+ u_decomposed_prims_for_vertices(shader->output_primitive,
+ shader->primitive_lengths[i]);
+ }
+ }
+
+#if 0
+ debug_printf("GS finished, prims = %d, verts = %d\n",
+ output_prims->primitive_count,
+ output_verts->count);
+#endif
+
+ return shader->emitted_vertices;
+}
+
+void draw_geometry_shader_prepare(struct draw_geometry_shader *shader,
+ struct draw_context *draw)
+{
+ boolean use_llvm = draw->llvm != NULL;
+ if (!use_llvm && shader && shader->machine->Tokens != shader->state.tokens) {
+ tgsi_exec_machine_bind_shader(shader->machine,
+ shader->state.tokens,
+ draw->gs.tgsi.sampler,
+ draw->gs.tgsi.image,
+ draw->gs.tgsi.buffer);
+ }
+}
+
+
+boolean
+draw_gs_init( struct draw_context *draw )
+{
+ if (!draw->llvm) {
+ draw->gs.tgsi.machine = tgsi_exec_machine_create(PIPE_SHADER_GEOMETRY);
+ if (!draw->gs.tgsi.machine)
+ return FALSE;
+
+ draw->gs.tgsi.machine->Primitives = align_malloc(
+ MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector), 16);
+ if (!draw->gs.tgsi.machine->Primitives)
+ return FALSE;
+ memset(draw->gs.tgsi.machine->Primitives, 0,
+ MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector));
+ }
+
+ return TRUE;
+}
+
+void draw_gs_destroy( struct draw_context *draw )
+{
+ if (draw->gs.tgsi.machine) {
+ align_free(draw->gs.tgsi.machine->Primitives);
+ tgsi_exec_machine_destroy(draw->gs.tgsi.machine);
+ }
+}