#include "glheader.h"
#include "mtypes.h"
#include "colormac.h"
#include "enums.h"
#include "image.h"
#include "imports.h"
#include "macros.h"
#include "swrast/s_context.h"
#include "swrast/s_fog.h"
#include "swrast_setup/swrast_setup.h"
#include "math/m_translate.h"
#include "tnl/tnl.h"
#include "tnl/t_context.h"
#include "tnl/t_imm_exec.h"
#include "tnl/t_pipeline.h"
#include "r200_context.h"
#include "r200_ioctl.h"
#include "r200_state.h"
#include "r200_swtcl.h"
#include "r200_tcl.h"
#define R200_XYZW_BIT 0x01
#define R200_RGBA_BIT 0x02
#define R200_SPEC_BIT 0x04
#define R200_TEX0_BIT 0x08
#define R200_TEX1_BIT 0x10
#define R200_PTEX_BIT 0x20
#define R200_MAX_SETUP 0x40
static void flush_last_swtcl_prim( r200ContextPtr rmesa );
static struct {
void (*emit)( GLcontext *, GLuint, GLuint, void *, GLuint );
interp_func interp;
copy_pv_func copy_pv;
GLboolean (*check_tex_sizes)( GLcontext *ctx );
GLuint vertex_size;
GLuint vertex_stride_shift;
GLuint vertex_format;
} setup_tab[R200_MAX_SETUP];
static int se_vtx_fmt_0[] = {
0,
(R200_VTX_XY |
R200_VTX_Z0 |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_0_SHIFT)),
(R200_VTX_XY |
R200_VTX_Z0 |
R200_VTX_W0 |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_0_SHIFT) |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_1_SHIFT)),
(R200_VTX_XY |
R200_VTX_Z0 |
R200_VTX_W0 |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_0_SHIFT) |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_1_SHIFT)),
(R200_VTX_XY |
R200_VTX_Z0 |
R200_VTX_W0 |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_0_SHIFT) |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_1_SHIFT)),
(R200_VTX_XY |
R200_VTX_Z0 |
R200_VTX_W0 |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_0_SHIFT) |
(R200_VTX_PK_RGBA << R200_VTX_COLOR_1_SHIFT))
};
static int se_vtx_fmt_1[] = {
0,
0,
0,
((2 << R200_VTX_TEX0_COMP_CNT_SHIFT)),
((2 << R200_VTX_TEX0_COMP_CNT_SHIFT) |
(2 << R200_VTX_TEX1_COMP_CNT_SHIFT)),
((3 << R200_VTX_TEX0_COMP_CNT_SHIFT) |
(3 << R200_VTX_TEX1_COMP_CNT_SHIFT)),
};
#define TINY_VERTEX_FORMAT 1
#define NOTEX_VERTEX_FORMAT 2
#define TEX0_VERTEX_FORMAT 3
#define TEX1_VERTEX_FORMAT 4
#define PROJ_TEX1_VERTEX_FORMAT 5
#define TEX2_VERTEX_FORMAT 0
#define TEX3_VERTEX_FORMAT 0
#define PROJ_TEX3_VERTEX_FORMAT 0
#define DO_XYZW (IND & R200_XYZW_BIT)
#define DO_RGBA (IND & R200_RGBA_BIT)
#define DO_SPEC (IND & R200_SPEC_BIT)
#define DO_FOG (IND & R200_SPEC_BIT)
#define DO_TEX0 (IND & R200_TEX0_BIT)
#define DO_TEX1 (IND & R200_TEX1_BIT)
#define DO_TEX2 0
#define DO_TEX3 0
#define DO_PTEX (IND & R200_PTEX_BIT)
#define VERTEX r200Vertex
#define VERTEX_COLOR r200_color_t
#define GET_VIEWPORT_MAT() 0
#define GET_TEXSOURCE(n) n
#define GET_VERTEX_FORMAT() R200_CONTEXT(ctx)->swtcl.vertex_format
#define GET_VERTEX_STORE() R200_CONTEXT(ctx)->swtcl.verts
#define GET_VERTEX_STRIDE_SHIFT() R200_CONTEXT(ctx)->swtcl.vertex_stride_shift
#define GET_UBYTE_COLOR_STORE() &R200_CONTEXT(ctx)->UbyteColor
#define GET_UBYTE_SPEC_COLOR_STORE() &R200_CONTEXT(ctx)->UbyteSecondaryColor
#define HAVE_HW_VIEWPORT 1
#define HAVE_HW_DIVIDE (IND & ~(R200_XYZW_BIT|R200_RGBA_BIT))
#define HAVE_TINY_VERTICES 1
#define HAVE_RGBA_COLOR 1
#define HAVE_NOTEX_VERTICES 1
#define HAVE_TEX0_VERTICES 1
#define HAVE_TEX1_VERTICES 1
#define HAVE_TEX2_VERTICES 0
#define HAVE_TEX3_VERTICES 0
#define HAVE_PTEX_VERTICES 1
#define CHECK_HW_DIVIDE (!(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE| \
DD_TRI_UNFILLED)))
#define IMPORT_QUALIFIER
#define IMPORT_FLOAT_COLORS r200_import_float_colors
#define IMPORT_FLOAT_SPEC_COLORS r200_import_float_spec_colors
#define INTERP_VERTEX setup_tab[R200_CONTEXT(ctx)->swtcl.SetupIndex].interp
#define COPY_PV_VERTEX setup_tab[R200_CONTEXT(ctx)->swtcl.SetupIndex].copy_pv
#define TAG(x) r200_##x
#define IND ~0
#include "tnl_dd/t_dd_vb.c"
#undef IND
#define IND (R200_XYZW_BIT|R200_RGBA_BIT)
#define TAG(x) x##_wg
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_TEX0_BIT)
#define TAG(x) x##_wgt0
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_TEX0_BIT|R200_PTEX_BIT)
#define TAG(x) x##_wgpt0
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_TEX0_BIT|R200_TEX1_BIT)
#define TAG(x) x##_wgt0t1
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_TEX0_BIT|R200_TEX1_BIT|\
R200_PTEX_BIT)
#define TAG(x) x##_wgpt0t1
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_SPEC_BIT)
#define TAG(x) x##_wgfs
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_SPEC_BIT|\
R200_TEX0_BIT)
#define TAG(x) x##_wgfst0
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_SPEC_BIT|\
R200_TEX0_BIT|R200_PTEX_BIT)
#define TAG(x) x##_wgfspt0
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_SPEC_BIT|\
R200_TEX0_BIT|R200_TEX1_BIT)
#define TAG(x) x##_wgfst0t1
#include "tnl_dd/t_dd_vbtmp.h"
#define IND (R200_XYZW_BIT|R200_RGBA_BIT|R200_SPEC_BIT|\
R200_TEX0_BIT|R200_TEX1_BIT|R200_PTEX_BIT)
#define TAG(x) x##_wgfspt0t1
#include "tnl_dd/t_dd_vbtmp.h"
static void init_setup_tab( void )
{
init_wg();
init_wgt0();
init_wgpt0();
init_wgt0t1();
init_wgpt0t1();
init_wgfs();
init_wgfst0();
init_wgfspt0();
init_wgfst0t1();
init_wgfspt0t1();
}
void r200PrintSetupFlags(char *msg, GLuint flags )
{
fprintf(stderr, "%s(%x): %s%s%s%s%s%s\n",
msg,
(int)flags,
(flags & R200_XYZW_BIT) ? " xyzw," : "",
(flags & R200_RGBA_BIT) ? " rgba," : "",
(flags & R200_SPEC_BIT) ? " spec/fog," : "",
(flags & R200_TEX0_BIT) ? " tex-0," : "",
(flags & R200_TEX1_BIT) ? " tex-1," : "",
(flags & R200_PTEX_BIT) ? " proj-tex," : "");
}
static void r200SetVertexFormat( GLcontext *ctx, GLuint ind )
{
r200ContextPtr rmesa = R200_CONTEXT( ctx );
TNLcontext *tnl = TNL_CONTEXT(ctx);
rmesa->swtcl.SetupIndex = ind;
if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) {
tnl->Driver.Render.Interp = r200_interp_extras;
tnl->Driver.Render.CopyPV = r200_copy_pv_extras;
}
else {
tnl->Driver.Render.Interp = setup_tab[ind].interp;
tnl->Driver.Render.CopyPV = setup_tab[ind].copy_pv;
}
if (setup_tab[ind].vertex_format != rmesa->swtcl.vertex_format) {
int i;
R200_NEWPRIM(rmesa);
i = rmesa->swtcl.vertex_format = setup_tab[ind].vertex_format;
rmesa->swtcl.vertex_size = setup_tab[ind].vertex_size;
rmesa->swtcl.vertex_stride_shift = setup_tab[ind].vertex_stride_shift;
R200_STATECHANGE( rmesa, vtx );
rmesa->hw.vtx.cmd[VTX_VTXFMT_0] = se_vtx_fmt_0[i];
rmesa->hw.vtx.cmd[VTX_VTXFMT_1] = se_vtx_fmt_1[i];
}
{
GLuint vte = rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL];
GLuint vap = rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL];
GLuint needproj;
if (setup_tab[ind].vertex_format == TINY_VERTEX_FORMAT ||
(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) {
needproj = GL_TRUE;
vte |= R200_VTX_XY_FMT | R200_VTX_Z_FMT;
vte &= ~R200_VTX_W0_FMT;
vap |= R200_VAP_FORCE_W_TO_ONE;
}
else {
needproj = GL_FALSE;
vte &= ~(R200_VTX_XY_FMT | R200_VTX_Z_FMT);
vte |= R200_VTX_W0_FMT;
vap &= ~R200_VAP_FORCE_W_TO_ONE;
}
_tnl_need_projected_coords( ctx, needproj );
if (vte != rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL]) {
R200_STATECHANGE( rmesa, vte );
rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] = vte;
}
if (vap != rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL]) {
R200_STATECHANGE( rmesa, vap );
rmesa->hw.vap.cmd[VAP_SE_VAP_CNTL] = vap;
}
}
}
static void r200RenderStart( GLcontext *ctx )
{
r200ContextPtr rmesa = R200_CONTEXT( ctx );
if (!setup_tab[rmesa->swtcl.SetupIndex].check_tex_sizes(ctx)) {
r200SetVertexFormat( ctx, rmesa->swtcl.SetupIndex | R200_PTEX_BIT);
}
if (rmesa->dma.flush != 0 &&
rmesa->dma.flush != flush_last_swtcl_prim)
rmesa->dma.flush( rmesa );
}
void r200BuildVertices( GLcontext *ctx, GLuint start, GLuint count,
GLuint newinputs )
{
r200ContextPtr rmesa = R200_CONTEXT( ctx );
GLubyte *v = ((GLubyte *)rmesa->swtcl.verts +
(start << rmesa->swtcl.vertex_stride_shift));
GLuint stride = 1 << rmesa->swtcl.vertex_stride_shift;
newinputs |= rmesa->swtcl.SetupNewInputs;
rmesa->swtcl.SetupNewInputs = 0;
if (!newinputs)
return;
setup_tab[rmesa->swtcl.SetupIndex].emit( ctx, start, count, v, stride );
}
void r200ChooseVertexState( GLcontext *ctx )
{
r200ContextPtr rmesa = R200_CONTEXT( ctx );
GLuint ind = (R200_XYZW_BIT | R200_RGBA_BIT);
if (!rmesa->TclFallback || rmesa->Fallback)
return;
if (ctx->Fog.Enabled || (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR))
ind |= R200_SPEC_BIT;
if (ctx->Texture._EnabledUnits & 0x2)
ind |= R200_TEX0_BIT|R200_TEX1_BIT;
else if (ctx->Texture._EnabledUnits & 0x1)
ind |= R200_TEX0_BIT;
r200SetVertexFormat( ctx, ind );
}
static void flush_last_swtcl_prim( r200ContextPtr rmesa )
{
if (R200_DEBUG & DEBUG_IOCTL)
fprintf(stderr, "%s\n", __FUNCTION__);
rmesa->dma.flush = 0;
if (rmesa->dma.current.buf) {
struct r200_dma_region *current = &rmesa->dma.current;
GLuint current_offset = (rmesa->r200Screen->gart_buffer_offset +
current->buf->buf->idx * RADEON_BUFFER_SIZE +
current->start);
assert (!(rmesa->swtcl.hw_primitive & R200_VF_PRIM_WALK_IND));
assert (current->start +
rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 ==
current->ptr);
if (rmesa->dma.current.start != rmesa->dma.current.ptr) {
r200EmitVertexAOS( rmesa,
rmesa->swtcl.vertex_size,
current_offset);
r200EmitVbufPrim( rmesa,
rmesa->swtcl.hw_primitive,
rmesa->swtcl.numverts);
}
rmesa->swtcl.numverts = 0;
current->start = current->ptr;
}
}
static __inline void *r200AllocDmaLowVerts( r200ContextPtr rmesa,
int nverts, int vsize )
{
GLuint bytes = vsize * nverts;
if ( rmesa->dma.current.ptr + bytes > rmesa->dma.current.end )
r200RefillCurrentDmaRegion( rmesa );
if (!rmesa->dma.flush) {
rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES;
rmesa->dma.flush = flush_last_swtcl_prim;
}
ASSERT( vsize == rmesa->swtcl.vertex_size * 4 );
ASSERT( rmesa->dma.flush == flush_last_swtcl_prim );
ASSERT( rmesa->dma.current.start +
rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 ==
rmesa->dma.current.ptr );
{
GLubyte *head = (GLubyte *) (rmesa->dma.current.address + rmesa->dma.current.ptr);
rmesa->dma.current.ptr += bytes;
rmesa->swtcl.numverts += nverts;
return head;
}
}
void r200_emit_contiguous_verts( GLcontext *ctx, GLuint start, GLuint count )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
GLuint vertex_size = rmesa->swtcl.vertex_size * 4;
CARD32 *dest = r200AllocDmaLowVerts( rmesa, count-start, vertex_size );
setup_tab[rmesa->swtcl.SetupIndex].emit( ctx, start, count, dest,
vertex_size );
}
void r200_emit_indexed_verts( GLcontext *ctx, GLuint start, GLuint count )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
r200AllocDmaRegionVerts( rmesa,
&rmesa->swtcl.indexed_verts,
count - start,
rmesa->swtcl.vertex_size * 4,
64);
setup_tab[rmesa->swtcl.SetupIndex].emit(
ctx, start, count,
rmesa->swtcl.indexed_verts.address + rmesa->swtcl.indexed_verts.start,
rmesa->swtcl.vertex_size * 4 );
}
#define HAVE_POINTS 1
#define HAVE_LINES 1
#define HAVE_LINE_STRIPS 1
#define HAVE_TRIANGLES 1
#define HAVE_TRI_STRIPS 1
#define HAVE_TRI_STRIP_1 0
#define HAVE_TRI_FANS 1
#define HAVE_QUADS 1
#define HAVE_QUAD_STRIPS 1
#define HAVE_POLYGONS 1
#define HAVE_ELTS 1
static const GLuint hw_prim[GL_POLYGON+1] = {
R200_VF_PRIM_POINTS,
R200_VF_PRIM_LINES,
0,
R200_VF_PRIM_LINE_STRIP,
R200_VF_PRIM_TRIANGLES,
R200_VF_PRIM_TRIANGLE_STRIP,
R200_VF_PRIM_TRIANGLE_FAN,
R200_VF_PRIM_QUADS,
R200_VF_PRIM_QUAD_STRIP,
R200_VF_PRIM_POLYGON
};
static __inline void r200DmaPrimitive( r200ContextPtr rmesa, GLenum prim )
{
R200_NEWPRIM( rmesa );
rmesa->swtcl.hw_primitive = hw_prim[prim];
assert(rmesa->dma.current.ptr == rmesa->dma.current.start);
}
static __inline void r200EltPrimitive( r200ContextPtr rmesa, GLenum prim )
{
R200_NEWPRIM( rmesa );
rmesa->swtcl.hw_primitive = hw_prim[prim] | R200_VF_PRIM_WALK_IND;
}
static void VERT_FALLBACK( GLcontext *ctx,
GLuint start,
GLuint count,
GLuint flags )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
tnl->Driver.Render.PrimitiveNotify( ctx, flags & PRIM_MODE_MASK );
tnl->Driver.Render.BuildVertices( ctx, start, count, ~0 );
tnl->Driver.Render.PrimTabVerts[flags&PRIM_MODE_MASK]( ctx, start, count, flags );
R200_CONTEXT(ctx)->swtcl.SetupNewInputs = VERT_BIT_CLIP;
}
static void ELT_FALLBACK( GLcontext *ctx,
GLuint start,
GLuint count,
GLuint flags )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
tnl->Driver.Render.PrimitiveNotify( ctx, flags & PRIM_MODE_MASK );
tnl->Driver.Render.BuildVertices( ctx, start, count, ~0 );
tnl->Driver.Render.PrimTabElts[flags&PRIM_MODE_MASK]( ctx, start, count, flags );
R200_CONTEXT(ctx)->swtcl.SetupNewInputs = VERT_BIT_CLIP;
}
#define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx)
#define ELTS_VARS GLushort *dest
#define INIT( prim ) r200DmaPrimitive( rmesa, prim )
#define ELT_INIT(prim) r200EltPrimitive( rmesa, prim )
#define NEW_PRIMITIVE() R200_NEWPRIM( rmesa )
#define NEW_BUFFER() r200RefillCurrentDmaRegion( rmesa )
#define GET_CURRENT_VB_MAX_VERTS() \
(((int)rmesa->dma.current.end - (int)rmesa->dma.current.ptr) / (rmesa->swtcl.vertex_size*4))
#define GET_SUBSEQUENT_VB_MAX_VERTS() \
((RADEON_BUFFER_SIZE) / (rmesa->swtcl.vertex_size*4))
#define GET_CURRENT_VB_MAX_ELTS() \
((R200_CMD_BUF_SZ - (rmesa->store.cmd_used + 16)) / 2)
#define GET_SUBSEQUENT_VB_MAX_ELTS() \
((R200_CMD_BUF_SZ - 1024) / 2)
#define ALLOC_ELTS(nr) \
do { \
if (rmesa->dma.flush == r200FlushElts && \
rmesa->store.cmd_used + nr*2 < R200_CMD_BUF_SZ) { \
\
dest = (GLushort *)(rmesa->store.cmd_buf + \
rmesa->store.cmd_used); \
rmesa->store.cmd_used += nr*2; \
} \
else { \
if (rmesa->dma.flush) { \
rmesa->dma.flush( rmesa ); \
} \
\
r200EmitVertexAOS( rmesa, \
rmesa->swtcl.vertex_size, \
(rmesa->r200Screen->gart_buffer_offset + \
rmesa->swtcl.indexed_verts.buf->buf->idx * \
RADEON_BUFFER_SIZE + \
rmesa->swtcl.indexed_verts.start)); \
\
dest = r200AllocEltsOpenEnded( rmesa, \
rmesa->swtcl.hw_primitive, \
nr ); \
} \
} while (0)
#define ALLOC_ELTS_NEW_PRIMITIVE(nr) ALLOC_ELTS( nr )
#ifdef MESA_BIG_ENDIAN
#define EMIT_ELT(offset, x) do { \
int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \
GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \
(des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0)
#else
#define EMIT_ELT(offset, x) (dest)[offset] = (GLushort) (x)
#endif
#define EMIT_TWO_ELTS(offset, x, y) *(GLuint *)(dest+offset) = ((y)<<16)|(x);
#define INCR_ELTS( nr ) dest += nr
#define RELEASE_ELT_VERTS() \
r200ReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts, __FUNCTION__ )
#define EMIT_VERTS( ctx, j, nr ) \
r200_emit_contiguous_verts(ctx, j, (j)+(nr))
#define EMIT_INDEXED_VERTS( ctx, start, count ) \
r200_emit_indexed_verts( ctx, start, count )
#define TAG(x) r200_dma_##x
#include "tnl_dd/t_dd_dmatmp.h"
static GLboolean r200_run_render( GLcontext *ctx,
struct gl_pipeline_stage *stage )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
GLuint i, length, flags = 0;
render_func *tab = TAG(render_tab_verts);
if (rmesa->swtcl.indexed_verts.buf && (!VB->Elts || stage->changed_inputs))
RELEASE_ELT_VERTS();
if ((R200_DEBUG & DEBUG_VERTS) ||
VB->ClipOrMask ||
rmesa->swtcl.RenderIndex != 0 ||
ctx->Line.StippleFlag)
return GL_TRUE;
if (VB->Elts) {
tab = TAG(render_tab_elts);
if (!rmesa->swtcl.indexed_verts.buf)
if (!TAG(emit_elt_verts)(ctx, 0, VB->Count))
return GL_TRUE;
}
tnl->Driver.Render.Start( ctx );
for (i = 0 ; !(flags & PRIM_LAST) ; i += length)
{
flags = VB->Primitive[i];
length = VB->PrimitiveLength[i];
if (R200_DEBUG & DEBUG_PRIMS)
fprintf(stderr, "r200_render.c: prim %s %d..%d\n",
_mesa_lookup_enum_by_nr(flags & PRIM_MODE_MASK),
i, i+length);
if (length)
tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags );
}
tnl->Driver.Render.Finish( ctx );
return GL_FALSE;
}
static void r200_check_render( GLcontext *ctx,
struct gl_pipeline_stage *stage )
{
GLuint inputs = VERT_BIT_POS | VERT_BIT_CLIP | VERT_BIT_COLOR0;
if (ctx->RenderMode == GL_RENDER) {
if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)
inputs |= VERT_BIT_COLOR1;
if (ctx->Texture.Unit[0]._ReallyEnabled)
inputs |= VERT_BIT_TEX0;
if (ctx->Texture.Unit[1]._ReallyEnabled)
inputs |= VERT_BIT_TEX1;
if (ctx->Fog.Enabled)
inputs |= VERT_BIT_FOG;
}
stage->inputs = inputs;
}
static void dtr( struct gl_pipeline_stage *stage )
{
(void)stage;
}
const struct gl_pipeline_stage _r200_render_stage =
{
"r200 render",
(_DD_NEW_SEPARATE_SPECULAR |
_NEW_TEXTURE|
_NEW_FOG|
_NEW_RENDERMODE),
0,
GL_TRUE,
0, 0,
0, 0,
dtr,
r200_check_render,
r200_run_render
};
static const GLuint reduced_hw_prim[GL_POLYGON+1] = {
R200_VF_PRIM_POINTS,
R200_VF_PRIM_LINES,
R200_VF_PRIM_LINES,
R200_VF_PRIM_LINES,
R200_VF_PRIM_TRIANGLES,
R200_VF_PRIM_TRIANGLES,
R200_VF_PRIM_TRIANGLES,
R200_VF_PRIM_TRIANGLES,
R200_VF_PRIM_TRIANGLES,
R200_VF_PRIM_TRIANGLES
};
static void r200RasterPrimitive( GLcontext *ctx, GLuint hwprim );
static void r200RenderPrimitive( GLcontext *ctx, GLenum prim );
static void r200ResetLineStipple( GLcontext *ctx );
#undef HAVE_QUADS
#define HAVE_QUADS 0
#undef HAVE_QUAD_STRIPS
#define HAVE_QUAD_STRIPS 0
#undef LOCAL_VARS
#define CTX_ARG r200ContextPtr rmesa
#define CTX_ARG2 rmesa
#define GET_VERTEX_DWORDS() rmesa->swtcl.vertex_size
#define ALLOC_VERTS( n, size ) r200AllocDmaLowVerts( rmesa, n, size * 4 )
#define LOCAL_VARS \
r200ContextPtr rmesa = R200_CONTEXT(ctx); \
const GLuint shift = rmesa->swtcl.vertex_stride_shift; \
const char *r200verts = (char *)rmesa->swtcl.verts;
#define VERT(x) (r200Vertex *)(r200verts + (x << shift))
#define VERTEX r200Vertex
#define DO_DEBUG_VERTS (1 && (R200_DEBUG & DEBUG_VERTS))
#define PRINT_VERTEX(v) r200_print_vertex(rmesa->glCtx, v)
#undef TAG
#define TAG(x) r200_##x
#include "tnl_dd/t_dd_triemit.h"
#define QUAD( a, b, c, d ) r200_quad( rmesa, a, b, c, d )
#define TRI( a, b, c ) r200_triangle( rmesa, a, b, c )
#define LINE( a, b ) r200_line( rmesa, a, b )
#define POINT( a ) r200_point( rmesa, a )
#define R200_TWOSIDE_BIT 0x01
#define R200_UNFILLED_BIT 0x02
#define R200_MAX_TRIFUNC 0x04
static struct {
points_func points;
line_func line;
triangle_func triangle;
quad_func quad;
} rast_tab[R200_MAX_TRIFUNC];
#define DO_FALLBACK 0
#define DO_UNFILLED (IND & R200_UNFILLED_BIT)
#define DO_TWOSIDE (IND & R200_TWOSIDE_BIT)
#define DO_FLAT 0
#define DO_OFFSET 0
#define DO_TRI 1
#define DO_QUAD 1
#define DO_LINE 1
#define DO_POINTS 1
#define DO_FULL_QUAD 1
#define HAVE_RGBA 1
#define HAVE_SPEC 1
#define HAVE_INDEX 0
#define HAVE_BACK_COLORS 0
#define HAVE_HW_FLATSHADE 1
#define TAB rast_tab
#define DEPTH_SCALE 1.0
#define UNFILLED_TRI unfilled_tri
#define UNFILLED_QUAD unfilled_quad
#define VERT_X(_v) _v->v.x
#define VERT_Y(_v) _v->v.y
#define VERT_Z(_v) _v->v.z
#define AREA_IS_CCW( a ) (a < 0)
#define GET_VERTEX(e) (rmesa->swtcl.verts + (e<<rmesa->swtcl.vertex_stride_shift))
#define VERT_SET_RGBA( v, c ) v->ui[coloroffset] = LE32_TO_CPU(*(GLuint *)c)
#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset]
#define VERT_SAVE_RGBA( idx ) color[idx] = CPU_TO_LE32(v[idx]->ui[coloroffset])
#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = LE32_TO_CPU(color[idx])
#define VERT_SET_SPEC( v0, c ) if (havespec) { \
v0->v.specular.red = (c)[0]; \
v0->v.specular.green = (c)[1]; \
v0->v.specular.blue = (c)[2]; }
#define VERT_COPY_SPEC( v0, v1 ) if (havespec) { \
v0->v.specular.red = v1->v.specular.red; \
v0->v.specular.green = v1->v.specular.green; \
v0->v.specular.blue = v1->v.specular.blue; }
#define VERT_SAVE_SPEC( idx ) if (havespec) spec[idx] = CPU_TO_LE32(v[idx]->ui[5])
#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[5] = LE32_TO_CPU(spec[idx])
#undef LOCAL_VARS
#undef TAG
#undef INIT
#define LOCAL_VARS(n) \
r200ContextPtr rmesa = R200_CONTEXT(ctx); \
GLuint color[n], spec[n]; \
GLuint coloroffset = (rmesa->swtcl.vertex_size == 4 ? 3 : 4); \
GLboolean havespec = (rmesa->swtcl.vertex_size > 4); \
(void) color; (void) spec; (void) coloroffset; (void) havespec;
#define RASTERIZE(x) r200RasterPrimitive( ctx, reduced_hw_prim[x] )
#define RENDER_PRIMITIVE rmesa->swtcl.render_primitive
#undef TAG
#define TAG(x) x
#include "tnl_dd/t_dd_unfilled.h"
#undef IND
#define IND (0)
#define TAG(x) x
#include "tnl_dd/t_dd_tritmp.h"
#define IND (R200_TWOSIDE_BIT)
#define TAG(x) x##_twoside
#include "tnl_dd/t_dd_tritmp.h"
#define IND (R200_UNFILLED_BIT)
#define TAG(x) x##_unfilled
#include "tnl_dd/t_dd_tritmp.h"
#define IND (R200_TWOSIDE_BIT|R200_UNFILLED_BIT)
#define TAG(x) x##_twoside_unfilled
#include "tnl_dd/t_dd_tritmp.h"
static void init_rast_tab( void )
{
init();
init_twoside();
init_unfilled();
init_twoside_unfilled();
}
#define VERT(x) (r200Vertex *)(r200verts + (x << shift))
#define RENDER_POINTS( start, count ) \
for ( ; start < count ; start++) \
r200_point( rmesa, VERT(start) )
#define RENDER_LINE( v0, v1 ) \
r200_line( rmesa, VERT(v0), VERT(v1) )
#define RENDER_TRI( v0, v1, v2 ) \
r200_triangle( rmesa, VERT(v0), VERT(v1), VERT(v2) )
#define RENDER_QUAD( v0, v1, v2, v3 ) \
r200_quad( rmesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) )
#define INIT(x) do { \
r200RenderPrimitive( ctx, x ); \
} while (0)
#undef LOCAL_VARS
#define LOCAL_VARS \
r200ContextPtr rmesa = R200_CONTEXT(ctx); \
const GLuint shift = rmesa->swtcl.vertex_stride_shift; \
const char *r200verts = (char *)rmesa->swtcl.verts; \
const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \
const GLboolean stipple = ctx->Line.StippleFlag; \
(void) elt; (void) stipple;
#define RESET_STIPPLE if ( stipple ) r200ResetLineStipple( ctx );
#define RESET_OCCLUSION
#define PRESERVE_VB_DEFS
#define ELT(x) (x)
#define TAG(x) r200_##x##_verts
#include "tnl/t_vb_rendertmp.h"
#undef ELT
#undef TAG
#define TAG(x) r200_##x##_elts
#define ELT(x) elt[x]
#include "tnl/t_vb_rendertmp.h"
void r200ChooseRenderState( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
r200ContextPtr rmesa = R200_CONTEXT(ctx);
GLuint index = 0;
GLuint flags = ctx->_TriangleCaps;
if (!rmesa->TclFallback || rmesa->Fallback)
return;
if (flags & DD_TRI_LIGHT_TWOSIDE) index |= R200_TWOSIDE_BIT;
if (flags & DD_TRI_UNFILLED) index |= R200_UNFILLED_BIT;
if (index != rmesa->swtcl.RenderIndex) {
tnl->Driver.Render.Points = rast_tab[index].points;
tnl->Driver.Render.Line = rast_tab[index].line;
tnl->Driver.Render.ClippedLine = rast_tab[index].line;
tnl->Driver.Render.Triangle = rast_tab[index].triangle;
tnl->Driver.Render.Quad = rast_tab[index].quad;
if (index == 0) {
tnl->Driver.Render.PrimTabVerts = r200_render_tab_verts;
tnl->Driver.Render.PrimTabElts = r200_render_tab_elts;
tnl->Driver.Render.ClippedPolygon = r200_fast_clipped_poly;
} else {
tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts;
tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts;
tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon;
}
rmesa->swtcl.RenderIndex = index;
}
}
static void r200RasterPrimitive( GLcontext *ctx, GLuint hwprim )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
if (rmesa->swtcl.hw_primitive != hwprim) {
R200_NEWPRIM( rmesa );
rmesa->swtcl.hw_primitive = hwprim;
}
}
static void r200RenderPrimitive( GLcontext *ctx, GLenum prim )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
rmesa->swtcl.render_primitive = prim;
if (prim < GL_TRIANGLES || !(ctx->_TriangleCaps & DD_TRI_UNFILLED))
r200RasterPrimitive( ctx, reduced_hw_prim[prim] );
}
static void r200RenderFinish( GLcontext *ctx )
{
}
static void r200ResetLineStipple( GLcontext *ctx )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
R200_STATECHANGE( rmesa, lin );
}
static const char * const fallbackStrings[] = {
"Texture mode",
"glDrawBuffer(GL_FRONT_AND_BACK)",
"glEnable(GL_STENCIL) without hw stencil buffer",
"glRenderMode(selection or feedback)",
"glBlendEquation",
"glBlendFunc(mode != ADD)",
"R200_NO_RAST",
"Mixing GL_CLAMP_TO_BORDER and GL_CLAMP (or GL_MIRROR_CLAMP_ATI)"
};
static const char *getFallbackString(GLuint bit)
{
int i = 0;
while (bit > 1) {
i++;
bit >>= 1;
}
return fallbackStrings[i];
}
void r200Fallback( GLcontext *ctx, GLuint bit, GLboolean mode )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
GLuint oldfallback = rmesa->Fallback;
if (mode) {
rmesa->Fallback |= bit;
if (oldfallback == 0) {
R200_FIREVERTICES( rmesa );
TCL_FALLBACK( ctx, R200_TCL_FALLBACK_RASTER, GL_TRUE );
_swsetup_Wakeup( ctx );
_tnl_need_projected_coords( ctx, GL_TRUE );
rmesa->swtcl.RenderIndex = ~0;
if (R200_DEBUG & DEBUG_FALLBACKS) {
fprintf(stderr, "R200 begin rasterization fallback: 0x%x %s\n",
bit, getFallbackString(bit));
}
}
}
else {
rmesa->Fallback &= ~bit;
if (oldfallback == bit) {
_swrast_flush( ctx );
tnl->Driver.Render.Start = r200RenderStart;
tnl->Driver.Render.PrimitiveNotify = r200RenderPrimitive;
tnl->Driver.Render.Finish = r200RenderFinish;
tnl->Driver.Render.BuildVertices = r200BuildVertices;
tnl->Driver.Render.ResetLineStipple = r200ResetLineStipple;
TCL_FALLBACK( ctx, R200_TCL_FALLBACK_RASTER, GL_FALSE );
if (rmesa->TclFallback) {
r200ChooseVertexState( ctx );
r200ChooseRenderState( ctx );
}
if (R200_DEBUG & DEBUG_FALLBACKS) {
fprintf(stderr, "R200 end rasterization fallback: 0x%x %s\n",
bit, getFallbackString(bit));
}
}
}
}
void
r200PointsBitmap( GLcontext *ctx, GLint px, GLint py,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLubyte *bitmap )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
const GLfloat *rc = ctx->Current.RasterColor;
GLint row, col;
r200Vertex vert;
GLuint orig_vte;
GLuint h;
TCL_FALLBACK( ctx, R200_TCL_FALLBACK_BITMAP, 1 );
r200SetVertexFormat( ctx, R200_XYZW_BIT | R200_RGBA_BIT );
r200RenderPrimitive( ctx, GL_POINTS );
R200_STATECHANGE( rmesa, vte );
orig_vte = rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL];
rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] &= ~(R200_VPORT_X_SCALE_ENA |
R200_VPORT_Y_SCALE_ENA |
R200_VPORT_Z_SCALE_ENA |
R200_VPORT_X_OFFSET_ENA |
R200_VPORT_Y_OFFSET_ENA |
R200_VPORT_Z_OFFSET_ENA);
if (ctx->Fog.Enabled) {
const GLfloat *fc = ctx->Fog.Color;
GLfloat color[4];
GLfloat f;
if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
f = _mesa_z_to_fogfactor(ctx, ctx->Current.Attrib[VERT_ATTRIB_FOG][0]);
else
f = _mesa_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
color[0] = f * rc[0] + (1.F - f) * fc[0];
color[1] = f * rc[1] + (1.F - f) * fc[1];
color[2] = f * rc[2] + (1.F - f) * fc[2];
color[3] = rc[3];
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.red, color[0]);
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.green, color[1]);
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.blue, color[2]);
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.alpha, color[3]);
}
else {
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.red, rc[0]);
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.green, rc[1]);
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.blue, rc[2]);
UNCLAMPED_FLOAT_TO_CHAN(vert.tv.color.alpha, rc[3]);
}
vert.tv.z = ctx->Current.RasterPos[2];
LOCK_HARDWARE( rmesa );
UNLOCK_HARDWARE( rmesa );
h = rmesa->dri.drawable->h + rmesa->dri.drawable->y;
px += rmesa->dri.drawable->x;
for (row=0; row<height; row++) {
const GLubyte *src = (const GLubyte *)
_mesa_image_address( unpack, bitmap, width, height,
GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 );
if (unpack->LsbFirst) {
GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
for (col=0; col<width; col++) {
if (*src & mask) {
vert.tv.x = px+col;
vert.tv.y = h - (py+row) - 1;
r200_point( rmesa, &vert );
}
src += (mask >> 7);
mask = ((mask << 1) & 0xff) | (mask >> 7);
}
if (mask != 1)
src++;
}
else {
GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
for (col=0; col<width; col++) {
if (*src & mask) {
vert.tv.x = px+col;
vert.tv.y = h - (py+row) - 1;
r200_point( rmesa, &vert );
}
src += mask & 1;
mask = ((mask << 7) & 0xff) | (mask >> 1);
}
if (mask != 128)
src++;
}
}
R200_STATECHANGE( rmesa, vte );
rmesa->hw.vte.cmd[VTE_SE_VTE_CNTL] = orig_vte;
TCL_FALLBACK( ctx, R200_TCL_FALLBACK_BITMAP, 0 );
if (rmesa->TclFallback)
r200ChooseVertexState( ctx );
}
void r200FlushVertices( GLcontext *ctx, GLuint flags )
{
_tnl_flush_vertices( ctx, flags );
if (flags & FLUSH_STORED_VERTICES)
R200_NEWPRIM( R200_CONTEXT( ctx ) );
}
void r200InitSwtcl( GLcontext *ctx )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
r200ContextPtr rmesa = R200_CONTEXT(ctx);
GLuint size = TNL_CONTEXT(ctx)->vb.Size;
static int firsttime = 1;
if (firsttime) {
init_rast_tab();
init_setup_tab();
firsttime = 0;
}
tnl->Driver.Render.Start = r200RenderStart;
tnl->Driver.Render.Finish = r200RenderFinish;
tnl->Driver.Render.PrimitiveNotify = r200RenderPrimitive;
tnl->Driver.Render.ResetLineStipple = r200ResetLineStipple;
tnl->Driver.Render.BuildVertices = r200BuildVertices;
rmesa->swtcl.verts = (GLubyte *)ALIGN_MALLOC( size * 16 * 4, 32 );
rmesa->swtcl.RenderIndex = ~0;
rmesa->swtcl.render_primitive = GL_TRIANGLES;
rmesa->swtcl.hw_primitive = 0;
}
void r200DestroySwtcl( GLcontext *ctx )
{
r200ContextPtr rmesa = R200_CONTEXT(ctx);
if (rmesa->swtcl.indexed_verts.buf)
r200ReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts, __FUNCTION__ );
if (rmesa->swtcl.verts) {
ALIGN_FREE(rmesa->swtcl.verts);
rmesa->swtcl.verts = 0;
}
if (rmesa->UbyteSecondaryColor.Ptr) {
ALIGN_FREE(rmesa->UbyteSecondaryColor.Ptr);
rmesa->UbyteSecondaryColor.Ptr = 0;
}
if (rmesa->UbyteColor.Ptr) {
ALIGN_FREE(rmesa->UbyteColor.Ptr);
rmesa->UbyteColor.Ptr = 0;
}
}