r300: Cleaned up r300_render.c using Indent with appropriate options.
[mesa.git] / src / mesa / drivers / dri / r300 / r300_render.c
index 71a060db4d1d673ca8841ca39ba43a31cedb74cd..db6b77a0c22824fe6b02cbece66510c9329caa81 100644 (file)
@@ -24,12 +24,22 @@ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 **************************************************************************/
-
 /*
- * Authors:
- *   Nicolai Haehnle <prefect_@gmx.net>
+ * \file
+ *
+ * \brief R300 Render (Vertex Buffer Implementation)
+ *
+ * The immediate implementation has been removed from CVS in favor of the vertex
+ * buffer implementation.
+ *
+ * When falling back to software TCL still attempt to use hardware
+ * rasterization.
+ *
+ * I am not sure that the cache related registers are setup correctly, but
+ * obviously this does work... Further investigation is needed.
+ *
+ * \author Nicolai Haehnle <prefect_@gmx.net>
  */
-
 #include "glheader.h"
 #include "state.h"
 #include "imports.h"
@@ -38,13 +48,12 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "context.h"
 #include "dd.h"
 #include "simple_list.h"
-
 #include "api_arrayelt.h"
 #include "swrast/swrast.h"
 #include "swrast_setup/swrast_setup.h"
-#include "array_cache/acache.h"
+#include "vbo/vbo.h"
 #include "tnl/tnl.h"
-
+#include "tnl/t_vp_build.h"
 #include "radeon_reg.h"
 #include "radeon_macros.h"
 #include "radeon_ioctl.h"
@@ -57,609 +66,321 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
 #include "r300_tex.h"
 #include "r300_maos.h"
 #include "r300_emit.h"
+extern int future_hw_tcl_on;
 
-/* Turns out we might not need this after all... */
-void update_zbias(GLcontext * ctx, int prim)
+static int r300PrimitiveType(r300ContextPtr rmesa, GLcontext * ctx,
+                            int prim)
 {
-    r300ContextPtr rmesa = R300_CONTEXT(ctx);
-    int enabled = 0;
-    uint32_t values[4];
-    //return ;
-    switch(prim & PRIM_MODE_MASK) {
-       case GL_POINTS:
-               if(ctx->Polygon.OffsetPoint == GL_TRUE)
-                       enabled=1;
-               break;          
-       case GL_LINES:
-       case GL_LINE_STRIP:
-       case GL_LINE_LOOP:
-               if(ctx->Polygon.OffsetLine == GL_TRUE)
-                       enabled=1;
-               break;
-       case GL_TRIANGLES:
-       case GL_TRIANGLE_STRIP:
-       case GL_TRIANGLE_FAN:
-       case GL_QUADS:
-       case GL_QUAD_STRIP:
-       case GL_POLYGON:
-               if(ctx->Polygon.OffsetFill == GL_TRUE)
-                       enabled=1;
-               break;
-       default:
-               fprintf(stderr, "%s:%s Do not know how to handle primitive %02x - help me !\n",
-                       __FILE__, __FUNCTION__,
-                       prim & PRIM_MODE_MASK);
-           
-    }
-    
-    if(enabled){
-           values[0]=values[2]=r300PackFloat32(ctx->Polygon.OffsetFactor * 12.0);
-           values[1]=values[3]=r300PackFloat32(ctx->Polygon.OffsetUnits * 4.0);
-    }else{
-           values[0]=values[2]=r300PackFloat32(0.0);
-           values[1]=values[3]=r300PackFloat32(0.0);
-    }
-    
-    if(values[0] != rmesa->hw.zbs.cmd[R300_ZBS_T_FACTOR] ||
-       values[1] != rmesa->hw.zbs.cmd[R300_ZBS_T_CONSTANT] ||
-       values[2] != rmesa->hw.zbs.cmd[R300_ZBS_W_FACTOR] ||
-       values[3] != rmesa->hw.zbs.cmd[R300_ZBS_W_CONSTANT]){
-
-              R300_STATECHANGE(rmesa, zbs);
-              rmesa->hw.zbs.cmd[R300_ZBS_T_FACTOR] = values[0];
-              rmesa->hw.zbs.cmd[R300_ZBS_T_CONSTANT] = values[1];
-              rmesa->hw.zbs.cmd[R300_ZBS_W_FACTOR] = values[2];
-              rmesa->hw.zbs.cmd[R300_ZBS_W_CONSTANT] = values[3];
-           
-    }
-}
-
-/**********************************************************************
-*                     Hardware rasterization
-*
-* When we fell back to software TCL, we still try to use the
-* rasterization hardware for rendering.
-**********************************************************************/
+       int type = -1;
 
