dc3a5ecd21952a41227c8b2ddc5a44e4089caade
[mesa.git] / src / gallium / aux / draw / draw_vf.c
1 /*
2 * Copyright 2003 Tungsten Graphics, inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * on the rights to use, copy, modify, merge, publish, distribute, sub
9 * license, and/or sell copies of the Software, and to permit persons to whom
10 * the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * TUNGSTEN GRAPHICS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
22 * USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Keith Whitwell <keithw@tungstengraphics.com>
26 */
27
28
29 #include <stddef.h>
30
31 #include "pipe/p_compiler.h"
32 #include "pipe/p_util.h"
33
34 #include "draw_vf.h"
35
36
37 #define DRAW_VF_DBG 0
38
39
40 /* TODO: remove this */
41 extern void
42 _mesa_exec_free( void *addr );
43
44
45 static boolean match_fastpath( struct draw_vertex_fetch *vf,
46 const struct draw_vf_fastpath *fp)
47 {
48 unsigned j;
49
50 if (vf->attr_count != fp->attr_count)
51 return FALSE;
52
53 for (j = 0; j < vf->attr_count; j++)
54 if (vf->attr[j].format != fp->attr[j].format ||
55 vf->attr[j].inputsize != fp->attr[j].size ||
56 vf->attr[j].vertoffset != fp->attr[j].offset)
57 return FALSE;
58
59 if (fp->match_strides) {
60 if (vf->vertex_stride != fp->vertex_stride)
61 return FALSE;
62
63 for (j = 0; j < vf->attr_count; j++)
64 if (vf->attr[j].inputstride != fp->attr[j].stride)
65 return FALSE;
66 }
67
68 return TRUE;
69 }
70
71 static boolean search_fastpath_emit( struct draw_vertex_fetch *vf )
72 {
73 struct draw_vf_fastpath *fp = vf->fastpath;
74
75 for ( ; fp ; fp = fp->next) {
76 if (match_fastpath(vf, fp)) {
77 vf->emit = fp->func;
78 return TRUE;
79 }
80 }
81
82 return FALSE;
83 }
84
85 void draw_vf_register_fastpath( struct draw_vertex_fetch *vf,
86 boolean match_strides )
87 {
88 struct draw_vf_fastpath *fastpath = CALLOC_STRUCT(draw_vf_fastpath);
89 unsigned i;
90
91 fastpath->vertex_stride = vf->vertex_stride;
92 fastpath->attr_count = vf->attr_count;
93 fastpath->match_strides = match_strides;
94 fastpath->func = vf->emit;
95 fastpath->attr = (struct draw_vf_attr_type *)
96 MALLOC(vf->attr_count * sizeof(fastpath->attr[0]));
97
98 for (i = 0; i < vf->attr_count; i++) {
99 fastpath->attr[i].format = vf->attr[i].format;
100 fastpath->attr[i].stride = vf->attr[i].inputstride;
101 fastpath->attr[i].size = vf->attr[i].inputsize;
102 fastpath->attr[i].offset = vf->attr[i].vertoffset;
103 }
104
105 fastpath->next = vf->fastpath;
106 vf->fastpath = fastpath;
107 }
108
109
110
111
112 /***********************************************************************
113 * Build codegen functions or return generic ones:
114 */
115 static void choose_emit_func( struct draw_vertex_fetch *vf,
116 unsigned count,
117 uint8_t *dest)
118 {
119 vf->emit = NULL;
120
121 /* Does this match an existing (hardwired, codegen or known-bad)
122 * fastpath?
123 */
124 if (search_fastpath_emit(vf)) {
125 /* Use this result. If it is null, then it is already known
126 * that the current state will fail for codegen and there is no
127 * point trying again.
128 */
129 }
130 else if (vf->codegen_emit) {
131 vf->codegen_emit( vf );
132 }
133
134 if (!vf->emit) {
135 draw_vf_generate_hardwired_emit(vf);
136 }
137
138 /* Otherwise use the generic version:
139 */
140 if (!vf->emit)
141 vf->emit = draw_vf_generic_emit;
142
143 vf->emit( vf, count, dest );
144 }
145
146
147
148
149
150 /***********************************************************************
151 * Public entrypoints, mostly dispatch to the above:
152 */
153
154
155
156 static unsigned
157 draw_vf_set_vertex_attributes( struct draw_vertex_fetch *vf,
158 const struct draw_vf_attr_map *map,
159 unsigned nr,
160 unsigned vertex_stride )
161 {
162 unsigned offset = 0;
163 unsigned i, j;
164
165 assert(nr < PIPE_ATTRIB_MAX);
166
167 for (j = 0, i = 0; i < nr; i++) {
168 const unsigned format = map[i].format;
169 if (format == DRAW_EMIT_PAD) {
170 #if (DRAW_VF_DBG)
171 debug_printf("%d: pad %d, offset %d\n", i,
172 map[i].offset, offset);
173 #endif
174
175 offset += map[i].offset;
176
177 }
178 else {
179 vf->attr[j].attrib = map[i].attrib;
180 vf->attr[j].format = format;
181 vf->attr[j].insert = draw_vf_format_info[format].insert;
182 vf->attr[j].vertattrsize = draw_vf_format_info[format].attrsize;
183 vf->attr[j].vertoffset = offset;
184 vf->attr[j].isconst = draw_vf_format_info[format].isconst;
185 if(vf->attr[j].isconst)
186 memcpy(vf->attr[j].data, &map[i].data, vf->attr[j].vertattrsize);
187
188 #if (DRAW_VF_DBG)
189 debug_printf("%d: %s, offset %d\n", i,
190 draw_vf_format_info[format].name,
191 vf->attr[j].vertoffset);
192 #endif
193
194 offset += draw_vf_format_info[format].attrsize;
195 j++;
196 }
197 }
198
199 vf->attr_count = j;
200 vf->vertex_stride = vertex_stride ? vertex_stride : offset;
201 vf->emit = choose_emit_func;
202
203 assert(vf->vertex_stride >= offset);
204 return vf->vertex_stride;
205 }
206
207
208 void draw_vf_set_vertex_info( struct draw_vertex_fetch *vf,
209 const struct vertex_info *vinfo,
210 float point_size )
211 {
212 unsigned i, j, k;
213 struct draw_vf_attr *a = vf->attr;
214 struct draw_vf_attr_map attrs[PIPE_MAX_SHADER_INPUTS];
215 unsigned count = 0; /* for debug/sanity */
216 unsigned nr_attrs = 0;
217
218 for (i = 0; i < vinfo->num_attribs; i++) {
219 j = vinfo->src_index[i];
220 switch (vinfo->emit[i]) {
221 case EMIT_OMIT:
222 /* no-op */
223 break;
224 case EMIT_ALL: {
225 /* just copy the whole vertex as-is to the vbuf */
226 unsigned s = vinfo->size;
227 assert(i == 0);
228 assert(j == 0);
229 /* copy the vertex header */
230 /* XXX: we actually don't copy the header, just pad it */
231 attrs[nr_attrs].attrib = 0;
232 attrs[nr_attrs].format = DRAW_EMIT_PAD;
233 attrs[nr_attrs].offset = offsetof(struct vertex_header, data);
234 s -= offsetof(struct vertex_header, data)/4;
235 count += offsetof(struct vertex_header, data)/4;
236 nr_attrs++;
237 /* copy the vertex data */
238 for(k = 0; k < (s & ~0x3); k += 4) {
239 attrs[nr_attrs].attrib = k/4;
240 attrs[nr_attrs].format = DRAW_EMIT_4F;
241 attrs[nr_attrs].offset = 0;
242 nr_attrs++;
243 count += 4;
244 }
245 /* tail */
246 /* XXX: actually, this shouldn't be needed */
247 attrs[nr_attrs].attrib = k/4;
248 attrs[nr_attrs].offset = 0;
249 switch(s & 0x3) {
250 case 0:
251 break;
252 case 1:
253 attrs[nr_attrs].format = DRAW_EMIT_1F;
254 nr_attrs++;
255 count += 1;
256 break;
257 case 2:
258 attrs[nr_attrs].format = DRAW_EMIT_2F;
259 nr_attrs++;
260 count += 2;
261 break;
262 case 3:
263 attrs[nr_attrs].format = DRAW_EMIT_3F;
264 nr_attrs++;
265 count += 3;
266 break;
267 }
268 break;
269 }
270 case EMIT_1F:
271 attrs[nr_attrs].attrib = j;
272 attrs[nr_attrs].format = DRAW_EMIT_1F;
273 attrs[nr_attrs].offset = 0;
274 nr_attrs++;
275 count++;
276 break;
277 case EMIT_1F_PSIZE:
278 attrs[nr_attrs].attrib = j;
279 attrs[nr_attrs].format = DRAW_EMIT_1F_CONST;
280 attrs[nr_attrs].offset = 0;
281 attrs[nr_attrs].data.f[0] = point_size;
282 nr_attrs++;
283 count++;
284 break;
285 case EMIT_2F:
286 attrs[nr_attrs].attrib = j;
287 attrs[nr_attrs].format = DRAW_EMIT_2F;
288 attrs[nr_attrs].offset = 0;
289 nr_attrs++;
290 count += 2;
291 break;
292 case EMIT_3F:
293 attrs[nr_attrs].attrib = j;
294 attrs[nr_attrs].format = DRAW_EMIT_3F;
295 attrs[nr_attrs].offset = 0;
296 nr_attrs++;
297 count += 3;
298 break;
299 case EMIT_4F:
300 attrs[nr_attrs].attrib = j;
301 attrs[nr_attrs].format = DRAW_EMIT_4F;
302 attrs[nr_attrs].offset = 0;
303 nr_attrs++;
304 count += 4;
305 break;
306 case EMIT_4UB:
307 attrs[nr_attrs].attrib = j;
308 attrs[nr_attrs].format = DRAW_EMIT_4UB_4F_BGRA;
309 attrs[nr_attrs].offset = 0;
310 nr_attrs++;
311 count += 1;
312 break;
313 default:
314 assert(0);
315 }
316 }
317
318 assert(count == vinfo->size);
319
320 draw_vf_set_vertex_attributes(vf,
321 attrs,
322 nr_attrs,
323 vinfo->size * sizeof(float) );
324
325 for (j = 0; j < vf->attr_count; j++) {
326 a[j].inputsize = 4;
327 a[j].do_insert = a[j].insert[4 - 1];
328 if(a[j].isconst) {
329 a[j].inputptr = a[j].data;
330 a[j].inputstride = 0;
331 }
332 }
333 }
334
335
336 #if 0
337 /* Set attribute pointers, adjusted for start position:
338 */
339 void draw_vf_set_sources( struct draw_vertex_fetch *vf,
340 GLvector4f * const sources[],
341 unsigned start )
342 {
343 struct draw_vf_attr *a = vf->attr;
344 unsigned j;
345
346 for (j = 0; j < vf->attr_count; j++) {
347 const GLvector4f *vptr = sources[a[j].attrib];
348
349 if ((a[j].inputstride != vptr->stride) ||
350 (a[j].inputsize != vptr->size))
351 vf->emit = choose_emit_func;
352
353 a[j].inputstride = vptr->stride;
354 a[j].inputsize = vptr->size;
355 a[j].do_insert = a[j].insert[vptr->size - 1];
356 a[j].inputptr = ((uint8_t *)vptr->data) + start * vptr->stride;
357 }
358 }
359 #endif
360
361
362 /**
363 * Emit a vertex to dest.
364 */
365 void draw_vf_emit_vertex( struct draw_vertex_fetch *vf,
366 struct vertex_header *vertex,
367 void *dest )
368 {
369 struct draw_vf_attr *a = vf->attr;
370 unsigned j;
371
372 for (j = 0; j < vf->attr_count; j++) {
373 if (!a[j].isconst) {
374 a[j].inputptr = (uint8_t *)&vertex->data[a[j].attrib][0];
375 a[j].inputstride = 0; /* XXX: one-vertex-max ATM */
376 }
377 }
378
379 vf->emit( vf, 1, (uint8_t*) dest );
380 }
381
382
383
384 struct draw_vertex_fetch *draw_vf_create( void )
385 {
386 struct draw_vertex_fetch *vf = CALLOC_STRUCT(draw_vertex_fetch);
387 unsigned i;
388
389 for (i = 0; i < PIPE_ATTRIB_MAX; i++)
390 vf->attr[i].vf = vf;
391
392 vf->identity[0] = 0.0;
393 vf->identity[1] = 0.0;
394 vf->identity[2] = 0.0;
395 vf->identity[3] = 1.0;
396
397 vf->codegen_emit = NULL;
398
399 #ifdef USE_SSE_ASM
400 if (!GETENV("GALLIUM_NO_CODEGEN"))
401 vf->codegen_emit = draw_vf_generate_sse_emit;
402 #endif
403
404 return vf;
405 }
406
407
408 void draw_vf_destroy( struct draw_vertex_fetch *vf )
409 {
410 struct draw_vf_fastpath *fp, *tmp;
411
412 for (fp = vf->fastpath ; fp ; fp = tmp) {
413 tmp = fp->next;
414 FREE(fp->attr);
415
416 /* KW: At the moment, fp->func is constrained to be allocated by
417 * _mesa_exec_alloc(), as the hardwired fastpaths in
418 * t_vertex_generic.c are handled specially. It would be nice
419 * to unify them, but this probably won't change until this
420 * module gets another overhaul.
421 */
422 //_mesa_exec_free((void *) fp->func);
423 FREE(fp);
424 }
425
426 vf->fastpath = NULL;
427 FREE(vf);
428 }