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>
32 #include "t_context.h"
37 /* Build and manage clipspace/ndc/window vertices.
40 static GLboolean
match_fastpath( struct tnl_clipspace
*vtx
,
41 const struct tnl_clipspace_fastpath
*fp
)
45 if (vtx
->attr_count
!= fp
->attr_count
)
48 for (j
= 0; j
< vtx
->attr_count
; j
++)
49 if (vtx
->attr
[j
].format
!= fp
->attr
[j
].format
)
52 if (fp
->match_strides
) {
53 if (vtx
->vertex_size
!= fp
->vertex_size
)
56 for (j
= 0; j
< vtx
->attr_count
; j
++)
57 if (vtx
->attr
[j
].inputstride
!= fp
->attr
[j
].stride
)
64 static GLboolean
search_fastpath_emit( struct tnl_clipspace
*vtx
)
66 struct tnl_clipspace_fastpath
*fp
= vtx
->fastpath
;
68 for ( ; fp
; fp
= fp
->next
) {
69 if (match_fastpath(vtx
, fp
)) {
78 void _tnl_register_fastpath( struct tnl_clipspace
*vtx
,
79 GLboolean match_strides
)
81 struct tnl_clipspace_fastpath
*fastpath
= CALLOC_STRUCT(tnl_clipspace_fastpath
);
84 fastpath
->vertex_size
= vtx
->vertex_size
;
85 fastpath
->attr_count
= vtx
->attr_count
;
86 fastpath
->match_strides
= match_strides
;
87 fastpath
->func
= vtx
->emit
;
88 fastpath
->attr
= MALLOC(vtx
->attr_count
* sizeof(fastpath
->attr
[0]));
90 for (i
= 0; i
< vtx
->attr_count
; i
++) {
91 fastpath
->attr
[i
].format
= vtx
->attr
[i
].format
;
92 fastpath
->attr
[i
].stride
= vtx
->attr
[i
].inputstride
;
95 fastpath
->next
= vtx
->fastpath
;
96 vtx
->fastpath
= fastpath
;
101 /***********************************************************************
102 * Build codegen functions or return generic ones:
104 static void choose_emit_func( GLcontext
*ctx
, GLuint count
, GLubyte
*dest
)
106 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
107 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
108 struct tnl_clipspace_attr
*a
= vtx
->attr
;
109 const GLuint attr_count
= vtx
->attr_count
;
112 for (j
= 0; j
< attr_count
; j
++) {
113 GLvector4f
*vptr
= VB
->AttribPtr
[a
[j
].attrib
];
114 a
[j
].inputstride
= vptr
->stride
;
115 a
[j
].inputsize
= vptr
->size
;
116 a
[j
].emit
= a
[j
].insert
[vptr
->size
- 1]; /* not always used */
121 /* Does this match an existing (hardwired, codegen or known-bad)
124 if (search_fastpath_emit(vtx
)) {
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.
130 else if (vtx
->codegen_emit
) {
131 vtx
->codegen_emit(ctx
);
135 _tnl_generate_hardwired_emit(ctx
);
138 /* Otherwise use the generic version:
141 vtx
->emit
= _tnl_generic_emit
;
143 vtx
->emit( ctx
, count
, dest
);
148 static void choose_interp_func( GLcontext
*ctx
,
150 GLuint edst
, GLuint eout
, GLuint ein
,
151 GLboolean force_boundary
)
153 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
155 if (vtx
->need_extras
&&
156 (ctx
->_TriangleCaps
& (DD_TRI_LIGHT_TWOSIDE
|DD_TRI_UNFILLED
))) {
157 vtx
->interp
= _tnl_generic_interp_extras
;
159 vtx
->interp
= _tnl_generic_interp
;
162 vtx
->interp( ctx
, t
, edst
, eout
, ein
, force_boundary
);
166 static void choose_copy_pv_func( GLcontext
*ctx
, GLuint edst
, GLuint esrc
)
168 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
170 if (vtx
->need_extras
&&
171 (ctx
->_TriangleCaps
& (DD_TRI_LIGHT_TWOSIDE
|DD_TRI_UNFILLED
))) {
172 vtx
->copy_pv
= _tnl_generic_copy_pv_extras
;
174 vtx
->copy_pv
= _tnl_generic_copy_pv
;
177 vtx
->copy_pv( ctx
, edst
, esrc
);
181 /***********************************************************************
182 * Public entrypoints, mostly dispatch to the above:
186 /* Interpolate between two vertices to produce a third:
188 void _tnl_interp( GLcontext
*ctx
,
190 GLuint edst
, GLuint eout
, GLuint ein
,
191 GLboolean force_boundary
)
193 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
194 vtx
->interp( ctx
, t
, edst
, eout
, ein
, force_boundary
);
197 /* Copy colors from one vertex to another:
199 void _tnl_copy_pv( GLcontext
*ctx
, GLuint edst
, GLuint esrc
)
201 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
202 vtx
->copy_pv( ctx
, edst
, esrc
);
206 /* Extract a named attribute from a hardware vertex. Will have to
207 * reverse any viewport transformation, swizzling or other conversions
208 * which may have been applied:
210 void _tnl_get_attr( GLcontext
*ctx
, const void *vin
,
211 GLenum attr
, GLfloat
*dest
)
213 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
214 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
215 const GLuint attr_count
= vtx
->attr_count
;
218 for (j
= 0; j
< attr_count
; j
++) {
219 if (a
[j
].attrib
== attr
) {
220 a
[j
].extract( &a
[j
], dest
, (GLubyte
*)vin
+ a
[j
].vertoffset
);
225 /* Else return the value from ctx->Current.
227 _mesa_memcpy( dest
, ctx
->Current
.Attrib
[attr
], 4*sizeof(GLfloat
));
231 /* Complementary operation to the above.
233 void _tnl_set_attr( GLcontext
*ctx
, void *vout
,
234 GLenum attr
, const GLfloat
*src
)
236 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
237 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
238 const GLuint attr_count
= vtx
->attr_count
;
241 for (j
= 0; j
< attr_count
; j
++) {
242 if (a
[j
].attrib
== attr
) {
243 a
[j
].insert
[4-1]( &a
[j
], (GLubyte
*)vout
+ a
[j
].vertoffset
, src
);
250 void *_tnl_get_vertex( GLcontext
*ctx
, GLuint nr
)
252 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
254 return vtx
->vertex_buf
+ nr
* vtx
->vertex_size
;
257 void _tnl_invalidate_vertex_state( GLcontext
*ctx
, GLuint new_state
)
259 if (new_state
& (_DD_NEW_TRI_LIGHT_TWOSIDE
|_DD_NEW_TRI_UNFILLED
) ) {
260 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
261 vtx
->new_inputs
= ~0;
262 vtx
->interp
= choose_interp_func
;
263 vtx
->copy_pv
= choose_copy_pv_func
;
267 static void invalidate_funcs( struct tnl_clipspace
*vtx
)
269 vtx
->emit
= choose_emit_func
;
270 vtx
->interp
= choose_interp_func
;
271 vtx
->copy_pv
= choose_copy_pv_func
;
272 vtx
->new_inputs
= ~0;
275 GLuint
_tnl_install_attrs( GLcontext
*ctx
, const struct tnl_attr_map
*map
,
276 GLuint nr
, const GLfloat
*vp
,
277 GLuint unpacked_size
)
279 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
283 assert(nr
< _TNL_ATTRIB_MAX
);
284 assert(nr
== 0 || map
[0].attrib
== VERT_ATTRIB_POS
);
286 vtx
->new_inputs
= ~0;
287 vtx
->need_viewport
= GL_FALSE
;
290 vtx
->need_viewport
= GL_TRUE
;
293 for (j
= 0, i
= 0; i
< nr
; i
++) {
294 const GLuint format
= map
[i
].format
;
295 if (format
== EMIT_PAD
) {
297 _mesa_printf("%d: pad %d, offset %d\n", i
,
298 map
[i
].offset
, offset
);
300 offset
+= map
[i
].offset
;
307 tmpoffset
= map
[i
].offset
;
311 if (vtx
->attr_count
!= j
||
312 vtx
->attr
[j
].attrib
!= map
[i
].attrib
||
313 vtx
->attr
[j
].format
!= format
||
314 vtx
->attr
[j
].vertoffset
!= tmpoffset
) {
315 invalidate_funcs(vtx
);
317 vtx
->attr
[j
].attrib
= map
[i
].attrib
;
318 vtx
->attr
[j
].format
= format
;
319 vtx
->attr
[j
].vp
= vp
;
320 vtx
->attr
[j
].insert
= _tnl_format_info
[format
].insert
;
321 vtx
->attr
[j
].extract
= _tnl_format_info
[format
].extract
;
322 vtx
->attr
[j
].vertattrsize
= _tnl_format_info
[format
].attrsize
;
323 vtx
->attr
[j
].vertoffset
= tmpoffset
;
328 _mesa_printf("%d: %s, vp %p, offset %d\n", i
,
329 _tnl_format_info
[format
].name
, (void *)vp
,
330 vtx
->attr
[j
].vertoffset
);
332 offset
+= _tnl_format_info
[format
].attrsize
;
340 vtx
->vertex_size
= unpacked_size
;
342 vtx
->vertex_size
= offset
;
344 assert(vtx
->vertex_size
<= vtx
->max_vertex_size
);
345 return vtx
->vertex_size
;
350 void _tnl_invalidate_vertices( GLcontext
*ctx
, GLuint newinputs
)
352 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
353 vtx
->new_inputs
|= newinputs
;
357 /* This event has broader use beyond this file - will move elsewhere
358 * and probably invoke a driver callback.
360 void _tnl_notify_pipeline_output_change( GLcontext
*ctx
)
362 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
363 invalidate_funcs(vtx
);
366 static void update_input_ptrs( GLcontext
*ctx
, GLuint start
)
368 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
369 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
370 struct tnl_clipspace_attr
*a
= vtx
->attr
;
371 const GLuint count
= vtx
->attr_count
;
374 for (j
= 0; j
< count
; j
++) {
375 GLvector4f
*vptr
= VB
->AttribPtr
[a
[j
].attrib
];
377 if (vtx
->emit
!= choose_emit_func
) {
378 assert(a
[j
].inputstride
== vptr
->stride
);
379 assert(a
[j
].inputsize
== vptr
->size
);
382 a
[j
].inputptr
= ((GLubyte
*)vptr
->data
) + start
* vptr
->stride
;
386 vtx
->vp_scale
[0] = a
->vp
[MAT_SX
];
387 vtx
->vp_scale
[1] = a
->vp
[MAT_SY
];
388 vtx
->vp_scale
[2] = a
->vp
[MAT_SZ
];
389 vtx
->vp_scale
[3] = 1.0;
390 vtx
->vp_xlate
[0] = a
->vp
[MAT_TX
];
391 vtx
->vp_xlate
[1] = a
->vp
[MAT_TY
];
392 vtx
->vp_xlate
[2] = a
->vp
[MAT_TZ
];
393 vtx
->vp_xlate
[3] = 0.0;
398 void _tnl_build_vertices( GLcontext
*ctx
,
403 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
404 update_input_ptrs( ctx
, start
);
405 vtx
->emit( ctx
, end
- start
,
406 (GLubyte
*)(vtx
->vertex_buf
+
407 start
* vtx
->vertex_size
));
410 /* Emit VB vertices start..end to dest. Note that VB vertex at
411 * postion start will be emitted to dest at position zero.
413 void *_tnl_emit_vertices_to_buffer( GLcontext
*ctx
,
418 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
420 update_input_ptrs(ctx
, start
);
422 /* Note: dest should not be adjusted for non-zero 'start' values:
424 vtx
->emit( ctx
, end
- start
, dest
);
425 return (void *)((GLubyte
*)dest
+ vtx
->vertex_size
* (end
- start
));
429 void _tnl_init_vertices( GLcontext
*ctx
,
431 GLuint max_vertex_size
)
433 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
435 _tnl_install_attrs( ctx
, NULL
, 0, NULL
, 0 );
437 vtx
->need_extras
= GL_TRUE
;
438 if (max_vertex_size
> vtx
->max_vertex_size
) {
439 _tnl_free_vertices( ctx
);
440 vtx
->max_vertex_size
= max_vertex_size
;
441 vtx
->vertex_buf
= (GLubyte
*)ALIGN_CALLOC(vb_size
* max_vertex_size
, 32 );
442 invalidate_funcs(vtx
);
446 case GL_UNSIGNED_BYTE
:
447 vtx
->chan_scale
[0] = 255.0;
448 vtx
->chan_scale
[1] = 255.0;
449 vtx
->chan_scale
[2] = 255.0;
450 vtx
->chan_scale
[3] = 255.0;
452 case GL_UNSIGNED_SHORT
:
453 vtx
->chan_scale
[0] = 65535.0;
454 vtx
->chan_scale
[1] = 65535.0;
455 vtx
->chan_scale
[2] = 65535.0;
456 vtx
->chan_scale
[3] = 65535.0;
459 vtx
->chan_scale
[0] = 1.0;
460 vtx
->chan_scale
[1] = 1.0;
461 vtx
->chan_scale
[2] = 1.0;
462 vtx
->chan_scale
[3] = 1.0;
466 vtx
->identity
[0] = 0.0;
467 vtx
->identity
[1] = 0.0;
468 vtx
->identity
[2] = 0.0;
469 vtx
->identity
[3] = 1.0;
471 vtx
->codegen_emit
= NULL
;
474 if (getenv("MESA_EXPERIMENTAL"))
475 vtx
->codegen_emit
= _tnl_generate_sse_emit
;
480 void _tnl_free_vertices( GLcontext
*ctx
)
482 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
483 struct tnl_clipspace_fastpath
*fp
, *tmp
;
485 if (vtx
->vertex_buf
) {
486 ALIGN_FREE(vtx
->vertex_buf
);
487 vtx
->vertex_buf
= NULL
;
490 for (fp
= vtx
->fastpath
; fp
; fp
= tmp
) {
493 FREE((void *)fp
->func
);
497 vtx
->fastpath
= NULL
;