2 * Copyright 2003 Tungsten Graphics, inc.
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:
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
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.
25 * Keith Whitwell <keithw@tungstengraphics.com>
31 #include "pipe/p_compiler.h"
32 #include "pipe/p_util.h"
33 #include "rtasm/rtasm_execmem.h"
41 static boolean
match_fastpath( struct draw_vertex_fetch
*vf
,
42 const struct draw_vf_fastpath
*fp
)
46 if (vf
->attr_count
!= fp
->attr_count
)
49 for (j
= 0; j
< vf
->attr_count
; j
++)
50 if (vf
->attr
[j
].format
!= fp
->attr
[j
].format
||
51 vf
->attr
[j
].inputsize
!= fp
->attr
[j
].size
||
52 vf
->attr
[j
].vertoffset
!= fp
->attr
[j
].offset
)
55 if (fp
->match_strides
) {
56 if (vf
->vertex_stride
!= fp
->vertex_stride
)
59 for (j
= 0; j
< vf
->attr_count
; j
++)
60 if (vf
->attr
[j
].inputstride
!= fp
->attr
[j
].stride
)
67 static boolean
search_fastpath_emit( struct draw_vertex_fetch
*vf
)
69 struct draw_vf_fastpath
*fp
= vf
->fastpath
;
71 for ( ; fp
; fp
= fp
->next
) {
72 if (match_fastpath(vf
, fp
)) {
81 void draw_vf_register_fastpath( struct draw_vertex_fetch
*vf
,
82 boolean match_strides
)
84 struct draw_vf_fastpath
*fastpath
= CALLOC_STRUCT(draw_vf_fastpath
);
87 fastpath
->vertex_stride
= vf
->vertex_stride
;
88 fastpath
->attr_count
= vf
->attr_count
;
89 fastpath
->match_strides
= match_strides
;
90 fastpath
->func
= vf
->emit
;
91 fastpath
->attr
= (struct draw_vf_attr_type
*)
92 MALLOC(vf
->attr_count
* sizeof(fastpath
->attr
[0]));
94 for (i
= 0; i
< vf
->attr_count
; i
++) {
95 fastpath
->attr
[i
].format
= vf
->attr
[i
].format
;
96 fastpath
->attr
[i
].stride
= vf
->attr
[i
].inputstride
;
97 fastpath
->attr
[i
].size
= vf
->attr
[i
].inputsize
;
98 fastpath
->attr
[i
].offset
= vf
->attr
[i
].vertoffset
;
101 fastpath
->next
= vf
->fastpath
;
102 vf
->fastpath
= fastpath
;
108 /***********************************************************************
109 * Build codegen functions or return generic ones:
111 static void choose_emit_func( struct draw_vertex_fetch
*vf
,
117 /* Does this match an existing (hardwired, codegen or known-bad)
120 if (search_fastpath_emit(vf
)) {
121 /* Use this result. If it is null, then it is already known
122 * that the current state will fail for codegen and there is no
123 * point trying again.
126 else if (vf
->codegen_emit
) {
127 vf
->codegen_emit( vf
);
131 draw_vf_generate_hardwired_emit(vf
);
134 /* Otherwise use the generic version:
137 vf
->emit
= draw_vf_generic_emit
;
139 vf
->emit( vf
, count
, dest
);
146 /***********************************************************************
147 * Public entrypoints, mostly dispatch to the above:
153 draw_vf_set_vertex_attributes( struct draw_vertex_fetch
*vf
,
154 const struct draw_vf_attr_map
*map
,
156 unsigned vertex_stride
)
161 assert(nr
< PIPE_ATTRIB_MAX
);
163 for (j
= 0, i
= 0; i
< nr
; i
++) {
164 const unsigned format
= map
[i
].format
;
165 if (format
== DRAW_EMIT_PAD
) {
167 debug_printf("%d: pad %d, offset %d\n", i
,
168 map
[i
].offset
, offset
);
171 offset
+= map
[i
].offset
;
175 vf
->attr
[j
].attrib
= map
[i
].attrib
;
176 vf
->attr
[j
].format
= format
;
177 vf
->attr
[j
].insert
= draw_vf_format_info
[format
].insert
;
178 vf
->attr
[j
].vertattrsize
= draw_vf_format_info
[format
].attrsize
;
179 vf
->attr
[j
].vertoffset
= offset
;
180 vf
->attr
[j
].isconst
= draw_vf_format_info
[format
].isconst
;
181 if(vf
->attr
[j
].isconst
)
182 memcpy(vf
->attr
[j
].data
, &map
[i
].data
, vf
->attr
[j
].vertattrsize
);
185 debug_printf("%d: %s, offset %d\n", i
,
186 draw_vf_format_info
[format
].name
,
187 vf
->attr
[j
].vertoffset
);
190 offset
+= draw_vf_format_info
[format
].attrsize
;
196 vf
->vertex_stride
= vertex_stride
? vertex_stride
: offset
;
197 vf
->emit
= choose_emit_func
;
199 assert(vf
->vertex_stride
>= offset
);
200 return vf
->vertex_stride
;
204 void draw_vf_set_vertex_info( struct draw_vertex_fetch
*vf
,
205 const struct vertex_info
*vinfo
,
209 struct draw_vf_attr
*a
= vf
->attr
;
210 struct draw_vf_attr_map attrs
[PIPE_MAX_SHADER_INPUTS
];
211 unsigned count
= 0; /* for debug/sanity */
212 unsigned nr_attrs
= 0;
214 for (i
= 0; i
< vinfo
->num_attribs
; i
++) {
215 j
= vinfo
->src_index
[i
];
216 switch (vinfo
->emit
[i
]) {
221 /* just copy the whole vertex as-is to the vbuf */
222 unsigned s
= vinfo
->size
;
225 /* copy the vertex header */
226 /* XXX: we actually don't copy the header, just pad it */
227 attrs
[nr_attrs
].attrib
= 0;
228 attrs
[nr_attrs
].format
= DRAW_EMIT_PAD
;
229 attrs
[nr_attrs
].offset
= offsetof(struct vertex_header
, data
);
230 s
-= offsetof(struct vertex_header
, data
)/4;
231 count
+= offsetof(struct vertex_header
, data
)/4;
233 /* copy the vertex data */
234 for(k
= 0; k
< (s
& ~0x3); k
+= 4) {
235 attrs
[nr_attrs
].attrib
= k
/4;
236 attrs
[nr_attrs
].format
= DRAW_EMIT_4F
;
237 attrs
[nr_attrs
].offset
= 0;
242 /* XXX: actually, this shouldn't be needed */
243 attrs
[nr_attrs
].attrib
= k
/4;
244 attrs
[nr_attrs
].offset
= 0;
249 attrs
[nr_attrs
].format
= DRAW_EMIT_1F
;
254 attrs
[nr_attrs
].format
= DRAW_EMIT_2F
;
259 attrs
[nr_attrs
].format
= DRAW_EMIT_3F
;
267 attrs
[nr_attrs
].attrib
= j
;
268 attrs
[nr_attrs
].format
= DRAW_EMIT_1F
;
269 attrs
[nr_attrs
].offset
= 0;
274 attrs
[nr_attrs
].attrib
= j
;
275 attrs
[nr_attrs
].format
= DRAW_EMIT_1F_CONST
;
276 attrs
[nr_attrs
].offset
= 0;
277 attrs
[nr_attrs
].data
.f
[0] = point_size
;
282 attrs
[nr_attrs
].attrib
= j
;
283 attrs
[nr_attrs
].format
= DRAW_EMIT_2F
;
284 attrs
[nr_attrs
].offset
= 0;
289 attrs
[nr_attrs
].attrib
= j
;
290 attrs
[nr_attrs
].format
= DRAW_EMIT_3F
;
291 attrs
[nr_attrs
].offset
= 0;
296 attrs
[nr_attrs
].attrib
= j
;
297 attrs
[nr_attrs
].format
= DRAW_EMIT_4F
;
298 attrs
[nr_attrs
].offset
= 0;
303 attrs
[nr_attrs
].attrib
= j
;
304 attrs
[nr_attrs
].format
= DRAW_EMIT_4UB_4F_BGRA
;
305 attrs
[nr_attrs
].offset
= 0;
314 assert(count
== vinfo
->size
);
316 draw_vf_set_vertex_attributes(vf
,
319 vinfo
->size
* sizeof(float) );
321 for (j
= 0; j
< vf
->attr_count
; j
++) {
323 a
[j
].do_insert
= a
[j
].insert
[4 - 1];
325 a
[j
].inputptr
= a
[j
].data
;
326 a
[j
].inputstride
= 0;
333 /* Set attribute pointers, adjusted for start position:
335 void draw_vf_set_sources( struct draw_vertex_fetch
*vf
,
336 GLvector4f
* const sources
[],
339 struct draw_vf_attr
*a
= vf
->attr
;
342 for (j
= 0; j
< vf
->attr_count
; j
++) {
343 const GLvector4f
*vptr
= sources
[a
[j
].attrib
];
345 if ((a
[j
].inputstride
!= vptr
->stride
) ||
346 (a
[j
].inputsize
!= vptr
->size
))
347 vf
->emit
= choose_emit_func
;
349 a
[j
].inputstride
= vptr
->stride
;
350 a
[j
].inputsize
= vptr
->size
;
351 a
[j
].do_insert
= a
[j
].insert
[vptr
->size
- 1];
352 a
[j
].inputptr
= ((uint8_t *)vptr
->data
) + start
* vptr
->stride
;
359 * Emit a vertex to dest.
361 void draw_vf_emit_vertex( struct draw_vertex_fetch
*vf
,
362 struct vertex_header
*vertex
,
365 struct draw_vf_attr
*a
= vf
->attr
;
368 for (j
= 0; j
< vf
->attr_count
; j
++) {
370 a
[j
].inputptr
= (uint8_t *)&vertex
->data
[a
[j
].attrib
][0];
371 a
[j
].inputstride
= 0; /* XXX: one-vertex-max ATM */
375 vf
->emit( vf
, 1, (uint8_t*) dest
);
380 struct draw_vertex_fetch
*draw_vf_create( void )
382 struct draw_vertex_fetch
*vf
= CALLOC_STRUCT(draw_vertex_fetch
);
385 for (i
= 0; i
< PIPE_ATTRIB_MAX
; i
++)
388 vf
->identity
[0] = 0.0;
389 vf
->identity
[1] = 0.0;
390 vf
->identity
[2] = 0.0;
391 vf
->identity
[3] = 1.0;
393 vf
->codegen_emit
= NULL
;
396 if (!GETENV("GALLIUM_NO_CODEGEN"))
397 vf
->codegen_emit
= draw_vf_generate_sse_emit
;
404 void draw_vf_destroy( struct draw_vertex_fetch
*vf
)
406 struct draw_vf_fastpath
*fp
, *tmp
;
408 for (fp
= vf
->fastpath
; fp
; fp
= tmp
) {
412 /* KW: At the moment, fp->func is constrained to be allocated by
413 * rtasm_exec_alloc(), as the hardwired fastpaths in
414 * t_vertex_generic.c are handled specially. It would be nice
415 * to unify them, but this probably won't change until this
416 * module gets another overhaul.
418 //rtasm_exec_free((void *) fp->func);