1 /* $Id: gld_vb_mesa_render_dx7.c,v 1.2 2004/07/01 13:14:06 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Keith Whitwell <keithw@valinux.com>
32 * Render whole vertex buffers, including projection of vertices from
33 * clip space and clipping of primitives.
35 * This file makes calls to project vertices and to the point, line
36 * and triangle rasterizers via the function pointers:
38 * context->Driver.Render.*
43 //---------------------------------------------------------------------------
45 //#include "../GLDirect.h"
46 //#include "../gld_log.h"
47 //#include "gld_dx8.h"
49 #include "dglcontext.h"
53 //---------------------------------------------------------------------------
62 #include "math/m_matrix.h"
63 #include "math/m_xform.h"
65 #include "tnl/t_pipeline.h"
67 /**********************************************************************/
68 /* Clip single primitives */
69 /**********************************************************************/
73 #define NEGATIVE(x) (GET_FLOAT_BITS(x) & (1<<31))
74 #define DIFFERENT_SIGNS(x,y) ((GET_FLOAT_BITS(x) ^ GET_FLOAT_BITS(y)) & (1<<31))
76 #define NEGATIVE(x) (x < 0)
77 #define DIFFERENT_SIGNS(x,y) (x * y <= 0 && x - y != 0)
78 /* Could just use (x*y<0) except for the flatshading requirements.
79 * Maybe there's a better way?
84 #define W(i) coord[i][3]
85 #define Z(i) coord[i][2]
86 #define Y(i) coord[i][1]
87 #define X(i) coord[i][0]
90 #include "tnl/t_vb_cliptmp.h"
94 /**********************************************************************/
95 /* Clip and render whole begin/end objects */
96 /**********************************************************************/
98 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
99 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
100 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
103 /* Vertices, with the possibility of clipping.
105 #define RENDER_POINTS( start, count ) \
106 tnl->Driver.Render.Points( ctx, start, count )
108 #define RENDER_LINE( v1, v2 ) \
110 GLubyte c1 = mask[v1], c2 = mask[v2]; \
111 GLubyte ormask = c1|c2; \
113 LineFunc( ctx, v1, v2 ); \
114 else if (!(c1 & c2 & 0x3f)) \
115 clip_line_4( ctx, v1, v2, ormask ); \
118 #define RENDER_TRI( v1, v2, v3 ) \
120 GLubyte c1 = mask[v1], c2 = mask[v2], c3 = mask[v3]; \
121 GLubyte ormask = c1|c2|c3; \
123 TriangleFunc( ctx, v1, v2, v3 ); \
124 else if (!(c1 & c2 & c3 & 0x3f)) \
125 clip_tri_4( ctx, v1, v2, v3, ormask ); \
128 #define RENDER_QUAD( v1, v2, v3, v4 ) \
130 GLubyte c1 = mask[v1], c2 = mask[v2]; \
131 GLubyte c3 = mask[v3], c4 = mask[v4]; \
132 GLubyte ormask = c1|c2|c3|c4; \
134 QuadFunc( ctx, v1, v2, v3, v4 ); \
135 else if (!(c1 & c2 & c3 & c4 & 0x3f)) \
136 clip_quad_4( ctx, v1, v2, v3, v4, ormask ); \
141 TNLcontext *tnl = TNL_CONTEXT(ctx); \
142 struct vertex_buffer *VB = &tnl->vb; \
143 const GLuint * const elt = VB->Elts; \
144 const GLubyte *mask = VB->ClipMask; \
145 const GLuint sz = VB->ClipPtr->size; \
146 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
147 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
148 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
149 const GLboolean stipple = ctx->Line.StippleFlag; \
150 (void) (LineFunc && TriangleFunc && QuadFunc); \
151 (void) elt; (void) mask; (void) sz; (void) stipple;
153 #define TAG(x) clip_##x##_verts
154 #define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
155 #define RESET_STIPPLE if (stipple) tnl->Driver.Render.ResetLineStipple( ctx )
156 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
157 #define PRESERVE_VB_DEFS
158 #include "tnl/t_vb_rendertmp.h"
162 /* Elts, with the possibility of clipping.
166 #define ELT(x) elt[x]
167 #define TAG(x) clip_##x##_elts
168 #include "tnl/t_vb_rendertmp.h"
170 /* TODO: do this for all primitives, verts and elts:
172 static void clip_elt_triangles( GLcontext
*ctx
,
177 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
178 tnl_render_func render_tris
= tnl
->Driver
.Render
.PrimTabElts
[GL_TRIANGLES
];
179 struct vertex_buffer
*VB
= &tnl
->vb
;
180 const GLuint
* const elt
= VB
->Elts
;
181 GLubyte
*mask
= VB
->ClipMask
;
182 GLuint last
= count
-2;
186 tnl
->Driver
.Render
.PrimitiveNotify( ctx
, GL_TRIANGLES
);
188 for (j
=start
; j
< last
; j
+=3 ) {
189 GLubyte c1
= mask
[elt
[j
]];
190 GLubyte c2
= mask
[elt
[j
+1]];
191 GLubyte c3
= mask
[elt
[j
+2]];
192 GLubyte ormask
= c1
|c2
|c3
;
195 render_tris( ctx
, start
, j
, 0 );
196 if (!(c1
&c2
&c3
&0x3f))
197 clip_tri_4( ctx
, elt
[j
], elt
[j
+1], elt
[j
+2], ormask
);
203 render_tris( ctx
, start
, j
, 0 );
206 /**********************************************************************/
207 /* Render whole begin/end objects */
208 /**********************************************************************/
210 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
211 #define EDGEFLAG_GET(idx) VB->EdgeFlag[idx]
212 #define EDGEFLAG_SET(idx, val) VB->EdgeFlag[idx] = val
215 /* Vertices, no clipping.
217 #define RENDER_POINTS( start, count ) \
218 tnl->Driver.Render.Points( ctx, start, count )
220 #define RENDER_LINE( v1, v2 ) \
221 LineFunc( ctx, v1, v2 )
223 #define RENDER_TRI( v1, v2, v3 ) \
224 TriangleFunc( ctx, v1, v2, v3 )
226 #define RENDER_QUAD( v1, v2, v3, v4 ) \
227 QuadFunc( ctx, v1, v2, v3, v4 )
229 #define TAG(x) _gld_tnl_##x##_verts
232 TNLcontext *tnl = TNL_CONTEXT(ctx); \
233 struct vertex_buffer *VB = &tnl->vb; \
234 const GLuint * const elt = VB->Elts; \
235 const tnl_line_func LineFunc = tnl->Driver.Render.Line; \
236 const tnl_triangle_func TriangleFunc = tnl->Driver.Render.Triangle; \
237 const tnl_quad_func QuadFunc = tnl->Driver.Render.Quad; \
238 (void) (LineFunc && TriangleFunc && QuadFunc); \
241 #define RESET_STIPPLE tnl->Driver.Render.ResetLineStipple( ctx )
242 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE
243 #define INIT(x) tnl->Driver.Render.PrimitiveNotify( ctx, x )
244 #define RENDER_TAB_QUALIFIER
245 #define PRESERVE_VB_DEFS
246 #include "tnl/t_vb_rendertmp.h"
249 /* Elts, no clipping.
252 #define TAG(x) _gld_tnl_##x##_elts
253 #define ELT(x) elt[x]
254 #include "tnl/t_vb_rendertmp.h"
257 /**********************************************************************/
258 /* Helper functions for drivers */
259 /**********************************************************************/
261 void _tnl_RenderClippedPolygon( GLcontext *ctx, const GLuint *elts, GLuint n )
263 TNLcontext *tnl = TNL_CONTEXT(ctx);
264 struct vertex_buffer *VB = &tnl->vb;
265 GLuint *tmp = VB->Elts;
267 VB->Elts = (GLuint *)elts;
268 tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END );
272 void _tnl_RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj )
274 TNLcontext *tnl = TNL_CONTEXT(ctx);
275 tnl->Driver.Render.Line( ctx, ii, jj );
280 /**********************************************************************/
281 /* Clip and render whole vertex buffers */
282 /**********************************************************************/
284 tnl_points_func _gldSetupPoints
[4] = {
290 tnl_line_func _gldSetupLine
[4] = {
292 gld_Line2DSmooth_DX7
,
294 gld_Line2DSmooth_DX7
,
296 tnl_triangle_func _gldSetupTriangle
[4] = {
297 gld_Triangle2DFlat_DX7
,
298 gld_Triangle2DSmooth_DX7
,
299 gld_Triangle2DFlatExtras_DX7
,
300 gld_Triangle2DSmoothExtras_DX7
302 tnl_quad_func _gldSetupQuad
[4] = {
304 gld_Quad2DSmooth_DX7
,
305 gld_Quad2DFlatExtras_DX7
,
306 gld_Quad2DSmoothExtras_DX7
309 //---------------------------------------------------------------------------
311 static GLboolean
_gld_mesa_render_stage_run(
313 struct gl_pipeline_stage
*stage
)
315 GLD_context
*gldCtx
= GLD_GET_CONTEXT(ctx
);
316 GLD_driver_dx7
*gld
= GLD_GET_DX7_DRIVER(gldCtx
);
318 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
319 struct vertex_buffer
*VB
= &tnl
->vb
;
320 GLuint new_inputs
= stage
->changed_inputs
;
321 tnl_render_func
*tab
;
326 /* Allow the drivers to lock before projected verts are built so
327 * that window coordinates are guarenteed not to change before
330 ASSERT(tnl
->Driver
.Render
.Start
);
332 tnl
->Driver
.Render
.Start( ctx
);
335 tnl
->Driver
.Render
.Points
= _gldSetupPoints
[gld
->iSetupFunc
];
336 tnl
->Driver
.Render
.Line
= _gldSetupLine
[gld
->iSetupFunc
];
337 tnl
->Driver
.Render
.Triangle
= _gldSetupTriangle
[gld
->iSetupFunc
];
338 tnl
->Driver
.Render
.Quad
= _gldSetupQuad
[gld
->iSetupFunc
];
340 dwFlags
= DDLOCK_DISCARDCONTENTS
| DDLOCK_WAIT
| DDLOCK_SURFACEMEMORYPTR
| DDLOCK_WRITEONLY
;
341 _GLD_DX7_VB(Lock(gldPB
->pVB
, dwFlags
, &gldPB
->pPoints
, NULL
));
342 gldPB
->nPoints
= gldPB
->nLines
= gldPB
->nTriangles
= 0;
344 // Allocate primitive pointers - gldPB->pPoints is always first
345 gldPB
->pLines
= gldPB
->pPoints
+ (gldPB
->dwStride
* gldPB
->iFirstLine
);
346 gldPB
->pTriangles
= gldPB
->pPoints
+ (gldPB
->dwStride
* gldPB
->iFirstTriangle
);
348 ASSERT(tnl
->Driver
.Render
.BuildVertices
);
349 ASSERT(tnl
->Driver
.Render
.PrimitiveNotify
);
350 ASSERT(tnl
->Driver
.Render
.Points
);
351 ASSERT(tnl
->Driver
.Render
.Line
);
352 ASSERT(tnl
->Driver
.Render
.Triangle
);
353 ASSERT(tnl
->Driver
.Render
.Quad
);
354 ASSERT(tnl
->Driver
.Render
.ResetLineStipple
);
355 ASSERT(tnl
->Driver
.Render
.Interp
);
356 ASSERT(tnl
->Driver
.Render
.CopyPV
);
357 ASSERT(tnl
->Driver
.Render
.ClippedLine
);
358 ASSERT(tnl
->Driver
.Render
.ClippedPolygon
);
359 ASSERT(tnl
->Driver
.Render
.Finish
);
361 tnl
->Driver
.Render
.BuildVertices( ctx
, 0, VB
->Count
, new_inputs
);
363 if (VB
->ClipOrMask
) {
364 tab
= VB
->Elts
? clip_render_tab_elts
: clip_render_tab_verts
;
365 clip_render_tab_elts
[GL_TRIANGLES
] = clip_elt_triangles
;
369 tnl
->Driver
.Render
.PrimTabElts
:
370 tnl
->Driver
.Render
.PrimTabVerts
);
374 GLuint i
, length
, flags
= 0;
375 for (i
= 0 ; !(flags
& PRIM_LAST
) ; i
+= length
) {
376 flags
= VB
->Primitive
[i
];
377 length
= VB
->PrimitiveLength
[i
];
378 ASSERT(length
|| (flags
& PRIM_LAST
));
379 ASSERT((flags
& PRIM_MODE_MASK
) <= GL_POLYGON
+1);
381 tab
[flags
& PRIM_MODE_MASK
]( ctx
, i
, i
+ length
, flags
);
383 } while (tnl
->Driver
.Render
.Multipass
&&
384 tnl
->Driver
.Render
.Multipass( ctx
, ++pass
));
387 // tnl->Driver.Render.Finish( ctx );
389 _GLD_DX7_VB(Unlock(gldPB
->pVB
));
391 if (gldPB
->nPoints
) {
392 _GLD_DX7_DEV(DrawPrimitiveVB(gld
->pDev
, D3DPT_POINTLIST
, gldPB
->pVB
, 0, gldPB
->nPoints
, 0));
397 _GLD_DX7_DEV(DrawPrimitiveVB(gld
->pDev
, D3DPT_LINELIST
, gldPB
->pVB
, gldPB
->iFirstLine
, gldPB
->nLines
*2, 0));
401 if (gldPB
->nTriangles
) {
402 _GLD_DX7_DEV(DrawPrimitiveVB(gld
->pDev
, D3DPT_TRIANGLELIST
, gldPB
->pVB
, gldPB
->iFirstTriangle
, gldPB
->nTriangles
*3, 0));
403 gldPB
->nTriangles
= 0;
406 return GL_FALSE
; /* finished the pipe */
410 /**********************************************************************/
411 /* Render pipeline stage */
412 /**********************************************************************/
416 /* Quite a bit of work involved in finding out the inputs for the
419 static void _gld_mesa_render_stage_check(
421 struct gl_pipeline_stage
*stage
)
423 GLuint inputs
= VERT_BIT_CLIP
;
426 if (ctx
->Visual
.rgbMode
) {
427 inputs
|= VERT_BIT_COLOR0
;
429 if (ctx
->_TriangleCaps
& DD_SEPARATE_SPECULAR
)
430 inputs
|= VERT_BIT_COLOR1
; //VERT_BIT_SPEC_RGB;
432 //if (ctx->Texture._ReallyEnabled) {
433 for (i
=0; i
<ctx
->Const
.MaxTextureUnits
; i
++) {
434 if (ctx
->Texture
.Unit
[i
]._ReallyEnabled
)
435 inputs
|= VERT_BIT_TEX(i
);
439 inputs
|= VERT_BIT_INDEX
;
442 if (ctx
->Point
._Attenuated
)
443 inputs
|= VERT_BIT_POINT_SIZE
;
445 /* How do drivers turn this off?
447 if (ctx
->Fog
.Enabled
)
448 inputs
|= VERT_BIT_FOG
; // VERT_FOG_COORD;
450 if (ctx
->_TriangleCaps
& DD_TRI_UNFILLED
)
451 inputs
|= VERT_BIT_EDGEFLAG
;
453 if (ctx
->RenderMode
==GL_FEEDBACK
)
454 inputs
|= VERT_BITS_TEX_ANY
;
456 stage
->inputs
= inputs
;
459 //---------------------------------------------------------------------------
462 static void _gld_mesa_render_stage_dtr(
463 struct gl_pipeline_stage
*stage
)
467 //---------------------------------------------------------------------------
469 const struct gl_pipeline_stage _gld_mesa_render_stage
=
471 "gld_mesa_render_stage",
473 _DD_NEW_SEPARATE_SPECULAR
|
479 _DD_NEW_TRI_UNFILLED
|
480 _NEW_RENDERMODE
), // re-check (new inputs, interp function)
481 0, /* re-run (always runs) */
482 GL_TRUE
, /* active */
483 0, 0, /* inputs (set in check_render), outputs */
484 0, 0, /* changed_inputs, private */
485 _gld_mesa_render_stage_dtr
, /* destructor */
486 _gld_mesa_render_stage_check
, /* check */
487 _gld_mesa_render_stage_run
/* run */
490 //---------------------------------------------------------------------------