/* * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include "glheader.h" #include "context.h" #include "mtypes.h" #include "macros.h" #include "colormac.h" #include "enums.h" #include "swrast/swrast.h" #include "swrast_setup/swrast_setup.h" #include "tnl/t_context.h" #include "tnl/t_pipeline.h" #include "via_context.h" #include "via_tris.h" #include "via_state.h" #include "via_span.h" #include "via_ioctl.h" #include "via_3d_reg.h" #include "via_tex.h" /*********************************************************************** * Emit primitives as inline vertices * ***********************************************************************/ #define LINE_FALLBACK (0) #define POINT_FALLBACK (0) #define TRI_FALLBACK (0) #define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK) #define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED) #if 0 #define COPY_DWORDS(vb, vertsize, v) \ do { \ via_sse_memcpy(vb, v, vertsize * 4); \ vb += vertsize; \ } while (0) #else #if defined( USE_X86_ASM ) #define COPY_DWORDS(vb, vertsize, v) \ do { \ int j; \ int __tmp; \ __asm__ __volatile__("rep ; movsl" \ : "=%c" (j), "=D" (vb), "=S" (__tmp) \ : "0" (vertsize), \ "D" ((long)vb), \ "S" ((long)v)); \ } while (0) #else #define COPY_DWORDS(vb, vertsize, v) \ do { \ int j; \ for (j = 0; j < vertsize; j++) \ vb[j] = ((GLuint *)v)[j]; \ vb += vertsize; \ } while (0) #endif #endif static void via_draw_triangle(struct via_context *vmesa, viaVertexPtr v0, viaVertexPtr v1, viaVertexPtr v2) { GLuint vertsize = vmesa->vertexSize; GLuint *vb = viaExtendPrimitive(vmesa, 3 * 4 * vertsize); COPY_DWORDS(vb, vertsize, v0); COPY_DWORDS(vb, vertsize, v1); COPY_DWORDS(vb, vertsize, v2); } static void via_draw_quad(struct via_context *vmesa, viaVertexPtr v0, viaVertexPtr v1, viaVertexPtr v2, viaVertexPtr v3) { GLuint vertsize = vmesa->vertexSize; GLuint *vb = viaExtendPrimitive(vmesa, 6 * 4 * vertsize); COPY_DWORDS(vb, vertsize, v0); COPY_DWORDS(vb, vertsize, v1); COPY_DWORDS(vb, vertsize, v3); COPY_DWORDS(vb, vertsize, v1); COPY_DWORDS(vb, vertsize, v2); COPY_DWORDS(vb, vertsize, v3); } static void via_draw_line(struct via_context *vmesa, viaVertexPtr v0, viaVertexPtr v1) { GLuint vertsize = vmesa->vertexSize; GLuint *vb = viaExtendPrimitive(vmesa, 2 * 4 * vertsize); COPY_DWORDS(vb, vertsize, v0); COPY_DWORDS(vb, vertsize, v1); } static void via_draw_point(struct via_context *vmesa, viaVertexPtr v0) { GLuint vertsize = vmesa->vertexSize; GLuint *vb = viaExtendPrimitive(vmesa, 4 * vertsize); COPY_DWORDS(vb, vertsize, v0); } /* Fallback drawing functions for the ptex hack. */ #define PTEX_VERTEX( tmp, vertex_size, v) \ do { \ GLuint j; \ GLfloat rhw = 1.0 / v->f[vertex_size]; \ for ( j = 0 ; j < vertex_size ; j++ ) \ tmp.f[j] = v->f[j]; \ tmp.f[3] *= v->f[vertex_size]; \ tmp.f[vertex_size-2] *= rhw; \ tmp.f[vertex_size-1] *= rhw; \ } while (0) static void via_ptex_tri (struct via_context *vmesa, viaVertexPtr v0, viaVertexPtr v1, viaVertexPtr v2) { GLuint vertsize = vmesa->hwVertexSize; GLuint *vb = viaExtendPrimitive(vmesa, 3*4*vertsize); viaVertex tmp; PTEX_VERTEX(tmp, vertsize, v0); COPY_DWORDS(vb, vertsize, &tmp); PTEX_VERTEX(tmp, vertsize, v1); COPY_DWORDS(vb, vertsize, &tmp); PTEX_VERTEX(tmp, vertsize, v2); COPY_DWORDS(vb, vertsize, &tmp); } static void via_ptex_line (struct via_context *vmesa, viaVertexPtr v0, viaVertexPtr v1) { GLuint vertsize = vmesa->hwVertexSize; GLuint *vb = viaExtendPrimitive(vmesa, 2*4*vertsize); viaVertex tmp; PTEX_VERTEX(tmp, vertsize, v0); COPY_DWORDS(vb, vertsize, &tmp); PTEX_VERTEX(tmp, vertsize, v1); COPY_DWORDS(vb, vertsize, &tmp); } static void via_ptex_point (struct via_context *vmesa, viaVertexPtr v0) { GLuint vertsize = vmesa->hwVertexSize; GLuint *vb = viaExtendPrimitive(vmesa, 1*4*vertsize); viaVertex tmp; PTEX_VERTEX(tmp, vertsize, v0); COPY_DWORDS(vb, vertsize, &tmp); } /*********************************************************************** * Macros for via_dd_tritmp.h to draw basic primitives * ***********************************************************************/ #define TRI(a, b, c) \ do { \ if (DO_FALLBACK) \ vmesa->drawTri(vmesa, a, b, c); \ else \ via_draw_triangle(vmesa, a, b, c); \ } while (0) #define QUAD(a, b, c, d) \ do { \ if (DO_FALLBACK) { \ vmesa->drawTri(vmesa, a, b, d); \ vmesa->drawTri(vmesa, b, c, d); \ } \ else \ via_draw_quad(vmesa, a, b, c, d); \ } while (0) #define LINE(v0, v1) \ do { \ if (DO_FALLBACK) \ vmesa->drawLine(vmesa, v0, v1); \ else \ via_draw_line(vmesa, v0, v1); \ } while (0) #define POINT(v0) \ do { \ if (DO_FALLBACK) \ vmesa->drawPoint(vmesa, v0); \ else \ via_draw_point(vmesa, v0); \ } while (0) /*********************************************************************** * Build render functions from dd templates * ***********************************************************************/ #define VIA_OFFSET_BIT 0x01 #define VIA_TWOSIDE_BIT 0x02 #define VIA_UNFILLED_BIT 0x04 #define VIA_FALLBACK_BIT 0x08 #define VIA_MAX_TRIFUNC 0x10 static struct { tnl_points_func points; tnl_line_func line; tnl_triangle_func triangle; tnl_quad_func quad; } rast_tab[VIA_MAX_TRIFUNC + 1]; #define DO_FALLBACK (IND & VIA_FALLBACK_BIT) #define DO_OFFSET (IND & VIA_OFFSET_BIT) #define DO_UNFILLED (IND & VIA_UNFILLED_BIT) #define DO_TWOSIDE (IND & VIA_TWOSIDE_BIT) #define DO_FLAT 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_BACK_COLORS 0 #define HAVE_HW_FLATSHADE 1 #define VERTEX viaVertex #define TAB rast_tab /* Only used to pull back colors into vertices (ie, we know color is * floating point). */ #define VIA_COLOR(dst, src) \ do { \ dst[0] = src[2]; \ dst[1] = src[1]; \ dst[2] = src[0]; \ dst[3] = src[3]; \ } while (0) #define VIA_SPEC(dst, src) \ do { \ dst[0] = src[2]; \ dst[1] = src[1]; \ dst[2] = src[0]; \ } while (0) #define DEPTH_SCALE vmesa->polygon_offset_scale #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) (vmesa->verts + (e * vmesa->vertexSize * sizeof(int))) #define VERT_SET_RGBA( v, c ) \ do { \ via_color_t *color = (via_color_t *)&((v)->ui[coloroffset]); \ UNCLAMPED_FLOAT_TO_UBYTE(color->red, (c)[0]); \ UNCLAMPED_FLOAT_TO_UBYTE(color->green, (c)[1]); \ UNCLAMPED_FLOAT_TO_UBYTE(color->blue, (c)[2]); \ UNCLAMPED_FLOAT_TO_UBYTE(color->alpha, (c)[3]); \ } while (0) #define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset] #define VERT_SET_SPEC( v, c ) \ do { \ if (specoffset) { \ via_color_t *color = (via_color_t *)&((v)->ui[specoffset]); \ UNCLAMPED_FLOAT_TO_UBYTE(color->red, (c)[0]); \ UNCLAMPED_FLOAT_TO_UBYTE(color->green, (c)[1]); \ UNCLAMPED_FLOAT_TO_UBYTE(color->blue, (c)[2]); \ } \ } while (0) #define VERT_COPY_SPEC( v0, v1 ) \ do { \ if (specoffset) { \ v0->ub4[specoffset][0] = v1->ub4[specoffset][0]; \ v0->ub4[specoffset][1] = v1->ub4[specoffset][1]; \ v0->ub4[specoffset][2] = v1->ub4[specoffset][2]; \ } \ } while (0) #define VERT_SAVE_RGBA( idx ) color[idx] = v[idx]->ui[coloroffset] #define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = color[idx] #define VERT_SAVE_SPEC( idx ) if (specoffset) spec[idx] = v[idx]->ui[specoffset] #define VERT_RESTORE_SPEC( idx ) if (specoffset) v[idx]->ui[specoffset] = spec[idx] #define LOCAL_VARS(n) \ struct via_context *vmesa = VIA_CONTEXT(ctx); \ GLuint color[n], spec[n]; \ GLuint coloroffset = vmesa->coloroffset; \ GLuint specoffset = vmesa->specoffset; \ (void)color; (void)spec; (void)coloroffset; (void)specoffset; /*********************************************************************** * Helpers for rendering unfilled primitives * ***********************************************************************/ static const GLenum hwPrim[GL_POLYGON + 2] = { GL_POINTS, GL_LINES, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_POLYGON+1 }; #define RASTERIZE(x) viaRasterPrimitive( ctx, x, hwPrim[x] ) #define RENDER_PRIMITIVE vmesa->renderPrimitive #define TAG(x) x #define IND VIA_FALLBACK_BIT #include "tnl_dd/t_dd_unfilled.h" #undef IND #undef RASTERIZE /*********************************************************************** * Generate GL render functions * ***********************************************************************/ #define RASTERIZE(x) #define IND (0) #define TAG(x) x #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_OFFSET_BIT) #define TAG(x) x##_offset #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT) #define TAG(x) x##_twoside #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT) #define TAG(x) x##_twoside_offset #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_UNFILLED_BIT) #define TAG(x) x##_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_OFFSET_BIT|VIA_UNFILLED_BIT) #define TAG(x) x##_offset_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT|VIA_UNFILLED_BIT) #define TAG(x) x##_twoside_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT|VIA_UNFILLED_BIT) #define TAG(x) x##_twoside_offset_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_FALLBACK_BIT) #define TAG(x) x##_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_OFFSET_BIT|VIA_FALLBACK_BIT) #define TAG(x) x##_offset_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT|VIA_FALLBACK_BIT) #define TAG(x) x##_twoside_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT|VIA_FALLBACK_BIT) #define TAG(x) x##_twoside_offset_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_UNFILLED_BIT|VIA_FALLBACK_BIT) #define TAG(x) x##_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_OFFSET_BIT|VIA_UNFILLED_BIT|VIA_FALLBACK_BIT) #define TAG(x) x##_offset_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT|VIA_UNFILLED_BIT|VIA_FALLBACK_BIT) #define TAG(x) x##_twoside_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (VIA_TWOSIDE_BIT|VIA_OFFSET_BIT|VIA_UNFILLED_BIT| \ VIA_FALLBACK_BIT) #define TAG(x) x##_twoside_offset_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" /* Catchall case for flat, separate specular triangles (via has flat * diffuse shading, but always does specular color with gouraud). */ #undef DO_FALLBACK #undef DO_OFFSET #undef DO_UNFILLED #undef DO_TWOSIDE #undef DO_FLAT #define DO_FALLBACK (0) #define DO_OFFSET (ctx->_TriangleCaps & DD_TRI_OFFSET) #define DO_UNFILLED (ctx->_TriangleCaps & DD_TRI_UNFILLED) #define DO_TWOSIDE (ctx->_TriangleCaps & DD_TRI_LIGHT_TWOSIDE) #define DO_FLAT 1 #define TAG(x) x##_flat_specular #define IND VIA_MAX_TRIFUNC #include "tnl_dd/t_dd_tritmp.h" static void init_rast_tab(void) { init(); init_offset(); init_twoside(); init_twoside_offset(); init_unfilled(); init_offset_unfilled(); init_twoside_unfilled(); init_twoside_offset_unfilled(); init_fallback(); init_offset_fallback(); init_twoside_fallback(); init_twoside_offset_fallback(); init_unfilled_fallback(); init_offset_unfilled_fallback(); init_twoside_unfilled_fallback(); init_twoside_offset_unfilled_fallback(); init_flat_specular(); /* special! */ } /*********************************************************************** * Rasterization fallback helpers * ***********************************************************************/ /* This code is hit only when a mix of accelerated and unaccelerated * primitives are being drawn, and only for the unaccelerated * primitives. */ static void via_fallback_tri(struct via_context *vmesa, viaVertex *v0, viaVertex *v1, viaVertex *v2) { GLcontext *ctx = vmesa->glCtx; SWvertex v[3]; _swsetup_Translate(ctx, v0, &v[0]); _swsetup_Translate(ctx, v1, &v[1]); _swsetup_Translate(ctx, v2, &v[2]); viaSpanRenderStart( ctx ); _swrast_Triangle(ctx, &v[0], &v[1], &v[2]); viaSpanRenderFinish( ctx ); } static void via_fallback_line(struct via_context *vmesa, viaVertex *v0, viaVertex *v1) { GLcontext *ctx = vmesa->glCtx; SWvertex v[2]; _swsetup_Translate(ctx, v0, &v[0]); _swsetup_Translate(ctx, v1, &v[1]); viaSpanRenderStart( ctx ); _swrast_Line(ctx, &v[0], &v[1]); viaSpanRenderFinish( ctx ); } static void via_fallback_point(struct via_context *vmesa, viaVertex *v0) { GLcontext *ctx = vmesa->glCtx; SWvertex v[1]; _swsetup_Translate(ctx, v0, &v[0]); viaSpanRenderStart( ctx ); _swrast_Point(ctx, &v[0]); viaSpanRenderFinish( ctx ); } static void viaResetLineStipple( GLcontext *ctx ) { struct via_context *vmesa = VIA_CONTEXT(ctx); vmesa->regCmdB |= HC_HLPrst_MASK; } /**********************************************************************/ /* Render unclipped begin/end objects */ /**********************************************************************/ #define IND 0 #define V(x) (viaVertex *)(vertptr + ((x) * vertsize * sizeof(int))) #define RENDER_POINTS(start, count) \ for (; start < count; start++) POINT(V(ELT(start))); #define RENDER_LINE(v0, v1) LINE(V(v0), V(v1)) #define RENDER_TRI( v0, v1, v2) TRI( V(v0), V(v1), V(v2)) #define RENDER_QUAD(v0, v1, v2, v3) QUAD(V(v0), V(v1), V(v2), V(v3)) #define INIT(x) viaRasterPrimitive(ctx, x, hwPrim[x]) #undef LOCAL_VARS #define LOCAL_VARS \ struct via_context *vmesa = VIA_CONTEXT(ctx); \ GLubyte *vertptr = (GLubyte *)vmesa->verts; \ const GLuint vertsize = vmesa->vertexSize; \ const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \ const GLboolean stipple = ctx->Line.StippleFlag; \ (void) elt; (void) stipple; #define RESET_STIPPLE if ( stipple ) viaResetLineStipple( ctx ); #define RESET_OCCLUSION #define PRESERVE_VB_DEFS #define ELT(x) x #define TAG(x) via_##x##_verts #include "tnl/t_vb_rendertmp.h" #undef ELT #undef TAG #define TAG(x) via_##x##_elts #define ELT(x) elt[x] #include "tnl/t_vb_rendertmp.h" #undef ELT #undef TAG #undef NEED_EDGEFLAG_SETUP #undef EDGEFLAG_GET #undef EDGEFLAG_SET #undef RESET_OCCLUSION /**********************************************************************/ /* Render clipped primitives */ /**********************************************************************/ static void viaRenderClippedPoly(GLcontext *ctx, const GLuint *elts, GLuint n) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; GLuint prim = VIA_CONTEXT(ctx)->renderPrimitive; /* Render the new vertices as an unclipped polygon. */ { GLuint *tmp = VB->Elts; VB->Elts = (GLuint *)elts; tnl->Driver.Render.PrimTabElts[GL_POLYGON](ctx, 0, n, PRIM_BEGIN|PRIM_END); VB->Elts = tmp; } /* Restore the render primitive */ if (prim != GL_POLYGON && prim != GL_POLYGON + 1) tnl->Driver.Render.PrimitiveNotify( ctx, prim ); } static void viaRenderClippedLine(GLcontext *ctx, GLuint ii, GLuint jj) { TNLcontext *tnl = TNL_CONTEXT(ctx); tnl->Driver.Render.Line(ctx, ii, jj); } static void viaFastRenderClippedPoly(GLcontext *ctx, const GLuint *elts, GLuint n) { struct via_context *vmesa = VIA_CONTEXT(ctx); GLuint vertsize = vmesa->vertexSize; GLuint *vb = viaExtendPrimitive(vmesa, (n - 2) * 3 * 4 * vertsize); GLubyte *vertptr = (GLubyte *)vmesa->verts; const GLuint *start = (const GLuint *)V(elts[0]); int i; for (i = 2; i < n; i++) { COPY_DWORDS(vb, vertsize, V(elts[i - 1])); COPY_DWORDS(vb, vertsize, V(elts[i])); COPY_DWORDS(vb, vertsize, start); } } /**********************************************************************/ /* Choose render functions */ /**********************************************************************/ #define _VIA_NEW_VERTEX (_NEW_TEXTURE | \ _DD_NEW_SEPARATE_SPECULAR | \ _DD_NEW_TRI_UNFILLED | \ _DD_NEW_TRI_LIGHT_TWOSIDE | \ _NEW_FOG) #define _VIA_NEW_RENDERSTATE (_DD_NEW_LINE_STIPPLE | \ _DD_NEW_TRI_UNFILLED | \ _DD_NEW_TRI_LIGHT_TWOSIDE | \ _DD_NEW_TRI_OFFSET | \ _DD_NEW_TRI_STIPPLE | \ _NEW_POLYGONSTIPPLE) static void viaChooseRenderState(GLcontext *ctx) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct via_context *vmesa = VIA_CONTEXT(ctx); GLuint flags = ctx->_TriangleCaps; GLuint index = 0; if (vmesa->ptexHack) { vmesa->drawPoint = via_ptex_point; vmesa->drawLine = via_ptex_line; vmesa->drawTri = via_ptex_tri; index |= VIA_FALLBACK_BIT; } else { vmesa->drawPoint = via_draw_point; vmesa->drawLine = via_draw_line; vmesa->drawTri = via_draw_triangle; } if (flags & (ANY_FALLBACK_FLAGS|ANY_RASTER_FLAGS)) { if (flags & DD_TRI_LIGHT_TWOSIDE) index |= VIA_TWOSIDE_BIT; if (flags & DD_TRI_OFFSET) index |= VIA_OFFSET_BIT; if (flags & DD_TRI_UNFILLED) index |= VIA_UNFILLED_BIT; if (flags & ANY_FALLBACK_FLAGS) index |= VIA_FALLBACK_BIT; /* Hook in fallbacks for specific primitives. */ if (flags & POINT_FALLBACK) vmesa->drawPoint = via_fallback_point; if (flags & LINE_FALLBACK) vmesa->drawLine = via_fallback_line; if (flags & TRI_FALLBACK) vmesa->drawTri = via_fallback_tri; } if ((flags & DD_SEPARATE_SPECULAR) && ctx->Light.ShadeModel == GL_FLAT) { index = VIA_MAX_TRIFUNC; /* flat specular */ } if (vmesa->renderIndex != index) { vmesa->renderIndex = index; tnl->Driver.Render.Points = rast_tab[index].points; tnl->Driver.Render.Line = 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 = via_render_tab_verts; tnl->Driver.Render.PrimTabElts = via_render_tab_elts; tnl->Driver.Render.ClippedLine = line; /* from tritmp.h */ tnl->Driver.Render.ClippedPolygon = viaFastRenderClippedPoly; } else { tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; tnl->Driver.Render.ClippedLine = viaRenderClippedLine; tnl->Driver.Render.ClippedPolygon = viaRenderClippedPoly; } } } #define VIA_EMIT_TEX1 0x01 #define VIA_EMIT_TEX0 0x02 #define VIA_EMIT_PTEX0 0x04 #define VIA_EMIT_RGBA 0x08 #define VIA_EMIT_SPEC 0x10 #define VIA_EMIT_FOG 0x20 #define VIA_EMIT_W 0x40 #define EMIT_ATTR( ATTR, STYLE, INDEX, REGB ) \ do { \ vmesa->vertex_attrs[vmesa->vertex_attr_count].attrib = (ATTR); \ vmesa->vertex_attrs[vmesa->vertex_attr_count].format = (STYLE); \ vmesa->vertex_attr_count++; \ setupIndex |= (INDEX); \ regCmdB |= (REGB); \ } while (0) #define EMIT_PAD( N ) \ do { \ vmesa->vertex_attrs[vmesa->vertex_attr_count].attrib = 0; \ vmesa->vertex_attrs[vmesa->vertex_attr_count].format = EMIT_PAD; \ vmesa->vertex_attrs[vmesa->vertex_attr_count].offset = (N); \ vmesa->vertex_attr_count++; \ } while (0) static void viaChooseVertexState( GLcontext *ctx ) { struct via_context *vmesa = VIA_CONTEXT(ctx); TNLcontext *tnl = TNL_CONTEXT(ctx); GLuint index = tnl->render_inputs; GLuint regCmdB = HC_HVPMSK_X | HC_HVPMSK_Y | HC_HVPMSK_Z; GLuint setupIndex = 0; vmesa->vertex_attr_count = 0; /* EMIT_ATTR's must be in order as they tell t_vertex.c how to * build up a hardware vertex. */ if (index & (_TNL_BITS_TEX_ANY|_TNL_BIT_FOG)) { EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, VIA_EMIT_W, HC_HVPMSK_W ); vmesa->coloroffset = 4; } else { EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT, 0, 0 ); vmesa->coloroffset = 3; } /* t_context.c always includes a diffuse color */ EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4UB_4F_BGRA, VIA_EMIT_RGBA, HC_HVPMSK_Cd ); vmesa->specoffset = 0; if (index & (_TNL_BIT_COLOR1|_TNL_BIT_FOG)) { if ((index & _TNL_BIT_COLOR1)) { vmesa->specoffset = vmesa->coloroffset + 1; EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_3UB_3F_BGR, VIA_EMIT_SPEC, HC_HVPMSK_Cs ); } else EMIT_PAD( 3 ); if ((index & _TNL_BIT_FOG)) EMIT_ATTR( _TNL_ATTRIB_FOG, EMIT_1UB_1F, VIA_EMIT_FOG, HC_HVPMSK_Cs ); else EMIT_PAD( 1 ); } if (index & _TNL_BIT_TEX(0)) { if (vmesa->ptexHack) EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_3F_XYW, VIA_EMIT_PTEX0, (HC_HVPMSK_S | HC_HVPMSK_T) ); else EMIT_ATTR( _TNL_ATTRIB_TEX0, EMIT_2F, VIA_EMIT_TEX0, (HC_HVPMSK_S | HC_HVPMSK_T) ); } if (index & _TNL_BIT_TEX(1)) { EMIT_ATTR( _TNL_ATTRIB_TEX1, EMIT_2F, VIA_EMIT_TEX1, (HC_HVPMSK_S | HC_HVPMSK_T) ); } if (setupIndex != vmesa->setupIndex) { vmesa->vertexSize = _tnl_install_attrs( ctx, vmesa->vertex_attrs, vmesa->vertex_attr_count, vmesa->ViewportMatrix.m, 0 ); vmesa->vertexSize >>= 2; vmesa->setupIndex = setupIndex; vmesa->regCmdB &= ~HC_HVPMSK_MASK; vmesa->regCmdB |= regCmdB; if (vmesa->ptexHack) vmesa->hwVertexSize = vmesa->vertexSize - 1; else vmesa->hwVertexSize = vmesa->vertexSize; } } /* Check if projective texture coordinates are used and if we can fake * them. Fallback to swrast if we can't. Returns GL_TRUE if projective * texture coordinates must be faked, GL_FALSE otherwise. */ static GLboolean viaCheckPTexHack( GLcontext *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; GLuint index = tnl->render_inputs; GLboolean fallback = GL_FALSE; GLboolean ptexHack = GL_FALSE; if (index & _TNL_BIT_TEX(0) && VB->TexCoordPtr[0]->size == 4) { if ((index & _TNL_BITS_TEX_ANY) == _TNL_BIT_TEX(0)) ptexHack = GL_TRUE; else fallback = GL_TRUE; } if ((index & _TNL_BIT_TEX(1)) && VB->TexCoordPtr[1]->size == 4) fallback = GL_TRUE; FALLBACK(VIA_CONTEXT(ctx), VIA_FALLBACK_PROJ_TEXTURE, fallback); return ptexHack; } /**********************************************************************/ /* High level hooks for t_vb_render.c */ /**********************************************************************/ static void viaRenderStart(GLcontext *ctx) { struct via_context *vmesa = VIA_CONTEXT(ctx); TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; { GLboolean ptexHack = viaCheckPTexHack( ctx ); if (ptexHack != vmesa->ptexHack) { vmesa->ptexHack = ptexHack; vmesa->newRenderState |= _VIA_NEW_RENDERSTATE; } } if (vmesa->newState) { vmesa->newRenderState |= vmesa->newState; viaValidateState( ctx ); } if (vmesa->Fallback) { tnl->Driver.Render.Start(ctx); return; } if (vmesa->newRenderState) { viaChooseVertexState(ctx); viaChooseRenderState(ctx); vmesa->newRenderState = 0; } /* Important: */ VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr; } static void viaRenderFinish(GLcontext *ctx) { VIA_FINISH_PRIM(VIA_CONTEXT(ctx)); } /* System to flush dma and emit state changes based on the rasterized * primitive. */ void viaRasterPrimitive(GLcontext *ctx, GLenum glprim, GLenum hwprim) { struct via_context *vmesa = VIA_CONTEXT(ctx); GLuint regCmdB; RING_VARS; if (VIA_DEBUG & DEBUG_PRIMS) fprintf(stderr, "%s: %s/%s/%s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(glprim), _mesa_lookup_enum_by_nr(hwprim), _mesa_lookup_enum_by_nr(ctx->Light.ShadeModel)); assert (!vmesa->newState); vmesa->renderPrimitive = glprim; if (hwprim != vmesa->hwPrimitive || ctx->Light.ShadeModel != vmesa->hwShadeModel) { VIA_FINISH_PRIM(vmesa); /* Ensure no wrapping inside this function */ viaCheckDma( vmesa, 1024 ); if (vmesa->newEmitState) { viaEmitState(vmesa); } vmesa->regCmdA_End = HC_ACMD_HCmdA; if (ctx->Light.ShadeModel == GL_SMOOTH) { vmesa->regCmdA_End |= HC_HShading_Gouraud; } vmesa->hwShadeModel = ctx->Light.ShadeModel; regCmdB = vmesa->regCmdB; switch (hwprim) { case GL_POINTS: vmesa->regCmdA_End |= HC_HPMType_Point | HC_HVCycle_Full; vmesa->regCmdA_End |= HC_HShading_Gouraud; /* always Gouraud shade points?!? */ break; case GL_LINES: vmesa->regCmdA_End |= HC_HPMType_Line | HC_HVCycle_Full; regCmdB |= HC_HLPrst_MASK; if (ctx->Light.ShadeModel == GL_FLAT) vmesa->regCmdA_End |= HC_HShading_FlatB; break; case GL_LINE_LOOP: case GL_LINE_STRIP: vmesa->regCmdA_End |= HC_HPMType_Line | HC_HVCycle_AFP | HC_HVCycle_AB | HC_HVCycle_NewB; regCmdB |= HC_HVCycle_AB | HC_HVCycle_NewB | HC_HLPrst_MASK; if (ctx->Light.ShadeModel == GL_FLAT) vmesa->regCmdA_End |= HC_HShading_FlatB; break; case GL_TRIANGLES: vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_Full; if (ctx->Light.ShadeModel == GL_FLAT) vmesa->regCmdA_End |= HC_HShading_FlatC; break; case GL_TRIANGLE_STRIP: vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_AFP | HC_HVCycle_AC | HC_HVCycle_BB | HC_HVCycle_NewC; regCmdB |= HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC; if (ctx->Light.ShadeModel == GL_FLAT) vmesa->regCmdA_End |= HC_HShading_FlatC; break; case GL_TRIANGLE_FAN: vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_AFP | HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC; regCmdB |= HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC; if (ctx->Light.ShadeModel == GL_FLAT) vmesa->regCmdA_End |= HC_HShading_FlatC; break; case GL_QUADS: abort(); return; case GL_QUAD_STRIP: abort(); return; case GL_POLYGON: vmesa->regCmdA_End |= HC_HPMType_Tri | HC_HVCycle_AFP | HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC; regCmdB |= HC_HVCycle_AA | HC_HVCycle_BC | HC_HVCycle_NewC; if (ctx->Light.ShadeModel == GL_FLAT) vmesa->regCmdA_End |= HC_HShading_FlatC; break; default: abort(); return; } /* assert((vmesa->dmaLow & 0x4) == 0); */ if (vmesa->dmaCliprectAddr == ~0) { if (VIA_DEBUG & DEBUG_DMA) fprintf(stderr, "reserve cliprect space at %x\n", vmesa->dmaLow); vmesa->dmaCliprectAddr = vmesa->dmaLow; BEGIN_RING(8); OUT_RING( HC_HEADER2 ); OUT_RING( (HC_ParaType_NotTex << 16) ); OUT_RING( 0xCCCCCCCC ); OUT_RING( 0xCCCCCCCC ); OUT_RING( 0xCCCCCCCC ); OUT_RING( 0xCCCCCCCC ); OUT_RING( 0xCCCCCCCC ); OUT_RING( 0xCCCCCCCC ); ADVANCE_RING(); } assert(vmesa->dmaLastPrim == 0); BEGIN_RING(8); OUT_RING( HC_HEADER2 ); OUT_RING( (HC_ParaType_NotTex << 16) ); OUT_RING( 0xCCCCCCCC ); OUT_RING( 0xDDDDDDDD ); OUT_RING( HC_HEADER2 ); OUT_RING( (HC_ParaType_CmdVdata << 16) ); OUT_RING( regCmdB ); OUT_RING( vmesa->regCmdA_End ); ADVANCE_RING(); vmesa->hwPrimitive = hwprim; vmesa->dmaLastPrim = vmesa->dmaLow; } else { assert(!vmesa->newEmitState); } } /* Callback for mesa: */ static void viaRenderPrimitive( GLcontext *ctx, GLuint prim ) { viaRasterPrimitive( ctx, prim, hwPrim[prim] ); } void viaFinishPrimitive(struct via_context *vmesa) { if (VIA_DEBUG & (DEBUG_DMA|DEBUG_PRIMS)) fprintf(stderr, "%s\n", __FUNCTION__); if (!vmesa->dmaLastPrim || vmesa->dmaCliprectAddr == ~0) { assert(0); } else if (vmesa->dmaLow != vmesa->dmaLastPrim) { GLuint cmdA = (vmesa->regCmdA_End | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK); RING_VARS; vmesa->dmaLastPrim = 0; /* KW: modified 0x1 to 0x4 below: */ if ((vmesa->dmaLow & 0x4) || !vmesa->useAgp) { BEGIN_RING_NOCHECK( 1 ); OUT_RING( cmdA ); ADVANCE_RING(); } else { BEGIN_RING_NOCHECK( 2 ); OUT_RING( cmdA ); OUT_RING( cmdA ); ADVANCE_RING(); } if (vmesa->dmaLow > VIA_DMA_HIGHWATER) viaFlushDma( vmesa ); } else { if (VIA_DEBUG & (DEBUG_DMA|DEBUG_PRIMS)) fprintf(stderr, "remove empty primitive\n"); /* Remove the primitive header: */ vmesa->dmaLastPrim = 0; vmesa->dmaLow -= 8 * sizeof(GLuint); /* Maybe remove the cliprect as well: */ if (vmesa->dmaCliprectAddr == vmesa->dmaLow - 8 * sizeof(GLuint)) { vmesa->dmaLow -= 8 * sizeof(GLuint); vmesa->dmaCliprectAddr = ~0; } } vmesa->renderPrimitive = GL_POLYGON + 1; vmesa->hwPrimitive = GL_POLYGON + 1; vmesa->dmaLastPrim = 0; } /**********************************************************************/ /* Transition to/from hardware rasterization. */ /**********************************************************************/ void viaFallback(struct via_context *vmesa, GLuint bit, GLboolean mode) { GLcontext *ctx = vmesa->glCtx; TNLcontext *tnl = TNL_CONTEXT(ctx); GLuint oldfallback = vmesa->Fallback; if (mode) { vmesa->Fallback |= bit; if (oldfallback == 0) { VIA_FLUSH_DMA(vmesa); if (VIA_DEBUG & DEBUG_FALLBACKS) fprintf(stderr, "ENTER FALLBACK %x\n", bit); _swsetup_Wakeup(ctx); vmesa->renderIndex = ~0; } } else { vmesa->Fallback &= ~bit; if (oldfallback == bit) { _swrast_flush( ctx ); if (VIA_DEBUG & DEBUG_FALLBACKS) fprintf(stderr, "LEAVE FALLBACK %x\n", bit); tnl->Driver.Render.Start = viaRenderStart; tnl->Driver.Render.PrimitiveNotify = viaRenderPrimitive; tnl->Driver.Render.Finish = viaRenderFinish; tnl->Driver.Render.BuildVertices = _tnl_build_vertices; tnl->Driver.Render.CopyPV = _tnl_copy_pv; tnl->Driver.Render.Interp = _tnl_interp; tnl->Driver.Render.ResetLineStipple = viaResetLineStipple; _tnl_invalidate_vertex_state( ctx, ~0 ); _tnl_invalidate_vertices( ctx, ~0 ); _tnl_install_attrs( ctx, vmesa->vertex_attrs, vmesa->vertex_attr_count, vmesa->ViewportMatrix.m, 0 ); vmesa->newState |= (_VIA_NEW_RENDERSTATE|_VIA_NEW_VERTEX); } } } static void viaRunPipeline( GLcontext *ctx ) { struct via_context *vmesa = VIA_CONTEXT(ctx); if (vmesa->newState) { vmesa->newRenderState |= vmesa->newState; viaValidateState( ctx ); } _tnl_run_pipeline( ctx ); } /**********************************************************************/ /* Initialization. */ /**********************************************************************/ void viaInitTriFuncs(GLcontext *ctx) { struct via_context *vmesa = VIA_CONTEXT(ctx); TNLcontext *tnl = TNL_CONTEXT(ctx); static int firsttime = 1; if (firsttime) { init_rast_tab(); firsttime = 0; } tnl->Driver.RunPipeline = viaRunPipeline; tnl->Driver.Render.Start = viaRenderStart; tnl->Driver.Render.Finish = viaRenderFinish; tnl->Driver.Render.PrimitiveNotify = viaRenderPrimitive; tnl->Driver.Render.ResetLineStipple = viaResetLineStipple; tnl->Driver.Render.BuildVertices = _tnl_build_vertices; tnl->Driver.Render.CopyPV = _tnl_copy_pv; tnl->Driver.Render.Interp = _tnl_interp; _tnl_init_vertices( ctx, ctx->Const.MaxArrayLockSize + 12, (6 + 2*ctx->Const.MaxTextureUnits) * sizeof(GLfloat) ); vmesa->verts = (GLubyte *)tnl->clipspace.vertex_buf; }