23da556f797ed019e8b75c13a135370438849399
[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 #include "translate/translate.h"
37
38
39 struct fetch_pipeline_middle_end {
40 struct draw_pt_middle_end base;
41 struct draw_context *draw;
42
43 struct pt_emit *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 draw->rasterizer->bypass_vs_clip_and_viewport),
102 (boolean)draw->rasterizer->gl_rasterization_rules,
103 (draw->vs.edgeflag_output ? true : false) );
104
105 if (!(opt & PT_PIPELINE)) {
106 draw_pt_emit_prepare( fpme->emit,
107 prim,
108 max_vertices );
109
110 *max_vertices = MAX2( *max_vertices,
111 DRAW_PIPE_MAX_VERTICES );
112 }
113 else {
114 *max_vertices = DRAW_PIPE_MAX_VERTICES;
115 }
116
117 /* return even number */
118 *max_vertices = *max_vertices & ~1;
119
120 /* No need to prepare the shader.
121 */
122 vs->prepare(vs, draw);
123 }
124
125
126
127 static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
128 const unsigned *fetch_elts,
129 unsigned fetch_count,
130 const ushort *draw_elts,
131 unsigned draw_count )
132 {
133 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
134 struct draw_context *draw = fpme->draw;
135 struct draw_vertex_shader *vshader = draw->vs.vertex_shader;
136 struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
137 unsigned opt = fpme->opt;
138 unsigned alloc_count = align( fetch_count, 4 );
139
140 struct vertex_header *pipeline_verts =
141 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
142
143 if (!pipeline_verts) {
144 /* Not much we can do here - just skip the rendering.
145 */
146 assert(0);
147 return;
148 }
149
150 /* Fetch into our vertex buffer
151 */
152 draw_pt_fetch_run( fpme->fetch,
153 fetch_elts,
154 fetch_count,
155 (char *)pipeline_verts );
156
157 /* Run the shader, note that this overwrites the data[] parts of
158 * the pipeline verts. If there is no shader, eg if
159 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
160 * already in the correct place.
161 */
162 if (opt & PT_SHADE)
163 {
164 vshader->run_linear(vshader,
165 (const float (*)[4])pipeline_verts->data,
166 ( float (*)[4])pipeline_verts->data,
167 (const float (*)[4])draw->pt.user.vs_constants,
168 fetch_count,
169 fpme->vertex_size,
170 fpme->vertex_size);
171 if (gshader)
172 draw_geometry_shader_run(gshader,
173 (const float (*)[4])pipeline_verts->data,
174 ( float (*)[4])pipeline_verts->data,
175 (const float (*)[4])draw->pt.user.gs_constants,
176 fetch_count,
177 fpme->vertex_size,
178 fpme->vertex_size);
179 }
180
181 if (draw_pt_post_vs_run( fpme->post_vs,
182 pipeline_verts,
183 fetch_count,
184 fpme->vertex_size ))
185 {
186 opt |= PT_PIPELINE;
187 }
188
189 /* Do we need to run the pipeline?
190 */
191 if (opt & PT_PIPELINE) {
192 draw_pipeline_run( fpme->draw,
193 fpme->prim,
194 pipeline_verts,
195 fetch_count,
196 fpme->vertex_size,
197 draw_elts,
198 draw_count );
199 }
200 else {
201 draw_pt_emit( fpme->emit,
202 (const float (*)[4])pipeline_verts->data,
203 fetch_count,
204 fpme->vertex_size,
205 draw_elts,
206 draw_count );
207 }
208
209
210 FREE(pipeline_verts);
211 }
212
213
214 static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
215 unsigned start,
216 unsigned count)
217 {
218 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
219 struct draw_context *draw = fpme->draw;
220 struct draw_vertex_shader *shader = draw->vs.vertex_shader;
221 struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
222 unsigned opt = fpme->opt;
223 unsigned alloc_count = align( count, 4 );
224
225 struct vertex_header *pipeline_verts =
226 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
227
228 if (!pipeline_verts) {
229 /* Not much we can do here - just skip the rendering.
230 */
231 assert(0);
232 return;
233 }
234
235 /* Fetch into our vertex buffer
236 */
237 draw_pt_fetch_run_linear( fpme->fetch,
238 start,
239 count,
240 (char *)pipeline_verts );
241
242 /* Run the shader, note that this overwrites the data[] parts of
243 * the pipeline verts. If there is no shader, ie if
244 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
245 * already in the correct place.
246 */
247 if (opt & PT_SHADE)
248 {
249 shader->run_linear(shader,
250 (const float (*)[4])pipeline_verts->data,
251 ( float (*)[4])pipeline_verts->data,
252 (const float (*)[4])draw->pt.user.vs_constants,
253 count,
254 fpme->vertex_size,
255 fpme->vertex_size);
256
257 if (geometry_shader)
258 draw_geometry_shader_run(geometry_shader,
259 (const float (*)[4])pipeline_verts->data,
260 ( float (*)[4])pipeline_verts->data,
261 (const float (*)[4])draw->pt.user.gs_constants,
262 count,
263 fpme->vertex_size,
264 fpme->vertex_size);
265 }
266
267 if (draw_pt_post_vs_run( fpme->post_vs,
268 pipeline_verts,
269 count,
270 fpme->vertex_size ))
271 {
272 opt |= PT_PIPELINE;
273 }
274
275 /* Do we need to run the pipeline?
276 */
277 if (opt & PT_PIPELINE) {
278 draw_pipeline_run_linear( fpme->draw,
279 fpme->prim,
280 pipeline_verts,
281 count,
282 fpme->vertex_size);
283 }
284 else {
285 draw_pt_emit_linear( fpme->emit,
286 (const float (*)[4])pipeline_verts->data,
287 fpme->vertex_size,
288 count );
289 }
290
291 FREE(pipeline_verts);
292 }
293
294
295
296 static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle,
297 unsigned start,
298 unsigned count,
299 const ushort *draw_elts,
300 unsigned draw_count )
301 {
302 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
303 struct draw_context *draw = fpme->draw;
304 struct draw_vertex_shader *shader = draw->vs.vertex_shader;
305 struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
306 unsigned opt = fpme->opt;
307 unsigned alloc_count = align( count, 4 );
308
309 struct vertex_header *pipeline_verts =
310 (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
311
312 if (!pipeline_verts)
313 return FALSE;
314
315 /* Fetch into our vertex buffer
316 */
317 draw_pt_fetch_run_linear( fpme->fetch,
318 start,
319 count,
320 (char *)pipeline_verts );
321
322 /* Run the shader, note that this overwrites the data[] parts of
323 * the pipeline verts. If there is no shader, ie if
324 * bypass_vs_clip_and_viewport, then the inputs == outputs, and are
325 * already in the correct place.
326 */
327 if (opt & PT_SHADE)
328 {
329 shader->run_linear(shader,
330 (const float (*)[4])pipeline_verts->data,
331 ( float (*)[4])pipeline_verts->data,
332 (const float (*)[4])draw->pt.user.vs_constants,
333 count,
334 fpme->vertex_size,
335 fpme->vertex_size);
336
337 if (geometry_shader)
338 draw_geometry_shader_run(geometry_shader,
339 (const float (*)[4])pipeline_verts->data,
340 ( float (*)[4])pipeline_verts->data,
341 (const float (*)[4])draw->pt.user.gs_constants,
342 count,
343 fpme->vertex_size,
344 fpme->vertex_size);
345 }
346
347 if (draw_pt_post_vs_run( fpme->post_vs,
348 pipeline_verts,
349 count,
350 fpme->vertex_size ))
351 {
352 opt |= PT_PIPELINE;
353 }
354
355 /* Do we need to run the pipeline?
356 */
357 if (opt & PT_PIPELINE) {
358 draw_pipeline_run( fpme->draw,
359 fpme->prim,
360 pipeline_verts,
361 count,
362 fpme->vertex_size,
363 draw_elts,
364 draw_count );
365 }
366 else {
367 draw_pt_emit( fpme->emit,
368 (const float (*)[4])pipeline_verts->data,
369 count,
370 fpme->vertex_size,
371 draw_elts,
372 draw_count );
373 }
374
375 FREE(pipeline_verts);
376 return TRUE;
377 }
378
379
380
381 static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
382 {
383 /* nothing to do */
384 }
385
386 static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
387 {
388 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
389
390 if (fpme->fetch)
391 draw_pt_fetch_destroy( fpme->fetch );
392
393 if (fpme->emit)
394 draw_pt_emit_destroy( fpme->emit );
395
396 if (fpme->post_vs)
397 draw_pt_post_vs_destroy( fpme->post_vs );
398
399 FREE(middle);
400 }
401
402
403 struct draw_pt_middle_end *draw_pt_fetch_pipeline_or_emit( struct draw_context *draw )
404 {
405 struct fetch_pipeline_middle_end *fpme = CALLOC_STRUCT( fetch_pipeline_middle_end );
406 if (!fpme)
407 goto fail;
408
409 fpme->base.prepare = fetch_pipeline_prepare;
410 fpme->base.run = fetch_pipeline_run;
411 fpme->base.run_linear = fetch_pipeline_linear_run;
412 fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
413 fpme->base.finish = fetch_pipeline_finish;
414 fpme->base.destroy = fetch_pipeline_destroy;
415
416 fpme->draw = draw;
417
418 fpme->fetch = draw_pt_fetch_create( draw );
419 if (!fpme->fetch)
420 goto fail;
421
422 fpme->post_vs = draw_pt_post_vs_create( draw );
423 if (!fpme->post_vs)
424 goto fail;
425
426 fpme->emit = draw_pt_emit_create( draw );
427 if (!fpme->emit)
428 goto fail;
429
430 return &fpme->base;
431
432 fail:
433 if (fpme)
434 fetch_pipeline_destroy( &fpme->base );
435
436 return NULL;
437 }