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
);
85 if (VIA_DEBUG
) fprintf(stderr
, "%s - in\n", __FUNCTION__
);
87 fprintf(stderr
, "VERT_FALLBACK\n");
88 tnl
->Driver
.Render
.PrimitiveNotify(ctx
, flags
& PRIM_MODE_MASK
);
89 tnl
->Driver
.Render
.BuildVertices(ctx
, start
, count
, ~0);
90 tnl
->Driver
.Render
.PrimTabVerts
[flags
& PRIM_MODE_MASK
](ctx
, start
,
92 VIA_CONTEXT(ctx
)->setupNewInputs
= VERT_BIT_CLIP
;
94 if (VIA_DEBUG
) fprintf(stderr
, "%s - out\n", __FUNCTION__
);
99 #define LOCAL_VARS viaContextPtr vmesa = VIA_CONTEXT(ctx)
103 VIA_STATECHANGE(vmesa, 0); \
104 viaRasterPrimitive(ctx, reducedPrim[prim], prim); \
109 viaRasterPrimitive(ctx, reducedPrim[prim], prim); \
111 #define NEW_PRIMITIVE() VIA_STATECHANGE(vmesa, 0)
112 #define NEW_BUFFER() VIA_FIREVERTICES(vmesa)
113 #define GET_CURRENT_VB_MAX_VERTS() \
114 (((int)vmesa->dmaHigh - (int)vmesa->dmaLow) / (vmesa->vertexSize * 4))
115 #define GET_SUBSEQUENT_VB_MAX_VERTS() \
116 (VIA_DMA_BUF_SZ - 4) / (vmesa->vertexSize * 4)
119 #define EMIT_VERTS(ctx, j, nr) \
120 via_emit_contiguous_verts(ctx, j, (j) + (nr))
124 vmesa->primitiveRendered = GL_TRUE; \
125 viaRasterPrimitiveFinish(ctx); \
129 #define TAG(x) via_fast##x
130 #include "via_dmatmp.h"
135 /**********************************************************************/
136 /* Fast Render pipeline stage */
137 /**********************************************************************/
138 static GLboolean
via_run_fastrender(GLcontext
*ctx
,
139 struct tnl_pipeline_stage
*stage
)
141 viaContextPtr vmesa
= VIA_CONTEXT(ctx
);
142 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
143 struct vertex_buffer
*VB
= &tnl
->vb
;
144 GLuint i
, length
, flags
= 0;
146 /* Don't handle clipping or indexed vertices.
148 #ifdef PERFORMANCE_MEASURE
149 if (VIA_PERFORMANCE
) P_M
;
152 if (VB
->ClipOrMask
|| vmesa
->renderIndex
!= 0 || VB
->Elts
) {
155 fprintf(stderr
, "slow path\n");
156 fprintf(stderr
, "ClipOrMask = %08x\n", VB
->ClipOrMask
);
157 fprintf(stderr
, "renderIndex = %08x\n", vmesa
->renderIndex
);
158 fprintf(stderr
, "Elts = %08x\n", (GLuint
)VB
->Elts
);
164 if (VIA_DEBUG
) fprintf(stderr
, "%s - in\n", __FUNCTION__
);
166 vmesa
->setupNewInputs
= VERT_BIT_CLIP
;
167 vmesa
->primitiveRendered
= GL_TRUE
;
169 tnl
->Driver
.Render
.Start(ctx
);
171 for (i
= 0; i
< VB
->PrimitiveCount
; ++i
) {
172 GLuint mode
= VB
->Primitive
[i
].mode
;
173 GLuint start
= VB
->Primitive
[i
].start
;
174 GLuint length
= VB
->Primitive
[i
].count
;
176 via_fastrender_tab_verts
[mode
& PRIM_MODE_MASK
](ctx
, start
, start
+length
, mode
);
179 tnl
->Driver
.Render
.Finish(ctx
);
181 /*=* DBG - viewperf7.0 : fix command buffer overflow *=*/
182 if (vmesa
->dmaLow
> (vmesa
->dma
[0].size
/ 2))
183 viaFlushPrims(vmesa
);
185 if (VIA_DEBUG
) fprintf(stderr
, "%s - out\n", __FUNCTION__
);
187 return GL_FALSE
; /* finished the pipe */
191 static void via_check_fastrender(GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
193 GLuint inputs
= VERT_BIT_CLIP
| VERT_BIT_COLOR0
;
195 if (ctx
->RenderMode
== GL_RENDER
) {
196 if (ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
197 inputs
|= VERT_BIT_COLOR1
;
199 if (ctx
->Texture
.Unit
[0]._ReallyEnabled
)
200 inputs
|= VERT_BIT_TEX0
;
202 if (ctx
->Texture
.Unit
[1]._ReallyEnabled
)
203 inputs
|= VERT_BIT_TEX1
;
205 if (ctx
->Fog
.Enabled
)
206 inputs
|= VERT_BIT_FOG
;
209 stage
->inputs
= inputs
;
213 static void fastdtr(struct tnl_pipeline_stage
*stage
)
219 const struct tnl_pipeline_stage _via_fastrender_stage
=
222 (_DD_NEW_SEPARATE_SPECULAR
|
225 _NEW_RENDERMODE
), /* re-check (new inputs) */
226 0, /* re-run (always runs) */
227 GL_TRUE
, /* active */
228 0, 0, /* inputs (set in check_render), outputs */
229 0, 0, /* changed_inputs, private */
230 fastdtr
, /* destructor */
231 via_check_fastrender
, /* check - initially set to alloc data */
232 via_run_fastrender
/* run */
237 * Render whole vertex buffers, including projection of vertices from
238 * clip space and clipping of primitives.
240 * This file makes calls to project vertices and to the point, line
241 * and triangle rasterizers via the function pointers:
243 * context->Driver.Render.*
248 /**********************************************************************/
249 /* Clip single primitives */
250 /**********************************************************************/
251 #undef DIFFERENT_SIGNS
252 #if defined(USE_IEEE)
253 #define NEGATIVE(x) (GET_FLOAT_BITS(x) & (1 << 31))
254 #define DIFFERENT_SIGNS(x, y) ((GET_FLOAT_BITS(x) ^ GET_FLOAT_BITS(y)) & (1 << 31))
256 #define NEGATIVE(x) (x < 0)
257 #define DIFFERENT_SIGNS(x,y) (x * y <= 0 && x - y != 0)
258 /* Could just use (x*y<0) except for the flatshading requirements.
259 * Maybe there's a better way?
263 #define W(i) coord[i][3]
264 #define Z(i) coord[i][2]
265 #define Y(i) coord[i][1]
266 #define X(i) coord[i][0]
269 #include "via_vb_cliptmp.h"
272 /**********************************************************************/
273 /* Clip and render whole begin/end objects */
274 /**********************************************************************/
275 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
276 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
277 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
280 /* Vertices, with the possibility of clipping.
282 #define RENDER_POINTS(start, count) \
283 tnl->Driver.Render.Points(ctx, start, count)
285 #define RENDER_LINE(v1, v2) \
287 GLubyte c1 = mask[v1], c2 = mask[v2]; \
288 GLubyte ormask = c1 | c2; \
290 LineFunc(ctx, v1, v2); \
291 else if (!(c1 & c2 & 0x3f)) \
292 clip_line_4(ctx, v1, v2, ormask); \
295 #define RENDER_TRI(v1, v2, v3) \
296 if (VIA_DEBUG) fprintf(stderr, "RENDER_TRI - clip\n"); \
298 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \
299 GLubyte ormask = c1 | c2 | c3; \
301 TriangleFunc(ctx, v1, v2, v3); \
302 else if (!(c1 & c2 & c3 & 0x3f)) \
303 clip_tri_4(ctx, v1, v2, v3, ormask); \
306 #define RENDER_QUAD(v1, v2, v3, v4) \
308 GLubyte c1 = mask[v1], c2 = mask[v2]; \
309 GLubyte c3 = mask[v3], c4 = mask[v4]; \
310 GLubyte ormask = c1 | c2 | c3 | c4; \
312 QuadFunc(ctx, v1, v2, v3, v4); \
313 else if (!(c1 & c2 & c3 & c4 & 0x3f)) \
314 clip_quad_4(ctx, v1, v2, v3, v4, ormask); \
319 TNLcontext *tnl = TNL_CONTEXT(ctx); \
320 struct vertex_buffer *VB = &tnl->vb; \
321 const GLuint * const elt = VB->Elts; \
322 const GLubyte *mask = VB->ClipMask; \
323 const GLuint sz = VB->ClipPtr->size; \
324 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
325 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
326 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
327 const GLboolean stipple = ctx->Line.StippleFlag; \
328 (void) (LineFunc && TriangleFunc && QuadFunc); \
329 (void) elt; (void) mask; (void) sz; (void) stipple;
332 viaRasterPrimitiveFinish(ctx)
334 #define TAG(x) clip_##x##_verts
335 #define INIT(x) tnl->Driver.Render.PrimitiveNotify(ctx, x)
336 #define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple(ctx)
337 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
338 #define PRESERVE_VB_DEFS
339 #include "via_vb_rendertmp.h"
342 /* Elts, with the possibility of clipping.
346 #define ELT(x) elt[x]
347 #define TAG(x) clip_##x##_elts
348 #include "via_vb_rendertmp.h"
350 /* TODO: do this for all primitives, verts and elts:
352 static void clip_elt_triangles(GLcontext
*ctx
,
357 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
358 tnl_render_func render_tris
= tnl
->Driver
.Render
.PrimTabElts
[GL_TRIANGLES
];
359 struct vertex_buffer
*VB
= &tnl
->vb
;
360 const GLuint
* const elt
= VB
->Elts
;
361 GLubyte
*mask
= VB
->ClipMask
;
362 GLuint last
= count
-2;
365 #ifdef PERFORMANCE_MEASURE
366 if (VIA_PERFORMANCE
) P_M
;
368 tnl
->Driver
.Render
.PrimitiveNotify(ctx
, GL_TRIANGLES
);
370 for (j
= start
; j
< last
; j
+= 3) {
371 GLubyte c1
= mask
[elt
[j
]];
372 GLubyte c2
= mask
[elt
[j
+ 1]];
373 GLubyte c3
= mask
[elt
[j
+ 2]];
374 GLubyte ormask
= c1
| c2
| c3
;
377 render_tris(ctx
, start
, j
, 0);
378 if (!(c1
& c2
& c3
& 0x3f))
379 clip_tri_4(ctx
, elt
[j
], elt
[j
+ 1], elt
[j
+ 2], ormask
);
385 render_tris(ctx
, start
, j
, 0);
387 viaRasterPrimitiveFinish(ctx
);
391 /**********************************************************************/
392 /* Helper functions for drivers */
393 /**********************************************************************/
395 void _tnl_RenderClippedPolygon(GLcontext *ctx, const GLuint *elts, GLuint n)
397 TNLcontext *tnl = TNL_CONTEXT(ctx);
398 struct vertex_buffer *VB = &tnl->vb;
399 GLuint *tmp = VB->Elts;
401 VB->Elts = (GLuint *)elts;
402 tnl->Driver.Render.PrimTabElts[GL_POLYGON](ctx, 0, n, PRIM_BEGIN|PRIM_END);
406 void _tnl_RenderClippedLine(GLcontext *ctx, GLuint ii, GLuint jj)
408 TNLcontext *tnl = TNL_CONTEXT(ctx);
409 tnl->Driver.Render.Line(ctx, ii, jj);
413 /**********************************************************************/
414 /* Render pipeline stage */
415 /**********************************************************************/
416 static GLboolean
via_run_render(GLcontext
*ctx
,
417 struct tnl_pipeline_stage
*stage
)
419 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
420 viaContextPtr vmesa
= VIA_CONTEXT(ctx
);
421 struct vertex_buffer
*VB
= &tnl
->vb
;
423 GLuint newInputs
= stage
->changed_inputs
;
424 /*GLuint newInputs = stage->inputs;*/
426 tnl_render_func
*tab
;
430 if (VIA_DEBUG
) fprintf(stderr
, "%s - in\n", __FUNCTION__
);
432 #ifdef PERFORMANCE_MEASURE
433 if (VIA_PERFORMANCE
) P_M
;
435 tnl
->Driver
.Render
.Start(ctx
);
436 tnl
->Driver
.Render
.BuildVertices(ctx
, 0, VB
->Count
, newInputs
);
437 if (VB
->ClipOrMask
) {
438 tab
= VB
->Elts
? clip_render_tab_elts
: clip_render_tab_verts
;
439 clip_render_tab_elts
[GL_TRIANGLES
] = clip_elt_triangles
;
442 tab
= VB
->Elts
? tnl
->Driver
.Render
.PrimTabElts
: tnl
->Driver
.Render
.PrimTabVerts
;
448 for (i
= 0; i
< VB
->PrimitiveCount
; i
++) {
449 GLuint flags
= VB
->Primitive
[i
].mode
;
450 GLuint start
= VB
->Primitive
[i
].start
;
451 GLuint length
= VB
->Primitive
[i
].count
;
452 ASSERT(length
|| (flags
& PRIM_END
));
453 ASSERT((flags
& PRIM_MODE_MASK
) <= GL_POLYGON
+ 1);
455 tab
[flags
& PRIM_MODE_MASK
](ctx
, start
, start
+ length
,flags
);
458 while (tnl
->Driver
.Render
.Multipass
&& tnl
->Driver
.Render
.Multipass(ctx
, ++pass
));
459 tnl
->Driver
.Render
.Finish(ctx
);
461 /*=* DBG - flush : if hw idel *=*/
463 GLuint volatile *pnEnginStatus = vmesa->regEngineStatus;
465 nStatus = *pnEnginStatus;
466 if ((nStatus & 0xFFFEFFFF) == 0x00020000)
467 viaFlushPrims(vmesa);
470 /*=* DBG viewperf7.0 : fix command buffer overflow *=*/
471 if (vmesa
->dmaLow
> (vmesa
->dma
[0].size
/ 2))
472 viaFlushPrims(vmesa
);
474 if (VIA_DEBUG
) fprintf(stderr
, "%s - out\n", __FUNCTION__
);
476 return GL_FALSE
; /* finished the pipe */
479 /* Quite a bit of work involved in finding out the inputs for the
483 static void via_check_render(GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
485 GLuint inputs
= VERT_BIT_CLIP
;
487 if (ctx
->Visual
.rgbMode
) {
488 inputs
|= VERT_BIT_COLOR0
;
490 if (ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
491 inputs
|= VERT_BIT_COLOR1
;
493 if (ctx
->Texture
.Unit
[0]._ReallyEnabled
) {
494 inputs
|= VERT_BIT_TEX0
;
497 if (ctx
->Texture
.Unit
[1]._ReallyEnabled
) {
498 inputs
|= VERT_BIT_TEX1
;
502 /*inputs |= VERT_BIT_INDEX;*/
505 /*if (ctx->Point._Attenuated)
506 inputs |= VERT_POINT_SIZE;*/
508 if (ctx
->Fog
.Enabled
)
509 inputs
|= VERT_BIT_FOG
;
511 /*if (ctx->_TriangleCaps & DD_TRI_UNFILLED)
514 if (ctx->RenderMode == GL_FEEDBACK)
515 inputs |= VERT_TEX_ANY;*/
517 stage
->inputs
= inputs
;
521 static void dtr(struct tnl_pipeline_stage
*stage
)
527 const struct tnl_pipeline_stage _via_render_stage
=
531 _DD_NEW_SEPARATE_SPECULAR
|
537 _DD_NEW_TRI_UNFILLED
|
538 _NEW_RENDERMODE
), /* re-check (new inputs) */
539 0, /* re-run (always runs) */
540 GL_TRUE
, /* active */
541 0, 0, /* inputs (set in check_render), outputs */
542 0, 0, /* changed_inputs, private */
543 dtr
, /* destructor */
544 via_check_render
, /* check - initially set to alloc data */
545 via_run_render
/* run */