Merge branch 'gallium-noconstbuf'
[mesa.git] / src / gallium / auxiliary / draw / draw_gs.c
1 /**************************************************************************
2 *
3 * Copyright 2009 VMWare Inc.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #include "draw_gs.h"
29
30 #include "draw_private.h"
31 #include "draw_context.h"
32
33 #include "tgsi/tgsi_parse.h"
34 #include "tgsi/tgsi_exec.h"
35
36 #include "pipe/p_shader_tokens.h"
37
38 #include "util/u_math.h"
39 #include "util/u_memory.h"
40
41 #define MAX_PRIM_VERTICES 6
42 /* fixme: move it from here */
43 #define MAX_PRIMITIVES 64
44
45 boolean
46 draw_gs_init( struct draw_context *draw )
47 {
48 draw->gs.machine = tgsi_exec_machine_create();
49 if (!draw->gs.machine)
50 return FALSE;
51
52 draw->gs.machine->Primitives = align_malloc(
53 MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector), 16);
54 if (!draw->gs.machine->Primitives)
55 return FALSE;
56 memset(draw->gs.machine->Primitives, 0,
57 MAX_PRIMITIVES * sizeof(struct tgsi_exec_vector));
58
59 return TRUE;
60 }
61
62
63 void draw_gs_set_constants( struct draw_context *draw,
64 const float (*constants)[4],
65 unsigned size )
66 {
67 }
68
69
70 struct draw_geometry_shader *
71 draw_create_geometry_shader(struct draw_context *draw,
72 const struct pipe_shader_state *state)
73 {
74 struct draw_geometry_shader *gs;
75 int i;
76
77 gs = CALLOC_STRUCT(draw_geometry_shader);
78
79 if (!gs)
80 return NULL;
81
82 gs->state = *state;
83 gs->state.tokens = tgsi_dup_tokens(state->tokens);
84 if (!gs->state.tokens) {
85 FREE(gs);
86 return NULL;
87 }
88
89 tgsi_scan_shader(state->tokens, &gs->info);
90
91 /* setup the defaults */
92 gs->input_primitive = PIPE_PRIM_TRIANGLES;
93 gs->output_primitive = PIPE_PRIM_TRIANGLE_STRIP;
94 gs->max_output_vertices = 32;
95
96 for (i = 0; i < gs->info.num_properties; ++i) {
97 if (gs->info.properties[i].name ==
98 TGSI_PROPERTY_GS_INPUT_PRIM)
99 gs->input_primitive = gs->info.properties[i].data[0];
100 else if (gs->info.properties[i].name ==
101 TGSI_PROPERTY_GS_OUTPUT_PRIM)
102 gs->output_primitive = gs->info.properties[i].data[0];
103 else if (gs->info.properties[i].name ==
104 TGSI_PROPERTY_GS_MAX_VERTICES)
105 gs->max_output_vertices = gs->info.properties[i].data[0];
106 }
107
108 gs->machine = draw->gs.machine;
109
110 if (gs)
111 {
112 uint i;
113 for (i = 0; i < gs->info.num_outputs; i++) {
114 if (gs->info.output_semantic_name[i] == TGSI_SEMANTIC_POSITION &&
115 gs->info.output_semantic_index[i] == 0)
116 gs->position_output = i;
117 }
118 }
119
120 return gs;
121 }
122
123 void draw_bind_geometry_shader(struct draw_context *draw,
124 struct draw_geometry_shader *dgs)
125 {
126 draw_do_flush(draw, DRAW_FLUSH_STATE_CHANGE);
127
128 if (dgs) {
129 draw->gs.geometry_shader = dgs;
130 draw->gs.num_gs_outputs = dgs->info.num_outputs;
131 draw->gs.position_output = dgs->position_output;
132 draw_geometry_shader_prepare(dgs, draw);
133 }
134 else {
135 draw->gs.geometry_shader = NULL;
136 draw->gs.num_gs_outputs = 0;
137 }
138 }
139
140 void draw_delete_geometry_shader(struct draw_context *draw,
141 struct draw_geometry_shader *dgs)
142 {
143 FREE(dgs);
144 }
145
146 static INLINE int num_vertices_for_prim(int prim)
147 {
148 switch(prim) {
149 case PIPE_PRIM_POINTS:
150 return 1;
151 case PIPE_PRIM_LINES:
152 return 2;
153 case PIPE_PRIM_LINE_LOOP:
154 return 2;
155 case PIPE_PRIM_LINE_STRIP:
156 return 2;
157 case PIPE_PRIM_TRIANGLES:
158 return 3;
159 case PIPE_PRIM_TRIANGLE_STRIP:
160 return 3;
161 case PIPE_PRIM_TRIANGLE_FAN:
162 return 3;
163 case PIPE_PRIM_LINES_ADJACENCY:
164 case PIPE_PRIM_LINE_STRIP_ADJACENCY:
165 return 4;
166 case PIPE_PRIM_TRIANGLES_ADJACENCY:
167 case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
168 return 6;
169 default:
170 assert(!"Bad geometry shader input");
171 return 0;
172 }
173 }
174
175 static void draw_fetch_geometry_input(struct draw_geometry_shader *shader,
176 int start_primitive,
177 int num_primitives,
178 const float (*input_ptr)[4],
179 unsigned input_vertex_stride,
180 unsigned inputs_from_vs)
181 {
182 struct tgsi_exec_machine *machine = shader->machine;
183 unsigned slot, vs_slot, k, j;
184 unsigned num_vertices = num_vertices_for_prim(shader->input_primitive);
185 int idx = 0;
186
187 for (slot = 0, vs_slot = 0; slot < shader->info.num_inputs; slot++) {
188 /*debug_printf("Slot = %d (semantic = %d)\n", slot,
189 shader->info.input_semantic_name[slot]);*/
190 if (shader->info.input_semantic_name[slot] ==
191 TGSI_SEMANTIC_PRIMID) {
192 for (j = 0; j < num_primitives; ++j) {
193 machine->Inputs[idx].xyzw[0].f[j] = (float)start_primitive + j;
194 machine->Inputs[idx].xyzw[1].f[j] = (float)start_primitive + j;
195 machine->Inputs[idx].xyzw[2].f[j] = (float)start_primitive + j;
196 machine->Inputs[idx].xyzw[3].f[j] = (float)start_primitive + j;
197 }
198 ++idx;
199 } else {
200 for (j = 0; j < num_primitives; ++j) {
201 int vidx = idx;
202 const float (*prim_ptr)[4];
203 /*debug_printf(" %d) Prim (num_verts = %d)\n", start_primitive + j,
204 num_vertices);*/
205 prim_ptr = (const float (*)[4])(
206 (const char *)input_ptr +
207 (j * num_vertices * input_vertex_stride));
208
209 for (k = 0; k < num_vertices; ++k, ++vidx) {
210 const float (*input)[4];
211 input = (const float (*)[4])(
212 (const char *)prim_ptr + (k * input_vertex_stride));
213 vidx = k * TGSI_EXEC_MAX_INPUT_ATTRIBS + slot;
214 /*debug_printf("\t%d)(%d) Input vert:\n", vidx, k);*/
215 #if 1
216 assert(!util_is_inf_or_nan(input[vs_slot][0]));
217 assert(!util_is_inf_or_nan(input[vs_slot][1]));
218 assert(!util_is_inf_or_nan(input[vs_slot][2]));
219 assert(!util_is_inf_or_nan(input[vs_slot][3]));
220 #endif
221 machine->Inputs[vidx].xyzw[0].f[j] = input[vs_slot][0];
222 machine->Inputs[vidx].xyzw[1].f[j] = input[vs_slot][1];
223 machine->Inputs[vidx].xyzw[2].f[j] = input[vs_slot][2];
224 machine->Inputs[vidx].xyzw[3].f[j] = input[vs_slot][3];
225 #if 0
226 debug_printf("\t\t%d %f %f %f %f\n", slot,
227 machine->Inputs[vidx].xyzw[0].f[j],
228 machine->Inputs[vidx].xyzw[1].f[j],
229 machine->Inputs[vidx].xyzw[2].f[j],
230 machine->Inputs[vidx].xyzw[3].f[j]);
231 #endif
232 }
233 }
234 ++vs_slot;
235 idx += num_vertices;
236 }
237 }
238 }
239
240 static INLINE void
241 draw_geometry_fetch_outputs(struct draw_geometry_shader *shader,
242 int num_primitives,
243 float (*output)[4],
244 unsigned vertex_size)
245 {
246 struct tgsi_exec_machine *machine = shader->machine;
247 unsigned prim_idx, j, slot;
248
249 /* Unswizzle all output results.
250 */
251 /* FIXME: handle all the primitives produced by the gs, not just
252 * the first one
253 unsigned prim_count =
254 mach->Temps[TEMP_PRIMITIVE_I].xyzw[TEMP_PRIMITIVE_C].u[0];*/
255 for (prim_idx = 0; prim_idx < num_primitives; ++prim_idx) {
256 unsigned num_verts_per_prim = machine->Primitives[0];
257 for (j = 0; j < num_verts_per_prim; j++) {
258 int idx = (prim_idx * num_verts_per_prim + j) *
259 shader->info.num_outputs;
260 #ifdef DEBUG_OUTPUTS
261 debug_printf("%d) Output vert:\n", idx);
262 #endif
263 for (slot = 0; slot < shader->info.num_outputs; slot++) {
264 output[slot][0] = machine->Outputs[idx + slot].xyzw[0].f[prim_idx];
265 output[slot][1] = machine->Outputs[idx + slot].xyzw[1].f[prim_idx];
266 output[slot][2] = machine->Outputs[idx + slot].xyzw[2].f[prim_idx];
267 output[slot][3] = machine->Outputs[idx + slot].xyzw[3].f[prim_idx];
268 #ifdef DEBUG_OUTPUTS
269 debug_printf("\t%d: %f %f %f %f\n", slot,
270 output[slot][0],
271 output[slot][1],
272 output[slot][2],
273 output[slot][3]);
274 #endif
275 debug_assert(!util_is_inf_or_nan(output[slot][0]));
276 }
277 output = (float (*)[4])((char *)output + vertex_size);
278 }
279 }
280 }
281
282 void draw_geometry_shader_run(struct draw_geometry_shader *shader,
283 const float (*input)[4],
284 float (*output)[4],
285 const float (*constants)[4],
286 unsigned count,
287 unsigned input_stride,
288 unsigned vertex_size)
289 {
290 struct tgsi_exec_machine *machine = shader->machine;
291 unsigned int i;
292 unsigned num_vertices = num_vertices_for_prim(shader->input_primitive);
293 unsigned num_primitives = count/num_vertices;
294 unsigned inputs_from_vs = 0;
295
296 machine->Consts = constants;
297
298 for (i = 0; i < shader->info.num_inputs; ++i) {
299 if (shader->info.input_semantic_name[i] != TGSI_SEMANTIC_PRIMID)
300 ++inputs_from_vs;
301 }
302
303 for (i = 0; i < num_primitives; ++i) {
304 unsigned int max_primitives = 1;
305
306 draw_fetch_geometry_input(shader, i, max_primitives, input,
307 input_stride, inputs_from_vs);
308
309 tgsi_set_exec_mask(machine,
310 1,
311 max_primitives > 1,
312 max_primitives > 2,
313 max_primitives > 3);
314
315 /* run interpreter */
316 tgsi_exec_machine_run(machine);
317
318 draw_geometry_fetch_outputs(shader, max_primitives,
319 output, vertex_size);
320 }
321 }
322
323 void draw_geometry_shader_delete(struct draw_geometry_shader *shader)
324 {
325 FREE((void*) shader->state.tokens);
326 FREE(shader);
327 }
328
329 void draw_geometry_shader_prepare(struct draw_geometry_shader *shader,
330 struct draw_context *draw)
331 {
332 if (shader->machine->Tokens != shader->state.tokens) {
333 tgsi_exec_machine_bind_shader(shader->machine,
334 shader->state.tokens,
335 draw->gs.num_samplers,
336 draw->gs.samplers);
337 }
338 }