Use SSE for vertex emit -- another good speedup.
[mesa.git] / src / mesa / drivers / dri / unichrome / via_tris.c
1 /*
2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. 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 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the 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 * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 */
24
25 #include <stdio.h>
26 #include <math.h>
27
28 #include "glheader.h"
29 #include "context.h"
30 #include "mtypes.h"
31 #include "macros.h"
32 #include "colormac.h"
33 #include "enums.h"
34
35 #include "swrast/swrast.h"
36 #include "swrast_setup/swrast_setup.h"
37 #include "tnl/t_context.h"
38 #include "tnl/t_pipeline.h"
39
40 #include "via_context.h"
41 #include "via_tris.h"
42 #include "via_state.h"
43 #include "via_span.h"
44 #include "via_ioctl.h"
45 #include "via_3d_reg.h"
46 #include "via_tex.h"
47
48 /***********************************************************************
49 * Emit primitives as inline vertices *
50 ***********************************************************************/
51
52 #if 1
53 #define COPY_DWORDS(vb, vertsize, v) \
54 do { \
55 via_sse_memcpy(vb, v, vertsize * 4); \
56 vb += vertsize; \
57 } while (0)
58 #else
59 #if 1
60 #define COPY_DWORDS(vb, vertsize, v) \
61 do { \
62 int j; \
63 int __tmp; \
64 __asm__ __volatile__("rep ; movsl" \
65 : "=%c" (j), "=D" (vb), "=S" (__tmp) \
66 : "0" (vertsize), \
67 "D" ((long)vb), \
68 "S" ((long)v)); \
69 } while (0)
70 #else
71 #define COPY_DWORDS(vb, vertsize, v) \
72 do { \
73 int j; \
74 for (j = 0; j < vertsize; j++) \
75 vb[j] = ((GLuint *)v)[j]; \
76 vb += vertsize; \
77 } while (0)
78 #endif
79 #endif
80
81 static void via_draw_triangle(struct via_context *vmesa,
82 viaVertexPtr v0,
83 viaVertexPtr v1,
84 viaVertexPtr v2)
85 {
86 GLuint vertsize = vmesa->vertexSize;
87 GLuint *vb = viaExtendPrimitive(vmesa, 3 * 4 * vertsize);
88
89 COPY_DWORDS(vb, vertsize, v0);
90 COPY_DWORDS(vb, vertsize, v1);
91 COPY_DWORDS(vb, vertsize, v2);
92 }
93
94
95 static void via_draw_quad(struct via_context *vmesa,
96 viaVertexPtr v0,
97 viaVertexPtr v1,
98 viaVertexPtr v2,
99 viaVertexPtr v3)
100 {
101 GLuint vertsize = vmesa->vertexSize;
102 GLuint *vb = viaExtendPrimitive(vmesa, 6 * 4 * vertsize);
103
104 COPY_DWORDS(vb, vertsize, v0);
105 COPY_DWORDS(vb, vertsize, v1);
106 COPY_DWORDS(vb, vertsize, v3);
107 COPY_DWORDS(vb, vertsize, v1);
108 COPY_DWORDS(vb, vertsize, v2);
109 COPY_DWORDS(vb, vertsize, v3);
110 }
111
112 static void via_draw_line(struct via_context *vmesa,
113 viaVertexPtr v0,
114 viaVertexPtr v1)
115 {
116 GLuint vertsize = vmesa->vertexSize;
117 GLuint *vb = viaExtendPrimitive(vmesa, 2 * 4 * vertsize);
118 COPY_DWORDS(vb, vertsize, v0);
119 COPY_DWORDS(vb, vertsize, v1);
120 }
121
122
123 static void via_draw_point(struct via_context *vmesa,
124 viaVertexPtr v0)
125 {
126 GLuint vertsize = vmesa->vertexSize;
127 GLuint *vb = viaExtendPrimitive(vmesa, 4 * vertsize);
128 COPY_DWORDS(vb, vertsize, v0);
129 }
130
131
132 /* Fallback drawing functions for the ptex hack.
133 */
134 #define PTEX_VERTEX( tmp, vertex_size, v) \
135 do { \
136 GLuint j; \
137 GLfloat rhw = 1.0 / v->f[vertex_size]; \
138 for ( j = 0 ; j < vertex_size ; j++ ) \
139 tmp.f[j] = v->f[j]; \
140 tmp.f[3] *= v->f[vertex_size]; \
141 tmp.f[vertex_size-2] *= rhw; \
142 tmp.f[vertex_size-1] *= rhw; \
143 } while (0)
144
145 static void via_ptex_tri (struct via_context *vmesa,
146 viaVertexPtr v0,
147 viaVertexPtr v1,
148 viaVertexPtr v2)
149 {
150 GLuint vertsize = vmesa->hwVertexSize;
151 GLuint *vb = viaExtendPrimitive(vmesa, 3*4*vertsize);
152 viaVertex tmp;
153
154 PTEX_VERTEX(tmp, vertsize, v0); COPY_DWORDS(vb, vertsize, &tmp);
155 PTEX_VERTEX(tmp, vertsize, v1); COPY_DWORDS(vb, vertsize, &tmp);
156 PTEX_VERTEX(tmp, vertsize, v2); COPY_DWORDS(vb, vertsize, &tmp);
157 }
158
159 static void via_ptex_line (struct via_context *vmesa,
160 viaVertexPtr v0,
161 viaVertexPtr v1)
162 {
163 GLuint vertsize = vmesa->hwVertexSize;
164 GLuint *vb = viaExtendPrimitive(vmesa, 2*4*vertsize);
165 viaVertex tmp;
166
167 PTEX_VERTEX(tmp, vertsize, v0); COPY_DWORDS(vb, vertsize, &tmp);
168 PTEX_VERTEX(tmp, vertsize, v1); COPY_DWORDS(vb, vertsize, &tmp);
169 }
170
171 static void via_ptex_point (struct via_context *vmesa,
172 viaVertexPtr v0)
173 {
174 GLuint vertsize = vmesa->hwVertexSize;
175 GLuint *vb = viaExtendPrimitive(vmesa, 1*4*vertsize);
176 viaVertex tmp;
177
178 PTEX_VERTEX(tmp, vertsize, v0); COPY_DWORDS(vb, vertsize, &tmp);
179 }
180
181
182
183
184
185 /***********************************************************************
186 * Macros for via_dd_tritmp.h to draw basic primitives *
187 ***********************************************************************/
188
189 #define TRI(a, b, c) \
190 do { \
191 if (DO_FALLBACK) \
192 vmesa->drawTri(vmesa, a, b, c); \
193 else \
194 via_draw_triangle(vmesa, a, b, c); \
195 } while (0)
196
197 #define QUAD(a, b, c, d) \
198 do { \
199 if (DO_FALLBACK) { \
200 vmesa->drawTri(vmesa, a, b, d); \
201 vmesa->drawTri(vmesa, b, c, d); \
202 } \
203 else \
204 via_draw_quad(vmesa, a, b, c, d); \
205 } while (0)
206
207 #define LINE(v0, v1) \
208 do { \
209 if (DO_FALLBACK) \
210 vmesa->drawLine(vmesa, v0, v1); \
211 else \
212 via_draw_line(vmesa, v0, v1); \
213 } while (0)
214
215 #define POINT(v0) \
216 do { \
217 if (DO_FALLBACK) \
218 vmesa->drawPoint(vmesa, v0); \
219 else \
220 via_draw_point(vmesa, v0); \
221 } while (0)
222
223
224 /***********************************************************************
225 * Build render functions from dd templates *
226 ***********************************************************************/
227
228 #define VIA_OFFSET_BIT 0x01
229 #define VIA_TWOSIDE_BIT 0x02
230 #define VIA_UNFILLED_BIT 0x04
231 #define VIA_FALLBACK_BIT 0x08
232 #define VIA_MAX_TRIFUNC 0x10
233
234
235 static struct {
236 tnl_points_func points;
237 tnl_line_func line;
238 tnl_triangle_func triangle;
239 tnl_quad_func quad;
240 } rast_tab[VIA_MAX_TRIFUNC];
241
242
243 #define DO_FALLBACK (IND & VIA_FALLBACK_BIT)
244 #define DO_OFFSET (IND & VIA_OFFSET_BIT)
245 #define DO_UNFILLED (IND & VIA_UNFILLED_BIT)
246 #define DO_TWOSIDE (IND & VIA_TWOSIDE_BIT)
247 #define DO_FLAT 0
248 #define DO_TRI 1
249 #define DO_QUAD 1
250 #define DO_LINE 1
251 #define DO_POINTS 1
252 #define DO_FULL_QUAD 1
253
254 #define HAVE_RGBA 1
255 #define HAVE_SPEC 1
256 #define HAVE_BACK_COLORS 0
257 #define HAVE_HW_FLATSHADE 1
258 #define VERTEX viaVertex
259 #define TAB rast_tab
260
261 /* Only used to pull back colors into vertices (ie, we know color is
262 * floating point).
263 */
264 #define VIA_COLOR(dst, src) \
265 do { \
266 dst[0] = src[2]; \
267 dst[1] = src[1]; \
268 dst[2] = src[0]; \
269 dst[3] = src[3]; \
270 } while (0)
271
272 #define VIA_SPEC(dst, src) \
273 do { \
274 dst[0] = src[2]; \
275 dst[1] = src[1]; \
276 dst[2] = src[0]; \
277 } while (0)
278
279
280 #define DEPTH_SCALE vmesa->polygon_offset_scale
281 #define UNFILLED_TRI unfilled_tri
282 #define UNFILLED_QUAD unfilled_quad
283 #define VERT_X(_v) _v->v.x
284 #define VERT_Y(_v) _v->v.y
285 #define VERT_Z(_v) _v->v.z
286 #define AREA_IS_CCW(a) (a > 0)
287 #define GET_VERTEX(e) (vmesa->verts + (e * vmesa->vertexSize * sizeof(int)))
288
289 #define VERT_SET_RGBA( v, c ) \
290 do { \
291 via_color_t *color = (via_color_t *)&((v)->ui[coloroffset]); \
292 UNCLAMPED_FLOAT_TO_UBYTE(color->red, (c)[0]); \
293 UNCLAMPED_FLOAT_TO_UBYTE(color->green, (c)[1]); \
294 UNCLAMPED_FLOAT_TO_UBYTE(color->blue, (c)[2]); \
295 UNCLAMPED_FLOAT_TO_UBYTE(color->alpha, (c)[3]); \
296 } while (0)
297
298 #define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset]
299
300 #define VERT_SET_SPEC( v0, c ) \
301 do { \
302 if (specoffset) { \
303 UNCLAMPED_FLOAT_TO_UBYTE(v0->v.specular.red, (c)[0]); \
304 UNCLAMPED_FLOAT_TO_UBYTE(v0->v.specular.green, (c)[1]); \
305 UNCLAMPED_FLOAT_TO_UBYTE(v0->v.specular.blue, (c)[2]); \
306 } \
307 } while (0)
308 #define VERT_COPY_SPEC( v0, v1 ) \
309 do { \
310 if (specoffset) { \
311 v0->v.specular.red = v1->v.specular.red; \
312 v0->v.specular.green = v1->v.specular.green; \
313 v0->v.specular.blue = v1->v.specular.blue; \
314 } \
315 } while (0)
316
317
318 #define VERT_SAVE_RGBA( idx ) color[idx] = v[idx]->ui[coloroffset]
319 #define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = color[idx]
320 #define VERT_SAVE_SPEC( idx ) if (specoffset) spec[idx] = v[idx]->ui[specoffset]
321 #define VERT_RESTORE_SPEC( idx ) if (specoffset) v[idx]->ui[specoffset] = spec[idx]
322
323
324 #define LOCAL_VARS(n) \
325 struct via_context *vmesa = VIA_CONTEXT(ctx); \
326 GLuint color[n], spec[n]; \
327 GLuint coloroffset = vmesa->coloroffset; \
328 GLuint specoffset = vmesa->specoffset; \
329 (void)color; (void)spec; (void)coloroffset; (void)specoffset;
330
331
332 /***********************************************************************
333 * Helpers for rendering unfilled primitives *
334 ***********************************************************************/
335
336 static const GLenum hwPrim[GL_POLYGON + 2] = {
337 GL_POINTS,
338 GL_LINES,
339 GL_LINES,
340 GL_LINES,
341 GL_TRIANGLES,
342 GL_TRIANGLES,
343 GL_TRIANGLES,
344 GL_TRIANGLES,
345 GL_TRIANGLES,
346 GL_TRIANGLES,
347 GL_POLYGON+1
348 };
349
350
351 #define RASTERIZE(x) viaRasterPrimitive( ctx, x, hwPrim[x] )
352 #define RENDER_PRIMITIVE vmesa->renderPrimitive
353 #define TAG(x) x
354 #define IND VIA_FALLBACK_BIT
355 #include "tnl_dd/t_dd_unfilled.h"
356 #undef IND
357 #undef RASTERIZE
358
359 /***********************************************************************
360 * Generate GL render functions *
361 ***********************************************************************/
362 #define RASTERIZE(x)
363
364 #define IND (0)
365 #define TAG(x) x
366 #include "tnl_dd/t_dd_tritmp.h"
367
368 #define IND (VIA_OFFSET_BIT)
369 #define TAG(x) x##_offset
370 #include "tnl_dd/t_dd_tritmp.h"
371
372 #define IND (VIA_TWOSIDE_BIT)
373 #define TAG(x) x##_twoside
374 #include "tnl_dd/t_dd_tritmp.h"
375
376 #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT)
377 #define TAG(x) x##_twoside_offset
378 #include "tnl_dd/t_dd_tritmp.h"
379
380 #define IND (VIA_UNFILLED_BIT)
381 #define TAG(x) x##_unfilled
382 #include "tnl_dd/t_dd_tritmp.h"
383
384 #define IND (VIA_OFFSET_BIT|VIA_UNFILLED_BIT)
385 #define TAG(x) x##_offset_unfilled
386 #include "tnl_dd/t_dd_tritmp.h"
387
388 #define IND (VIA_TWOSIDE_BIT|VIA_UNFILLED_BIT)
389 #define TAG(x) x##_twoside_unfilled
390 #include "tnl_dd/t_dd_tritmp.h"
391
392 #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT|VIA_UNFILLED_BIT)
393 #define TAG(x) x##_twoside_offset_unfilled
394 #include "tnl_dd/t_dd_tritmp.h"
395
396 #define IND (VIA_FALLBACK_BIT)
397 #define TAG(x) x##_fallback
398 #include "tnl_dd/t_dd_tritmp.h"
399
400 #define IND (VIA_OFFSET_BIT|VIA_FALLBACK_BIT)
401 #define TAG(x) x##_offset_fallback
402 #include "tnl_dd/t_dd_tritmp.h"
403
404 #define IND (VIA_TWOSIDE_BIT|VIA_FALLBACK_BIT)
405 #define TAG(x) x##_twoside_fallback
406 #include "tnl_dd/t_dd_tritmp.h"
407
408 #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT|VIA_FALLBACK_BIT)
409 #define TAG(x) x##_twoside_offset_fallback
410 #include "tnl_dd/t_dd_tritmp.h"
411
412 #define IND (VIA_UNFILLED_BIT|VIA_FALLBACK_BIT)
413 #define TAG(x) x##_unfilled_fallback
414 #include "tnl_dd/t_dd_tritmp.h"
415
416 #define IND (VIA_OFFSET_BIT|VIA_UNFILLED_BIT|VIA_FALLBACK_BIT)
417 #define TAG(x) x##_offset_unfilled_fallback
418 #include "tnl_dd/t_dd_tritmp.h"
419
420 #define IND (VIA_TWOSIDE_BIT|VIA_UNFILLED_BIT|VIA_FALLBACK_BIT)
421 #define TAG(x) x##_twoside_unfilled_fallback
422 #include "tnl_dd/t_dd_tritmp.h"
423
424 #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT|VIA_UNFILLED_BIT| \
425 VIA_FALLBACK_BIT)
426 #define TAG(x) x##_twoside_offset_unfilled_fallback
427 #include "tnl_dd/t_dd_tritmp.h"
428
429
430 static void init_rast_tab(void)
431 {
432 init();
433 init_offset();
434 init_twoside();
435 init_twoside_offset();
436 init_unfilled();
437 init_offset_unfilled();
438 init_twoside_unfilled();
439 init_twoside_offset_unfilled();
440 init_fallback();
441 init_offset_fallback();
442 init_twoside_fallback();
443 init_twoside_offset_fallback();
444 init_unfilled_fallback();
445 init_offset_unfilled_fallback();
446 init_twoside_unfilled_fallback();
447 init_twoside_offset_unfilled_fallback();
448 }
449
450
451 /***********************************************************************
452 * Rasterization fallback helpers *
453 ***********************************************************************/
454
455
456 /* This code is hit only when a mix of accelerated and unaccelerated
457 * primitives are being drawn, and only for the unaccelerated
458 * primitives.
459 */
460 static void
461 via_fallback_tri(struct via_context *vmesa,
462 viaVertex *v0,
463 viaVertex *v1,
464 viaVertex *v2)
465 {
466 GLcontext *ctx = vmesa->glCtx;
467 SWvertex v[3];
468 _swsetup_Translate(ctx, v0, &v[0]);
469 _swsetup_Translate(ctx, v1, &v[1]);
470 _swsetup_Translate(ctx, v2, &v[2]);
471 viaSpanRenderStart( ctx );
472 _swrast_Triangle(ctx, &v[0], &v[1], &v[2]);
473 viaSpanRenderFinish( ctx );
474 }
475
476
477 static void
478 via_fallback_line(struct via_context *vmesa,
479 viaVertex *v0,
480 viaVertex *v1)
481 {
482 GLcontext *ctx = vmesa->glCtx;
483 SWvertex v[2];
484 _swsetup_Translate(ctx, v0, &v[0]);
485 _swsetup_Translate(ctx, v1, &v[1]);
486 viaSpanRenderStart( ctx );
487 _swrast_Line(ctx, &v[0], &v[1]);
488 viaSpanRenderFinish( ctx );
489 }
490
491
492 static void
493 via_fallback_point(struct via_context *vmesa,
494 viaVertex *v0)
495 {
496 GLcontext *ctx = vmesa->glCtx;
497 SWvertex v[1];
498 _swsetup_Translate(ctx, v0, &v[0]);
499 viaSpanRenderStart( ctx );
500 _swrast_Point(ctx, &v[0]);
501 viaSpanRenderFinish( ctx );
502 }
503
504 static void viaResetLineStipple( GLcontext *ctx )
505 {
506 struct via_context *vmesa = VIA_CONTEXT(ctx);
507 vmesa->regCmdB |= HC_HLPrst_MASK;
508 }
509
510 /**********************************************************************/
511 /* Render unclipped begin/end objects */
512 /**********************************************************************/
513 #define IND 0
514 #define V(x) (viaVertex *)(vertptr + ((x) * vertsize * sizeof(int)))
515 #define RENDER_POINTS(start, count) \
516 for (; start < count; start++) POINT(V(ELT(start)));
517 #define RENDER_LINE(v0, v1) LINE(V(v0), V(v1))
518 #define RENDER_TRI( v0, v1, v2) TRI( V(v0), V(v1), V(v2))
519 #define RENDER_QUAD(v0, v1, v2, v3) QUAD(V(v0), V(v1), V(v2), V(v3))
520 #define INIT(x) viaRasterPrimitive(ctx, x, hwPrim[x])
521 #undef LOCAL_VARS
522 #define LOCAL_VARS \
523 struct via_context *vmesa = VIA_CONTEXT(ctx); \
524 GLubyte *vertptr = (GLubyte *)vmesa->verts; \
525 const GLuint vertsize = vmesa->vertexSize; \
526 const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \
527 const GLboolean stipple = ctx->Line.StippleFlag; \
528 (void) elt; (void) stipple;
529 #define RESET_STIPPLE if ( stipple ) viaResetLineStipple( ctx );
530 #define RESET_OCCLUSION
531 #define PRESERVE_VB_DEFS
532 #define ELT(x) x
533 #define TAG(x) via_##x##_verts
534 #include "tnl/t_vb_rendertmp.h"
535 #undef ELT
536 #undef TAG
537 #define TAG(x) via_##x##_elts
538 #define ELT(x) elt[x]
539 #include "tnl/t_vb_rendertmp.h"
540 #undef ELT
541 #undef TAG
542 #undef NEED_EDGEFLAG_SETUP
543 #undef EDGEFLAG_GET
544 #undef EDGEFLAG_SET
545 #undef RESET_OCCLUSION
546
547
548 /**********************************************************************/
549 /* Render clipped primitives */
550 /**********************************************************************/
551
552
553
554 static void viaRenderClippedPoly(GLcontext *ctx, const GLuint *elts,
555 GLuint n)
556 {
557 TNLcontext *tnl = TNL_CONTEXT(ctx);
558 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
559 GLuint prim = VIA_CONTEXT(ctx)->renderPrimitive;
560
561 /* Render the new vertices as an unclipped polygon.
562 */
563 {
564 GLuint *tmp = VB->Elts;
565 VB->Elts = (GLuint *)elts;
566 tnl->Driver.Render.PrimTabElts[GL_POLYGON](ctx, 0, n,
567 PRIM_BEGIN|PRIM_END);
568 VB->Elts = tmp;
569 }
570
571 /* Restore the render primitive
572 */
573 if (prim != GL_POLYGON &&
574 prim != GL_POLYGON + 1)
575 tnl->Driver.Render.PrimitiveNotify( ctx, prim );
576 }
577
578 static void viaRenderClippedLine(GLcontext *ctx, GLuint ii, GLuint jj)
579 {
580 TNLcontext *tnl = TNL_CONTEXT(ctx);
581 tnl->Driver.Render.Line(ctx, ii, jj);
582 }
583
584 static void viaFastRenderClippedPoly(GLcontext *ctx, const GLuint *elts,
585 GLuint n)
586 {
587 struct via_context *vmesa = VIA_CONTEXT(ctx);
588 GLuint vertsize = vmesa->vertexSize;
589 GLuint *vb = viaExtendPrimitive(vmesa, (n - 2) * 3 * 4 * vertsize);
590 GLubyte *vertptr = (GLubyte *)vmesa->verts;
591 const GLuint *start = (const GLuint *)V(elts[0]);
592 int i;
593
594 for (i = 2; i < n; i++) {
595 COPY_DWORDS(vb, vertsize, V(elts[i - 1]));
596 COPY_DWORDS(vb, vertsize, V(elts[i]));
597 COPY_DWORDS(vb, vertsize, start);
598 }
599 }
600
601 /**********************************************************************/
602 /* Choose render functions */
603 /**********************************************************************/
604
605
606
607
608 #define _VIA_NEW_VERTEX (_NEW_TEXTURE | \
609 _DD_NEW_SEPARATE_SPECULAR | \
610 _DD_NEW_TRI_UNFILLED | \
611 _DD_NEW_TRI_LIGHT_TWOSIDE | \
612 _NEW_FOG)
613
614 #define _VIA_NEW_RENDERSTATE (_DD_NEW_LINE_STIPPLE | \
615 _DD_NEW_TRI_UNFILLED | \
616 _DD_NEW_TRI_LIGHT_TWOSIDE | \
617 _DD_NEW_TRI_OFFSET | \
618 _DD_NEW_TRI_STIPPLE | \
619 _NEW_POLYGONSTIPPLE)
620
621 #define LINE_FALLBACK (0)
622 #define POINT_FALLBACK (0)
623 #define TRI_FALLBACK (0)
624 #define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)
625 #define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED)
626
627 static void viaChooseRenderState(GLcontext *ctx)
628 {
629 TNLcontext *tnl = TNL_CONTEXT(ctx);
630 struct via_context *vmesa = VIA_CONTEXT(ctx);
631 GLuint flags = ctx->_TriangleCaps;
632 GLuint index = 0;
633
634 if (vmesa->ptexHack) {
635 vmesa->drawPoint = via_ptex_point;
636 vmesa->drawLine = via_ptex_line;
637 vmesa->drawTri = via_ptex_tri;
638 index |= VIA_FALLBACK_BIT;
639 }
640 else {
641 vmesa->drawPoint = via_draw_point;
642 vmesa->drawLine = via_draw_line;
643 vmesa->drawTri = via_draw_triangle;
644 }
645
646 if (flags & (ANY_FALLBACK_FLAGS|ANY_RASTER_FLAGS)) {
647 if (flags & DD_TRI_LIGHT_TWOSIDE) index |= VIA_TWOSIDE_BIT;
648 if (flags & DD_TRI_OFFSET) index |= VIA_OFFSET_BIT;
649 if (flags & DD_TRI_UNFILLED) index |= VIA_UNFILLED_BIT;
650 if (flags & ANY_FALLBACK_FLAGS) index |= VIA_FALLBACK_BIT;
651
652 /* Hook in fallbacks for specific primitives.
653 */
654 if (flags & POINT_FALLBACK)
655 vmesa->drawPoint = via_fallback_point;
656
657 if (flags & LINE_FALLBACK)
658 vmesa->drawLine = via_fallback_line;
659
660 if (flags & TRI_FALLBACK)
661 vmesa->drawTri = via_fallback_tri;
662 }
663
664 if (vmesa->renderIndex != index) {
665 vmesa->renderIndex = index;
666
667 tnl->Driver.Render.Points = rast_tab[index].points;
668 tnl->Driver.Render.Line = rast_tab[index].line;
669 tnl->Driver.Render.Triangle = rast_tab[index].triangle;
670 tnl->Driver.Render.Quad = rast_tab[index].quad;
671
672 if (index == 0) {
673 tnl->Driver.Render.PrimTabVerts = via_render_tab_verts;
674 tnl->Driver.Render.PrimTabElts = via_render_tab_elts;
675 tnl->Driver.Render.ClippedLine = line; /* from tritmp.h */
676 tnl->Driver.Render.ClippedPolygon = viaFastRenderClippedPoly;
677 }
678 else {
679 tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
680 tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
681 tnl->Driver.Render.ClippedLine = viaRenderClippedLine;
682 tnl->Driver.Render.ClippedPolygon = viaRenderClippedPoly;
683 }
684 }
685 }
686
687
688 #define VIA_EMIT_TEX1 0x01
689 #define VIA_EMIT_TEX0 0x02
690 #define VIA_EMIT_PTEX0 0x04
691 #define VIA_EMIT_RGBA 0x08
692 #define VIA_EMIT_SPEC 0x10
693 #define VIA_EMIT_FOG 0x20
694 #define VIA_EMIT_W 0x40
695
696 #define EMIT_ATTR( ATTR, STYLE, INDEX, REGB ) \
697 do { \
698 vmesa->vertex_attrs[vmesa->vertex_attr_count].attrib = (ATTR); \
699 vmesa->vertex_attrs[vmesa->vertex_attr_count].format = (STYLE); \
700 vmesa->vertex_attr_count++; \
701 setupIndex |= (INDEX); \
702 regCmdB |= (REGB); \
703 } while (0)
704
705 #define EMIT_PAD( N ) \
706 do { \
707 vmesa->vertex_attrs[vmesa->vertex_attr_count].attrib = 0; \
708 vmesa->vertex_attrs[vmesa->vertex_attr_count].format = EMIT_PAD; \
709 vmesa->vertex_attrs[vmesa->vertex_attr_count].offset = (N); \
710 vmesa->vertex_attr_count++; \
711 } while (0)
712
713
714
715 static void viaChooseVertexState( GLcontext *ctx )
716 {
717 struct via_context *vmesa = VIA_CONTEXT(ctx);
718 TNLcontext *tnl = TNL_CONTEXT(ctx);
719 GLuint index = tnl->render_inputs;
720 GLuint regCmdB = HC_HVPMSK_X | HC_HVPMSK_Y | HC_HVPMSK_Z;
721 GLuint setupIndex = 0;
722
723 vmesa->vertex_attr_count = 0;
724
725 /* EMIT_ATTR's must be in order as they tell t_vertex.c how to
726 * build up a hardware vertex.
727 */
728 if (index & (_TNL_BITS_TEX_ANY|_TNL_BIT_FOG)) {
729 EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, VIA_EMIT_W, HC_HVPMSK_W );
730 vmesa->coloroffset = 4;
731 }
732 else {
733 EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT, 0, 0 );
734 vmesa->coloroffset = 3;
735 }
736
737 /* t_context.c always includes a diffuse color */
738 EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4UB_4F_BGRA, VIA_EMIT_RGBA,
739 HC_HVPMSK_Cd );
740
741 vmesa->specoffset = 0;
742 if (index & (_TNL_BIT_COLOR1|_TNL_BIT_FOG)) {
743 if ((index & _TNL_BIT_COLOR1)) {
744 vmesa->specoffset = vmesa->coloroffset + 1;
745 EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_3UB_3F_BGR, VIA_EMIT_SPEC,
746 HC_HVPMSK_Cs );
747 }
748 else
749 EMIT_PAD( 3 );
750
751 if ((index & _TNL_BIT_FOG))
752 EMIT_ATTR( _TNL_ATTRIB_FOG, EMIT_1UB_1F, VIA_EMIT_FOG, HC_HVPMSK_Cs );
753 else
754 EMIT_PAD( 1 );
755 }
756
757 if (index & _TNL_BIT_TEX(0)) {
758 if (vmesa->ptexHack)
759 EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_3F_XYW, VIA_EMIT_PTEX0,
760 (HC_HVPMSK_S | HC_HVPMSK_T) );
761 else
762 EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_2F, VIA_EMIT_TEX0,
763 (HC_HVPMSK_S | HC_HVPMSK_T) );
764 }
765
766 if (index & _TNL_BIT_TEX(1)) {
767 EMIT_ATTR( _TNL_ATTRIB_TEX1, EMIT_2F, VIA_EMIT_TEX1,
768 (HC_HVPMSK_S | HC_HVPMSK_T) );
769 }
770
771 if (setupIndex != vmesa->setupIndex) {
772 vmesa->vertexSize = _tnl_install_attrs( ctx,
773 vmesa->vertex_attrs,
774 vmesa->vertex_attr_count,
775 vmesa->ViewportMatrix.m, 0 );
776 vmesa->vertexSize >>= 2;
777 vmesa->setupIndex = setupIndex;
778 vmesa->regCmdB &= ~HC_HVPMSK_MASK;
779 vmesa->regCmdB |= regCmdB;
780
781 if (vmesa->ptexHack)
782 vmesa->hwVertexSize = vmesa->vertexSize - 1;
783 else
784 vmesa->hwVertexSize = vmesa->vertexSize;
785 }
786 }
787
788
789
790
791 /* Check if projective texture coordinates are used and if we can fake
792 * them. Fallback to swrast if we can't. Returns GL_TRUE if projective
793 * texture coordinates must be faked, GL_FALSE otherwise.
794 */
795 static GLboolean viaCheckPTexHack( GLcontext *ctx )
796 {
797 TNLcontext *tnl = TNL_CONTEXT(ctx);
798 struct vertex_buffer *VB = &tnl->vb;
799 GLuint index = tnl->render_inputs;
800 GLboolean fallback = GL_FALSE;
801 GLboolean ptexHack = GL_FALSE;
802
803 if (index & _TNL_BIT_TEX(0) && VB->TexCoordPtr[0]->size == 4) {
804 if ((index & _TNL_BITS_TEX_ANY) == _TNL_BIT_TEX(0))
805 ptexHack = GL_TRUE;
806 else
807 fallback = GL_TRUE;
808 }
809 if ((index & _TNL_BIT_TEX(1)) && VB->TexCoordPtr[1]->size == 4)
810 fallback = GL_TRUE;
811
812 FALLBACK(VIA_CONTEXT(ctx), VIA_FALLBACK_PROJ_TEXTURE, fallback);
813 return ptexHack;
814 }
815
816
817
818
819 /**********************************************************************/
820 /* High level hooks for t_vb_render.c */
821 /**********************************************************************/
822
823
824 static void viaRenderStart(GLcontext *ctx)
825 {
826 struct via_context *vmesa = VIA_CONTEXT(ctx);
827 TNLcontext *tnl = TNL_CONTEXT(ctx);
828 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
829
830 {
831 GLboolean ptexHack = viaCheckPTexHack( ctx );
832 if (ptexHack != vmesa->ptexHack) {
833 vmesa->ptexHack = ptexHack;
834 vmesa->newRenderState |= _VIA_NEW_RENDERSTATE;
835 }
836 }
837
838 if (vmesa->newState) {
839 vmesa->newRenderState |= vmesa->newState;
840 viaValidateState( ctx );
841 }
842
843 if (vmesa->Fallback) {
844 tnl->Driver.Render.Start(ctx);
845 return;
846 }
847
848 if (vmesa->newRenderState) {
849 viaChooseVertexState(ctx);
850 viaChooseRenderState(ctx);
851 vmesa->newRenderState = 0;
852 }
853
854 /* Important:
855 */
856 VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr;
857 }
858
859 static void viaRenderFinish(GLcontext *ctx)
860 {
861 VIA_FINISH_PRIM(VIA_CONTEXT(ctx));
862 }
863
864
865 /* System to flush dma and emit state changes based on the rasterized
866 * primitive.
867 */
868 void viaRasterPrimitive(GLcontext *ctx,
869 GLenum glprim,
870 GLenum hwprim)
871 {
872 struct via_context *vmesa = VIA_CONTEXT(ctx);
873 GLuint regCmdB;
874 RING_VARS;
875
876 if (VIA_DEBUG & DEBUG_PRIMS)
877 fprintf(stderr, "%s: %s/%s\n",
878 __FUNCTION__, _mesa_lookup_enum_by_nr(glprim),
879 _mesa_lookup_enum_by_nr(hwprim));
880
881 vmesa->renderPrimitive = glprim;
882
883 if (hwprim != vmesa->hwPrimitive) {
884 VIA_FINISH_PRIM(vmesa);
885
886 /* Ensure no wrapping inside this function */
887 viaCheckDma( vmesa, 1024 );
888
889 if (vmesa->newEmitState) {
890 viaEmitState(vmesa);
891 }
892
893 vmesa->regCmdA_End = HC_ACMD_HCmdA;
894
895 if (ctx->Light.ShadeModel == GL_SMOOTH) {
896 vmesa->regCmdA_End |= HC_HShading_Gouraud;
897 }
898
899 regCmdB = vmesa->regCmdB;
900
901 switch (hwprim) {
902 case GL_POINTS:
903 vmesa->regCmdA_End |= HC_HPMType_Point | HC_HVCycle_Full;
904 vmesa->regCmdA_End |= HC_HShading_Gouraud; /* always Gouraud
905 shade points?!? */
906 break;
907 case GL_LINES:
908 vmesa->regCmdA_End |= HC_HPMType_Line | HC_HVCycle_Full;
909 regCmdB |= HC_HLPrst_MASK;
910 if (ctx->Light.ShadeModel == GL_FLAT)
911 vmesa->regCmdA_End |= HC_HShading_FlatB;
912 break;
913 case GL_LINE_LOOP:
914 case GL_LINE_STRIP:
915 vmesa->regCmdA_End |= HC_HPMType_Line | HC_HVCycle_AFP |
916 HC_HVCycle_AB | HC_HVCycle_NewB;
917 regCmdB |= HC_HVCycle_AB | HC_HVCycle_NewB | HC_HLPrst_MASK;
918 if (ctx->Light.ShadeModel == GL_FLAT)
919 vmesa->regCmdA_End |= HC_HShading_FlatB;
920 break;
921 case GL_TRIANGLES:
922 vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_Full;
923 if (ctx->Light.ShadeModel == GL_FLAT)
924 vmesa->regCmdA_End |= HC_HShading_FlatC;
925 break;
926 case GL_TRIANGLE_STRIP:
927 vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_AFP |
928 HC_HVCycle_AC | HC_HVCycle_BB | HC_HVCycle_NewC;
929 regCmdB |= HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC;
930 if (ctx->Light.ShadeModel == GL_FLAT)
931 vmesa->regCmdA_End |= HC_HShading_FlatC;
932 break;
933 case GL_TRIANGLE_FAN:
934 vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_AFP |
935 HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC;
936 regCmdB |= HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC;
937 if (ctx->Light.ShadeModel == GL_FLAT)
938 vmesa->regCmdA_End |= HC_HShading_FlatC;
939 break;
940 case GL_QUADS:
941 abort();
942 return;
943 case GL_QUAD_STRIP:
944 abort();
945 return;
946 case GL_POLYGON:
947 vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_AFP |
948 HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC;
949 regCmdB |= HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC;
950 if (ctx->Light.ShadeModel == GL_FLAT)
951 vmesa->regCmdA_End |= HC_HShading_FlatC;
952 break;
953 default:
954 abort();
955 return;
956 }
957
958 /* assert((vmesa->dmaLow & 0x4) == 0); */
959
960 if (vmesa->dmaCliprectAddr == ~0) {
961 if (VIA_DEBUG & DEBUG_DMA)
962 fprintf(stderr, "reserve cliprect space at %x\n", vmesa->dmaLow);
963 vmesa->dmaCliprectAddr = vmesa->dmaLow;
964 BEGIN_RING(8);
965 OUT_RING( HC_HEADER2 );
966 OUT_RING( (HC_ParaType_NotTex << 16) );
967 OUT_RING( 0xCCCCCCCC );
968 OUT_RING( 0xCCCCCCCC );
969 OUT_RING( 0xCCCCCCCC );
970 OUT_RING( 0xCCCCCCCC );
971 OUT_RING( 0xCCCCCCCC );
972 OUT_RING( 0xCCCCCCCC );
973 ADVANCE_RING();
974 }
975
976 assert(vmesa->dmaLastPrim == 0);
977
978 BEGIN_RING(8);
979 OUT_RING( HC_HEADER2 );
980 OUT_RING( (HC_ParaType_NotTex << 16) );
981 OUT_RING( 0xCCCCCCCC );
982 OUT_RING( 0xDDDDDDDD );
983
984 OUT_RING( HC_HEADER2 );
985 OUT_RING( (HC_ParaType_CmdVdata << 16) );
986 OUT_RING( regCmdB );
987 OUT_RING( vmesa->regCmdA_End );
988 ADVANCE_RING();
989
990 vmesa->hwPrimitive = hwprim;
991 vmesa->dmaLastPrim = vmesa->dmaLow;
992 }
993 else {
994 assert(!vmesa->newEmitState);
995 }
996 }
997
998 /* Callback for mesa:
999 */
1000 static void viaRenderPrimitive( GLcontext *ctx, GLuint prim )
1001 {
1002 viaRasterPrimitive( ctx, prim, hwPrim[prim] );
1003 }
1004
1005
1006 void viaFinishPrimitive(struct via_context *vmesa)
1007 {
1008 if (VIA_DEBUG & (DEBUG_DMA|DEBUG_PRIMS))
1009 fprintf(stderr, "%s\n", __FUNCTION__);
1010
1011 if (!vmesa->dmaLastPrim || vmesa->dmaCliprectAddr == ~0) {
1012 assert(0);
1013 }
1014 else if (vmesa->dmaLow != vmesa->dmaLastPrim) {
1015 GLuint cmdA = (vmesa->regCmdA_End | HC_HPLEND_MASK |
1016 HC_HPMValidN_MASK | HC_HE3Fire_MASK);
1017 RING_VARS;
1018
1019 vmesa->dmaLastPrim = 0;
1020
1021 /* KW: modified 0x1 to 0x4 below:
1022 */
1023 if ((vmesa->dmaLow & 0x4) || !vmesa->useAgp) {
1024 BEGIN_RING_NOCHECK( 1 );
1025 OUT_RING( cmdA );
1026 ADVANCE_RING();
1027 }
1028 else {
1029 BEGIN_RING_NOCHECK( 2 );
1030 OUT_RING( cmdA );
1031 OUT_RING( cmdA );
1032 ADVANCE_RING();
1033 }
1034
1035 if (vmesa->dmaLow > VIA_DMA_HIGHWATER)
1036 viaFlushDma( vmesa );
1037 }
1038 else {
1039 if (VIA_DEBUG & (DEBUG_DMA|DEBUG_PRIMS))
1040 fprintf(stderr, "remove empty primitive\n");
1041
1042 /* Remove the primitive header:
1043 */
1044 vmesa->dmaLastPrim = 0;
1045 vmesa->dmaLow -= 8 * sizeof(GLuint);
1046
1047 /* Maybe remove the cliprect as well:
1048 */
1049 if (vmesa->dmaCliprectAddr == vmesa->dmaLow - 8 * sizeof(GLuint)) {
1050 vmesa->dmaLow -= 8 * sizeof(GLuint);
1051 vmesa->dmaCliprectAddr = ~0;
1052 }
1053 }
1054
1055 vmesa->renderPrimitive = GL_POLYGON + 1;
1056 vmesa->hwPrimitive = GL_POLYGON + 1;
1057 vmesa->dmaLastPrim = 0;
1058 }
1059
1060
1061 /**********************************************************************/
1062 /* Transition to/from hardware rasterization. */
1063 /**********************************************************************/
1064
1065
1066 void viaFallback(struct via_context *vmesa, GLuint bit, GLboolean mode)
1067 {
1068 GLcontext *ctx = vmesa->glCtx;
1069 TNLcontext *tnl = TNL_CONTEXT(ctx);
1070 GLuint oldfallback = vmesa->Fallback;
1071
1072 if (mode) {
1073 vmesa->Fallback |= bit;
1074 if (oldfallback == 0) {
1075 VIA_FLUSH_DMA(vmesa);
1076
1077 if (VIA_DEBUG & DEBUG_FALLBACKS)
1078 fprintf(stderr, "ENTER FALLBACK %x\n", bit);
1079
1080 _swsetup_Wakeup(ctx);
1081 vmesa->renderIndex = ~0;
1082 }
1083 }
1084 else {
1085 vmesa->Fallback &= ~bit;
1086 if (oldfallback == bit) {
1087 _swrast_flush( ctx );
1088
1089 if (VIA_DEBUG & DEBUG_FALLBACKS)
1090 fprintf(stderr, "LEAVE FALLBACK %x\n", bit);
1091
1092 tnl->Driver.Render.Start = viaRenderStart;
1093 tnl->Driver.Render.PrimitiveNotify = viaRenderPrimitive;
1094 tnl->Driver.Render.Finish = viaRenderFinish;
1095
1096 tnl->Driver.Render.BuildVertices = _tnl_build_vertices;
1097 tnl->Driver.Render.CopyPV = _tnl_copy_pv;
1098 tnl->Driver.Render.Interp = _tnl_interp;
1099 tnl->Driver.Render.ResetLineStipple = viaResetLineStipple;
1100
1101 _tnl_invalidate_vertex_state( ctx, ~0 );
1102 _tnl_invalidate_vertices( ctx, ~0 );
1103 _tnl_install_attrs( ctx,
1104 vmesa->vertex_attrs,
1105 vmesa->vertex_attr_count,
1106 vmesa->ViewportMatrix.m, 0 );
1107
1108 vmesa->newState |= (_VIA_NEW_RENDERSTATE|_VIA_NEW_VERTEX);
1109 }
1110 }
1111 }
1112
1113 static void viaRunPipeline( GLcontext *ctx )
1114 {
1115 struct via_context *vmesa = VIA_CONTEXT(ctx);
1116
1117 if (vmesa->newState) {
1118 vmesa->newRenderState |= vmesa->newState;
1119 viaValidateState( ctx );
1120 }
1121
1122 _tnl_run_pipeline( ctx );
1123 }
1124
1125
1126 /**********************************************************************/
1127 /* Initialization. */
1128 /**********************************************************************/
1129
1130
1131 void viaInitTriFuncs(GLcontext *ctx)
1132 {
1133 struct via_context *vmesa = VIA_CONTEXT(ctx);
1134 TNLcontext *tnl = TNL_CONTEXT(ctx);
1135 static int firsttime = 1;
1136
1137 if (firsttime) {
1138 init_rast_tab();
1139 firsttime = 0;
1140 }
1141
1142 tnl->Driver.RunPipeline = viaRunPipeline;
1143 tnl->Driver.Render.Start = viaRenderStart;
1144 tnl->Driver.Render.Finish = viaRenderFinish;
1145 tnl->Driver.Render.PrimitiveNotify = viaRenderPrimitive;
1146 tnl->Driver.Render.ResetLineStipple = viaResetLineStipple;
1147 tnl->Driver.Render.BuildVertices = _tnl_build_vertices;
1148 tnl->Driver.Render.CopyPV = _tnl_copy_pv;
1149 tnl->Driver.Render.Interp = _tnl_interp;
1150
1151 _tnl_init_vertices( ctx, ctx->Const.MaxArrayLockSize + 12,
1152 (6 + 2*ctx->Const.MaxTextureUnits) * sizeof(GLfloat) );
1153
1154 vmesa->verts = (GLubyte *)tnl->clipspace.vertex_buf;
1155
1156 }