1 /* $Id: t_vb_render.c,v 1.3 2000/12/27 21:49:40 keithw Exp $ */
4 * Mesa 3-D graphics library
7 * Copyright (C) 1999-2000 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.
29 * Render whole vertex buffers, including projection of vertices from
30 * clip space and clipping of primitives.
32 * This file makes calls to project vertices and to the point, line
33 * and triangle rasterizers via the function pointers:
35 * context->Driver.BuildProjectedVertices()
36 * context->Driver.PointsFunc()
37 * context->Driver.LineFunc()
38 * context->Driver.TriangleFunc()
39 * context->Driver.QuadFunc()
52 #include "math/m_matrix.h"
53 #include "math/m_xform.h"
55 #include "t_pipeline.h"
58 typedef GLuint (*interp_func
)( GLcontext
*ctx
,
59 GLfloat t
, GLuint in
, GLuint out
,
60 GLboolean force_boundary
);
62 typedef void (*clip_line_func
)( GLcontext
*ctx
,
66 typedef void (*clip_poly_func
)( GLcontext
*ctx
,
67 GLuint n
, GLuint vlist
[],
68 GLuint pv
, GLubyte mask
);
71 typedef void (*render_func
)( GLcontext
*ctx
,
78 struct render_stage_data
{
80 /* Clipping functions for current state.
82 interp_func interp
; /* Clip interpolation function */
83 GLuint _ClipInputs
; /* Inputs referenced by interpfunc */
87 #define RENDER_STAGE_DATA(stage) ((struct render_stage_data *)stage->private)
89 static void render_poly_pv_raw_elts( GLcontext
*ctx
,
95 /**********************************************************************/
96 /* Interpolate between pairs of vertices */
97 /**********************************************************************/
100 #define INTERP_RGBA 0x1
101 #define INTERP_TEX 0x2
102 #define INTERP_INDEX 0x4
103 #define INTERP_SPEC 0x8
104 #define INTERP_FOG 0x10
105 #define INTERP_EDGE 0x20
106 #define MAX_INTERP 0x40
109 #define LINTERP_SZ( t, vec, to, a, b, sz ) \
112 case 4: vec[to][3] = LINTERP( t, vec[a][3], vec[b][3] ); \
113 case 3: vec[to][2] = LINTERP( t, vec[a][2], vec[b][2] ); \
114 case 2: vec[to][1] = LINTERP( t, vec[a][1], vec[b][1] ); \
115 case 1: vec[to][0] = LINTERP( t, vec[a][0], vec[b][0] ); \
122 #define LINTERP_RGBA(nr, t, out, a, b) { \
124 for (i = 0; i < nr; i++) { \
125 GLfloat fa = CHAN_TO_FLOAT(a[i]); \
126 GLfloat fb = CHAN_TO_FLOAT(b[i]); \
127 GLfloat fo = LINTERP(t, fa, fb); \
128 FLOAT_COLOR_TO_CHAN(out[i], fo); \
134 #define LINTERP_RGBA(nr, t, out, a, b) { \
136 const GLuint ti = FloatToInt(t*256.0F); \
137 const GLubyte *Ib = (const GLubyte *)&a[0]; \
138 const GLubyte *Jb = (const GLubyte *)&b[0]; \
139 GLubyte *Ob = (GLubyte *)&out[0]; \
141 for (n = 0 ; n < nr ; n++) \
142 Ob[n] = (GLubyte) (Ib[n] + ((ti * (Jb[n] - Ib[n]))/256)); \
149 static interp_func interp_tab
[0x80];
152 #define IND (INTERP_RGBA)
153 #define NAME interp_RGBA
154 #include "t_vb_interptmp.h"
156 #define IND (INTERP_RGBA|INTERP_SPEC)
157 #define NAME interp_RGBA_SPEC
158 #include "t_vb_interptmp.h"
160 #define IND (INTERP_RGBA|INTERP_FOG)
161 #define NAME interp_RGBA_FOG
162 #include "t_vb_interptmp.h"
164 #define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG)
165 #define NAME interp_RGBA_SPEC_FOG
166 #include "t_vb_interptmp.h"
168 #define IND (INTERP_RGBA|INTERP_TEX)
169 #define NAME interp_RGBA_TEX
170 #include "t_vb_interptmp.h"
172 #define IND (INTERP_RGBA|INTERP_SPEC|INTERP_TEX)
173 #define NAME interp_RGBA_SPEC_TEX
174 #include "t_vb_interptmp.h"
176 #define IND (INTERP_RGBA|INTERP_FOG|INTERP_TEX)
177 #define NAME interp_RGBA_FOG_TEX
178 #include "t_vb_interptmp.h"
180 #define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX)
181 #define NAME interp_RGBA_SPEC_FOG_TEX
182 #include "t_vb_interptmp.h"
184 #define IND (INTERP_INDEX)
185 #define NAME interp_INDEX
186 #include "t_vb_interptmp.h"
188 #define IND (INTERP_FOG|INTERP_INDEX)
189 #define NAME interp_FOG_INDEX
190 #include "t_vb_interptmp.h"
192 #define IND (INTERP_TEX|INTERP_INDEX)
193 #define NAME interp_TEX_INDEX
194 #include "t_vb_interptmp.h"
196 #define IND (INTERP_FOG|INTERP_TEX|INTERP_INDEX)
197 #define NAME interp_FOG_TEX_INDEX
198 #include "t_vb_interptmp.h"
200 #define IND (INTERP_RGBA|INTERP_EDGE)
201 #define NAME interp_RGBA_EDGE
202 #include "t_vb_interptmp.h"
204 #define IND (INTERP_RGBA|INTERP_SPEC|INTERP_EDGE)
205 #define NAME interp_RGBA_SPEC_EDGE
206 #include "t_vb_interptmp.h"
208 #define IND (INTERP_RGBA|INTERP_FOG|INTERP_EDGE)
209 #define NAME interp_RGBA_FOG_EDGE
210 #include "t_vb_interptmp.h"
212 #define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_EDGE)
213 #define NAME interp_RGBA_SPEC_FOG_EDGE
214 #include "t_vb_interptmp.h"
216 #define IND (INTERP_RGBA|INTERP_TEX|INTERP_EDGE)
217 #define NAME interp_RGBA_TEX_EDGE
218 #include "t_vb_interptmp.h"
220 #define IND (INTERP_RGBA|INTERP_SPEC|INTERP_TEX|INTERP_EDGE)
221 #define NAME interp_RGBA_SPEC_TEX_EDGE
222 #include "t_vb_interptmp.h"
224 #define IND (INTERP_RGBA|INTERP_FOG|INTERP_TEX|INTERP_EDGE)
225 #define NAME interp_RGBA_FOG_TEX_EDGE
226 #include "t_vb_interptmp.h"
228 #define IND (INTERP_RGBA|INTERP_SPEC|INTERP_FOG|INTERP_TEX|INTERP_EDGE)
229 #define NAME interp_RGBA_SPEC_FOG_TEX_EDGE
230 #include "t_vb_interptmp.h"
232 #define IND (INTERP_INDEX|INTERP_EDGE)
233 #define NAME interp_INDEX_EDGE
234 #include "t_vb_interptmp.h"
236 #define IND (INTERP_FOG|INTERP_INDEX|INTERP_EDGE)
237 #define NAME interp_FOG_INDEX_EDGE
238 #include "t_vb_interptmp.h"
240 #define IND (INTERP_TEX|INTERP_INDEX|INTERP_EDGE)
241 #define NAME interp_TEX_INDEX_EDGE
242 #include "t_vb_interptmp.h"
244 #define IND (INTERP_FOG|INTERP_TEX|INTERP_INDEX|INTERP_EDGE)
245 #define NAME interp_FOG_TEX_INDEX_EDGE
246 #include "t_vb_interptmp.h"
250 static GLuint
interp_invalid( GLcontext
*ctx
,
252 GLuint in
, GLuint out
,
255 (void)(ctx
&& t
&& in
&& out
&& boundary
);
256 fprintf(stderr
, "Invalid interpolation function in t_vbrender.c\n");
261 static void interp_init( void )
265 /* Use the maximal function as the default. I don't believe any of
266 * the non-implemented combinations are reachable, but this gives
267 * some safety from crashes.
269 for (i
= 0 ; i
< Elements(interp_tab
) ; i
++)
270 interp_tab
[i
] = interp_invalid
;
272 interp_tab
[INTERP_RGBA
] = interp_RGBA
;
273 interp_tab
[INTERP_RGBA
|INTERP_SPEC
] = interp_RGBA_SPEC
;
274 interp_tab
[INTERP_RGBA
|INTERP_FOG
] = interp_RGBA_FOG
;
275 interp_tab
[INTERP_RGBA
|INTERP_SPEC
|INTERP_FOG
] = interp_RGBA_SPEC_FOG
;
276 interp_tab
[INTERP_RGBA
|INTERP_TEX
] = interp_RGBA_TEX
;
277 interp_tab
[INTERP_RGBA
|INTERP_SPEC
|INTERP_TEX
] = interp_RGBA_SPEC_TEX
;
278 interp_tab
[INTERP_RGBA
|INTERP_FOG
|INTERP_TEX
] = interp_RGBA_FOG_TEX
;
279 interp_tab
[INTERP_RGBA
|INTERP_SPEC
|INTERP_FOG
|INTERP_TEX
] = interp_RGBA_SPEC_FOG_TEX
;
280 interp_tab
[INTERP_INDEX
] = interp_INDEX
;
281 interp_tab
[INTERP_FOG
|INTERP_INDEX
] = interp_FOG_INDEX
;
282 interp_tab
[INTERP_TEX
|INTERP_INDEX
] = interp_TEX_INDEX
;
283 interp_tab
[INTERP_FOG
|INTERP_TEX
|INTERP_INDEX
] = interp_FOG_TEX_INDEX
;
284 interp_tab
[INTERP_RGBA
|INTERP_EDGE
] = interp_RGBA_EDGE
;
285 interp_tab
[INTERP_RGBA
|INTERP_SPEC
|INTERP_EDGE
] = interp_RGBA_SPEC_EDGE
;
286 interp_tab
[INTERP_RGBA
|INTERP_FOG
|INTERP_EDGE
] = interp_RGBA_FOG_EDGE
;
287 interp_tab
[INTERP_RGBA
|INTERP_SPEC
|INTERP_FOG
|INTERP_EDGE
] = interp_RGBA_SPEC_FOG_EDGE
;
288 interp_tab
[INTERP_RGBA
|INTERP_TEX
|INTERP_EDGE
] = interp_RGBA_TEX_EDGE
;
289 interp_tab
[INTERP_RGBA
|INTERP_SPEC
|INTERP_TEX
|INTERP_EDGE
] = interp_RGBA_SPEC_TEX_EDGE
;
290 interp_tab
[INTERP_RGBA
|INTERP_FOG
|INTERP_TEX
|INTERP_EDGE
] = interp_RGBA_FOG_TEX_EDGE
;
291 interp_tab
[INTERP_RGBA
|INTERP_SPEC
|INTERP_FOG
|INTERP_TEX
|INTERP_EDGE
] = interp_RGBA_SPEC_FOG_TEX_EDGE
;
292 interp_tab
[INTERP_INDEX
|INTERP_EDGE
] = interp_INDEX_EDGE
;
293 interp_tab
[INTERP_FOG
|INTERP_INDEX
|INTERP_EDGE
] = interp_FOG_INDEX_EDGE
;
294 interp_tab
[INTERP_TEX
|INTERP_INDEX
|INTERP_EDGE
] = interp_TEX_INDEX_EDGE
;
295 interp_tab
[INTERP_FOG
|INTERP_TEX
|INTERP_INDEX
|INTERP_EDGE
] = interp_FOG_TEX_INDEX_EDGE
;
299 /**********************************************************************/
300 /* Clip single primitives */
301 /**********************************************************************/
305 #define NEGATIVE(x) ((*(int *)&x)<0)
306 #define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
308 #define NEGATIVE(x) (x < 0)
309 #define DIFFERENT_SIGNS(a,b) ((a*b) < 0)
312 #define W(i) coord[i][3]
313 #define Z(i) coord[i][2]
314 #define Y(i) coord[i][1]
315 #define X(i) coord[i][0]
318 #include "t_vb_cliptmp.h"
321 #define Z(i) coord[i][2]
322 #define Y(i) coord[i][1]
323 #define X(i) coord[i][0]
326 #include "t_vb_cliptmp.h"
330 #define Y(i) coord[i][1]
331 #define X(i) coord[i][0]
334 #include "t_vb_cliptmp.h"
336 static clip_poly_func clip_poly_tab
[5] = {
344 static clip_line_func clip_line_tab
[5] = {
354 /**********************************************************************/
355 /* Clip and render single primitives */
356 /**********************************************************************/
360 static INLINE
void draw_line(GLcontext
*ctx
, GLuint v1
, GLuint v2
)
362 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
363 GLubyte c1
= VB
->ClipMask
[v1
], c2
= VB
->ClipMask
[v2
];
364 GLubyte ormask
= c1
|c2
;
366 ctx
->Driver
.LineFunc( ctx
, v1
, v2
, v2
);
367 else if (!(c1
& c2
& 0x3f))
368 clip_line_tab
[VB
->ClipPtr
->size
]( ctx
, v1
, v2
, ormask
);
371 static INLINE
void draw_triangle(GLcontext
*ctx
,
372 GLuint v1
, GLuint v2
, GLuint v3
,
375 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
376 GLubyte c1
= VB
->ClipMask
[v1
], c2
= VB
->ClipMask
[v2
], c3
= VB
->ClipMask
[v3
];
377 GLubyte ormask
= c1
|c2
|c3
;
379 ctx
->Driver
.TriangleFunc( ctx
, v1
, v2
, v3
, pv
);
380 else if (!(c1
& c2
& c3
& 0x3f)) {
381 GLuint vlist
[MAX_CLIPPED_VERTICES
];
382 ASSIGN_3V(vlist
, v1
, v2
, v3
);
383 clip_poly_tab
[VB
->ClipPtr
->size
]( ctx
, 3, vlist
, pv
, ormask
);
388 static INLINE
void draw_quad( GLcontext
*ctx
,
389 GLuint v1
, GLuint v2
, GLuint v3
,
390 GLuint v4
, GLuint pv
)
392 struct vertex_buffer
*VB
= &TNL_CONTEXT(ctx
)->vb
;
393 GLubyte c1
= VB
->ClipMask
[v1
], c2
= VB
->ClipMask
[v2
];
394 GLubyte c3
= VB
->ClipMask
[v3
], c4
= VB
->ClipMask
[v4
];
395 GLubyte ormask
= c1
|c2
|c3
|c4
;
397 ctx
->Driver
.QuadFunc( ctx
, v1
, v2
, v3
, v4
, pv
);
398 else if (!(c1
& c2
& c3
& c4
& 0x3f)) {
399 GLuint vlist
[MAX_CLIPPED_VERTICES
];
400 ASSIGN_4V(vlist
, v1
, v2
, v3
, v4
);
401 clip_poly_tab
[VB
->ClipPtr
->size
]( ctx
, 4, vlist
, pv
, ormask
);
406 /**********************************************************************/
407 /* Clip and render whole begin/end objects */
408 /**********************************************************************/
410 #define NEED_EDGEFLAG_SETUP (ctx->_TriangleCaps & DD_TRI_UNFILLED)
411 #define EDGEFLAG_GET(idx) VB->EdgeFlagPtr->data[idx]
412 #define EDGEFLAG_SET(idx, val) VB->EdgeFlagPtr->data[idx] = val
415 /* Vertices, no clipping.
417 #define RENDER_POINTS( start, count ) \
418 ctx->Driver.PointsFunc( ctx, start, count-1 )
420 #define RENDER_LINE( i1, i ) \
421 ctx->Driver.LineFunc( ctx, i1, i, i )
423 #define RENDER_TRI( i2, i1, i, pv, parity ) \
426 ctx->Driver.TriangleFunc( ctx, i1, i2, i, pv ); \
428 ctx->Driver.TriangleFunc( ctx, i2, i1, i, pv ); \
431 #define RENDER_QUAD( i3, i2, i1, i, pv ) \
432 ctx->Driver.QuadFunc( ctx, i3, i2, i1, i, pv );
434 #define TAG(x) x##_raw
437 struct vertex_buffer *VB = &(TNL_CONTEXT(ctx)->vb); \
440 #define RESET_STIPPLE ctx->Driver.ResetLineStipple( ctx )
441 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE;
442 #define PRESERVE_VB_DEFS
443 #include "t_vb_rendertmp.h"
446 /* Elts, no clipping.
451 #define TAG(x) x##_raw_elts
452 #define ELT(x) elt[x]
454 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \
455 const GLuint * const elt = VB->Elts; \
457 #include "t_vb_rendertmp.h"
462 /* Vertices, with the possibility of clipping.
464 #define RENDER_POINTS( start, count ) \
465 ctx->Driver.PointsFunc( ctx, start, count-1 )
467 #define RENDER_LINE( i1, i ) \
468 draw_line( ctx, i1, i )
470 #define RENDER_TRI( i2, i1, i, pv, parity) \
472 GLuint e2=i2, e1=i1; \
473 if (parity) { GLuint t=e2; e2=e1; e1=t; } \
474 draw_triangle(ctx,e2,e1,i,pv); \
477 #define RENDER_QUAD( i3, i2, i1, i, pv) \
478 draw_quad(ctx,i3,i2,i1,i,pv)
482 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \
485 #define TAG(x) x##_clipped
486 #define RESET_STIPPLE ctx->Driver.ResetLineStipple( ctx )
487 #define RESET_OCCLUSION ctx->OcclusionResult = GL_TRUE;
488 #define PRESERVE_VB_DEFS
489 #include "t_vb_rendertmp.h"
493 /* Elts, with the possibility of clipping.
498 #define ELT(x) elt[x]
500 struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; \
501 const GLuint * const elt = VB->Elts; \
503 #define TAG(x) x##_clipped_elts
505 #include "t_vb_rendertmp.h"
509 /**********************************************************************/
510 /* Clip and render whole vertex buffers */
511 /**********************************************************************/
514 static GLboolean
run_render( GLcontext
*ctx
,
515 struct gl_pipeline_stage
*stage
)
517 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
518 struct vertex_buffer
*VB
= &tnl
->vb
;
519 GLuint new_inputs
= stage
->changed_inputs
;
523 VB
->interpfunc
= (void *)RENDER_STAGE_DATA(stage
)->interp
;
526 GLuint importable
= new_inputs
& VB
->importable_data
;
527 GLuint interested
= 0;
532 if (ctx
->_TriangleCaps
& DD_TRI_UNFILLED
)
533 interested
|= VERT_EDGE
;
535 importable
&= interested
;
538 VB
->import_data( ctx
, importable
, VEC_NOT_WRITEABLE
|VEC_BAD_STRIDE
);
540 if (ctx
->Driver
.BuildProjectedVertices
)
541 ctx
->Driver
.BuildProjectedVertices( ctx
, 0, VB
->Count
, new_inputs
);
544 /* Rendering is considered a side-effect, and must be repeated each
545 * time the stage is run, even if no inputs have changed.
548 tab
= VB
->ClipOrMask
? render_tab_clipped_elts
: render_tab_raw_elts
;
550 tab
= VB
->ClipOrMask
? render_tab_clipped
: render_tab_raw
;
553 if (ctx
->Driver
.RenderStart
)
554 ctx
->Driver
.RenderStart( ctx
);
558 GLuint i
, length
, flags
= 0;
559 for (i
= 0 ; !(flags
& PRIM_LAST
) ; i
+= length
)
561 flags
= VB
->Primitive
[i
];
562 length
= VB
->PrimitiveLength
[i
];
563 ASSERT(length
|| (flags
& PRIM_LAST
));
564 ASSERT((flags
& PRIM_MODE_MASK
) <= GL_POLYGON
+1);
565 /* fprintf(stderr, "render %s %d..%d\n", */
566 /* _mesa_prim_name[flags & PRIM_MODE_MASK], */
569 tab
[flags
& PRIM_MODE_MASK
]( ctx
, i
, i
+ length
, flags
);
571 } while (ctx
->Driver
.MultipassFunc
&&
572 ctx
->Driver
.MultipassFunc( ctx
, ++pass
));
574 if (ctx
->Driver
.RenderFinish
)
575 ctx
->Driver
.RenderFinish( ctx
);
577 return GL_FALSE
; /* finished the pipe */
581 /**********************************************************************/
582 /* Render pipeline stage */
583 /**********************************************************************/
587 /* Quite a bit of work involved in finding out the inputs for the
588 * render stage. This function also identifies which vertex
589 * interpolation function to use, as these are essentially the same
592 static void check_render( GLcontext
*ctx
, struct gl_pipeline_stage
*stage
)
594 struct render_stage_data
*store
= RENDER_STAGE_DATA(stage
);
596 GLuint inputs
= VERT_CLIP
;
599 if (ctx
->Visual
.RGBAflag
)
601 interp
|= INTERP_RGBA
;
604 if (ctx
->_TriangleCaps
& DD_SEPERATE_SPECULAR
) {
605 interp
|= INTERP_SPEC
;
606 inputs
|= VERT_SPEC_RGB
;
609 if (ctx
->Texture
._ReallyEnabled
) {
610 interp
|= INTERP_TEX
;
612 for (i
= 0 ; i
< ctx
->Const
.MaxTextureUnits
; i
++) {
613 if (ctx
->Texture
.Unit
[i
]._ReallyEnabled
)
614 inputs
|= VERT_TEX(i
);
618 else if (ctx
->Light
.ShadeModel
==GL_SMOOTH
)
620 interp
|= INTERP_INDEX
;
621 inputs
|= VERT_INDEX
;
624 if (ctx
->Point
._Attenuated
)
625 inputs
|= VERT_POINT_SIZE
;
627 /* How do drivers turn this off?
629 if (ctx
->Fog
.Enabled
) {
630 interp
|= INTERP_FOG
;
631 inputs
|= VERT_FOG_COORD
;
634 if (ctx
->_TriangleCaps
& DD_TRI_UNFILLED
) {
636 interp
|= INTERP_EDGE
;
639 if (ctx
->RenderMode
==GL_FEEDBACK
) {
640 interp
|= INTERP_TEX
;
641 inputs
|= VERT_TEX_ANY
;
644 store
->interp
= interp_tab
[interp
];
645 stage
->inputs
= inputs
;
649 /* Called the first time stage->check() is invoked.
651 static void alloc_render_data( GLcontext
*ctx
,
652 struct gl_pipeline_stage
*stage
)
654 struct render_stage_data
*store
;
655 static GLboolean first_time
= 1;
662 stage
->private = MALLOC(sizeof(*store
));
668 stage
->check
= check_render
;
669 stage
->check( ctx
, stage
);
674 static void dtr( struct gl_pipeline_stage
*stage
)
676 struct render_stage_data
*store
= RENDER_STAGE_DATA(stage
);
684 const struct gl_pipeline_stage _tnl_render_stage
=
688 _DD_NEW_SEPERATE_SPECULAR
|
693 _DD_NEW_TRI_UNFILLED
|
694 _NEW_RENDERMODE
), /* re-check (new inputs, interp function) */
695 0, /* re-run (always runs) */
696 GL_TRUE
, /* active */
697 0, 0, /* inputs (set in check_render), outputs */
698 0, 0, /* changed_inputs, private */
699 dtr
, /* destructor */
700 alloc_render_data
, /* check - initially set to alloc data */