2 * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
3 * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
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:
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
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.
27 * Render unclipped vertex buffers by emitting vertices directly to
28 * dma buffers. Use strip/fan hardware acceleration where possible.
36 #include "tnl/t_context.h"
38 #include "via_context.h"
40 #include "via_state.h"
42 #include "via_ioctl.h"
45 * Render unclipped vertex buffers by emitting vertices directly to
46 * dma buffers. Use strip/fan hardware primitives where possible.
47 * Try to simulate missing primitives with indexed vertices.
51 #define HAVE_LINE_STRIPS 1
52 #define HAVE_LINE_LOOP 1
53 #define HAVE_TRIANGLES 1
54 #define HAVE_TRI_STRIPS 1
55 #define HAVE_TRI_STRIP_1 0 /* has it, template can't use it yet */
56 #define HAVE_TRI_FANS 1
57 #define HAVE_POLYGONS 1
59 #define HAVE_QUAD_STRIPS 0
63 static const GLenum reducedPrim
[GL_POLYGON
+ 1] = {
76 /* Fallback to normal rendering.
78 static void VERT_FALLBACK(GLcontext
*ctx
,
83 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
84 if (VIA_DEBUG
) fprintf(stderr
, "%s - in\n", __FUNCTION__
);
85 fprintf(stderr
, "VERT_FALLBACK\n");
86 tnl
->Driver
.Render
.PrimitiveNotify(ctx
, flags
& PRIM_MODE_MASK
);
87 tnl
->Driver
.Render
.BuildVertices(ctx
, start
, count
, ~0);
88 tnl
->Driver
.Render
.PrimTabVerts
[flags
& PRIM_MODE_MASK
](ctx
, start
,
90 VIA_CONTEXT(ctx
)->setupNewInputs
= VERT_BIT_CLIP
;
91 if (VIA_DEBUG
) fprintf(stderr
, "%s - out\n", __FUNCTION__
);
95 #define LOCAL_VARS viaContextPtr vmesa = VIA_CONTEXT(ctx)
99 VIA_STATECHANGE(vmesa, 0); \
100 viaRasterPrimitive(ctx, reducedPrim[prim], prim); \
105 viaRasterPrimitive(ctx, reducedPrim[prim], prim); \
107 #define NEW_PRIMITIVE() VIA_STATECHANGE(vmesa, 0)
108 #define NEW_BUFFER() VIA_FIREVERTICES(vmesa)
109 #define GET_CURRENT_VB_MAX_VERTS() \
110 (((int)vmesa->dmaHigh - (int)vmesa->dmaLow) / (vmesa->vertexSize * 4))
111 #define GET_SUBSEQUENT_VB_MAX_VERTS() \
112 (VIA_DMA_BUF_SZ - 4) / (vmesa->vertexSize * 4)
115 #define EMIT_VERTS(ctx, j, nr) \
116 via_emit_contiguous_verts(ctx, j, (j) + (nr))
120 vmesa->primitiveRendered = GL_TRUE; \
121 viaRasterPrimitiveFinish(ctx); \
125 #define TAG(x) via_fast##x
126 #include "via_dmatmp.h"
131 /**********************************************************************/
132 /* Fast Render pipeline stage */
133 /**********************************************************************/
134 static GLboolean
via_run_fastrender(GLcontext
*ctx
,
135 struct tnl_pipeline_stage
*stage
)
137 viaContextPtr vmesa
= VIA_CONTEXT(ctx
);
138 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
139 struct vertex_buffer
*VB
= &tnl
->vb
;
140 GLuint i
, length
, flags
= 0;
142 /* Don't handle clipping or indexed vertices.
144 #ifdef PERFORMANCE_MEASURE
145 if (VIA_PERFORMANCE
) P_M
;
148 if (VB
->ClipOrMask
|| vmesa
->renderIndex
!= 0 || VB
->Elts
) {
150 fprintf(stderr
, "slow path\n");
151 fprintf(stderr
, "ClipOrMask = %08x\n", VB
->ClipOrMask
);
152 fprintf(stderr
, "renderIndex = %08x\n", vmesa
->renderIndex
);
153 fprintf(stderr
, "Elts = %08x\n", (GLuint
)VB
->Elts
);
157 if (VIA_DEBUG
) fprintf(stderr
, "%s - in\n", __FUNCTION__
);
158 vmesa
->setupNewInputs
= VERT_BIT_CLIP
;
159 vmesa
->primitiveRendered
= GL_TRUE
;
161 tnl
->Driver
.Render
.Start(ctx
);
163 for (i
= 0; i
< VB
->PrimitiveCount
; ++i
) {
164 GLuint mode
= VB
->Primitive
[i
].mode
;
165 GLuint start
= VB
->Primitive
[i
].start
;
166 GLuint length
= VB
->Primitive
[i
].count
;
168 via_fastrender_tab_verts
[mode
& PRIM_MODE_MASK
](ctx
, start
, start
+length
, mode
);
171 tnl
->Driver
.Render
.Finish(ctx
);
173 /*=* DBG - viewperf7.0 : fix command buffer overflow *=*/
174 if (vmesa
->dmaLow
> (VIA_DMA_BUFSIZ
/ 2))
175 viaFlushPrims(vmesa
);
176 if (VIA_DEBUG
) fprintf(stderr
, "%s - out\n", __FUNCTION__
);
177 return GL_FALSE
; /* finished the pipe */
181 static void via_check_fastrender(GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
183 GLuint inputs
= VERT_BIT_CLIP
| VERT_BIT_COLOR0
;
185 if (ctx
->RenderMode
== GL_RENDER
) {
186 if (ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
187 inputs
|= VERT_BIT_COLOR1
;
189 if (ctx
->Texture
.Unit
[0]._ReallyEnabled
)
190 inputs
|= VERT_BIT_TEX0
;
192 if (ctx
->Texture
.Unit
[1]._ReallyEnabled
)
193 inputs
|= VERT_BIT_TEX1
;
195 if (ctx
->Fog
.Enabled
)
196 inputs
|= VERT_BIT_FOG
;
199 stage
->inputs
= inputs
;
203 static void fastdtr(struct tnl_pipeline_stage
*stage
)
209 const struct tnl_pipeline_stage _via_fastrender_stage
=
212 (_DD_NEW_SEPARATE_SPECULAR
|
215 _NEW_RENDERMODE
), /* re-check (new inputs) */
216 0, /* re-run (always runs) */
217 GL_TRUE
, /* active */
218 0, 0, /* inputs (set in check_render), outputs */
219 0, 0, /* changed_inputs, private */
220 fastdtr
, /* destructor */
221 via_check_fastrender
, /* check - initially set to alloc data */
222 via_run_fastrender
/* run */
227 * Render whole vertex buffers, including projection of vertices from
228 * clip space and clipping of primitives.
230 * This file makes calls to project vertices and to the point, line
231 * and triangle rasterizers via the function pointers:
233 * context->Driver.Render.*
238 /**********************************************************************/
239 /* Clip single primitives */
240 /**********************************************************************/
241 #undef DIFFERENT_SIGNS
242 #if defined(USE_IEEE)
243 #define NEGATIVE(x) (GET_FLOAT_BITS(x) & (1 << 31))
244 #define DIFFERENT_SIGNS(x, y) ((GET_FLOAT_BITS(x) ^ GET_FLOAT_BITS(y)) & (1 << 31))
246 #define NEGATIVE(x) (x < 0)
247 #define DIFFERENT_SIGNS(x,y) (x * y <= 0 && x - y != 0)
248 /* Could just use (x*y<0) except for the flatshading requirements.
249 * Maybe there's a better way?
253 #define W(i) coord[i][3]
254 #define Z(i) coord[i][2]
255 #define Y(i) coord[i][1]
256 #define X(i) coord[i][0]
259 #include "via_vb_cliptmp.h"
262 /**********************************************************************/
263 /* Clip and render whole begin/end objects */
264 /**********************************************************************/
265 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
266 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
267 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
270 /* Vertices, with the possibility of clipping.
272 #define RENDER_POINTS(start, count) \
273 tnl->Driver.Render.Points(ctx, start, count)
275 #define RENDER_LINE(v1, v2) \
277 GLubyte c1 = mask[v1], c2 = mask[v2]; \
278 GLubyte ormask = c1 | c2; \
280 LineFunc(ctx, v1, v2); \
281 else if (!(c1 & c2 & 0x3f)) \
282 clip_line_4(ctx, v1, v2, ormask); \
285 #define RENDER_TRI(v1, v2, v3) \
286 if (VIA_DEBUG) fprintf(stderr, "RENDER_TRI - clip\n"); \
288 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \
289 GLubyte ormask = c1 | c2 | c3; \
291 TriangleFunc(ctx, v1, v2, v3); \
292 else if (!(c1 & c2 & c3 & 0x3f)) \
293 clip_tri_4(ctx, v1, v2, v3, ormask); \
296 #define RENDER_QUAD(v1, v2, v3, v4) \
298 GLubyte c1 = mask[v1], c2 = mask[v2]; \
299 GLubyte c3 = mask[v3], c4 = mask[v4]; \
300 GLubyte ormask = c1 | c2 | c3 | c4; \
302 QuadFunc(ctx, v1, v2, v3, v4); \
303 else if (!(c1 & c2 & c3 & c4 & 0x3f)) \
304 clip_quad_4(ctx, v1, v2, v3, v4, ormask); \
309 TNLcontext *tnl = TNL_CONTEXT(ctx); \
310 struct vertex_buffer *VB = &tnl->vb; \
311 const GLuint * const elt = VB->Elts; \
312 const GLubyte *mask = VB->ClipMask; \
313 const GLuint sz = VB->ClipPtr->size; \
314 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
315 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
316 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
317 const GLboolean stipple = ctx->Line.StippleFlag; \
318 (void) (LineFunc && TriangleFunc && QuadFunc); \
319 (void) elt; (void) mask; (void) sz; (void) stipple;
322 viaRasterPrimitiveFinish(ctx)
324 #define TAG(x) clip_##x##_verts
325 #define INIT(x) tnl->Driver.Render.PrimitiveNotify(ctx, x)
326 #define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple(ctx)
327 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
328 #define PRESERVE_VB_DEFS
329 #include "via_vb_rendertmp.h"
332 /* Elts, with the possibility of clipping.
336 #define ELT(x) elt[x]
337 #define TAG(x) clip_##x##_elts
338 #include "via_vb_rendertmp.h"
340 /* TODO: do this for all primitives, verts and elts:
342 static void clip_elt_triangles(GLcontext
*ctx
,
347 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
348 tnl_render_func render_tris
= tnl
->Driver
.Render
.PrimTabElts
[GL_TRIANGLES
];
349 struct vertex_buffer
*VB
= &tnl
->vb
;
350 const GLuint
* const elt
= VB
->Elts
;
351 GLubyte
*mask
= VB
->ClipMask
;
352 GLuint last
= count
-2;
355 #ifdef PERFORMANCE_MEASURE
356 if (VIA_PERFORMANCE
) P_M
;
358 tnl
->Driver
.Render
.PrimitiveNotify(ctx
, GL_TRIANGLES
);
360 for (j
= start
; j
< last
; j
+= 3) {
361 GLubyte c1
= mask
[elt
[j
]];
362 GLubyte c2
= mask
[elt
[j
+ 1]];
363 GLubyte c3
= mask
[elt
[j
+ 2]];
364 GLubyte ormask
= c1
| c2
| c3
;
367 render_tris(ctx
, start
, j
, 0);
368 if (!(c1
& c2
& c3
& 0x3f))
369 clip_tri_4(ctx
, elt
[j
], elt
[j
+ 1], elt
[j
+ 2], ormask
);
375 render_tris(ctx
, start
, j
, 0);
377 viaRasterPrimitiveFinish(ctx
);
381 /**********************************************************************/
382 /* Helper functions for drivers */
383 /**********************************************************************/
385 void _tnl_RenderClippedPolygon(GLcontext *ctx, const GLuint *elts, GLuint n)
387 TNLcontext *tnl = TNL_CONTEXT(ctx);
388 struct vertex_buffer *VB = &tnl->vb;
389 GLuint *tmp = VB->Elts;
391 VB->Elts = (GLuint *)elts;
392 tnl->Driver.Render.PrimTabElts[GL_POLYGON](ctx, 0, n, PRIM_BEGIN|PRIM_END);
396 void _tnl_RenderClippedLine(GLcontext *ctx, GLuint ii, GLuint jj)
398 TNLcontext *tnl = TNL_CONTEXT(ctx);
399 tnl->Driver.Render.Line(ctx, ii, jj);
403 /**********************************************************************/
404 /* Render pipeline stage */
405 /**********************************************************************/
406 static GLboolean
via_run_render(GLcontext
*ctx
,
407 struct tnl_pipeline_stage
*stage
)
409 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
410 viaContextPtr vmesa
= VIA_CONTEXT(ctx
);
411 struct vertex_buffer
*VB
= &tnl
->vb
;
413 GLuint newInputs
= stage
->changed_inputs
;
414 /*GLuint newInputs = stage->inputs;*/
416 tnl_render_func
*tab
;
419 if (VIA_DEBUG
) fprintf(stderr
, "%s - in\n", __FUNCTION__
);
420 #ifdef PERFORMANCE_MEASURE
421 if (VIA_PERFORMANCE
) P_M
;
423 tnl
->Driver
.Render
.Start(ctx
);
424 tnl
->Driver
.Render
.BuildVertices(ctx
, 0, VB
->Count
, newInputs
);
425 if (VB
->ClipOrMask
) {
426 tab
= VB
->Elts
? clip_render_tab_elts
: clip_render_tab_verts
;
427 clip_render_tab_elts
[GL_TRIANGLES
] = clip_elt_triangles
;
430 tab
= VB
->Elts
? tnl
->Driver
.Render
.PrimTabElts
: tnl
->Driver
.Render
.PrimTabVerts
;
436 for (i
= 0; i
< VB
->PrimitiveCount
; i
++) {
437 GLuint flags
= VB
->Primitive
[i
].mode
;
438 GLuint start
= VB
->Primitive
[i
].start
;
439 GLuint length
= VB
->Primitive
[i
].count
;
440 ASSERT(length
|| (flags
& PRIM_END
));
441 ASSERT((flags
& PRIM_MODE_MASK
) <= GL_POLYGON
+ 1);
443 tab
[flags
& PRIM_MODE_MASK
](ctx
, start
, start
+ length
,flags
);
446 while (tnl
->Driver
.Render
.Multipass
&& tnl
->Driver
.Render
.Multipass(ctx
, ++pass
));
447 tnl
->Driver
.Render
.Finish(ctx
);
449 /*=* DBG - flush : if hw idel *=*/
451 GLuint volatile *pnEnginStatus = vmesa->regEngineStatus;
453 nStatus = *pnEnginStatus;
454 if ((nStatus & 0xFFFEFFFF) == 0x00020000)
455 viaFlushPrims(vmesa);
458 /*=* DBG viewperf7.0 : fix command buffer overflow *=*/
459 if (vmesa
->dmaLow
> (VIA_DMA_BUFSIZ
/ 2))
460 viaFlushPrims(vmesa
);
461 if (VIA_DEBUG
) fprintf(stderr
, "%s - out\n", __FUNCTION__
);
462 return GL_FALSE
; /* finished the pipe */
465 /* Quite a bit of work involved in finding out the inputs for the
469 static void via_check_render(GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
471 GLuint inputs
= VERT_BIT_CLIP
;
473 if (ctx
->Visual
.rgbMode
) {
474 inputs
|= VERT_BIT_COLOR0
;
476 if (ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
477 inputs
|= VERT_BIT_COLOR1
;
479 if (ctx
->Texture
.Unit
[0]._ReallyEnabled
) {
480 inputs
|= VERT_BIT_TEX0
;
483 if (ctx
->Texture
.Unit
[1]._ReallyEnabled
) {
484 inputs
|= VERT_BIT_TEX1
;
488 /*inputs |= VERT_BIT_INDEX;*/
491 /*if (ctx->Point._Attenuated)
492 inputs |= VERT_POINT_SIZE;*/
494 if (ctx
->Fog
.Enabled
)
495 inputs
|= VERT_BIT_FOG
;
497 /*if (ctx->_TriangleCaps & DD_TRI_UNFILLED)
500 if (ctx->RenderMode == GL_FEEDBACK)
501 inputs |= VERT_TEX_ANY;*/
503 stage
->inputs
= inputs
;
507 static void dtr(struct tnl_pipeline_stage
*stage
)
513 const struct tnl_pipeline_stage _via_render_stage
=
517 _DD_NEW_SEPARATE_SPECULAR
|
523 _DD_NEW_TRI_UNFILLED
|
524 _NEW_RENDERMODE
), /* re-check (new inputs) */
525 0, /* re-run (always runs) */
526 GL_TRUE
, /* active */
527 0, 0, /* inputs (set in check_render), outputs */
528 0, 0, /* changed_inputs, private */
529 dtr
, /* destructor */
530 via_check_render
, /* check - initially set to alloc data */
531 via_run_render
/* run */