-static int r300_get_primitive_type(r300ContextPtr rmesa, GLcontext *ctx, int prim)
-{
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   GLuint i;
-   int type=-1;
-   
        switch (prim & PRIM_MODE_MASK) {
        case GL_POINTS:
-               type=R300_VAP_VF_CNTL__PRIM_POINTS;
-               break;          
+               type = R300_VAP_VF_CNTL__PRIM_POINTS;
+               break;
        case GL_LINES:
-               type=R300_VAP_VF_CNTL__PRIM_LINES;
-               break;          
+               type = R300_VAP_VF_CNTL__PRIM_LINES;
+               break;
        case GL_LINE_STRIP:
-               type=R300_VAP_VF_CNTL__PRIM_LINE_STRIP;
-               break;
+               type = R300_VAP_VF_CNTL__PRIM_LINE_STRIP;
+               break;
        case GL_LINE_LOOP:
-               type=R300_VAP_VF_CNTL__PRIM_LINE_LOOP;
-               break;
-       case GL_TRIANGLES:
-               type=R300_VAP_VF_CNTL__PRIM_TRIANGLES;
-               break;
-       case GL_TRIANGLE_STRIP:
-               type=R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP;
-               break;
-       case GL_TRIANGLE_FAN:
-               type=R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN;
-               break;
+               type = R300_VAP_VF_CNTL__PRIM_LINE_LOOP;
+               break;
+       case GL_TRIANGLES:
+               type = R300_VAP_VF_CNTL__PRIM_TRIANGLES;
+               break;
+       case GL_TRIANGLE_STRIP:
+               type = R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP;
+               break;
+       case GL_TRIANGLE_FAN:
+               type = R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN;
+               break;
        case GL_QUADS:
-               type=R300_VAP_VF_CNTL__PRIM_QUADS;
-               break;
+               type = R300_VAP_VF_CNTL__PRIM_QUADS;
+               break;
        case GL_QUAD_STRIP:
-               type=R300_VAP_VF_CNTL__PRIM_QUAD_STRIP;
-               break;
+               type = R300_VAP_VF_CNTL__PRIM_QUAD_STRIP;
+               break;
        case GL_POLYGON:
-               type=R300_VAP_VF_CNTL__PRIM_POLYGON;
+               type = R300_VAP_VF_CNTL__PRIM_POLYGON;
                break;
-       default:
-               fprintf(stderr, "%s:%s Do not know how to handle primitive %02x - help me !\n",
-                       __FILE__, __FUNCTION__,
-                       prim & PRIM_MODE_MASK);
+       default:
+               fprintf(stderr,
+                       "%s:%s Do not know how to handle primitive 0x%04x - help me !\n",
+                       __FILE__, __FUNCTION__, prim & PRIM_MODE_MASK);
                return -1;
-               break;
-       }
-   return type;
+               break;
+       }
+       return type;
 }
 
