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