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