s/Tungsten Graphics/VMware/
[mesa.git] / src / mesa / tnl / t_vertex.c
1 /*
2 * Copyright 2003 VMware, 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 * 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.
23 *
24 * Authors:
25 * Keith Whitwell <keithw@vmware.com>
26 */
27
28 #include "main/glheader.h"
29 #include "main/context.h"
30 #include "main/colormac.h"
31 #include "swrast/s_chan.h"
32 #include "t_context.h"
33 #include "t_vertex.h"
34
35 #define DBG 0
36
37 /* Build and manage clipspace/ndc/window vertices.
38 */
39
40 static GLboolean match_fastpath( struct tnl_clipspace *vtx,
41 const struct tnl_clipspace_fastpath *fp)
42 {
43 GLuint j;
44
45 if (vtx->attr_count != fp->attr_count)
46 return GL_FALSE;
47
48 for (j = 0; j < vtx->attr_count; j++)
49 if (vtx->attr[j].format != fp->attr[j].format ||
50 vtx->attr[j].inputsize != fp->attr[j].size ||
51 vtx->attr[j].vertoffset != fp->attr[j].offset)
52 return GL_FALSE;
53
54 if (fp->match_strides) {
55 if (vtx->vertex_size != fp->vertex_size)
56 return GL_FALSE;
57
58 for (j = 0; j < vtx->attr_count; j++)
59 if (vtx->attr[j].inputstride != fp->attr[j].stride)
60 return GL_FALSE;
61 }
62
63 return GL_TRUE;
64 }
65
66 static GLboolean search_fastpath_emit( struct tnl_clipspace *vtx )
67 {
68 struct tnl_clipspace_fastpath *fp = vtx->fastpath;
69
70 for ( ; fp ; fp = fp->next) {
71 if (match_fastpath(vtx, fp)) {
72 vtx->emit = fp->func;
73 return GL_TRUE;
74 }
75 }
76
77 return GL_FALSE;
78 }
79
80 void _tnl_register_fastpath( struct tnl_clipspace *vtx,
81 GLboolean match_strides )
82 {
83 struct tnl_clipspace_fastpath *fastpath = CALLOC_STRUCT(tnl_clipspace_fastpath);
84 GLuint i;
85
86 fastpath->vertex_size = vtx->vertex_size;
87 fastpath->attr_count = vtx->attr_count;
88 fastpath->match_strides = match_strides;
89 fastpath->func = vtx->emit;
90 fastpath->attr =
91 malloc(vtx->attr_count * sizeof(fastpath->attr[0]));
92
93 for (i = 0; i < vtx->attr_count; i++) {
94 fastpath->attr[i].format = vtx->attr[i].format;
95 fastpath->attr[i].stride = vtx->attr[i].inputstride;
96 fastpath->attr[i].size = vtx->attr[i].inputsize;
97 fastpath->attr[i].offset = vtx->attr[i].vertoffset;
98 }
99
100 fastpath->next = vtx->fastpath;
101 vtx->fastpath = fastpath;
102 }
103
104
105
106 /***********************************************************************
107 * Build codegen functions or return generic ones:
108 */
109 static void choose_emit_func( struct gl_context *ctx, GLuint count, GLubyte *dest)
110 {
111 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
112 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
113 struct tnl_clipspace_attr *a = vtx->attr;
114 const GLuint attr_count = vtx->attr_count;
115 GLuint j;
116
117 for (j = 0; j < attr_count; j++) {
118 GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
119 a[j].inputstride = vptr->stride;
120 a[j].inputsize = vptr->size;
121 a[j].emit = a[j].insert[vptr->size - 1]; /* not always used */
122 }
123
124 vtx->emit = NULL;
125
126 /* Does this match an existing (hardwired, codegen or known-bad)
127 * fastpath?
128 */
129 if (search_fastpath_emit(vtx)) {
130 /* Use this result. If it is null, then it is already known
131 * that the current state will fail for codegen and there is no
132 * point trying again.
133 */
134 }
135 else if (vtx->codegen_emit) {
136 vtx->codegen_emit(ctx);
137 }
138
139 if (!vtx->emit) {
140 _tnl_generate_hardwired_emit(ctx);
141 }
142
143 /* Otherwise use the generic version:
144 */
145 if (!vtx->emit)
146 vtx->emit = _tnl_generic_emit;
147
148 vtx->emit( ctx, count, dest );
149 }
150
151
152
153 static void choose_interp_func( struct gl_context *ctx,
154 GLfloat t,
155 GLuint edst, GLuint eout, GLuint ein,
156 GLboolean force_boundary )
157 {
158 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
159 GLboolean unfilled = (ctx->Polygon.FrontMode != GL_FILL ||
160 ctx->Polygon.BackMode != GL_FILL);
161 GLboolean twosided = ctx->Light.Enabled && ctx->Light.Model.TwoSide;
162
163 if (vtx->need_extras && (twosided || unfilled)) {
164 vtx->interp = _tnl_generic_interp_extras;
165 } else {
166 vtx->interp = _tnl_generic_interp;
167 }
168
169 vtx->interp( ctx, t, edst, eout, ein, force_boundary );
170 }
171
172
173 static void choose_copy_pv_func( struct gl_context *ctx, GLuint edst, GLuint esrc )
174 {
175 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
176 GLboolean unfilled = (ctx->Polygon.FrontMode != GL_FILL ||
177 ctx->Polygon.BackMode != GL_FILL);
178
179 GLboolean twosided = ctx->Light.Enabled && ctx->Light.Model.TwoSide;
180
181 if (vtx->need_extras && (twosided || unfilled)) {
182 vtx->copy_pv = _tnl_generic_copy_pv_extras;
183 } else {
184 vtx->copy_pv = _tnl_generic_copy_pv;
185 }
186
187 vtx->copy_pv( ctx, edst, esrc );
188 }
189
190
191 /***********************************************************************
192 * Public entrypoints, mostly dispatch to the above:
193 */
194
195
196 /* Interpolate between two vertices to produce a third:
197 */
198 void _tnl_interp( struct gl_context *ctx,
199 GLfloat t,
200 GLuint edst, GLuint eout, GLuint ein,
201 GLboolean force_boundary )
202 {
203 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
204 vtx->interp( ctx, t, edst, eout, ein, force_boundary );
205 }
206
207 /* Copy colors from one vertex to another:
208 */
209 void _tnl_copy_pv( struct gl_context *ctx, GLuint edst, GLuint esrc )
210 {
211 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
212 vtx->copy_pv( ctx, edst, esrc );
213 }
214
215
216 /* Extract a named attribute from a hardware vertex. Will have to
217 * reverse any viewport transformation, swizzling or other conversions
218 * which may have been applied:
219 */
220 void _tnl_get_attr( struct gl_context *ctx, const void *vin,
221 GLenum attr, GLfloat *dest )
222 {
223 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
224 const struct tnl_clipspace_attr *a = vtx->attr;
225 const GLuint attr_count = vtx->attr_count;
226 GLuint j;
227
228 for (j = 0; j < attr_count; j++) {
229 if (a[j].attrib == attr) {
230 a[j].extract( &a[j], dest, (GLubyte *)vin + a[j].vertoffset );
231 return;
232 }
233 }
234
235 /* Else return the value from ctx->Current.
236 */
237 if (attr == _TNL_ATTRIB_POINTSIZE) {
238 /* If the hardware vertex doesn't have point size then use size from
239 * struct gl_context. XXX this will be wrong if drawing attenuated points!
240 */
241 dest[0] = ctx->Point.Size;
242 }
243 else {
244 memcpy( dest, ctx->Current.Attrib[attr], 4*sizeof(GLfloat));
245 }
246 }
247
248
249 /* Complementary operation to the above.
250 */
251 void _tnl_set_attr( struct gl_context *ctx, void *vout,
252 GLenum attr, const GLfloat *src )
253 {
254 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
255 const struct tnl_clipspace_attr *a = vtx->attr;
256 const GLuint attr_count = vtx->attr_count;
257 GLuint j;
258
259 for (j = 0; j < attr_count; j++) {
260 if (a[j].attrib == attr) {
261 a[j].insert[4-1]( &a[j], (GLubyte *)vout + a[j].vertoffset, src );
262 return;
263 }
264 }
265 }
266
267
268 void *_tnl_get_vertex( struct gl_context *ctx, GLuint nr )
269 {
270 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
271
272 return vtx->vertex_buf + nr * vtx->vertex_size;
273 }
274
275 void _tnl_invalidate_vertex_state( struct gl_context *ctx, GLuint new_state )
276 {
277 /* if two-sided lighting changes or filled/unfilled polygon state changes */
278 if (new_state & (_NEW_LIGHT | _NEW_POLYGON) ) {
279 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
280 vtx->new_inputs = ~0;
281 vtx->interp = choose_interp_func;
282 vtx->copy_pv = choose_copy_pv_func;
283 }
284 }
285
286 static void invalidate_funcs( struct tnl_clipspace *vtx )
287 {
288 vtx->emit = choose_emit_func;
289 vtx->interp = choose_interp_func;
290 vtx->copy_pv = choose_copy_pv_func;
291 vtx->new_inputs = ~0;
292 }
293
294 GLuint _tnl_install_attrs( struct gl_context *ctx, const struct tnl_attr_map *map,
295 GLuint nr, const GLfloat *vp,
296 GLuint unpacked_size )
297 {
298 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
299 GLuint offset = 0;
300 GLuint i, j;
301
302 assert(nr < _TNL_ATTRIB_MAX);
303 assert(nr == 0 || map[0].attrib == VERT_ATTRIB_POS);
304
305 vtx->new_inputs = ~0;
306 vtx->need_viewport = GL_FALSE;
307
308 if (vp) {
309 vtx->need_viewport = GL_TRUE;
310 }
311
312 for (j = 0, i = 0; i < nr; i++) {
313 const GLuint format = map[i].format;
314 if (format == EMIT_PAD) {
315 if (DBG)
316 printf("%d: pad %d, offset %d\n", i,
317 map[i].offset, offset);
318
319 offset += map[i].offset;
320
321 }
322 else {
323 GLuint tmpoffset;
324
325 if (unpacked_size)
326 tmpoffset = map[i].offset;
327 else
328 tmpoffset = offset;
329
330 if (vtx->attr_count != j ||
331 vtx->attr[j].attrib != map[i].attrib ||
332 vtx->attr[j].format != format ||
333 vtx->attr[j].vertoffset != tmpoffset) {
334 invalidate_funcs(vtx);
335
336 vtx->attr[j].attrib = map[i].attrib;
337 vtx->attr[j].format = format;
338 vtx->attr[j].vp = vp;
339 vtx->attr[j].insert = _tnl_format_info[format].insert;
340 vtx->attr[j].extract = _tnl_format_info[format].extract;
341 vtx->attr[j].vertattrsize = _tnl_format_info[format].attrsize;
342 vtx->attr[j].vertoffset = tmpoffset;
343 }
344
345
346 if (DBG)
347 printf("%d: %s, vp %p, offset %d\n", i,
348 _tnl_format_info[format].name, (void *)vp,
349 vtx->attr[j].vertoffset);
350
351 offset += _tnl_format_info[format].attrsize;
352 j++;
353 }
354 }
355
356 vtx->attr_count = j;
357
358 if (unpacked_size)
359 vtx->vertex_size = unpacked_size;
360 else
361 vtx->vertex_size = offset;
362
363 assert(vtx->vertex_size <= vtx->max_vertex_size);
364 return vtx->vertex_size;
365 }
366
367
368
369 void _tnl_invalidate_vertices( struct gl_context *ctx, GLuint newinputs )
370 {
371 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
372 vtx->new_inputs |= newinputs;
373 }
374
375
376 /* This event has broader use beyond this file - will move elsewhere
377 * and probably invoke a driver callback.
378 */
379 void _tnl_notify_pipeline_output_change( struct gl_context *ctx )
380 {
381 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
382 invalidate_funcs(vtx);
383 }
384
385
386 static void adjust_input_ptrs( struct gl_context *ctx, GLint diff)
387 {
388 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
389 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
390 struct tnl_clipspace_attr *a = vtx->attr;
391 const GLuint count = vtx->attr_count;
392 GLuint j;
393
394 diff -= 1;
395 for (j=0; j<count; ++j) {
396 register GLvector4f *vptr = VB->AttribPtr[a->attrib];
397 (a++)->inputptr += diff*vptr->stride;
398 }
399 }
400
401 static void update_input_ptrs( struct gl_context *ctx, GLuint start )
402 {
403 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
404 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
405 struct tnl_clipspace_attr *a = vtx->attr;
406 const GLuint count = vtx->attr_count;
407 GLuint j;
408
409 for (j = 0; j < count; j++) {
410 GLvector4f *vptr = VB->AttribPtr[a[j].attrib];
411
412 if (vtx->emit != choose_emit_func) {
413 assert(a[j].inputstride == vptr->stride);
414 assert(a[j].inputsize == vptr->size);
415 }
416
417 a[j].inputptr = ((GLubyte *)vptr->data) + start * vptr->stride;
418 }
419
420 if (a->vp) {
421 vtx->vp_scale[0] = a->vp[MAT_SX];
422 vtx->vp_scale[1] = a->vp[MAT_SY];
423 vtx->vp_scale[2] = a->vp[MAT_SZ];
424 vtx->vp_scale[3] = 1.0;
425 vtx->vp_xlate[0] = a->vp[MAT_TX];
426 vtx->vp_xlate[1] = a->vp[MAT_TY];
427 vtx->vp_xlate[2] = a->vp[MAT_TZ];
428 vtx->vp_xlate[3] = 0.0;
429 }
430 }
431
432
433 void _tnl_build_vertices( struct gl_context *ctx,
434 GLuint start,
435 GLuint end,
436 GLuint newinputs )
437 {
438 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
439 update_input_ptrs( ctx, start );
440 vtx->emit( ctx, end - start,
441 (GLubyte *)(vtx->vertex_buf +
442 start * vtx->vertex_size));
443 }
444
445 /* Emit VB vertices start..end to dest. Note that VB vertex at
446 * postion start will be emitted to dest at position zero.
447 */
448 void *_tnl_emit_vertices_to_buffer( struct gl_context *ctx,
449 GLuint start,
450 GLuint end,
451 void *dest )
452 {
453 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
454
455 update_input_ptrs(ctx, start);
456 /* Note: dest should not be adjusted for non-zero 'start' values:
457 */
458 vtx->emit( ctx, end - start, (GLubyte*) dest );
459 return (void *)((GLubyte *)dest + vtx->vertex_size * (end - start));
460 }
461
462 /* Emit indexed VB vertices start..end to dest. Note that VB vertex at
463 * postion start will be emitted to dest at position zero.
464 */
465
466 void *_tnl_emit_indexed_vertices_to_buffer( struct gl_context *ctx,
467 const GLuint *elts,
468 GLuint start,
469 GLuint end,
470 void *dest )
471 {
472 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
473 GLuint oldIndex;
474 GLubyte *cdest = dest;
475
476 update_input_ptrs(ctx, oldIndex = elts[start++]);
477 vtx->emit( ctx, 1, cdest );
478 cdest += vtx->vertex_size;
479
480 for (; start < end; ++start) {
481 adjust_input_ptrs(ctx, elts[start] - oldIndex);
482 oldIndex = elts[start];
483 vtx->emit( ctx, 1, cdest);
484 cdest += vtx->vertex_size;
485 }
486
487 return (void *) cdest;
488 }
489
490
491 void _tnl_init_vertices( struct gl_context *ctx,
492 GLuint vb_size,
493 GLuint max_vertex_size )
494 {
495 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
496
497 _tnl_install_attrs( ctx, NULL, 0, NULL, 0 );
498
499 vtx->need_extras = GL_TRUE;
500 if (max_vertex_size > vtx->max_vertex_size) {
501 _tnl_free_vertices( ctx );
502 vtx->max_vertex_size = max_vertex_size;
503 vtx->vertex_buf = _mesa_align_calloc(vb_size * max_vertex_size, 32 );
504 invalidate_funcs(vtx);
505 }
506
507 switch(CHAN_TYPE) {
508 case GL_UNSIGNED_BYTE:
509 vtx->chan_scale[0] = 255.0;
510 vtx->chan_scale[1] = 255.0;
511 vtx->chan_scale[2] = 255.0;
512 vtx->chan_scale[3] = 255.0;
513 break;
514 case GL_UNSIGNED_SHORT:
515 vtx->chan_scale[0] = 65535.0;
516 vtx->chan_scale[1] = 65535.0;
517 vtx->chan_scale[2] = 65535.0;
518 vtx->chan_scale[3] = 65535.0;
519 break;
520 default:
521 vtx->chan_scale[0] = 1.0;
522 vtx->chan_scale[1] = 1.0;
523 vtx->chan_scale[2] = 1.0;
524 vtx->chan_scale[3] = 1.0;
525 break;
526 }
527
528 vtx->identity[0] = 0.0;
529 vtx->identity[1] = 0.0;
530 vtx->identity[2] = 0.0;
531 vtx->identity[3] = 1.0;
532
533 vtx->codegen_emit = NULL;
534
535 #ifdef USE_SSE_ASM
536 if (!_mesa_getenv("MESA_NO_CODEGEN"))
537 vtx->codegen_emit = _tnl_generate_sse_emit;
538 #endif
539 }
540
541
542 void _tnl_free_vertices( struct gl_context *ctx )
543 {
544 TNLcontext *tnl = TNL_CONTEXT(ctx);
545 if (tnl) {
546 struct tnl_clipspace *vtx = GET_VERTEX_STATE(ctx);
547 struct tnl_clipspace_fastpath *fp, *tmp;
548
549 _mesa_align_free(vtx->vertex_buf);
550 vtx->vertex_buf = NULL;
551
552 for (fp = vtx->fastpath ; fp ; fp = tmp) {
553 tmp = fp->next;
554 free(fp->attr);
555
556 /* KW: At the moment, fp->func is constrained to be allocated by
557 * _mesa_exec_alloc(), as the hardwired fastpaths in
558 * t_vertex_generic.c are handled specially. It would be nice
559 * to unify them, but this probably won't change until this
560 * module gets another overhaul.
561 */
562 _mesa_exec_free((void *) fp->func);
563 free(fp);
564 }
565
566 vtx->fastpath = NULL;
567 }
568 }