draw: add passthrough path to the pipeline
[mesa.git] / src / gallium / auxiliary / draw / draw_pt_fetch_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 /*
29 * Authors:
30 * Keith Whitwell <keith@tungstengraphics.com>
31 */
32
33 #include "pipe/p_util.h"
34 #include "draw/draw_context.h"
35 #include "draw/draw_private.h"
36 #include "draw/draw_vertex.h"
37 #include "draw/draw_pt.h"
38
39 /* The simplest 'middle end' in the new vertex code.
40 *
41 * The responsibilities of a middle end are to:
42 * - perform vertex fetch using
43 * - draw vertex element/buffer state
44 * - a list of fetch indices we received as an input
45 * - run the vertex shader
46 * - cliptest,
47 * - clip coord calculation
48 * - viewport transformation
49 * - if necessary, run the primitive pipeline, passing it:
50 * - a linear array of vertex_header vertices constructed here
51 * - a set of draw indices we received as an input
52 * - otherwise, drive the hw backend,
53 * - allocate space for hardware format vertices
54 * - translate the vertex-shader output vertices to hw format
55 * - calling the backend draw functions.
56 *
57 * For convenience, we provide a helper function to drive the hardware
58 * backend given similar inputs to those required to run the pipeline.
59 *
60 * In the case of passthrough mode, many of these actions are disabled
61 * or noops, so we end up doing:
62 *
63 * - perform vertex fetch
64 * - drive the hw backend
65 *
66 * IE, basically just vertex fetch to post-vs-format vertices,
67 * followed by a call to the backend helper function.
68 */
69
70
71 struct fetch_pipeline_middle_end {
72 struct draw_pt_middle_end base;
73 struct draw_context *draw;
74
75 struct {
76 const ubyte *ptr;
77 unsigned pitch;
78 void (*fetch)( const void *from, float *attrib);
79 void (*emit)( const float *attrib, float **out );
80 } fetch[PIPE_MAX_ATTRIBS];
81
82 unsigned nr_fetch;
83 unsigned pipeline_vertex_size;
84 unsigned prim;
85 };
86
87
88 static void fetch_NULL( const void *from,
89 float *attrib )
90 {
91 }
92
93
94
95 static void emit_R32_FLOAT( const float *attrib,
96 float **out )
97 {
98 (*out)[0] = attrib[0];
99 (*out) += 1;
100 }
101
102 static void emit_R32G32_FLOAT( const float *attrib,
103 float **out )
104 {
105 (*out)[0] = attrib[0];
106 (*out)[1] = attrib[1];
107 (*out) += 2;
108 }
109
110 static void emit_R32G32B32_FLOAT( const float *attrib,
111 float **out )
112 {
113 (*out)[0] = attrib[0];
114 (*out)[1] = attrib[1];
115 (*out)[2] = attrib[2];
116 (*out) += 3;
117 }
118
119 static void emit_R32G32B32A32_FLOAT( const float *attrib,
120 float **out )
121 {
122 (*out)[0] = attrib[0];
123 (*out)[1] = attrib[1];
124 (*out)[2] = attrib[2];
125 (*out)[3] = attrib[3];
126 (*out) += 4;
127 }
128
129 static void emit_header( const float *attrib,
130 float **out )
131 {
132 (*out)[0] = 0;
133 (*out)[1] = 0;
134 (*out)[2] = 0;
135 (*out)[3] = 0;
136 (*out)[3] = 1;
137 (*out) += 5;
138 }
139
140 /**
141 * General-purpose fetch from user's vertex arrays, emit to driver's
142 * vertex buffer.
143 *
144 * XXX this is totally temporary.
145 */
146 static void
147 fetch_store_general( struct fetch_pipeline_middle_end *fpme,
148 void *out_ptr,
149 const unsigned *fetch_elts,
150 unsigned count )
151 {
152 float *out = (float *)out_ptr;
153 uint i, j;
154
155 for (i = 0; i < count; i++) {
156 unsigned elt = fetch_elts[i];
157
158 for (j = 0; j < fpme->nr_fetch; j++) {
159 float attrib[4];
160 const ubyte *from = (fpme->fetch[j].ptr +
161 fpme->fetch[j].pitch * elt);
162
163 fpme->fetch[j].fetch( from, attrib );
164 fpme->fetch[j].emit( attrib, &out );
165 }
166 }
167 }
168
169
170 /* We aren't running a vertex shader, but are running the pipeline.
171 * That means the vertices we need to build look like:
172 *
173 * dw0: vertex header (zero?)
174 * dw1: clip coord 0
175 * dw2: clip coord 1
176 * dw3: clip coord 2
177 * dw4: clip coord 4
178 * dw5: screen coord 0
179 * dw6: screen coord 0
180 * dw7: screen coord 0
181 * dw8: screen coord 0
182 * dw9: other attribs...
183 *
184 */
185 static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
186 unsigned prim )
187 {
188 static const float zero = 0;
189 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
190 struct draw_context *draw = fpme->draw;
191 unsigned i, nr = 0;
192
193 fpme->prim = prim;
194
195 /* Emit the vertex header and empty clipspace coord field:
196 */
197 {
198 fpme->fetch[nr].ptr = NULL;
199 fpme->fetch[nr].pitch = 0;
200 fpme->fetch[nr].fetch = fetch_NULL;
201 fpme->fetch[nr].emit = emit_header;
202 nr++;
203 }
204
205
206 /* Need to look at vertex shader inputs (we know it is a
207 * passthrough shader, so these define the outputs too). If we
208 * were running a shader, we'd still be looking at the inputs at
209 * this point.
210 */
211 for (i = 0; i < draw->vertex_shader->info.num_inputs; i++) {
212 unsigned buf = draw->vertex_element[i].vertex_buffer_index;
213 enum pipe_format format = draw->vertex_element[i].src_format;
214
215 fpme->fetch[nr].ptr = ((const ubyte *) draw->user.vbuffer[buf] +
216 draw->vertex_buffer[buf].buffer_offset +
217 draw->vertex_element[i].src_offset);
218
219 fpme->fetch[nr].pitch = draw->vertex_buffer[buf].pitch;
220 fpme->fetch[nr].fetch = draw_get_fetch_func( format );
221
222 /* Always do this -- somewhat redundant...
223 */
224 fpme->fetch[nr].emit = emit_R32G32B32A32_FLOAT;
225 nr++;
226 }
227
228 fpme->nr_fetch = nr;
229 fpme->pipeline_vertex_size = (5 + (nr-1) * 4) * sizeof(float);
230 }
231
232
233
234 /**
235 * Add a point to the primitive queue.
236 * \param i0 index into user's vertex arrays
237 */
238 static void do_point( struct draw_context *draw,
239 const char *v0 )
240 {
241 struct prim_header prim;
242
243 prim.reset_line_stipple = 0;
244 prim.edgeflags = 1;
245 prim.pad = 0;
246 prim.v[0] = (struct vertex_header *)v0;
247
248 draw->pipeline.first->point( draw->pipeline.first, &prim );
249 }
250
251
252 /**
253 * Add a line to the primitive queue.
254 * \param i0 index into user's vertex arrays
255 * \param i1 index into user's vertex arrays
256 */
257 static void do_line( struct draw_context *draw,
258 const char *v0,
259 const char *v1 )
260 {
261 struct prim_header prim;
262
263 prim.reset_line_stipple = 1; /* fixme */
264 prim.edgeflags = 1;
265 prim.pad = 0;
266 prim.v[0] = (struct vertex_header *)v0;
267 prim.v[1] = (struct vertex_header *)v1;
268
269 draw->pipeline.first->line( draw->pipeline.first, &prim );
270 }
271
272 /**
273 * Add a triangle to the primitive queue.
274 */
275 static void do_triangle( struct draw_context *draw,
276 char *v0,
277 char *v1,
278 char *v2 )
279 {
280 struct prim_header prim;
281
282 // _mesa_printf("tri %d %d %d\n", i0, i1, i2);
283 prim.reset_line_stipple = 1;
284 prim.edgeflags = ~0;
285 prim.pad = 0;
286 prim.v[0] = (struct vertex_header *)v0;
287 prim.v[1] = (struct vertex_header *)v1;
288 prim.v[2] = (struct vertex_header *)v2;
289
290 draw->pipeline.first->tri( draw->pipeline.first, &prim );
291 }
292
293
294 static void run_pipeline( struct fetch_pipeline_middle_end *fpme,
295 char *verts,
296 const ushort *elts,
297 unsigned count )
298 {
299 struct draw_context *draw = fpme->draw;
300 unsigned stride = fpme->pipeline_vertex_size;
301 unsigned i;
302
303 switch (fpme->prim) {
304 case PIPE_PRIM_POINTS:
305 for (i = 0; i < count; i++)
306 do_point( draw,
307 verts + stride * elts[i] );
308 break;
309 case PIPE_PRIM_LINES:
310 for (i = 0; i+1 < count; i += 2)
311 do_line( draw,
312 verts + stride * elts[i+0],
313 verts + stride * elts[i+1]);
314 break;
315 case PIPE_PRIM_TRIANGLES:
316 for (i = 0; i+2 < count; i += 3)
317 do_triangle( draw,
318 verts + stride * elts[i+0],
319 verts + stride * elts[i+1],
320 verts + stride * elts[i+2]);
321 break;
322 }
323 }
324
325
326
327
328 static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
329 const unsigned *fetch_elts,
330 unsigned fetch_count,
331 const ushort *draw_elts,
332 unsigned draw_count )
333 {
334 struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
335 struct draw_context *draw = fpme->draw;
336 char *pipeline_verts;
337
338 pipeline_verts = MALLOC( fpme->pipeline_vertex_size *
339 fetch_count );
340 if (!pipeline_verts) {
341 assert(0);
342 return;
343 }
344
345
346 /* Single routine to fetch vertices and emit pipeline verts.
347 */
348 fetch_store_general( fpme,
349 pipeline_verts,
350 fetch_elts,
351 fetch_count );
352
353
354 run_pipeline( fpme,
355 pipeline_verts,
356 draw_elts,
357 draw_count );
358
359
360 /* Done -- that was easy, wasn't it:
361 */
362 FREE( pipeline_verts );
363 }
364
365
366
367 static void fetch_pipeline_finish( struct draw_pt_middle_end *middle )
368 {
369 /* nothing to do */
370 }
371
372 static void fetch_pipeline_destroy( struct draw_pt_middle_end *middle )
373 {
374 FREE(middle);
375 }
376
377
378 struct draw_pt_middle_end *draw_pt_fetch_pipeline( struct draw_context *draw )
379 {
380 struct fetch_pipeline_middle_end *fetch_pipeline = CALLOC_STRUCT( fetch_pipeline_middle_end );
381
382 fetch_pipeline->base.prepare = fetch_pipeline_prepare;
383 fetch_pipeline->base.run = fetch_pipeline_run;
384 fetch_pipeline->base.finish = fetch_pipeline_finish;
385 fetch_pipeline->base.destroy = fetch_pipeline_destroy;
386
387 fetch_pipeline->draw = draw;
388
389 return &fetch_pipeline->base;
390 }
391