-static int r300_get_num_verts(r300ContextPtr rmesa, 
-       GLcontext *ctx,
-       int num_verts,
-       int prim)
+static int r300NumVerts(r300ContextPtr rmesa, int num_verts, int prim)
 {
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   GLuint i;
-   int type=-1, verts_off=0;
-   char *name="UNKNOWN";
-   
+       int verts_off = 0;
+
        switch (prim & PRIM_MODE_MASK) {
        case GL_POINTS:
-               name="P";
                verts_off = 0;
-               break;          
+               break;
        case GL_LINES:
-               name="L";
                verts_off = num_verts % 2;
-               break;          
+               break;
        case GL_LINE_STRIP:
-               name="LS";
-               if(num_verts < 2)
+               if (num_verts < 2)
                        verts_off = num_verts;
-               break;
+               break;
        case GL_LINE_LOOP:
-               name="LL";
-               if(num_verts < 2)
+               if (num_verts < 2)
                        verts_off = num_verts;
-               break;
-       case GL_TRIANGLES:
-               name="T";
+               break;
+       case GL_TRIANGLES:
                verts_off = num_verts % 3;
-               break;
-       case GL_TRIANGLE_STRIP:
-               name="TS";
-               if(num_verts < 3)
+               break;
+       case GL_TRIANGLE_STRIP:
+               if (num_verts < 3)
                        verts_off = num_verts;
-               break;
-       case GL_TRIANGLE_FAN:
-               name="TF";
-               if(num_verts < 3)
+               break;
+       case GL_TRIANGLE_FAN:
+               if (num_verts < 3)
                        verts_off = num_verts;
-               break;
+               break;
        case GL_QUADS:
-               name="Q";
                verts_off = num_verts % 4;
-               break;
+               break;
        case GL_QUAD_STRIP:
-               name="QS";
-               if(num_verts < 4)
+               if (num_verts < 4)
                        verts_off = num_verts;
                else
                        verts_off = num_verts % 2;
-               break;
+               break;
        case GL_POLYGON:
-               name="P";
-               if(num_verts < 3)
+               if (num_verts < 3)
                        verts_off = num_verts;
                break;
-       default:
-               fprintf(stderr, "%s:%s Do not know how to handle primitive %02x - help me !\n",
-                       __FILE__, __FUNCTION__,
-                       prim & PRIM_MODE_MASK);
+       default:
+               fprintf(stderr,
+                       "%s:%s Do not know how to handle primitive 0x%04x - help me !\n",
+                       __FILE__, __FUNCTION__, prim & PRIM_MODE_MASK);
                return -1;
-               break;
-       }
-       
-       if(num_verts - verts_off == 0){
-               WARN_ONCE("user error: Need more than %d vertices to draw primitive %s !\n", num_verts, name);
-               return 0;
+               break;
        }
-       
-       if(verts_off > 0){
-               WARN_ONCE("user error: %d is not a valid number of vertices for primitive %s !\n", num_verts, name);
+
+       if (RADEON_DEBUG & DEBUG_VERTS) {
+               if (num_verts - verts_off == 0) {
+                       WARN_ONCE
+                           ("user error: Need more than %d vertices to draw primitive 0x%04x !\n",
+                            num_verts, prim & PRIM_MODE_MASK);
+                       return 0;
+               }
+
+               if (verts_off > 0) {
+                       WARN_ONCE
+                           ("user error: %d is not a valid number of vertices for primitive 0x%04x !\n",
+                            num_verts, prim & PRIM_MODE_MASK);
+               }
        }
-       
+
        return num_verts - verts_off;
 }
 
-void dump_inputs(GLcontext *ctx, int render_inputs)
+static void inline r300FireEB(r300ContextPtr rmesa, unsigned long addr,
+                             int vertex_count, int type, int elt_size)
 {
-       int k;
-       fprintf(stderr, "inputs:");
-       fprintf(stderr, "%08x ", render_inputs);
-       
-       if(render_inputs & _TNL_BIT_POS)
-               fprintf(stderr, "_TNL_BIT_POS ");
-       if(render_inputs & _TNL_BIT_NORMAL)
-               fprintf(stderr, "_TNL_BIT_NORMAL ");
-               
-               /* color components */
-       if(render_inputs & _TNL_BIT_COLOR0)
-               fprintf(stderr, "_TNL_BIT_COLOR0 ");
-       if(render_inputs & _TNL_BIT_COLOR1)
-               fprintf(stderr, "_TNL_BIT_COLOR1 ");
-
-       if(render_inputs & _TNL_BIT_FOG)
-               fprintf(stderr, "_TNL_BIT_FOG ");
-                                       
-               /* texture coordinates */
-       for(k=0;k < ctx->Const.MaxTextureUnits;k++)
-               if(render_inputs & (_TNL_BIT_TEX0<<k))
-                       fprintf(stderr, "_TNL_BIT_TEX%d ", k);
-               
-       if(render_inputs & _TNL_BIT_INDEX)
-               fprintf(stderr, "_TNL_BIT_INDEX ");
-       if(render_inputs & _TNL_BIT_POINTSIZE)
-               fprintf(stderr, "_TNL_BIT_POINTSIZE ");
-       
-       fprintf(stderr, "\n");
-}
-
-/* This function compiles GL context into state registers that 
-   describe data routing inside of R300 pipeline.
-   
-   In particular, it programs input_route, output_vtx_fmt, texture
-   unit configuration and gb_output_vtx_fmt
-   
-   This function encompasses setup_AOS() from r300_lib.c
-*/
-
-
+       int cmd_reserved = 0;
+       int cmd_written = 0;
+       drm_radeon_cmd_header_t *cmd = NULL;
+       unsigned long t_addr;
+       unsigned long magic_1, magic_2;
+       GLcontext *ctx;
+       ctx = rmesa->radeon.glCtx;
+
+       assert(elt_size == 2 || elt_size == 4);
+
+       if (addr & (elt_size - 1)) {
+               WARN_ONCE("Badly aligned buffer\n");
+               return;
+       }
 
+       magic_1 = (addr % 32) / 4;
+       t_addr = addr & (~0x1d);
+       magic_2 = (vertex_count + 1 + (t_addr & 0x2)) / 2 + magic_1;
 
-/* Immediate implementation - vertex data is sent via command stream */
+       check_space(6);
 
-static GLfloat default_vector[4]={0.0, 0.0, 0.0, 1.0};
+       start_packet3(RADEON_CP_PACKET3_3D_DRAW_INDX_2, 0);
+       if (elt_size == 4) {
+               e32(R300_VAP_VF_CNTL__PRIM_WALK_INDICES |
+                   (vertex_count << 16) | type |
+                   R300_VAP_VF_CNTL__INDEX_SIZE_32bit);
+       } else {
+               e32(R300_VAP_VF_CNTL__PRIM_WALK_INDICES |
+                   (vertex_count << 16) | type);
+       }
 
-#define output_vector(v, i) \
-       { \
-       int _i; \
-       for(_i=0;_i<v->size;_i++){ \
-               efloat(VEC_ELT(v, GLfloat, i)[_i]); \
-               } \
-       for(_i=v->size;_i<4;_i++){ \
-                       efloat(default_vector[_i]); \
-                       } \
+       start_packet3(RADEON_CP_PACKET3_INDX_BUFFER, 2);
+#ifdef OPTIMIZE_ELTS
+       if (elt_size == 4) {
+               e32(R300_EB_UNK1 | (0 << 16) | R300_EB_UNK2);
+               e32(addr);
+       } else {
+               e32(R300_EB_UNK1 | (magic_1 << 16) | R300_EB_UNK2);
+               e32(t_addr);
        }
+#else
+       e32(R300_EB_UNK1 | (0 << 16) | R300_EB_UNK2);
+       e32(addr);
+#endif
 
-/* Immediate implementation - vertex data is sent via command stream */
+       if (elt_size == 4) {
+               e32(vertex_count);
+       } else {
+#ifdef OPTIMIZE_ELTS
+               e32(magic_2);
+#else
+               e32((vertex_count + 1) / 2);
+#endif
+       }
+}
 
-static void r300_render_immediate_primitive(r300ContextPtr rmesa, 
-       GLcontext *ctx,
-       int start,
-       int end,
-       int prim)
+static void r300RunRenderPrimitive(r300ContextPtr rmesa, GLcontext * ctx,
+                                  int start, int end, int prim)
 {
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   GLuint i, render_inputs;
-   int k, type, num_verts;
-   LOCAL_VARS
-                  
-   type=r300_get_primitive_type(rmesa, ctx, prim);
-   num_verts=r300_get_num_verts(rmesa, ctx, end-start, prim);
-   
-               #if 0
-               fprintf(stderr,"ObjPtr: size=%d stride=%d\n", 
-                       VB->ObjPtr->size, VB->ObjPtr->stride);
-               fprintf(stderr,"ColorPtr[0]: size=%d stride=%d\n", 
-                       VB->ColorPtr[0]->size, VB->ColorPtr[0]->stride);
-               fprintf(stderr,"TexCoordPtr[0]: size=%d stride=%d\n", 
-                       VB->TexCoordPtr[0]->size, VB->TexCoordPtr[0]->stride);
-               #endif
-   
-   if(type<0 || num_verts <= 0)return;
-
-   if(!VB->ObjPtr){
-       WARN_ONCE("FIXME: Don't know how to handle GL_ARB_vertex_buffer_object correctly\n");
-       return;
-   }
-   /* A packet cannot have more than 16383 data words.. */
-   if((num_verts*4*rmesa->state.aos_count)>16380){
-       WARN_ONCE("Too many vertices to paint. Fix me !\n");
-       return;         
-       }
+       int type, num_verts;
 
-   //fprintf(stderr, "aos_count=%d start=%d end=%d\n", rmesa->state.aos_count, start, end);
-
-   if(rmesa->state.aos_count==0){
-       WARN_ONCE("Aeiee ! aos_count==0, while it shouldn't. Skipping rendering\n");
-       return;
-       }
-  
-   render_inputs = rmesa->state.render_inputs;
-
-   if(!render_inputs){
-       WARN_ONCE("Aeiee ! render_inputs==0. Skipping rendering.\n");
-       return;
-       }
-
-       //dump_inputs(ctx, render_inputs); return ;
-       
-   start_immediate_packet(num_verts, type, 4*rmesa->state.aos_count);
-
-       for(i=start;i<start+num_verts;i++){
-               #if 0
-               fprintf(stderr, "* (%f %f %f %f) (%f %f %f %f)\n", 
-                       VEC_ELT(VB->ObjPtr, GLfloat, i)[0],
-                       VEC_ELT(VB->ObjPtr, GLfloat, i)[1],
-                       VEC_ELT(VB->ObjPtr, GLfloat, i)[2],
-                       VEC_ELT(VB->ObjPtr, GLfloat, i)[3],
-                       
-                       VEC_ELT(VB->ColorPtr[0], GLfloat, i)[0],
-                       VEC_ELT(VB->ColorPtr[0], GLfloat, i)[1],
-                       VEC_ELT(VB->ColorPtr[0], GLfloat, i)[2],
-                       VEC_ELT(VB->ColorPtr[0], GLfloat, i)[3]
-                       );
-               #endif
-               
-               
-               /* coordinates */
-               if(render_inputs & _TNL_BIT_POS)
-                       output_vector(VB->ObjPtr, i);
-               if(render_inputs & _TNL_BIT_NORMAL)
-                       output_vector(VB->NormalPtr, i);
-               
-               /* color components */
-               if(render_inputs & _TNL_BIT_COLOR0)
-                       output_vector(VB->ColorPtr[0], i);
-               if(render_inputs & _TNL_BIT_COLOR1)
-                       output_vector(VB->SecondaryColorPtr[0], i);
-
-/*             if(render_inputs & _TNL_BIT_FOG) // Causes lock ups when immediate mode is on
-                       output_vector(VB->FogCoordPtr, i);*/
-                                       
-               /* texture coordinates */
-               for(k=0;k < ctx->Const.MaxTextureUnits;k++)
-                       if(render_inputs & (_TNL_BIT_TEX0<<k))
-                               output_vector(VB->TexCoordPtr[k], i);
-               
-               if(render_inputs & _TNL_BIT_INDEX)
-                       output_vector(VB->IndexPtr[0], i);
-               if(render_inputs & _TNL_BIT_POINTSIZE)
-                       output_vector(VB->PointSizePtr, i);
-               }
+       type = r300PrimitiveType(rmesa, ctx, prim);
+       num_verts = r300NumVerts(rmesa, end - start, prim);
 
-}
+       if (type < 0 || num_verts <= 0)
+               return;
 
+       if (rmesa->state.VB.Elts) {
+               r300EmitAOS(rmesa, rmesa->state.aos_count, /*0 */ start);
+               if (num_verts > 65535) {        /* not implemented yet */
+                       WARN_ONCE("Too many elts\n");
+                       return;
+               }
+               r300EmitElts(ctx, rmesa->state.VB.Elts, num_verts,
+                            rmesa->state.VB.elt_size);
+               r300FireEB(rmesa, rmesa->state.elt_dma.aos_offset,
+                          num_verts, type, rmesa->state.VB.elt_size);
+       } else {
+               r300EmitAOS(rmesa, rmesa->state.aos_count, start);
+               fire_AOS(rmesa, num_verts, type);
+       }
+}
 
