2 * Copyright 2003 VMware, 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 * VMWARE 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@vmware.com>
29 #include "main/glheader.h"
30 #include "main/context.h"
31 #include "main/execmem.h"
32 #include "util/u_memory.h"
33 #include "swrast/s_chan.h"
34 #include "t_context.h"
39 /* Build and manage clipspace/ndc/window vertices.
42 static GLboolean
match_fastpath( struct tnl_clipspace
*vtx
,
43 const struct tnl_clipspace_fastpath
*fp
)
47 if (vtx
->attr_count
!= fp
->attr_count
)
50 for (j
= 0; j
< vtx
->attr_count
; j
++)
51 if (vtx
->attr
[j
].format
!= fp
->attr
[j
].format
||
52 vtx
->attr
[j
].inputsize
!= fp
->attr
[j
].size
||
53 vtx
->attr
[j
].vertoffset
!= fp
->attr
[j
].offset
)
56 if (fp
->match_strides
) {
57 if (vtx
->vertex_size
!= fp
->vertex_size
)
60 for (j
= 0; j
< vtx
->attr_count
; j
++)
61 if (vtx
->attr
[j
].inputstride
!= fp
->attr
[j
].stride
)
68 static GLboolean
search_fastpath_emit( struct tnl_clipspace
*vtx
)
70 struct tnl_clipspace_fastpath
*fp
= vtx
->fastpath
;
72 for ( ; fp
; fp
= fp
->next
) {
73 if (match_fastpath(vtx
, fp
)) {
82 void _tnl_register_fastpath( struct tnl_clipspace
*vtx
,
83 GLboolean match_strides
)
85 struct tnl_clipspace_fastpath
*fastpath
= CALLOC_STRUCT(tnl_clipspace_fastpath
);
88 if (fastpath
== NULL
) {
89 _mesa_error_no_memory(__func__
);
93 fastpath
->vertex_size
= vtx
->vertex_size
;
94 fastpath
->attr_count
= vtx
->attr_count
;
95 fastpath
->match_strides
= match_strides
;
96 fastpath
->func
= vtx
->emit
;
97 fastpath
->attr
= malloc(vtx
->attr_count
* sizeof(fastpath
->attr
[0]));
99 if (fastpath
->attr
== NULL
) {
101 _mesa_error_no_memory(__func__
);
105 for (i
= 0; i
< vtx
->attr_count
; i
++) {
106 fastpath
->attr
[i
].format
= vtx
->attr
[i
].format
;
107 fastpath
->attr
[i
].stride
= vtx
->attr
[i
].inputstride
;
108 fastpath
->attr
[i
].size
= vtx
->attr
[i
].inputsize
;
109 fastpath
->attr
[i
].offset
= vtx
->attr
[i
].vertoffset
;
112 fastpath
->next
= vtx
->fastpath
;
113 vtx
->fastpath
= fastpath
;
118 /***********************************************************************
119 * Build codegen functions or return generic ones:
121 static void choose_emit_func( struct gl_context
*ctx
, GLuint count
, GLubyte
*dest
)
123 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
124 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
125 struct tnl_clipspace_attr
*a
= vtx
->attr
;
126 const GLuint attr_count
= vtx
->attr_count
;
129 for (j
= 0; j
< attr_count
; j
++) {
130 GLvector4f
*vptr
= VB
->AttribPtr
[a
[j
].attrib
];
131 a
[j
].inputstride
= vptr
->stride
;
132 a
[j
].inputsize
= vptr
->size
;
133 a
[j
].emit
= a
[j
].insert
[vptr
->size
- 1]; /* not always used */
138 /* Does this match an existing (hardwired, codegen or known-bad)
141 if (search_fastpath_emit(vtx
)) {
142 /* Use this result. If it is null, then it is already known
143 * that the current state will fail for codegen and there is no
144 * point trying again.
147 else if (vtx
->codegen_emit
) {
148 vtx
->codegen_emit(ctx
);
152 _tnl_generate_hardwired_emit(ctx
);
155 /* Otherwise use the generic version:
158 vtx
->emit
= _tnl_generic_emit
;
160 vtx
->emit( ctx
, count
, dest
);
165 static void choose_interp_func( struct gl_context
*ctx
,
167 GLuint edst
, GLuint eout
, GLuint ein
,
168 GLboolean force_boundary
)
170 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
171 GLboolean unfilled
= (ctx
->Polygon
.FrontMode
!= GL_FILL
||
172 ctx
->Polygon
.BackMode
!= GL_FILL
);
173 GLboolean twosided
= ctx
->Light
.Enabled
&& ctx
->Light
.Model
.TwoSide
;
175 if (vtx
->need_extras
&& (twosided
|| unfilled
)) {
176 vtx
->interp
= _tnl_generic_interp_extras
;
178 vtx
->interp
= _tnl_generic_interp
;
181 vtx
->interp( ctx
, t
, edst
, eout
, ein
, force_boundary
);
185 static void choose_copy_pv_func( struct gl_context
*ctx
, GLuint edst
, GLuint esrc
)
187 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
188 GLboolean unfilled
= (ctx
->Polygon
.FrontMode
!= GL_FILL
||
189 ctx
->Polygon
.BackMode
!= GL_FILL
);
191 GLboolean twosided
= ctx
->Light
.Enabled
&& ctx
->Light
.Model
.TwoSide
;
193 if (vtx
->need_extras
&& (twosided
|| unfilled
)) {
194 vtx
->copy_pv
= _tnl_generic_copy_pv_extras
;
196 vtx
->copy_pv
= _tnl_generic_copy_pv
;
199 vtx
->copy_pv( ctx
, edst
, esrc
);
203 /***********************************************************************
204 * Public entrypoints, mostly dispatch to the above:
208 /* Interpolate between two vertices to produce a third:
210 void _tnl_interp( struct gl_context
*ctx
,
212 GLuint edst
, GLuint eout
, GLuint ein
,
213 GLboolean force_boundary
)
215 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
216 vtx
->interp( ctx
, t
, edst
, eout
, ein
, force_boundary
);
219 /* Copy colors from one vertex to another:
221 void _tnl_copy_pv( struct gl_context
*ctx
, GLuint edst
, GLuint esrc
)
223 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
224 vtx
->copy_pv( ctx
, edst
, esrc
);
228 /* Extract a named attribute from a hardware vertex. Will have to
229 * reverse any viewport transformation, swizzling or other conversions
230 * which may have been applied:
232 void _tnl_get_attr( struct gl_context
*ctx
, const void *vin
,
233 GLenum attr
, GLfloat
*dest
)
235 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
236 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
237 const GLuint attr_count
= vtx
->attr_count
;
240 for (j
= 0; j
< attr_count
; j
++) {
241 if (a
[j
].attrib
== attr
) {
242 a
[j
].extract( &a
[j
], dest
, (GLubyte
*)vin
+ a
[j
].vertoffset
);
247 /* Else return the value from ctx->Current.
249 if (attr
== _TNL_ATTRIB_POINTSIZE
) {
250 /* If the hardware vertex doesn't have point size then use size from
251 * struct gl_context. XXX this will be wrong if drawing attenuated points!
253 dest
[0] = ctx
->Point
.Size
;
256 memcpy( dest
, ctx
->Current
.Attrib
[attr
], 4*sizeof(GLfloat
));
261 /* Complementary operation to the above.
263 void _tnl_set_attr( struct gl_context
*ctx
, void *vout
,
264 GLenum attr
, const GLfloat
*src
)
266 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
267 const struct tnl_clipspace_attr
*a
= vtx
->attr
;
268 const GLuint attr_count
= vtx
->attr_count
;
271 for (j
= 0; j
< attr_count
; j
++) {
272 if (a
[j
].attrib
== attr
) {
273 a
[j
].insert
[4-1]( &a
[j
], (GLubyte
*)vout
+ a
[j
].vertoffset
, src
);
280 void *_tnl_get_vertex( struct gl_context
*ctx
, GLuint nr
)
282 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
284 return vtx
->vertex_buf
+ nr
* vtx
->vertex_size
;
287 void _tnl_invalidate_vertex_state( struct gl_context
*ctx
, GLuint new_state
)
289 /* if two-sided lighting changes or filled/unfilled polygon state changes */
290 if (new_state
& (_NEW_LIGHT
| _NEW_POLYGON
) ) {
291 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
292 vtx
->new_inputs
= ~0;
293 vtx
->interp
= choose_interp_func
;
294 vtx
->copy_pv
= choose_copy_pv_func
;
298 static void invalidate_funcs( struct tnl_clipspace
*vtx
)
300 vtx
->emit
= choose_emit_func
;
301 vtx
->interp
= choose_interp_func
;
302 vtx
->copy_pv
= choose_copy_pv_func
;
303 vtx
->new_inputs
= ~0;
306 GLuint
_tnl_install_attrs( struct gl_context
*ctx
, const struct tnl_attr_map
*map
,
307 GLuint nr
, const GLfloat
*vp
,
308 GLuint unpacked_size
)
310 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
314 assert(nr
< _TNL_ATTRIB_MAX
);
315 assert(nr
== 0 || map
[0].attrib
== VERT_ATTRIB_POS
);
317 vtx
->new_inputs
= ~0;
318 vtx
->need_viewport
= GL_FALSE
;
321 vtx
->need_viewport
= GL_TRUE
;
324 for (j
= 0, i
= 0; i
< nr
; i
++) {
325 const GLuint format
= map
[i
].format
;
326 if (format
== EMIT_PAD
) {
328 printf("%d: pad %d, offset %d\n", i
,
329 map
[i
].offset
, offset
);
331 offset
+= map
[i
].offset
;
338 tmpoffset
= map
[i
].offset
;
342 if (vtx
->attr_count
!= j
||
343 vtx
->attr
[j
].attrib
!= map
[i
].attrib
||
344 vtx
->attr
[j
].format
!= format
||
345 vtx
->attr
[j
].vertoffset
!= tmpoffset
) {
346 invalidate_funcs(vtx
);
348 vtx
->attr
[j
].attrib
= map
[i
].attrib
;
349 vtx
->attr
[j
].format
= format
;
350 vtx
->attr
[j
].vp
= vp
;
351 vtx
->attr
[j
].insert
= _tnl_format_info
[format
].insert
;
352 vtx
->attr
[j
].extract
= _tnl_format_info
[format
].extract
;
353 vtx
->attr
[j
].vertattrsize
= _tnl_format_info
[format
].attrsize
;
354 vtx
->attr
[j
].vertoffset
= tmpoffset
;
359 printf("%d: %s, vp %p, offset %d\n", i
,
360 _tnl_format_info
[format
].name
, (void *)vp
,
361 vtx
->attr
[j
].vertoffset
);
363 offset
+= _tnl_format_info
[format
].attrsize
;
371 vtx
->vertex_size
= unpacked_size
;
373 vtx
->vertex_size
= offset
;
375 assert(vtx
->vertex_size
<= vtx
->max_vertex_size
);
376 return vtx
->vertex_size
;
381 void _tnl_invalidate_vertices( struct gl_context
*ctx
, GLuint newinputs
)
383 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
384 vtx
->new_inputs
|= newinputs
;
388 /* This event has broader use beyond this file - will move elsewhere
389 * and probably invoke a driver callback.
391 void _tnl_notify_pipeline_output_change( struct gl_context
*ctx
)
393 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
394 invalidate_funcs(vtx
);
398 static void adjust_input_ptrs( struct gl_context
*ctx
, GLint diff
)
400 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
401 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
402 struct tnl_clipspace_attr
*a
= vtx
->attr
;
403 const GLuint count
= vtx
->attr_count
;
407 for (j
=0; j
<count
; ++j
) {
408 register GLvector4f
*vptr
= VB
->AttribPtr
[a
->attrib
];
409 (a
++)->inputptr
+= diff
*vptr
->stride
;
413 static void update_input_ptrs( struct gl_context
*ctx
, GLuint start
)
415 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
416 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
417 struct tnl_clipspace_attr
*a
= vtx
->attr
;
418 const GLuint count
= vtx
->attr_count
;
421 for (j
= 0; j
< count
; j
++) {
422 GLvector4f
*vptr
= VB
->AttribPtr
[a
[j
].attrib
];
424 if (vtx
->emit
!= choose_emit_func
) {
425 assert(a
[j
].inputstride
== vptr
->stride
);
426 assert(a
[j
].inputsize
== vptr
->size
);
429 a
[j
].inputptr
= ((GLubyte
*)vptr
->data
) + start
* vptr
->stride
;
433 vtx
->vp_scale
[0] = a
->vp
[MAT_SX
];
434 vtx
->vp_scale
[1] = a
->vp
[MAT_SY
];
435 vtx
->vp_scale
[2] = a
->vp
[MAT_SZ
];
436 vtx
->vp_scale
[3] = 1.0;
437 vtx
->vp_xlate
[0] = a
->vp
[MAT_TX
];
438 vtx
->vp_xlate
[1] = a
->vp
[MAT_TY
];
439 vtx
->vp_xlate
[2] = a
->vp
[MAT_TZ
];
440 vtx
->vp_xlate
[3] = 0.0;
445 void _tnl_build_vertices( struct gl_context
*ctx
,
450 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
451 update_input_ptrs( ctx
, start
);
452 vtx
->emit( ctx
, end
- start
,
453 (GLubyte
*)(vtx
->vertex_buf
+
454 start
* vtx
->vertex_size
));
457 /* Emit VB vertices start..end to dest. Note that VB vertex at
458 * postion start will be emitted to dest at position zero.
460 void *_tnl_emit_vertices_to_buffer( struct gl_context
*ctx
,
465 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
467 update_input_ptrs(ctx
, start
);
468 /* Note: dest should not be adjusted for non-zero 'start' values:
470 vtx
->emit( ctx
, end
- start
, (GLubyte
*) dest
);
471 return (void *)((GLubyte
*)dest
+ vtx
->vertex_size
* (end
- start
));
474 /* Emit indexed VB vertices start..end to dest. Note that VB vertex at
475 * postion start will be emitted to dest at position zero.
478 void *_tnl_emit_indexed_vertices_to_buffer( struct gl_context
*ctx
,
484 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
486 GLubyte
*cdest
= dest
;
488 update_input_ptrs(ctx
, oldIndex
= elts
[start
++]);
489 vtx
->emit( ctx
, 1, cdest
);
490 cdest
+= vtx
->vertex_size
;
492 for (; start
< end
; ++start
) {
493 adjust_input_ptrs(ctx
, elts
[start
] - oldIndex
);
494 oldIndex
= elts
[start
];
495 vtx
->emit( ctx
, 1, cdest
);
496 cdest
+= vtx
->vertex_size
;
499 return (void *) cdest
;
503 void _tnl_init_vertices( struct gl_context
*ctx
,
505 GLuint max_vertex_size
)
507 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
509 _tnl_install_attrs( ctx
, NULL
, 0, NULL
, 0 );
511 vtx
->need_extras
= GL_TRUE
;
512 if (max_vertex_size
> vtx
->max_vertex_size
) {
513 _tnl_free_vertices( ctx
);
514 vtx
->max_vertex_size
= max_vertex_size
;
515 vtx
->vertex_buf
= align_calloc(vb_size
* max_vertex_size
, 32 );
516 invalidate_funcs(vtx
);
520 case GL_UNSIGNED_BYTE
:
521 vtx
->chan_scale
[0] = 255.0;
522 vtx
->chan_scale
[1] = 255.0;
523 vtx
->chan_scale
[2] = 255.0;
524 vtx
->chan_scale
[3] = 255.0;
526 case GL_UNSIGNED_SHORT
:
527 vtx
->chan_scale
[0] = 65535.0;
528 vtx
->chan_scale
[1] = 65535.0;
529 vtx
->chan_scale
[2] = 65535.0;
530 vtx
->chan_scale
[3] = 65535.0;
533 vtx
->chan_scale
[0] = 1.0;
534 vtx
->chan_scale
[1] = 1.0;
535 vtx
->chan_scale
[2] = 1.0;
536 vtx
->chan_scale
[3] = 1.0;
540 vtx
->identity
[0] = 0.0;
541 vtx
->identity
[1] = 0.0;
542 vtx
->identity
[2] = 0.0;
543 vtx
->identity
[3] = 1.0;
545 vtx
->codegen_emit
= NULL
;
548 if (!getenv("MESA_NO_CODEGEN"))
549 vtx
->codegen_emit
= _tnl_generate_sse_emit
;
554 void _tnl_free_vertices( struct gl_context
*ctx
)
556 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
558 struct tnl_clipspace
*vtx
= GET_VERTEX_STATE(ctx
);
559 struct tnl_clipspace_fastpath
*fp
, *tmp
;
561 align_free(vtx
->vertex_buf
);
562 vtx
->vertex_buf
= NULL
;
564 for (fp
= vtx
->fastpath
; fp
; fp
= tmp
) {
568 /* KW: At the moment, fp->func is constrained to be allocated by
569 * _mesa_exec_alloc(), as the hardwired fastpaths in
570 * t_vertex_generic.c are handled specially. It would be nice
571 * to unify them, but this probably won't change until this
572 * module gets another overhaul.
574 _mesa_exec_free((void *) fp
->func
);
578 vtx
->fastpath
= NULL
;