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