gallium: a lot more complete implementation of stream output
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_shade_pipeline.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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 "util/u_math.h"
29 #include "util/u_memory.h"
30 #include "draw/draw_context.h"
31 #include "draw/draw_vbuf.h"
32 #include "draw/draw_vertex.h"
33 #include "draw/draw_pt.h"
34 #include "draw/draw_vs.h"
35 #include "draw/draw_gs.h"
36
37
38 struct fetch_pipeline_middle_end {
39 struct draw_pt_middle_end base;
40 struct draw_context *draw;
41
42 struct pt_emit *emit;
43 struct pt_so_emit *so_emit;
44 struct pt_fetch *fetch;
45 struct pt_post_vs *post_vs;
46
47 unsigned vertex_data_offset;
48 unsigned vertex_size;
49 unsigned prim;
50 unsigned opt;
51 };
52
53
54 static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
55 unsigned prim,
56 unsigned opt,
57 unsigned *max_vertices )
58 {
59 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
60 struct draw_context *draw = fpme->draw;
61 struct draw_vertex_shader *vs = draw->vs.vertex_shader;
62 unsigned i;
63 unsigned instance_id_index = ~0;
64
65 /* Add one to num_outputs because the pipeline occasionally tags on
66 * an additional texcoord, eg for AA lines.
67 */
68 unsigned nr = MAX2( vs->info.num_inputs,
69 vs->info.num_outputs + 1 );
70
71 /* Scan for instanceID system value.
72 */
73 for (i = 0; i < vs->info.num_inputs; i++) {
74 if (vs->info.input_semantic_name[i] == TGSI_SEMANTIC_INSTANCEID) {
75 instance_id_index = i;
76 break;
77 }
78 }
79
80 fpme->prim = prim;
81 fpme->opt = opt;
82
83 /* Always leave room for the vertex header whether we need it or
84 * not. It's hard to get rid of it in particular because of the
85 * viewport code in draw_pt_post_vs.c.
86 */
87 fpme->vertex_size = sizeof(struct vertex_header) + nr * 4 * sizeof(float);
88
89
90
91 draw_pt_fetch_prepare( fpme->fetch,
92 vs->info.num_inputs,
93 fpme->vertex_size,
94 instance_id_index );
95 /* XXX: it's not really gl rasterization rules we care about here,
96 * but gl vs dx9 clip spaces.
97 */
98 draw_pt_post_vs_prepare( fpme->post_vs,
99 (boolean)draw->bypass_clipping,
100 (boolean)draw->identity_viewport,
101 (boolean)draw->rasterizer->gl_rasterization_rules,
102 (draw->vs.edgeflag_output ? true : false) );
103
104 draw_pt_so_emit_prepare( fpme->so_emit, prim );
105
106 if (!(opt & PT_PIPELINE)) {
107 draw_pt_emit_prepare( fpme->emit,
108 prim,
109 max_vertices );
110
111 *max_vertices = MAX2( *max_vertices,
112 DRAW_PIPE_MAX_VERTICES );
113 }
114 else {
115 *max_vertices = DRAW_PIPE_MAX_VERTICES;
116 }
117
118 /* return even number */
119 *max_vertices = *max_vertices & ~1;
120
121 /* No need to prepare the shader.
122 */
123 vs->prepare(vs, draw);
124 }
125
126
127
128 static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
129 const unsigned *fetch_elts,
130 unsigned fetch_count,
131 const ushort *draw_elts,
132 unsigned draw_count )
133 {
134 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
135 struct draw_context *draw = fpme->draw;
136 struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
137 struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
138 unsigned opt = fpme->opt;
139 unsigned alloc_count = align( fetch_count, 4 );
140
141 struct vertex_header *pipeline_verts =
142 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
143
144 if (!pipeline_verts) {
145 /* Not much we can do here - just skip the rendering.
146 */
147 assert(0);
148 return;
149 }
150
151 /* Fetch into our vertex buffer
152 */
153 draw_pt_fetch_run( fpme->fetch,
154 fetch_elts,
155 fetch_count,
156 (char *)pipeline_verts );
157
158 /* Run the shader, note that this overwrites the data[] parts of
159 * the pipeline verts.
160 */
161 if (opt & PT_SHADE)
162 {
163 vshader->run_linear(vshader,
164 (const float (*)[4])pipeline_verts->data,
165 ( float (*)[4])pipeline_verts->data,
166 draw->pt.user.vs_constants,
167 fetch_count,
168 fpme->vertex_size,
169 fpme->vertex_size);
170 if (gshader)
171 draw_geometry_shader_run(gshader,
172 (const float (*)[4])pipeline_verts->data,
173 ( float (*)[4])pipeline_verts->data,
174 draw->pt.user.gs_constants,
175 fetch_count,
176 fpme->vertex_size,
177 fpme->vertex_size);
178 }
179
180 /* stream output needs to be done before clipping */
181 draw_pt_so_emit( fpme->so_emit,
182 (const float (*)[4])pipeline_verts->data,
183 fetch_count,
184 fpme->vertex_size );
185
186 if (draw_pt_post_vs_run( fpme->post_vs,
187 pipeline_verts,
188 fetch_count,
189 fpme->vertex_size ))
190 {
191 opt |= PT_PIPELINE;
192 }
193
194 /* Do we need to run the pipeline?
195 */
196 if (opt & PT_PIPELINE) {
197 draw_pipeline_run( fpme->draw,
198 fpme->prim,
199 pipeline_verts,
200 fetch_count,
201 fpme->vertex_size,
202 draw_elts,
203 draw_count );
204 }
205 else {
206 draw_pt_emit( fpme->emit,
207 (const float (*)[4])pipeline_verts->data,
208 fetch_count,
209 fpme->vertex_size,
210 draw_elts,
211 draw_count );
212 }
213
214
215 FREE(pipeline_verts);
216 }
217
218
219 static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
220 unsigned start,
221 unsigned count)
222 {
223 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
224 struct draw_context *draw = fpme->draw;
225 struct draw_vertex_shader *shader = draw->vs.vertex_shader;
226 struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
227 unsigned opt = fpme->opt;
228 unsigned alloc_count = align( count, 4 );
229
230 struct vertex_header *pipeline_verts =
231 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
232
233 if (!pipeline_verts) {
234 /* Not much we can do here - just skip the rendering.
235 */
236 assert(0);
237 return;
238 }
239
240 /* Fetch into our vertex buffer
241 */
242 draw_pt_fetch_run_linear( fpme->fetch,
243 start,
244 count,
245 (char *)pipeline_verts );
246
247 /* Run the shader, note that this overwrites the data[] parts of
248 * the pipeline verts.
249 */
250 if (opt & PT_SHADE)
251 {
252 shader->run_linear(shader,
253 (const float (*)[4])pipeline_verts->data,
254 ( float (*)[4])pipeline_verts->data,
255 draw->pt.user.vs_constants,
256 count,
257 fpme->vertex_size,
258 fpme->vertex_size);
259
260 if (geometry_shader)
261 draw_geometry_shader_run(geometry_shader,
262 (const float (*)[4])pipeline_verts->data,
263 ( float (*)[4])pipeline_verts->data,
264 draw->pt.user.gs_constants,
265 count,
266 fpme->vertex_size,
267 fpme->vertex_size);
268 }
269
270 /* stream output needs to be done before clipping */
271 draw_pt_so_emit( fpme->so_emit,
272 (const float (*)[4])pipeline_verts->data,
273 count,
274 fpme->vertex_size );
275
276 if (draw_pt_post_vs_run( fpme->post_vs,
277 pipeline_verts,
278 count,
279 fpme->vertex_size ))
280 {
281 opt |= PT_PIPELINE;
282 }
283
284 /* Do we need to run the pipeline?
285 */
286 if (opt & PT_PIPELINE) {
287 draw_pipeline_run_linear( fpme->draw,
288 fpme->prim,
289 pipeline_verts,
290 count,
291 fpme->vertex_size);
292 }
293 else {
294 draw_pt_emit_linear( fpme->emit,
295 (const float (*)[4])pipeline_verts->data,
296 fpme->vertex_size,
297 count );
298 }
299
300 FREE(pipeline_verts);
301 }
302
303
304
305 static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle,
306 unsigned start,
307 unsigned count,
308 const ushort *draw_elts,
309 unsigned draw_count )
310 {
311 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
312 struct draw_context *draw = fpme->draw;
313 struct draw_vertex_shader *shader = draw->vs.vertex_shader;
314 struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
315 unsigned opt = fpme->opt;
316 unsigned alloc_count = align( count, 4 );
317
318 struct vertex_header *pipeline_verts =
319 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
320
321 if (!pipeline_verts)
322 return FALSE;
323
324 /* Fetch into our vertex buffer
325 */
326 draw_pt_fetch_run_linear( fpme->fetch,
327 start,
328 count,
329 (char *)pipeline_verts );
330
331 /* Run the shader, note that this overwrites the data[] parts of
332 * the pipeline verts.
333 */
334 if (opt & PT_SHADE)
335 {
336 shader->run_linear(shader,
337 (const float (*)[4])pipeline_verts->data,
338 ( float (*)[4])pipeline_verts->data,
339 draw->pt.user.vs_constants,
340 count,
341 fpme->vertex_size,
342 fpme->vertex_size);
343
344 if (geometry_shader)
345 draw_geometry_shader_run(geometry_shader,
346 (const float (*)[4])pipeline_verts->data,
347 ( float (*)[4])pipeline_verts->data,
348 draw->pt.user.gs_constants,
349 count,
350 fpme->vertex_size,
351 fpme->vertex_size);
352 }
353
354 /* stream output needs to be done before clipping */
355 draw_pt_so_emit( fpme->so_emit,
356 (const float (*)[4])pipeline_verts->data,
357 count,
358 fpme->vertex_size );
359
360 if (draw_pt_post_vs_run( fpme->post_vs,
361 pipeline_verts,
362 count,
363 fpme->vertex_size ))
364 {
365 opt |= PT_PIPELINE;
366 }
367
368 /* Do we need to run the pipeline?
369 */
370 if (opt & PT_PIPELINE) {
371 draw_pipeline_run( fpme->draw,
372 fpme->prim,
373 pipeline_verts,
374 count,
375 fpme->vertex_size,
376 draw_elts,
377 draw_count );
378 }
379 else {
380 draw_pt_emit( fpme->emit,
381 (const float (*)[4])pipeline_verts->data,
382 count,
383 fpme->vertex_size,
384 draw_elts,
385 draw_count );
386 }
387
388 FREE(pipeline_verts);
389 return TRUE;
390 }
391
392
393
394 static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
395 {
396 /* nothing to do */
397 }
398
399 static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
400 {
401 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
402
403 if (fpme->fetch)
404 draw_pt_fetch_destroy( fpme->fetch );
405
406 if (fpme->emit)
407 draw_pt_emit_destroy( fpme->emit );
408
409 if (fpme->so_emit)
410 draw_pt_so_emit_destroy( fpme->so_emit );
411
412 if (fpme->post_vs)
413 draw_pt_post_vs_destroy( fpme->post_vs );
414
415 FREE(middle);
416 }
417
418
419 struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw )
420 {
421 struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end );
422 if (!fpme)
423 goto fail;
424
425 fpme->base.prepare = fetch_pipeline_prepare;
426 fpme->base.run = fetch_pipeline_run;
427 fpme->base.run_linear = fetch_pipeline_linear_run;
428 fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
429 fpme->base.finish = fetch_pipeline_finish;
430 fpme->base.destroy = fetch_pipeline_destroy;
431
432 fpme->draw = draw;
433
434 fpme->fetch = draw_pt_fetch_create( draw );
435 if (!fpme->fetch)
436 goto fail;
437
438 fpme->post_vs = draw_pt_post_vs_create( draw );
439 if (!fpme->post_vs)
440 goto fail;
441
442 fpme->emit = draw_pt_emit_create( draw );
443 if (!fpme->emit)
444 goto fail;
445
446 fpme->so_emit = draw_pt_so_emit_create( draw );
447 if (!fpme->so_emit)
448 goto fail;
449
450 return &fpme->base;
451
452 fail:
453 if (fpme)
454 fetch_pipeline_destroy( &fpme->base );
455
456 return NULL;
457 }