-static GLboolean r300_run_immediate_render(GLcontext *ctx,
-                                struct tnl_pipeline_stage *stage)
+static GLboolean r300RunRender(GLcontext * ctx,
+                              struct tnl_pipeline_stage *stage)
 {
-   r300ContextPtr rmesa = R300_CONTEXT(ctx);
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   GLuint i;
-   /* Only do 2d textures */
-   struct gl_texture_object *to=ctx->Texture.Unit[0].Current2D;
-   r300TexObjPtr t=to->DriverData;
-   LOCAL_VARS
-       
-  
-   /* Update texture state - needs to be done only when actually changed..
-      All the time for now.. */
-
-
-       if (RADEON_DEBUG == DEBUG_PRIMS)
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct radeon_vertex_buffer *VB = &rmesa->state.VB;
+       int i;
+       int cmd_reserved = 0;
+       int cmd_written = 0;
+       drm_radeon_cmd_header_t *cmd = NULL;
+
+       if (RADEON_DEBUG & DEBUG_PRIMS)
                fprintf(stderr, "%s\n", __FUNCTION__);
-               
-   #if 1 /* we need this, somehow */
-   /* Flush state - make sure command buffer is nice and large */
-   r300Flush(ctx);
-   /* Make sure we have enough space */
-   #else
-   /* Count is very imprecize, but should be good upper bound */
-   r300EnsureCmdBufSpace(rmesa, rmesa->hw.max_state_size + 4+2+30
-       +VB->PrimitiveCount*(1+8)+VB->Count*4*rmesa->state.texture.tc_count+4, __FUNCTION__);
-   #endif
-     
-   /* needed before starting 3d operation .. */
-   reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
-       e32(0x0000000a);
-   
-   reg_start(0x4f18,0);
-       e32(0x00000003);
-       
-   
-       #if 0 /* looks like the Z offset issue got fixed */
-   rmesa->hw.vte.cmd[1] = R300_VPORT_X_SCALE_ENA
-                               | R300_VPORT_X_OFFSET_ENA
-                               | R300_VPORT_Y_SCALE_ENA
-                               | R300_VPORT_Y_OFFSET_ENA
-                               | R300_VTX_W0_FMT;
-   R300_STATECHANGE(rmesa, vte);
-       #endif
-   
-       
-      
-   /* Magic register - note it is right after 20b0 */
-
-   
-   if(rmesa->state.texture.tc_count>0){
-       reg_start(0x20b4,0);
-               e32(0x0000000c);
-   
+
+       if (stage) {
+               TNLcontext *tnl = TNL_CONTEXT(ctx);
+               radeon_vb_to_rvb(rmesa, VB, &tnl->vb);
        }
-               
-   r300EmitState(rmesa);
-   
-   #if 0
-   reg_start(R300_RB3D_COLORMASK, 0);
-       e32(0xf);
-   
-   vsf_start_fragment(0x406, 4);
-   efloat(0.0);
-   efloat(0.0);
-   efloat(0.0);
-   efloat(1.0);
-
-   vsf_start_fragment(0x400, 4);
-   efloat(0.0);
-   efloat(0.0);
-   efloat(0.0);
-   efloat(1.0);
-   #endif
-   
-/* Setup INPUT_ROUTE and INPUT_CNTL */
-       r300EmitArrays(ctx, GL_TRUE);
-
-/* Why do we need this for immediate mode?? Vertex processor needs it to know proper regs */
-//     r300EmitLOAD_VBPNTR(rmesa, 0);
-/* Okay, it seems I misunderstood something, EmitAOS does the same thing */
-       r300EmitAOS(rmesa, rmesa->state.aos_count, 0);
-
-   for(i=0; i < VB->PrimitiveCount; i++){
-       GLuint prim = VB->Primitive[i].mode;
-       GLuint start = VB->Primitive[i].start;
-       GLuint length = VB->Primitive[i].count;
-
-       r300_render_immediate_primitive(rmesa, ctx, start, start + length, prim);
-       }
-       
-    /* This sequence is required after any 3d drawing packet
-      I suspect it work arounds a bug (or deficiency) in hardware */
-  
-   reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
-       e32(0x0000000a);
-   
-   reg_start(0x4f18,0);
-       e32(0x00000003);
-         
-   return GL_FALSE;
-}
 
-/* vertex buffer implementation */
-void emit_elts(GLcontext * ctx, GLuint *elts,
-               unsigned long n_elts, unsigned long n_fake_elts, int align);
+       r300UpdateShaders(rmesa);
+       if (r300EmitArrays(ctx))
+               return GL_TRUE;
 
-#    define R300_EB_UNK1_SHIFT 24
-#    define R300_EB_UNK1 (0x80<<24)
-#    define R300_EB_UNK2 0x0810
+       r300UpdateShaderStates(rmesa);
 
-//#define PLAY_WITH_MAGIC_1
+       reg_start(R300_RB3D_DSTCACHE_CTLSTAT, 0);
+       e32(R300_RB3D_DSTCACHE_UNKNOWN_0A);
 
-unsigned long get_num_elts(unsigned long count)
-{
-#ifdef PLAY_WITH_MAGIC_1
-       return count;
-#else  
-       /* round up elt count so that magic_1 is 0 (divisable by 4)*/
-       return (count+3) & (~3);
-       //return count - (count % 4);
-#endif
-}
+       reg_start(R300_RB3D_ZCACHE_CTLSTAT, 0);
+       e32(R300_RB3D_ZCACHE_UNKNOWN_03);
 
-int get_align(int vertex_count)
-{
-       unsigned char magic1_tbl[4]={ 0, 6, 4, 2 };
+       r300EmitState(rmesa);
 
-       return magic1_tbl[vertex_count % 4];
-}
+       for (i = 0; i < VB->PrimitiveCount; i++) {
+               GLuint prim = _tnl_translate_prim(&VB->Primitive[i]);
+               GLuint start = VB->Primitive[i].start;
+               GLuint length = VB->Primitive[i].count;
 
-static void inline fire_EB(PREFIX unsigned long addr, int vertex_count, int type)
-{
-       LOCAL_VARS
-       unsigned long magic_1;
-
-       magic_1 = get_align(vertex_count);
-#ifndef PLAY_WITH_MAGIC_1
-       if(magic_1 != 0){
-               WARN_ONCE("Dont know how to handle this yet!\n");
-               return ;
+               r300RunRenderPrimitive(rmesa, ctx, start, start + length,
+                                      prim);
        }
-#endif 
-       check_space(6);
-       
-       start_packet3(RADEON_CP_PACKET3_3D_DRAW_INDX_2, 0);
-       e32(R300_VAP_VF_CNTL__PRIM_WALK_INDICES | (vertex_count<<16) | type);
-       
-       start_packet3(RADEON_CP_PACKET3_INDX_BUFFER, 2);
-       e32(R300_EB_UNK1 | (magic_1 << 16) | R300_EB_UNK2);
-       e32(addr);
-       e32(((vertex_count+1) / 2) + magic_1); /* This still fails once in a while */
-}
 
-static void r300_render_vb_primitive(r300ContextPtr rmesa, 
-       GLcontext *ctx,
-       int start,
-       int end,
-       int prim)
-{
-   int type, num_verts;
-   radeonScreenPtr rsp=rmesa->radeon.radeonScreen;
-   LOCAL_VARS
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   int i;
-   
-   type=r300_get_primitive_type(rmesa, ctx, prim);
-   num_verts=r300_get_num_verts(rmesa, ctx, end-start, prim);
-   
-   if(type<0 || num_verts <= 0)return;
-   
-   if(rmesa->state.Elts){
-       unsigned long elt_count;
-       
-       WARN_ONCE("Rendering with elts\n");
-#if 1  
-       start_index32_packet(num_verts, type);
-       for(i=0; i < num_verts; i++)
-               e32(rmesa->state.Elts[start+i]); /* start ? */
-#else  
-       elt_count=get_num_elts(num_verts);
-       //emit_elts(ctx, rmesa->state.Elts, VB->Count, get_num_elts(VB->Count));
-       emit_elts(ctx, rmesa->state.Elts+start, num_verts, elt_count, get_align(elt_count));
-       fire_EB(PASS_PREFIX rsp->gartTextures.handle/*rmesa->state.elt_ao.aos_offset*/, elt_count, type);
-#endif 
-   }else
-          fire_AOS(PASS_PREFIX num_verts, type);
+       reg_start(R300_RB3D_DSTCACHE_CTLSTAT, 0);
+       e32(R300_RB3D_DSTCACHE_UNKNOWN_0A
+           /*R300_RB3D_DSTCACHE_UNKNOWN_02 */ );
+
+       reg_start(R300_RB3D_ZCACHE_CTLSTAT, 0);
+       e32(R300_RB3D_ZCACHE_UNKNOWN_03 /*R300_RB3D_ZCACHE_UNKNOWN_01 */ );
+
+#ifdef USER_BUFFERS
+       r300UseArrays(ctx);
+#endif
+       r300ReleaseArrays(ctx);
+       return GL_FALSE;
 }
 
-static GLboolean r300_run_vb_render(GLcontext *ctx,
-                                struct tnl_pipeline_stage *stage)
+#define FALLBACK_IF(expr)                                              \
+       do {                                                            \
+               if (expr) {                                             \
+                       if (1 || RADEON_DEBUG & DEBUG_FALLBACKS)        \
+                               WARN_ONCE("Software fallback:%s\n",     \
+                                         #expr);                       \
+                       return R300_FALLBACK_RAST;                      \
+               }                                                       \
+       } while(0)
+
+int r300Fallback(GLcontext * ctx)
 {
-   r300ContextPtr rmesa = R300_CONTEXT(ctx);
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   int i, j;
-   LOCAL_VARS
-       
-       if (RADEON_DEBUG == DEBUG_PRIMS)
-               fprintf(stderr, "%s\n", __FUNCTION__);
+       r300ContextPtr r300 = R300_CONTEXT(ctx);
+       struct r300_fragment_program *fp = (struct r300_fragment_program *)
+           (char *)ctx->FragmentProgram._Current;
 
-   
-       r300ReleaseArrays(ctx);
-       r300EmitArrays(ctx, GL_FALSE);
-       //dump_inputs(ctx, rmesa->state.render_inputs);
-#if 0 /* Cant do this here yet due to magic_1 */
-       if(rmesa->state.Elts)
-               emit_elts(ctx, rmesa->state.Elts, /*600*/VB->Count, get_num_elts(/*600*/VB->Count));
-#endif 
-       
-//     LOCK_HARDWARE(&(rmesa->radeon));
-
-       reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
-       e32(0x0000000a);
-   
-       reg_start(0x4f18,0);
-       e32(0x00000003);
-
-       r300EmitState(rmesa);           
-
-       rmesa->state.Elts = VB->Elts;
-
-       for(i=0; i < VB->PrimitiveCount; i++){
-               GLuint prim = VB->Primitive[i].mode;
-               GLuint start = VB->Primitive[i].start;
-               GLuint length = VB->Primitive[i].count;
-               if(rmesa->state.Elts)
-                       r300EmitAOS(rmesa, rmesa->state.aos_count, 0);
-               else
-                       r300EmitAOS(rmesa, rmesa->state.aos_count, start);
-               r300_render_vb_primitive(rmesa, ctx, start, start + length, prim);
+       if (fp) {
+               if (!fp->translated)
+                       r300_translate_fragment_shader(r300, fp);
+               FALLBACK_IF(!fp->translated);
        }
 
-       reg_start(R300_RB3D_DSTCACHE_CTLSTAT,0);
-       e32(0x0000000a);
-  
-       reg_start(0x4f18,0);
-       e32(0x00000003);
-
-//     end_3d(PASS_PREFIX_VOID);
-   
-   /* Flush state - we are done drawing.. */
-//     r300FlushCmdBufLocked(rmesa, __FUNCTION__);
-//     radeonWaitForIdleLocked(&(rmesa->radeon));
-   
-//     UNLOCK_HARDWARE(&(rmesa->radeon));
-       return GL_FALSE;
+       FALLBACK_IF(ctx->RenderMode != GL_RENDER);
+
+       FALLBACK_IF(ctx->Stencil._TestTwoSide
+                   && (ctx->Stencil.Ref[0] != ctx->Stencil.Ref[1]
+                       || ctx->Stencil.ValueMask[0] !=
+                       ctx->Stencil.ValueMask[1]
+                       || ctx->Stencil.WriteMask[0] !=
+                       ctx->Stencil.WriteMask[1]));
+
+       /* GL_COLOR_LOGIC_OP */
+       FALLBACK_IF(ctx->Color.ColorLogicOpEnabled);
+
+       /* GL_POINT_SPRITE_ARB, GL_POINT_SPRITE_NV */
+       if (ctx->Extensions.NV_point_sprite
+           || ctx->Extensions.ARB_point_sprite)
+               FALLBACK_IF(ctx->Point.PointSprite);
+
+       if (!r300->disable_lowimpact_fallback) {
+               /* GL_POLYGON_OFFSET_POINT */
+               FALLBACK_IF(ctx->Polygon.OffsetPoint);
+               /* GL_POLYGON_OFFSET_LINE */
+               FALLBACK_IF(ctx->Polygon.OffsetLine);
+               /* GL_POLYGON_STIPPLE */
+               FALLBACK_IF(ctx->Polygon.StippleFlag);
+               /* GL_MULTISAMPLE */
+               FALLBACK_IF(ctx->Multisample.Enabled);
+               /* GL_LINE_STIPPLE */
+               FALLBACK_IF(ctx->Line.StippleFlag);
+               /* GL_LINE_SMOOTH */
+               FALLBACK_IF(ctx->Line.SmoothFlag);
+               /* GL_POINT_SMOOTH */
+               FALLBACK_IF(ctx->Point.SmoothFlag);
+       }
+
+       return R300_FALLBACK_NONE;
 }
 
 /**
@@ -668,144 +389,62 @@ static GLboolean r300_run_vb_render(GLcontext *ctx,
  * rasterization) or false to indicate that the pipeline has finished
  * after we render something.
  */
-static GLboolean r300_run_render(GLcontext *ctx,
-                                struct tnl_pipeline_stage *stage)
+static GLboolean r300RunNonTNLRender(GLcontext * ctx,
+                                    struct tnl_pipeline_stage *stage)
 {
-   r300ContextPtr rmesa = R300_CONTEXT(ctx);
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   GLuint i;
-       
-       if (RADEON_DEBUG == DEBUG_PRIMS)
+       if (RADEON_DEBUG & DEBUG_PRIMS)
                fprintf(stderr, "%s\n", __FUNCTION__);
-       
-       
-   #if 1
-       
-       #if 1
-        return r300_run_immediate_render(ctx, stage);
-       #else 
-        return r300_run_vb_render(ctx, stage);
-       #endif
-   #else
-       return GL_TRUE;
-   #endif
-
-#if 0
-   mgaContextPtr mmesa = MGA_CONTEXT(ctx);
-   TNLcontext *tnl = TNL_CONTEXT(ctx);
-   struct vertex_buffer *VB = &tnl->vb;
-   GLuint i;
-
-   /* Don't handle clipping or indexed vertices or vertex manipulations.
-    */
-   if (mmesa->RenderIndex != 0 ||
-       !mga_validate_render( ctx, VB )) {
-      return GL_TRUE;
-   }
-
-   tnl->Driver.Render.Start( ctx );
-   mmesa->SetupNewInputs = ~0;
-
-   for (i = 0 ; i < VB->PrimitiveCount ; i++)
-   {
-      GLuint prim = VB->Primitive[i].mode;
-      GLuint start = VB->Primitive[i].start;
-      GLuint length = VB->Primitive[i].count;
-
-      if (!length)
-        continue;
-
-      mga_render_tab_verts[prim & PRIM_MODE_MASK]( ctx, start, start + length,
-                                                  prim);
-   }
-
-   tnl->Driver.Render.Finish( ctx );
-
-   return GL_FALSE;            /* finished the pipe */
-#endif
-}
 
+       if (r300Fallback(ctx) >= R300_FALLBACK_RAST)
+               return GL_TRUE;
 
-/**
- * Called by the pipeline manager once before rendering.
- * We check the GL state here to
- *  a) decide whether we can do the current state in hardware and
- *  b) update hardware registers
- */
-#define FALLBACK_IF(expr) \
-do {                                                                           \
-       if (expr) {                                                             \
-               if (1 || RADEON_DEBUG & DEBUG_FALLBACKS)                                \
-                       fprintf(stderr, "%s: fallback:%s\n",                    \
-                               __FUNCTION__, #expr);                           \
-               stage->active = GL_FALSE;                                       \
-               return;                                                         \
-       }                                                                       \
-} while(0)
-
-static void r300_check_render(GLcontext *ctx, struct tnl_pipeline_stage *stage)
+       return r300RunRender(ctx, stage);
+}
+
+static GLboolean r300RunTCLRender(GLcontext * ctx,
+                                 struct tnl_pipeline_stage *stage)
 {
-       r300ContextPtr r300 = R300_CONTEXT(ctx);
-       int i;
+       r300ContextPtr rmesa = R300_CONTEXT(ctx);
+       struct r300_vertex_program *vp;
+
+       hw_tcl_on = future_hw_tcl_on;
 
-       if (RADEON_DEBUG & DEBUG_STATE)
+       if (RADEON_DEBUG & DEBUG_PRIMS)
                fprintf(stderr, "%s\n", __FUNCTION__);
 
-       /* We only support rendering in hardware for now */
-       if (ctx->RenderMode != GL_RENDER) {
-               stage->active = GL_FALSE;
-               return;
+       if (hw_tcl_on == GL_FALSE)
+               return GL_TRUE;
+
+       if (r300Fallback(ctx) >= R300_FALLBACK_TCL) {
+               hw_tcl_on = GL_FALSE;
+               return GL_TRUE;
        }
-       
-       // I failed to figure out how dither works in hardware,
-       // let's just ignore it for now
-       //FALLBACK_IF(ctx->Color.DitherFlag);
-       
-       /* I'm almost certain I forgot something here */
-       #if 0 /* This should work now.. */
-       FALLBACK_IF(ctx->Color.AlphaEnabled); // GL_ALPHA_TEST
-       FALLBACK_IF(ctx->Color.BlendEnabled); // GL_BLEND
-       #endif
-       //FALLBACK_IF(ctx->Fog.Enabled); // GL_FOG disable as swtcl doesnt seem to support this
-       FALLBACK_IF(ctx->Line.SmoothFlag); // GL_LINE_SMOOTH
-       FALLBACK_IF(ctx->Line.StippleFlag); // GL_LINE_STIPPLE
-       FALLBACK_IF(ctx->Point.SmoothFlag); // GL_POINT_SMOOTH
-       if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite)
-               FALLBACK_IF(ctx->Point.PointSprite); // GL_POINT_SPRITE_NV
-       //FALLBACK_IF(ctx->Polygon.OffsetPoint); // GL_POLYGON_OFFSET_POINT
-       //FALLBACK_IF(ctx->Polygon.OffsetLine); // GL_POLYGON_OFFSET_LINE
-       //FALLBACK_IF(ctx->Polygon.OffsetFill); // GL_POLYGON_OFFSET_FILL
-       //if(ctx->Polygon.OffsetFill)WARN_ONCE("Polygon.OffsetFill not implemented, ignoring\n");
-       FALLBACK_IF(ctx->Polygon.SmoothFlag); // GL_POLYGON_SMOOTH
-       FALLBACK_IF(ctx->Polygon.StippleFlag); // GL_POLYGON_STIPPLE
-       //FALLBACK_IF(ctx->Stencil.Enabled); // GL_STENCIL_TEST
-       FALLBACK_IF(ctx->Multisample.Enabled); // GL_MULTISAMPLE_ARB
-       
-       /* One step at a time - let one texture pass.. */
-       for (i = 1; i < ctx->Const.MaxTextureUnits; i++)
-               FALLBACK_IF(ctx->Texture.Unit[i].Enabled);
-
-       /* let r300_run_render do its job */
-       #if 0  
-       stage->active = GL_FALSE;
-       #endif
-}
 
+       r300UpdateShaders(rmesa);
 
-static void dtr(struct tnl_pipeline_stage *stage)
-{
-       (void)stage;
+       vp = (struct r300_vertex_program *)CURRENT_VERTEX_SHADER(ctx);
+       if (vp->native == GL_FALSE) {
+               hw_tcl_on = GL_FALSE;
+               return GL_TRUE;
+       }
+
+       return r300RunRender(ctx, stage);
 }
 
 const struct tnl_pipeline_stage _r300_render_stage = {
-       "r300 hw rasterize",
-       _NEW_ALL,               /* re-check (always re-check for now) */
-       0,                      /* re-run (always runs) */
-       GL_TRUE,                /* active */
-       0, 0,                   /* inputs (set in check_render), outputs */
-       0, 0,                   /* changed_inputs, private */
-       dtr,                    /* destructor */
-       r300_check_render,      /* check */
-       r300_run_render         /* run */
+       "r300 Hardware Rasterization",
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       r300RunNonTNLRender
+};
+
+const struct tnl_pipeline_stage _r300_tcl_stage = {
+       "r300 Hardware Transform, Clipping and Lighting",
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       r300RunTCLRender
 };