Vertex programs work now with some restrictions. I expect arbvptorus to work
[profile/ivi/mesa.git] / src / mesa / drivers / dri / r300 / r300_render.c
1 /**************************************************************************
2
3 Copyright (C) 2004 Nicolai Haehnle.
4
5 All Rights Reserved.
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
16 Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26 **************************************************************************/
27
28 /*
29  * Authors:
30  *   Nicolai Haehnle <prefect_@gmx.net>
31  */
32
33 #include "glheader.h"
34 #include "state.h"
35 #include "imports.h"
36 #include "enums.h"
37 #include "macros.h"
38 #include "context.h"
39 #include "dd.h"
40 #include "simple_list.h"
41
42 #include "api_arrayelt.h"
43 #include "swrast/swrast.h"
44 #include "swrast_setup/swrast_setup.h"
45 #include "array_cache/acache.h"
46 #include "tnl/tnl.h"
47
48 #include "radeon_reg.h"
49 #include "radeon_macros.h"
50 #include "radeon_ioctl.h"
51 #include "radeon_state.h"
52 #include "r300_context.h"
53 #include "r300_ioctl.h"
54 #include "r300_state.h"
55 #include "r300_reg.h"
56 #include "r300_program.h"
57 #include "r300_tex.h"
58
59 #include "r300_emit.h"
60
61 /**********************************************************************
62 *                     Hardware rasterization
63 *
64 * When we fell back to software TCL, we still try to use the
65 * rasterization hardware for rendering.
66 **********************************************************************/
67
68 static int r300_get_primitive_type(r300ContextPtr rmesa, 
69         GLcontext *ctx,
70         int start,
71         int end,
72         int prim)
73 {
74    TNLcontext *tnl = TNL_CONTEXT(ctx);
75    struct vertex_buffer *VB = &tnl->vb;
76    GLuint i;
77    int type=-1, min_vertices=0;
78    char *name="UNKNOWN";
79    
80    if(end<=start)return -1; /* do we need to watch for this ? */
81    
82         switch (prim & PRIM_MODE_MASK) {
83         case GL_POINTS:
84                 name="P";
85                 type=R300_VAP_VF_CNTL__PRIM_POINTS;
86                 min_vertices=1;
87                 break;          
88         case GL_LINES:
89                 name="L";
90                 type=R300_VAP_VF_CNTL__PRIM_LINES;
91                 min_vertices=2;
92                 break;          
93         case GL_LINE_STRIP:
94                 name="LS";
95                 type=R300_VAP_VF_CNTL__PRIM_LINE_STRIP;
96                 min_vertices=2;
97                 break;
98         case GL_LINE_LOOP:
99                 name="LL";
100                 min_vertices=2;
101                 return -1;
102                 break;
103         case GL_TRIANGLES:
104                 name="T";
105                 type=R300_VAP_VF_CNTL__PRIM_TRIANGLES;
106                 min_vertices=3;
107                 break;
108         case GL_TRIANGLE_STRIP:
109                 name="TS";
110                 type=R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP;
111                 min_vertices=3;
112                 break;
113         case GL_TRIANGLE_FAN:
114                 name="TF";
115                 type=R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN;
116                 min_vertices=3;
117                 break;
118         case GL_QUADS:
119                 name="Q";
120                 type=R300_VAP_VF_CNTL__PRIM_QUADS;
121                 min_vertices=4;
122                 break;
123         case GL_QUAD_STRIP:
124                 name="QS";
125                 type=R300_VAP_VF_CNTL__PRIM_QUAD_STRIP;
126                 min_vertices=4;
127                 break;
128         case GL_POLYGON:
129                 name="P";
130                         type=R300_VAP_VF_CNTL__PRIM_POLYGON;
131                 min_vertices=3;
132                 break;
133         default:
134                 fprintf(stderr, "%s:%s Do not know how to handle primitive %02x - help me !\n",
135                         __FILE__, __FUNCTION__,
136                         prim & PRIM_MODE_MASK);
137                 return -1;
138                 break;
139         }
140    #if 0
141    fprintf(stderr, "[%d-%d]%s ", start, end, name);
142    #endif
143    if(start+min_vertices>end){
144         static int warn_once=1;
145         if(warn_once){
146                 fprintf(stderr, "%s:%s ***WARN_ONCE*** Not enough vertices to draw primitive %02x - help me !\n",
147                                 __FILE__, __FUNCTION__,
148                                 prim & PRIM_MODE_MASK);
149                         warn_once=0;
150                         }
151         return -1;
152         }
153    return type;
154 }
155
156 /* This function compiles GL context into state registers that 
157    describe data routing inside of R300 pipeline.
158    
159    In particular, it programs input_route, output_vtx_fmt, texture
160    unit configuration and gb_output_vtx_fmt
161    
162    This function encompasses setup_AOS() from r300_lib.c
163 */
164
165
166
167
168 /* Immediate implementation - vertex data is sent via command stream */
169
170 static GLfloat default_vector[4]={0.0, 0.0, 0.0, 1.0};
171
172 #define output_vector(v, i) \
173         { \
174         int _i; \
175         for(_i=0;_i<v->size;_i++){ \
176                 efloat(VEC_ELT(v, GLfloat, i)[_i]); \
177                 } \
178         for(_i=v->size;_i<4;_i++){ \
179                         efloat(default_vector[_i]); \
180                         } \
181         }
182
183 /* Immediate implementation - vertex data is sent via command stream */
184
185 static void r300_render_immediate_primitive(r300ContextPtr rmesa, 
186         GLcontext *ctx,
187         int start,
188         int end,
189         int prim)
190 {
191    TNLcontext *tnl = TNL_CONTEXT(ctx);
192    struct vertex_buffer *VB = &tnl->vb;
193    GLuint i;
194    int k, type;
195    LOCAL_VARS
196                    
197    type=r300_get_primitive_type(rmesa, ctx, start, end, prim);
198                 
199                 #if 0
200                 fprintf(stderr,"ObjPtr: size=%d stride=%d\n", 
201                         VB->ObjPtr->size, VB->ObjPtr->stride);
202                 fprintf(stderr,"ColorPtr[0]: size=%d stride=%d\n", 
203                         VB->ColorPtr[0]->size, VB->ColorPtr[0]->stride);
204                 fprintf(stderr,"TexCoordPtr[0]: size=%d stride=%d\n", 
205                         VB->TexCoordPtr[0]->size, VB->TexCoordPtr[0]->stride);
206                 #endif
207    
208    if(type<0)return;
209    
210    if(!VB->ObjPtr){
211         fprintf(stderr, "FIXME: Dont know how to handle GL_ARB_vertex_buffer_object "
212                         "correctly\n");
213         return;
214    }
215    /* A packet cannot have more than 16383 data words.. */
216    if(((end-start)*4*rmesa->state.aos_count)>16380){
217         fprintf(stderr, "%s:%s: Too many vertices to paint. Fix me !\n");
218         return;         
219         }
220
221    //fprintf(stderr, "aos_count=%d start=%d end=%d\n", rmesa->state.aos_count, start, end);
222         
223    start_immediate_packet(end-start, type, 4*rmesa->state.aos_count);
224
225         for(i=start;i<end;i++){
226                 #if 0
227                 fprintf(stderr, "* (%f %f %f %f) (%f %f %f %f)\n", 
228                         VEC_ELT(VB->ObjPtr, GLfloat, i)[0],
229                         VEC_ELT(VB->ObjPtr, GLfloat, i)[1],
230                         VEC_ELT(VB->ObjPtr, GLfloat, i)[2],
231                         VEC_ELT(VB->ObjPtr, GLfloat, i)[3],
232                         
233                         VEC_ELT(VB->ColorPtr[0], GLfloat, i)[0],
234                         VEC_ELT(VB->ColorPtr[0], GLfloat, i)[1],
235                         VEC_ELT(VB->ColorPtr[0], GLfloat, i)[2],
236                         VEC_ELT(VB->ColorPtr[0], GLfloat, i)[3]
237                         );
238                 #endif
239                 
240                 
241                 /* coordinates */
242                 if(tnl->render_inputs & _TNL_BIT_POS)
243                         output_vector(VB->ObjPtr, i);
244                 if(tnl->render_inputs & _TNL_BIT_NORMAL)
245                         output_vector(VB->NormalPtr, i);
246                 
247                 /* color components */
248                 if(tnl->render_inputs & _TNL_BIT_COLOR0)
249                         output_vector(VB->ColorPtr[0], i);
250                 if(tnl->render_inputs & _TNL_BIT_COLOR1)
251                         output_vector(VB->SecondaryColorPtr[0], i);
252
253                 if(tnl->render_inputs & _TNL_BIT_FOG)
254                         output_vector(VB->FogCoordPtr, i);
255                                         
256                 /* texture coordinates */
257                 for(k=0;k < ctx->Const.MaxTextureUnits;k++)
258                         if(tnl->render_inputs & (_TNL_BIT_TEX0<<k))
259                                 output_vector(VB->TexCoordPtr[k], i);
260                 
261                 if(tnl->render_inputs & _TNL_BIT_INDEX)
262                         output_vector(VB->IndexPtr[0], i);
263                 if(tnl->render_inputs & _TNL_BIT_POINTSIZE)
264                         output_vector(VB->PointSizePtr, i);
265                 }
266
267 }
268
269
270 static GLboolean r300_run_immediate_render(GLcontext *ctx,
271                                  struct tnl_pipeline_stage *stage)
272 {
273    r300ContextPtr rmesa = R300_CONTEXT(ctx);
274    TNLcontext *tnl = TNL_CONTEXT(ctx);
275    struct vertex_buffer *VB = &tnl->vb;
276    GLuint i;
277    /* Only do 2d textures */
278    struct gl_texture_object *to=ctx->Texture.Unit[0].Current2D;
279    r300TexObjPtr t=to->DriverData;
280    LOCAL_VARS
281         
282   
283    /* Update texture state - needs to be done only when actually changed..
284       All the time for now.. */
285
286
287         if (RADEON_DEBUG == DEBUG_PRIMS)
288                 fprintf(stderr, "%s\n", __FUNCTION__);
289
290    #if 1 /* we need this, somehow */
291    /* Flush state - make sure command buffer is nice and large */
292    r300Flush(ctx);
293    /* Make sure we have enough space */
294    #else 0
295    /* Count is very imprecize, but should be good upper bound */
296    r300EnsureCmdBufSpace(rmesa, rmesa->hw.max_state_size + 4+2+30
297         +VB->PrimitiveCount*(1+8)+VB->Count*4*rmesa->state.texture.tc_count+4, __FUNCTION__);
298    #endif
299      
300    /* needed before starting 3d operation .. */
301    reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
302         e32(0x0000000a);
303    
304    reg_start(0x4f18,0);
305         e32(0x00000003);
306         
307    
308         #if 0 /* looks like the Z offset issue got fixed */
309    rmesa->hw.vte.cmd[1] = R300_VPORT_X_SCALE_ENA
310                                 | R300_VPORT_X_OFFSET_ENA
311                                 | R300_VPORT_Y_SCALE_ENA
312                                 | R300_VPORT_Y_OFFSET_ENA
313                                 | R300_VTX_W0_FMT;
314    R300_STATECHANGE(rmesa, vte);
315         #endif
316    
317         
318       
319    /* Magic register - note it is right after 20b0 */
320
321    
322    if(rmesa->state.texture.tc_count>0){
323         reg_start(0x20b4,0);
324                 e32(0x0000000c);
325    
326         }
327                 
328    r300EmitState(rmesa);
329    
330    #if 0
331    reg_start(R300_RB3D_COLORMASK, 0);
332         e32(0xf);
333    
334    vsf_start_fragment(0x406, 4);
335    efloat(0.0);
336    efloat(0.0);
337    efloat(0.0);
338    efloat(1.0);
339
340    vsf_start_fragment(0x400, 4);
341    efloat(0.0);
342    efloat(0.0);
343    efloat(0.0);
344    efloat(1.0);
345    #endif
346    
347    /* We need LOAD_VBPNTR to setup AOS_ATTR fields.. the offsets are irrelevant */
348    r300EmitLOAD_VBPNTR(rmesa, 0);
349    
350    for(i=0; i < VB->PrimitiveCount; i++){
351        GLuint prim = VB->Primitive[i].mode;
352        GLuint start = VB->Primitive[i].start;
353        GLuint length = VB->Primitive[i].count;
354         r300_render_immediate_primitive(rmesa, ctx, start, start + length, prim);
355         }
356         
357     /* This sequence is required after any 3d drawing packet
358       I suspect it work arounds a bug (or deficiency) in hardware */
359   
360    reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
361         e32(0x0000000a);
362    
363    reg_start(0x4f18,0);
364         e32(0x00000003);
365          
366    return GL_FALSE;
367 }
368
369
370 /* vertex buffer implementation */
371
372 /* We use the start part of GART texture buffer for vertices */
373
374
375 static void upload_vertex_buffer(r300ContextPtr rmesa, GLcontext *ctx)
376 {
377         TNLcontext *tnl = TNL_CONTEXT(ctx);
378         struct vertex_buffer *VB = &tnl->vb;
379         int idx=0;
380         int i,j,k;
381         radeonScreenPtr rsp=rmesa->radeon.radeonScreen;
382         
383         /* A hack - we don't want to overwrite vertex buffers, so we
384         just use AGP space for them.. Fix me ! */
385         static int offset=0;
386         if(offset>2*1024*1024){
387                 //fprintf(stderr, "Wrapping agp vertex buffer offset\n");
388                 offset=0;
389                 }
390         /* Not the most efficient implementation, but, for now, I just want something that
391         works */
392         /* to do - make single memcpy per column (is it possible ?) */
393         /* to do - use dirty flags to avoid redundant copies */
394         #define UPLOAD_VECTOR(v)\
395                 { \
396                 /* Is the data dirty ? */ \
397                 if (v->flags & ((1<<v->size)-1)) { \
398                         /* fprintf(stderr, "size=%d vs stride=%d\n", v->size, v->stride); */ \
399                         if(v->size*4==v->stride){\
400                                 /* fast path */  \
401                                 memcpy(rsp->gartTextures.map+offset, v->data, v->stride*VB->Count); \
402                                 } else { \
403                                 for(i=0;i<VB->Count;i++){ \
404                                         /* copy one vertex at a time*/ \
405                                         memcpy(rsp->gartTextures.map+offset+i*v->size*4, VEC_ELT(v, GLfloat, i), v->size*4); \
406                                         } \
407                                 } \
408                         /* v->flags &= ~((1<<v->size)-1);*/ \
409                         } \
410                 rmesa->state.aos[idx].offset=rsp->gartTextures.handle+offset; \
411                 offset+=v->size*4*VB->Count; \
412                 idx++; \
413                 }
414                 
415         UPLOAD_VECTOR(VB->ObjPtr);
416         UPLOAD_VECTOR(VB->ColorPtr[0]);
417         /* texture coordinates */
418         for(k=0;k < ctx->Const.MaxTextureUnits;k++)
419                 if(ctx->Texture.Unit[k].Enabled)
420                         UPLOAD_VECTOR(VB->TexCoordPtr[k]);
421
422         if(idx>=R300_MAX_AOS_ARRAYS){
423                 fprintf(stderr, "Aieee ! Maximum AOS arrays count exceeded.. \n");
424                 exit(-1);
425                 }
426 }
427
428 static void r300_render_vb_primitive(r300ContextPtr rmesa, 
429         GLcontext *ctx,
430         int start,
431         int end,
432         int prim)
433 {
434    int type;
435    LOCAL_VARS
436         
437    if(end<=start)return; /* do we need to watch for this ? */
438    
439    type=r300_get_primitive_type(rmesa, ctx, start, end, prim);
440    if(type<0)return;
441
442    fire_AOS(PASS_PREFIX end-start, type);
443 }
444
445 static GLboolean r300_run_vb_render(GLcontext *ctx,
446                                  struct tnl_pipeline_stage *stage)
447 {
448    r300ContextPtr rmesa = R300_CONTEXT(ctx);
449    TNLcontext *tnl = TNL_CONTEXT(ctx);
450    struct vertex_buffer *VB = &tnl->vb;
451    int i, j;
452    LOCAL_VARS
453         
454         if (RADEON_DEBUG == DEBUG_PRIMS)
455                 fprintf(stderr, "%s\n", __FUNCTION__);
456
457    
458    reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
459         e32(0x0000000a);
460    
461    reg_start(0x4f18,0);
462         e32(0x00000003);
463    
464    r300_setup_routing(ctx, GL_FALSE);
465         
466    r300EmitState(rmesa);
467
468    /* setup array of structures data */
469    LOCK_HARDWARE(&(rmesa->radeon));
470
471    upload_vertex_buffer(rmesa, ctx);
472    //fprintf(stderr, "Using %d AOS arrays\n", n_arrays);
473    
474    for(i=0; i < VB->PrimitiveCount; i++){
475        GLuint prim = VB->Primitive[i].mode;
476        GLuint start = VB->Primitive[i].start;
477        GLuint length = VB->Primitive[i].count;
478                 
479            /* We need LOAD_VBPNTR to setup AOS_ATTR fields.. */
480         r300EmitLOAD_VBPNTR(rmesa, start);
481        
482         r300_render_vb_primitive(rmesa, ctx, start, start + length, prim);
483         }
484         
485     /* This sequence is required after any 3d drawing packet
486       I suspect it works around a bug (or deficiency) in hardware */
487   
488   reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
489         e32(0x0000000a);
490    
491    reg_start(0x4f18,0);
492         e32(0x00000003);
493    
494    end_3d(PASS_PREFIX_VOID);
495    
496    /* Flush state - we are done drawing.. */
497    r300FlushCmdBufLocked(ctx, __FUNCTION__);
498    radeonWaitForIdleLocked(&(rmesa->radeon));
499    
500    UNLOCK_HARDWARE(&(rmesa->radeon));
501    return GL_FALSE;
502 }
503
504
505 /**
506  * Called by the pipeline manager to render a batch of primitives.
507  * We can return true to pass on to the next stage (i.e. software
508  * rasterization) or false to indicate that the pipeline has finished
509  * after we render something.
510  */
511 static GLboolean r300_run_render(GLcontext *ctx,
512                                  struct tnl_pipeline_stage *stage)
513 {
514    r300ContextPtr rmesa = R300_CONTEXT(ctx);
515    TNLcontext *tnl = TNL_CONTEXT(ctx);
516    struct vertex_buffer *VB = &tnl->vb;
517    GLuint i;
518         
519         if (RADEON_DEBUG == DEBUG_PRIMS)
520                 fprintf(stderr, "%s\n", __FUNCTION__);
521
522                 
523    #if 1
524         
525         #if 1
526         return r300_run_immediate_render(ctx, stage);
527         #else 
528         return r300_run_vb_render(ctx, stage);
529         #endif
530    #else
531         return GL_TRUE;
532    #endif
533
534 #if 0
535    mgaContextPtr mmesa = MGA_CONTEXT(ctx);
536    TNLcontext *tnl = TNL_CONTEXT(ctx);
537    struct vertex_buffer *VB = &tnl->vb;
538    GLuint i;
539
540    /* Don't handle clipping or indexed vertices or vertex manipulations.
541     */
542    if (mmesa->RenderIndex != 0 ||
543        !mga_validate_render( ctx, VB )) {
544       return GL_TRUE;
545    }
546
547    tnl->Driver.Render.Start( ctx );
548    mmesa->SetupNewInputs = ~0;
549
550    for (i = 0 ; i < VB->PrimitiveCount ; i++)
551    {
552       GLuint prim = VB->Primitive[i].mode;
553       GLuint start = VB->Primitive[i].start;
554       GLuint length = VB->Primitive[i].count;
555
556       if (!length)
557          continue;
558
559       mga_render_tab_verts[prim & PRIM_MODE_MASK]( ctx, start, start + length,
560                                                    prim);
561    }
562
563    tnl->Driver.Render.Finish( ctx );
564
565    return GL_FALSE;             /* finished the pipe */
566 #endif
567 }
568
569
570 /**
571  * Called by the pipeline manager once before rendering.
572  * We check the GL state here to
573  *  a) decide whether we can do the current state in hardware and
574  *  b) update hardware registers
575  */
576 #define FALLBACK_IF(expr) \
577 do {                                                                            \
578         if (expr) {                                                             \
579                 if (1 || RADEON_DEBUG & DEBUG_FALLBACKS)                                \
580                         fprintf(stderr, "%s: fallback:%s\n",                    \
581                                 __FUNCTION__, #expr);                           \
582                 stage->active = GL_FALSE;                                       \
583                 return;                                                         \
584         }                                                                       \
585 } while(0)
586
587 static void r300_check_render(GLcontext *ctx, struct tnl_pipeline_stage *stage)
588 {
589         r300ContextPtr r300 = R300_CONTEXT(ctx);
590         int i;
591
592         if (RADEON_DEBUG & DEBUG_STATE)
593                 fprintf(stderr, "%s\n", __FUNCTION__);
594
595         /* We only support rendering in hardware for now */
596         if (ctx->RenderMode != GL_RENDER) {
597                 stage->active = GL_FALSE;
598                 return;
599         }
600
601         // I failed to figure out how dither works in hardware,
602         // let's just ignore it for now
603         //FALLBACK_IF(ctx->Color.DitherFlag);
604
605         /* I'm almost certain I forgot something here */
606         #if 0 /* This should work now.. */
607         FALLBACK_IF(ctx->Color.AlphaEnabled); // GL_ALPHA_TEST
608         FALLBACK_IF(ctx->Color.BlendEnabled); // GL_BLEND
609         #endif
610         FALLBACK_IF(ctx->Fog.Enabled); // GL_FOG
611         FALLBACK_IF(ctx->Line.SmoothFlag); // GL_LINE_SMOOTH
612         FALLBACK_IF(ctx->Line.StippleFlag); // GL_LINE_STIPPLE
613         FALLBACK_IF(ctx->Point.SmoothFlag); // GL_POINT_SMOOTH
614         if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite)
615                 FALLBACK_IF(ctx->Point.PointSprite); // GL_POINT_SPRITE_NV
616         FALLBACK_IF(ctx->Polygon.OffsetPoint); // GL_POLYGON_OFFSET_POINT
617         FALLBACK_IF(ctx->Polygon.OffsetLine); // GL_POLYGON_OFFSET_LINE
618         //FALLBACK_IF(ctx->Polygon.OffsetFill); // GL_POLYGON_OFFSET_FILL
619         if(ctx->Polygon.OffsetFill)WARN_ONCE("Polygon.OffsetFill not implemented, ignoring\n");
620         FALLBACK_IF(ctx->Polygon.SmoothFlag); // GL_POLYGON_SMOOTH
621         FALLBACK_IF(ctx->Polygon.StippleFlag); // GL_POLYGON_STIPPLE
622         //FALLBACK_IF(ctx->Stencil.Enabled); // GL_STENCIL_TEST
623         FALLBACK_IF(ctx->Multisample.Enabled); // GL_MULTISAMPLE_ARB
624
625         /* One step at a time - let one texture pass.. */
626         for (i = 1; i < ctx->Const.MaxTextureUnits; i++)
627                 FALLBACK_IF(ctx->Texture.Unit[i].Enabled);
628
629         /* let r300_run_render do its job */
630         #if 0  
631         stage->active = GL_FALSE;
632         #endif
633 }
634
635
636 static void dtr(struct tnl_pipeline_stage *stage)
637 {
638         (void)stage;
639 }
640
641 const struct tnl_pipeline_stage _r300_render_stage = {
642         "r300 hw rasterize",
643         _NEW_ALL,               /* re-check (always re-check for now) */
644         0,                      /* re-run (always runs) */
645         GL_TRUE,                /* active */
646         0, 0,                   /* inputs (set in check_render), outputs */
647         0, 0,                   /* changed_inputs, private */
648         dtr,                    /* destructor */
649         r300_check_render,      /* check */
650         r300_run_render         /* run */
651 };