#include "r300_maos.h"
#include "r300_emit.h"
-/* Turns out we might not need this after all... */
-void update_zbias(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
*
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;
+ break;
case GL_LINES:
type=R300_VAP_VF_CNTL__PRIM_LINES;
- break;
+ break;
case GL_LINE_STRIP:
type=R300_VAP_VF_CNTL__PRIM_LINE_STRIP;
break;
return type;
}
-static int r300_get_num_verts(r300ContextPtr rmesa,
+static int r300_get_num_verts(r300ContextPtr rmesa,
GLcontext *ctx,
int num_verts,
int prim)
GLuint i;
int type=-1, verts_off=0;
char *name="UNKNOWN";
-
+
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)
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;
}
-
+
if(verts_off > 0){
WARN_ONCE("user error: %d is not a valid number of vertices for primitive %s !\n", num_verts, name);
}
-
+
return num_verts - verts_off;
}
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_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
+/* 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
*/
/* Immediate implementation - vertex data is sent via command stream */
-static void r300_render_immediate_primitive(r300ContextPtr rmesa,
+static void r300_render_immediate_primitive(r300ContextPtr rmesa,
GLcontext *ctx,
int start,
int end,
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",
+
+#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",
+ 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",
+ fprintf(stderr,"TexCoordPtr[0]: size=%d stride=%d\n",
VB->TexCoordPtr[0]->size, VB->TexCoordPtr[0]->stride);
- #endif
-
+#endif
+
if(type<0 || num_verts <= 0)return;
if(!VB->ObjPtr){
/* 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;
+ return;
}
//fprintf(stderr, "aos_count=%d start=%d end=%d\n", rmesa->state.aos_count, start, end);
WARN_ONCE("Aeiee ! aos_count==0, while it shouldn't. Skipping rendering\n");
return;
}
-
+
render_inputs = rmesa->state.render_inputs;
if(!render_inputs){
}
//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",
+#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
-
-
+#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_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)
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)
fprintf(stderr, "%s\n", __FUNCTION__);
-
- #if 1 /* we need this, somehow */
+
+#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
+#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
-
+#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 */
+
+
+#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
-
-
-
+#endif
+
+
+
/* Magic register - note it is right after 20b0 */
-
+
if(rmesa->state.texture.tc_count>0){
reg_start(0x20b4,0);
e32(0x0000000c);
-
+
}
-
+
r300EmitState(rmesa);
-
- #if 0
+
+#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(0.0);
efloat(1.0);
- #endif
-
+#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, 0);
+ r300EmitAOS(rmesa, rmesa->state.aos_count, 0);
for(i=0; i < VB->PrimitiveCount; i++){
GLuint prim = VB->Primitive[i].mode;
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, int oec, int ec);
-
-# define R300_EB_UNK1_SHIFT 24
-# define R300_EB_UNK1 (0x80<<24)
-# define R300_EB_UNK2 0x0810
-
-unsigned long get_num_elts(unsigned long count)
-{
- unsigned long magic_1;
-
- /* round up elt count so that magic_1 is 0 (divisable by 4)*/
- return (count+3) & (~3);
- //return count - (count % 4);
-}
static void inline fire_EB(PREFIX unsigned long addr, int vertex_count, int type)
{
LOCAL_VARS
- unsigned long magic_1;
- unsigned char magic1_tbl[4]={ 0, 6, 4, 2 };
-
- magic_1 = magic1_tbl[vertex_count % 4];
-
- if(magic_1 != 0){
- WARN_ONCE("Dont know how to handle this yet!\n");
+ unsigned long addr_a;
+
+ if(addr & 1){
+ WARN_ONCE("Badly aligned buffer\n");
return ;
}
+ addr_a = 0; /*addr & 0x1c;*/
check_space(6);
start_packet3(RADEON_CP_PACKET3_3D_DRAW_INDX_2, 0);
+ /* TODO: R300_VAP_VF_CNTL__INDEX_SIZE_32bit . */
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);
+ e32(R300_EB_UNK1 | (addr_a << 16) | R300_EB_UNK2);
+ e32(addr /*& 0xffffffe3*/);
+ e32((vertex_count+1)/2 /*+ addr_a/4*/); /* Total number of dwords needed? */
}
-static void r300_render_vb_primitive(r300ContextPtr rmesa,
+static void r300_render_vb_primitive(r300ContextPtr rmesa,
GLcontext *ctx,
int start,
int end,
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");
+ r300EmitAOS(rmesa, rmesa->state.aos_count, 0);
+#if 0
+ start_index32_packet(num_verts, type);
+ for(i=0; i < num_verts; i++)
+ e32(rmesa->state.Elts[start+i]); /* start ? */
+#else
+ WARN_ONCE("Rendering with elt buffers\n");
+ if(num_verts == 1){
+ start_index32_packet(num_verts, type);
+ e32(rmesa->state.Elts[start]);
+ return;
+ }
- 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);
- fire_EB(PASS_PREFIX rsp->gartTextures.handle/*rmesa->state.elt_ao.aos_offset*/, elt_count, type);
- }else
+ if(num_verts > 65535){ /* not implemented yet */
+ WARN_ONCE("Too many elts\n");
+ return;
+ }
+ r300EmitElts(ctx, rmesa->state.Elts+start, num_verts);
+ fire_EB(PASS_PREFIX GET_START(&(rmesa->state.elt_dma)), num_verts, type);
+#endif
+ }else{
+ r300EmitAOS(rmesa, rmesa->state.aos_count, start);
fire_AOS(PASS_PREFIX num_verts, type);
+ }
}
static GLboolean r300_run_vb_render(GLcontext *ctx,
struct vertex_buffer *VB = &tnl->vb;
int i, j;
LOCAL_VARS
-
- if (RADEON_DEBUG == DEBUG_PRIMS)
+
+ if (RADEON_DEBUG & DEBUG_PRIMS)
fprintf(stderr, "%s\n", __FUNCTION__);
+
-
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);
+ r300EmitState(rmesa);
rmesa->state.Elts = VB->Elts;
GLuint prim = VB->Primitive[i].mode;
GLuint start = VB->Primitive[i].start;
GLuint length = VB->Primitive[i].count;
-
- r300EmitAOS(rmesa, rmesa->state.aos_count, start);
-
+
r300_render_vb_primitive(rmesa, ctx, start, start + length, prim);
}
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;
}
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
+
+
+#if 1
+
+#if 0
+ return r300_run_immediate_render(ctx, stage);
+#else
+ return r300_run_vb_render(ctx, stage);
+#endif
+#else
return GL_TRUE;
- #endif
+#endif
#if 0
mgaContextPtr mmesa = MGA_CONTEXT(ctx);
stage->active = GL_FALSE;
return;
}
-
- // 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.. */
+#if 0 /* These should work now.. */
+ FALLBACK_IF(ctx->Color.DitherFlag);
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.OffsetFill); // GL_POLYGON_OFFSET_FILL
+#endif
//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
+ //FALLBACK_IF(ctx->Fog.Enabled); // GL_FOG disable as swtcl doesnt seem to support this
+ //FALLBACK_IF(ctx->Polygon.SmoothFlag); // GL_POLYGON_SMOOTH disabling to get blender going
+ FALLBACK_IF(ctx->Polygon.StippleFlag); // GL_POLYGON_STIPPLE
+ FALLBACK_IF(ctx->Multisample.Enabled); // GL_MULTISAMPLE_ARB
+
+#if 0 /* ut2k3 fails to start if this is on */
/* One step at a time - let one texture pass.. */
for (i = 1; i < ctx->Const.MaxTextureUnits; i++)
FALLBACK_IF(ctx->Texture.Unit[i].Enabled);
-
+#endif
+
+ /* Assumed factor reg is found but pattern is still missing */
+ //FALLBACK_IF(ctx->Line.StippleFlag); // GL_LINE_STIPPLE disabling to get blender going
+
+ /* HW doesnt appear to directly support these */
+ //FALLBACK_IF(ctx->Line.SmoothFlag); // GL_LINE_SMOOTH disabling to get blender going
+ FALLBACK_IF(ctx->Point.SmoothFlag); // GL_POINT_SMOOTH
+ /* Rest could be done with vertex fragments */
+ if (ctx->Extensions.NV_point_sprite || ctx->Extensions.ARB_point_sprite)
+ FALLBACK_IF(ctx->Point.PointSprite); // GL_POINT_SPRITE_NV
+ //GL_POINT_DISTANCE_ATTENUATION_ARB
+ //GL_POINT_FADE_THRESHOLD_SIZE_ARB
+
/* let r300_run_render do its job */
- #if 0
+#if 0
stage->active = GL_FALSE;
- #endif
+#endif
}
r300_check_render, /* check */
r300_run_render /* run */
};
+
+static GLboolean r300_run_tcl_render(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)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ return r300_run_vb_render(ctx, stage);
+}
+
+static void r300_check_tcl_render(GLcontext *ctx, struct tnl_pipeline_stage *stage)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ int i;
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ /* We only support rendering in hardware for now */
+ if (ctx->RenderMode != GL_RENDER) {
+ stage->active = GL_FALSE;
+ return;
+ }
+ if(VERTPROG_ACTIVE(ctx)) {
+ stage->active = GL_TRUE;
+ stage->inputs = ctx->VertexProgram.Current->InputsRead;
+ } else {
+ stage->active = GL_FALSE;
+ }
+}
+
+const struct tnl_pipeline_stage _r300_tcl_stage = {
+ "r300 tcl",
+ _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_tcl_render, /* check */
+ r300_run_tcl_render /* run */
+};