/* -*- mode: c; c-basic-offset: 3 -*- * * Copyright 2000 VA Linux Systems Inc., Fremont, California. * * 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, sublicense, * 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 NONINFRINGEMENT. IN NO EVENT SHALL * VA LINUX SYSTEMS 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. */ /* New fixes: * Daniel Borca , 19 Jul 2004 * * Authors: * Keith Whitwell */ #include "main/glheader.h" #include "main/mtypes.h" #include "main/macros.h" #include "main/colormac.h" #include "swrast/swrast.h" #include "swrast_setup/swrast_setup.h" #include "swrast_setup/ss_context.h" #include "tnl/t_context.h" #include "tnl/t_pipeline.h" #include "tdfx_tris.h" #include "tdfx_state.h" #include "tdfx_vb.h" #include "tdfx_lock.h" #include "tdfx_render.h" static void tdfxRasterPrimitive( struct gl_context *ctx, GLenum prim ); static void tdfxRenderPrimitive( struct gl_context *ctx, GLenum prim ); static GLenum reduced_prim[GL_POLYGON+1] = { GL_POINTS, GL_LINES, GL_LINES, GL_LINES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES, GL_TRIANGLES }; /*********************************************************************** * Macros for t_dd_tritmp.h to draw basic primitives * ***********************************************************************/ #define TRI( a, b, c ) \ do { \ if (DO_FALLBACK) \ fxMesa->draw_triangle( fxMesa, a, b, c ); \ else \ fxMesa->Glide.grDrawTriangle( a, b, c ); \ } while (0) \ #define QUAD( a, b, c, d ) \ do { \ if (DO_FALLBACK) { \ fxMesa->draw_triangle( fxMesa, a, b, d ); \ fxMesa->draw_triangle( fxMesa, b, c, d ); \ } else { \ tdfxVertex *_v_[4]; \ _v_[0] = d; \ _v_[1] = a; \ _v_[2] = b; \ _v_[3] = c; \ fxMesa->Glide.grDrawVertexArray(GR_TRIANGLE_FAN, 4, _v_);\ /*fxMesa->Glide.grDrawTriangle( a, b, d );*/\ /*fxMesa->Glide.grDrawTriangle( b, c, d );*/\ } \ } while (0) #define LINE( v0, v1 ) \ do { \ if (DO_FALLBACK) \ fxMesa->draw_line( fxMesa, v0, v1 ); \ else { \ v0->x += LINE_X_OFFSET - TRI_X_OFFSET; \ v0->y += LINE_Y_OFFSET - TRI_Y_OFFSET; \ v1->x += LINE_X_OFFSET - TRI_X_OFFSET; \ v1->y += LINE_Y_OFFSET - TRI_Y_OFFSET; \ fxMesa->Glide.grDrawLine( v0, v1 ); \ v0->x -= LINE_X_OFFSET - TRI_X_OFFSET; \ v0->y -= LINE_Y_OFFSET - TRI_Y_OFFSET; \ v1->x -= LINE_X_OFFSET - TRI_X_OFFSET; \ v1->y -= LINE_Y_OFFSET - TRI_Y_OFFSET; \ } \ } while (0) #define POINT( v0 ) \ do { \ if (DO_FALLBACK) \ fxMesa->draw_point( fxMesa, v0 ); \ else { \ v0->x += PNT_X_OFFSET - TRI_X_OFFSET; \ v0->y += PNT_Y_OFFSET - TRI_Y_OFFSET; \ fxMesa->Glide.grDrawPoint( v0 ); \ v0->x -= PNT_X_OFFSET - TRI_X_OFFSET; \ v0->y -= PNT_Y_OFFSET - TRI_Y_OFFSET; \ } \ } while (0) /*********************************************************************** * Fallback to swrast for basic primitives * ***********************************************************************/ /* Build an SWvertex from a hardware vertex. * * This code is hit only when a mix of accelerated and unaccelerated * primitives are being drawn, and only for the unaccelerated * primitives. */ static void tdfx_translate_vertex( struct gl_context *ctx, const tdfxVertex *src, SWvertex *dst) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); if (fxMesa->vertexFormat == TDFX_LAYOUT_TINY) { dst->attrib[FRAG_ATTRIB_WPOS][0] = src->x - fxMesa->x_offset; dst->attrib[FRAG_ATTRIB_WPOS][1] = src->y - (fxMesa->screen_height - fxMesa->height - fxMesa->y_offset); dst->attrib[FRAG_ATTRIB_WPOS][2] = src->z; dst->attrib[FRAG_ATTRIB_WPOS][3] = 1.0; dst->color[0] = src->color[2]; dst->color[1] = src->color[1]; dst->color[2] = src->color[0]; dst->color[3] = src->color[3]; } else { GLfloat w = 1.0 / src->rhw; dst->attrib[FRAG_ATTRIB_WPOS][0] = src->x - fxMesa->x_offset; dst->attrib[FRAG_ATTRIB_WPOS][1] = src->y - (fxMesa->screen_height - fxMesa->height - fxMesa->y_offset); dst->attrib[FRAG_ATTRIB_WPOS][2] = src->z; dst->attrib[FRAG_ATTRIB_WPOS][3] = src->rhw; dst->color[0] = src->color[2]; dst->color[1] = src->color[1]; dst->color[2] = src->color[0]; dst->color[3] = src->color[3]; dst->attrib[FRAG_ATTRIB_TEX0][0] = 1.0 / fxMesa->sScale0 * w * src->tu0; dst->attrib[FRAG_ATTRIB_TEX0][1] = 1.0 / fxMesa->tScale0 * w * src->tv0; if (fxMesa->vertexFormat == TDFX_LAYOUT_PROJ1 || fxMesa->vertexFormat == TDFX_LAYOUT_PROJ2) { dst->attrib[FRAG_ATTRIB_TEX0][3] = w * src->tq0; } else { dst->attrib[FRAG_ATTRIB_TEX0][3] = 1.0; } if (fxMesa->SetupIndex & TDFX_TEX1_BIT) { dst->attrib[FRAG_ATTRIB_TEX1][0] = 1.0 / fxMesa->sScale1 * w * src->tu1; dst->attrib[FRAG_ATTRIB_TEX1][1] = 1.0 / fxMesa->tScale1 * w * src->tv1; if (fxMesa->vertexFormat == TDFX_LAYOUT_PROJ2) { dst->attrib[FRAG_ATTRIB_TEX1][3] = w * src->tq1; } else { dst->attrib[FRAG_ATTRIB_TEX1][3] = 1.0; } } } dst->pointSize = ctx->Point.Size; } static void tdfx_fallback_tri( tdfxContextPtr fxMesa, tdfxVertex *v0, tdfxVertex *v1, tdfxVertex *v2 ) { struct gl_context *ctx = fxMesa->glCtx; SWvertex v[3]; tdfx_translate_vertex( ctx, v0, &v[0] ); tdfx_translate_vertex( ctx, v1, &v[1] ); tdfx_translate_vertex( ctx, v2, &v[2] ); _swrast_Triangle( ctx, &v[0], &v[1], &v[2] ); } static void tdfx_fallback_line( tdfxContextPtr fxMesa, tdfxVertex *v0, tdfxVertex *v1 ) { struct gl_context *ctx = fxMesa->glCtx; SWvertex v[2]; tdfx_translate_vertex( ctx, v0, &v[0] ); tdfx_translate_vertex( ctx, v1, &v[1] ); _swrast_Line( ctx, &v[0], &v[1] ); } static void tdfx_fallback_point( tdfxContextPtr fxMesa, tdfxVertex *v0 ) { struct gl_context *ctx = fxMesa->glCtx; SWvertex v[1]; tdfx_translate_vertex( ctx, v0, &v[0] ); _swrast_Point( ctx, &v[0] ); } /*********************************************************************** * Functions to draw basic primitives * ***********************************************************************/ static void tdfx_print_vertex( struct gl_context *ctx, const tdfxVertex *v ) { tdfxContextPtr tmesa = TDFX_CONTEXT( ctx ); fprintf(stderr, "vertex at %p\n", (void *)v); if (tmesa->vertexFormat == TDFX_LAYOUT_TINY) { fprintf(stderr, "x %f y %f z %f\n", v->x, v->y, v->z); } else { fprintf(stderr, "x %f y %f z %f oow %f\n", v->x, v->y, v->z, v->rhw); } fprintf(stderr, "r %d g %d b %d a %d\n", v->color[0], v->color[1], v->color[2], v->color[3]); fprintf(stderr, "\n"); } #define DO_FALLBACK 0 /* Need to do clip loop at each triangle when mixing swrast and hw * rendering. These functions are only used when mixed-mode rendering * is occurring. */ static void tdfx_draw_triangle( tdfxContextPtr fxMesa, tdfxVertexPtr v0, tdfxVertexPtr v1, tdfxVertexPtr v2 ) { /* fprintf(stderr, "%s\n", __FUNCTION__); */ /* tdfx_print_vertex( fxMesa->glCtx, v0 ); */ /* tdfx_print_vertex( fxMesa->glCtx, v1 ); */ /* tdfx_print_vertex( fxMesa->glCtx, v2 ); */ BEGIN_CLIP_LOOP_LOCKED(fxMesa) { TRI( v0, v1, v2 ); } END_CLIP_LOOP_LOCKED(fxMesa); } static void tdfx_draw_line( tdfxContextPtr fxMesa, tdfxVertexPtr v0, tdfxVertexPtr v1 ) { /* No support for wide lines (avoid wide/aa line fallback). */ BEGIN_CLIP_LOOP_LOCKED(fxMesa) { LINE(v0, v1); } END_CLIP_LOOP_LOCKED(fxMesa); } static void tdfx_draw_point( tdfxContextPtr fxMesa, tdfxVertexPtr v0 ) { /* No support for wide points. */ BEGIN_CLIP_LOOP_LOCKED(fxMesa) { POINT( v0 ); } END_CLIP_LOOP_LOCKED(fxMesa); } #undef DO_FALLBACK #define TDFX_UNFILLED_BIT 0x1 #define TDFX_OFFSET_BIT 0x2 #define TDFX_TWOSIDE_BIT 0x4 #define TDFX_FLAT_BIT 0x8 #define TDFX_FALLBACK_BIT 0x10 #define TDFX_MAX_TRIFUNC 0x20 static struct { tnl_points_func points; tnl_line_func line; tnl_triangle_func triangle; tnl_quad_func quad; } rast_tab[TDFX_MAX_TRIFUNC]; #define DO_FALLBACK (IND & TDFX_FALLBACK_BIT) #define DO_OFFSET (IND & TDFX_OFFSET_BIT) #define DO_UNFILLED (IND & TDFX_UNFILLED_BIT) #define DO_TWOSIDE (IND & TDFX_TWOSIDE_BIT) #define DO_FLAT (IND & TDFX_FLAT_BIT) #define DO_TRI 1 #define DO_QUAD 1 #define DO_LINE 1 #define DO_POINTS 1 #define DO_FULL_QUAD 1 #define HAVE_SPEC 0 #define HAVE_HW_FLATSHADE 0 #define HAVE_BACK_COLORS 0 #define VERTEX tdfxVertex #define TAB rast_tab #define DEPTH_SCALE 1.0 #define UNFILLED_TRI unfilled_tri #define UNFILLED_QUAD unfilled_quad #define VERT_X(_v) _v->x #define VERT_Y(_v) _v->y #define VERT_Z(_v) _v->z #define AREA_IS_CCW( a ) (a < 0) #define GET_VERTEX(e) (fxMesa->verts + (e)) #define VERT_SET_RGBA( dst, f ) \ do { \ UNCLAMPED_FLOAT_TO_UBYTE(dst->color[2], f[0]);\ UNCLAMPED_FLOAT_TO_UBYTE(dst->color[1], f[1]);\ UNCLAMPED_FLOAT_TO_UBYTE(dst->color[0], f[2]);\ UNCLAMPED_FLOAT_TO_UBYTE(dst->color[3], f[3]);\ } while (0) #define VERT_COPY_RGBA( v0, v1 ) \ *(GLuint *)&v0->color = *(GLuint *)&v1->color #define VERT_SAVE_RGBA( idx ) \ *(GLuint *)&color[idx] = *(GLuint *)&v[idx]->color #define VERT_RESTORE_RGBA( idx ) \ *(GLuint *)&v[idx]->color = *(GLuint *)&color[idx] #define LOCAL_VARS(n) \ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); \ GLubyte color[n][4]; \ (void) color; /*********************************************************************** * Functions to draw basic unfilled primitives * ***********************************************************************/ #define RASTERIZE(x) if (fxMesa->raster_primitive != reduced_prim[x]) \ tdfxRasterPrimitive( ctx, reduced_prim[x] ) #define RENDER_PRIMITIVE fxMesa->render_primitive #define IND TDFX_FALLBACK_BIT #define TAG(x) x #include "tnl_dd/t_dd_unfilled.h" #undef IND /*********************************************************************** * Functions to draw GL primitives * ***********************************************************************/ #define IND (0) #define TAG(x) x #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT) #define TAG(x) x##_offset #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT) #define TAG(x) x##_twoside #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT) #define TAG(x) x##_twoside_offset #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_UNFILLED_BIT) #define TAG(x) x##_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT) #define TAG(x) x##_offset_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT) #define TAG(x) x##_twoside_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT) #define TAG(x) x##_twoside_offset_unfilled #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_FALLBACK_BIT) #define TAG(x) x##_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT) #define TAG(x) x##_offset_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_FALLBACK_BIT) #define TAG(x) x##_twoside_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT) #define TAG(x) x##_twoside_offset_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT) #define TAG(x) x##_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT) #define TAG(x) x##_offset_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT) #define TAG(x) x##_twoside_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT| \ TDFX_FALLBACK_BIT) #define TAG(x) x##_twoside_offset_unfilled_fallback #include "tnl_dd/t_dd_tritmp.h" /* Tdfx doesn't support provoking-vertex flat-shading? */ #define IND (TDFX_FLAT_BIT) #define TAG(x) x##_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_offset_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_offset_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_UNFILLED_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_unfilled_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_offset_unfilled_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_unfilled_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_offset_unfilled_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_fallback_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_offset_fallback_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_fallback_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_offset_fallback_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_unfilled_fallback_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_offset_unfilled_fallback_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_UNFILLED_BIT|TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_unfilled_fallback_flat #include "tnl_dd/t_dd_tritmp.h" #define IND (TDFX_TWOSIDE_BIT|TDFX_OFFSET_BIT|TDFX_UNFILLED_BIT| \ TDFX_FALLBACK_BIT|TDFX_FLAT_BIT) #define TAG(x) x##_twoside_offset_unfilled_fallback_flat #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(); init_offset_flat(); init_twoside_flat(); init_twoside_offset_flat(); init_unfilled_flat(); init_offset_unfilled_flat(); init_twoside_unfilled_flat(); init_twoside_offset_unfilled_flat(); init_fallback_flat(); init_offset_fallback_flat(); init_twoside_fallback_flat(); init_twoside_offset_fallback_flat(); init_unfilled_fallback_flat(); init_offset_unfilled_fallback_flat(); init_twoside_unfilled_fallback_flat(); init_twoside_offset_unfilled_fallback_flat(); } /**********************************************************************/ /* Render whole begin/end objects */ /**********************************************************************/ /* Accelerate vertex buffer rendering when renderindex == 0 and * there is no clipping. */ #define INIT(x) tdfxRenderPrimitive( ctx, x ) static void tdfx_render_vb_points( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; GLint i; (void) flags; INIT(GL_POINTS); /* Adjust point coords */ for (i = start; i < count; i++) { fxVB[i].x += PNT_X_OFFSET - TRI_X_OFFSET; fxVB[i].y += PNT_Y_OFFSET - TRI_Y_OFFSET; } fxMesa->Glide.grDrawVertexArrayContiguous( GR_POINTS, count-start, fxVB + start, sizeof(tdfxVertex)); /* restore point coords */ for (i = start; i < count; i++) { fxVB[i].x -= PNT_X_OFFSET - TRI_X_OFFSET; fxVB[i].y -= PNT_Y_OFFSET - TRI_Y_OFFSET; } } static void tdfx_render_vb_line_strip( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; GLint i; (void) flags; INIT(GL_LINE_STRIP); /* adjust line coords */ for (i = start; i < count; i++) { fxVB[i].x += LINE_X_OFFSET - TRI_X_OFFSET; fxVB[i].y += LINE_Y_OFFSET - TRI_Y_OFFSET; } fxMesa->Glide.grDrawVertexArrayContiguous( GR_LINE_STRIP, count-start, fxVB + start, sizeof(tdfxVertex) ); /* restore line coords */ for (i = start; i < count; i++) { fxVB[i].x -= LINE_X_OFFSET - TRI_X_OFFSET; fxVB[i].y -= LINE_Y_OFFSET - TRI_Y_OFFSET; } } static void tdfx_render_vb_line_loop( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; GLint i; GLint j = start; (void) flags; INIT(GL_LINE_LOOP); if (!(flags & PRIM_BEGIN)) { j++; } /* adjust line coords */ for (i = start; i < count; i++) { fxVB[i].x += LINE_X_OFFSET - TRI_X_OFFSET; fxVB[i].y += LINE_Y_OFFSET - TRI_Y_OFFSET; } fxMesa->Glide.grDrawVertexArrayContiguous( GR_LINE_STRIP, count-j, fxVB + j, sizeof(tdfxVertex)); if (flags & PRIM_END) fxMesa->Glide.grDrawLine( fxVB + (count - 1), fxVB + start ); /* restore line coords */ for (i = start; i < count; i++) { fxVB[i].x -= LINE_X_OFFSET - TRI_X_OFFSET; fxVB[i].y -= LINE_Y_OFFSET - TRI_Y_OFFSET; } } static void tdfx_render_vb_lines( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; GLint i; (void) flags; INIT(GL_LINES); /* adjust line coords */ for (i = start; i < count; i++) { fxVB[i].x += LINE_X_OFFSET - TRI_X_OFFSET; fxVB[i].y += LINE_Y_OFFSET - TRI_Y_OFFSET; } fxMesa->Glide.grDrawVertexArrayContiguous( GR_LINES, count-start, fxVB + start, sizeof(tdfxVertex)); /* restore line coords */ for (i = start; i < count; i++) { fxVB[i].x -= LINE_X_OFFSET - TRI_X_OFFSET; fxVB[i].y -= LINE_Y_OFFSET - TRI_Y_OFFSET; } } static void tdfx_render_vb_triangles( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; (void) flags; INIT(GL_TRIANGLES); #if 0 /* [dBorca] * apparently, this causes troubles with some programs (GLExcess); * might be a bug in Glide... However, "grDrawVertexArrayContiguous" * eventually calls "grDrawTriangle" for GR_TRIANGLES, so we're better * off doing it by hand... */ fxMesa->Glide.grDrawVertexArrayContiguous( GR_TRIANGLES, count-start, fxVB + start, sizeof(tdfxVertex)); #else { GLuint j; for (j=start+2; jGlide.grDrawTriangle(fxVB + (j-2), fxVB + (j-1), fxVB + j); } } #endif } static void tdfx_render_vb_tri_strip( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; int mode; (void) flags; INIT(GL_TRIANGLE_STRIP); /* fprintf(stderr, "%s/%d\n", __FUNCTION__, 1<Glide.grDrawVertexArrayContiguous( mode, count-start, fxVB + start, sizeof(tdfxVertex)); } static void tdfx_render_vb_tri_fan( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; (void) flags; INIT(GL_TRIANGLE_FAN); fxMesa->Glide.grDrawVertexArrayContiguous( GR_TRIANGLE_FAN, count-start, fxVB + start, sizeof(tdfxVertex) ); } static void tdfx_render_vb_quads( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; GLuint i; (void) flags; INIT(GL_QUADS); for (i = start + 3 ; i < count ; i += 4 ) { #define VERT(x) (fxVB + (x)) tdfxVertex *_v_[4]; _v_[0] = VERT(i); _v_[1] = VERT(i-3); _v_[2] = VERT(i-2); _v_[3] = VERT(i-1); fxMesa->Glide.grDrawVertexArray(GR_TRIANGLE_FAN, 4, _v_); /*fxMesa->Glide.grDrawTriangle( VERT(i-3), VERT(i-2), VERT(i) );*/ /*fxMesa->Glide.grDrawTriangle( VERT(i-2), VERT(i-1), VERT(i) );*/ #undef VERT } } static void tdfx_render_vb_quad_strip( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; (void) flags; INIT(GL_QUAD_STRIP); count -= (count-start)&1; fxMesa->Glide.grDrawVertexArrayContiguous( GR_TRIANGLE_STRIP, count-start, fxVB + start, sizeof(tdfxVertex)); } static void tdfx_render_vb_poly( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxVertex *fxVB = fxMesa->verts; (void) flags; INIT(GL_POLYGON); fxMesa->Glide.grDrawVertexArrayContiguous( GR_POLYGON, count-start, fxVB + start, sizeof(tdfxVertex)); } static void tdfx_render_vb_noop( struct gl_context *ctx, GLuint start, GLuint count, GLuint flags ) { (void) (ctx && start && count && flags); } static void (*tdfx_render_tab_verts[GL_POLYGON+2])(struct gl_context *, GLuint, GLuint, GLuint) = { tdfx_render_vb_points, tdfx_render_vb_lines, tdfx_render_vb_line_loop, tdfx_render_vb_line_strip, tdfx_render_vb_triangles, tdfx_render_vb_tri_strip, tdfx_render_vb_tri_fan, tdfx_render_vb_quads, tdfx_render_vb_quad_strip, tdfx_render_vb_poly, tdfx_render_vb_noop, }; #undef INIT /**********************************************************************/ /* Render whole (indexed) begin/end objects */ /**********************************************************************/ #define VERT(x) (tdfxVertex *)(vertptr + (x)) #define RENDER_POINTS( start, count ) \ for ( ; start < count ; start++) \ fxMesa->Glide.grDrawPoint( VERT(ELT(start)) ); #define RENDER_LINE( v0, v1 ) \ fxMesa->Glide.grDrawLine( VERT(v0), VERT(v1) ) #define RENDER_TRI( v0, v1, v2 ) \ fxMesa->Glide.grDrawTriangle( VERT(v0), VERT(v1), VERT(v2) ) #define RENDER_QUAD( v0, v1, v2, v3 ) \ do { \ tdfxVertex *_v_[4]; \ _v_[0] = VERT(v3); \ _v_[1] = VERT(v0); \ _v_[2] = VERT(v1); \ _v_[3] = VERT(v2); \ fxMesa->Glide.grDrawVertexArray(GR_TRIANGLE_FAN, 4, _v_);\ /*fxMesa->Glide.grDrawTriangle( VERT(v0), VERT(v1), VERT(v3) );*/\ /*fxMesa->Glide.grDrawTriangle( VERT(v1), VERT(v2), VERT(v3) );*/\ } while (0) #define INIT(x) tdfxRenderPrimitive( ctx, x ) #undef LOCAL_VARS #define LOCAL_VARS \ tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); \ tdfxVertex *vertptr = fxMesa->verts; \ const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \ (void) elt; #define RESET_STIPPLE #define RESET_OCCLUSION #define PRESERVE_VB_DEFS /* Elts, no clipping. */ #undef ELT #undef TAG #define TAG(x) tdfx_##x##_elts #define ELT(x) elt[x] #include "tnl_dd/t_dd_rendertmp.h" /* Verts, no clipping. */ #undef ELT #undef TAG #define TAG(x) tdfx_##x##_verts #define ELT(x) x /*#include "tnl_dd/t_dd_rendertmp.h"*/ /**********************************************************************/ /* Render clipped primitives */ /**********************************************************************/ static void tdfxRenderClippedPoly( struct gl_context *ctx, const GLuint *elts, GLuint n ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); TNLcontext *tnl = TNL_CONTEXT(ctx); struct vertex_buffer *VB = &tnl->vb; GLuint prim = fxMesa->render_primitive; /* 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) tnl->Driver.Render.PrimitiveNotify( ctx, prim ); } static void tdfxRenderClippedLine( struct gl_context *ctx, GLuint ii, GLuint jj ) { TNLcontext *tnl = TNL_CONTEXT(ctx); tnl->Driver.Render.Line( ctx, ii, jj ); } static void tdfxFastRenderClippedPoly( struct gl_context *ctx, const GLuint *elts, GLuint n ) { int i; tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx ); tdfxVertex *vertptr = fxMesa->verts; if (n == 3) { fxMesa->Glide.grDrawTriangle( VERT(elts[0]), VERT(elts[1]), VERT(elts[2]) ); } else if (n <= 32) { tdfxVertex *newvptr[32]; for (i = 0 ; i < n ; i++) { newvptr[i] = VERT(elts[i]); } fxMesa->Glide.grDrawVertexArray(GR_TRIANGLE_FAN, n, newvptr); } else { const tdfxVertex *start = VERT(elts[0]); for (i = 2 ; i < n ; i++) { fxMesa->Glide.grDrawTriangle( start, VERT(elts[i-1]), VERT(elts[i]) ); } } } /**********************************************************************/ /* Choose render functions */ /**********************************************************************/ #define POINT_FALLBACK (DD_POINT_SMOOTH) #define LINE_FALLBACK (DD_LINE_STIPPLE) #define TRI_FALLBACK (DD_TRI_SMOOTH) #define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK|DD_TRI_STIPPLE) #define ANY_RASTER_FLAGS (DD_FLATSHADE|DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET| \ DD_TRI_UNFILLED) /* All state referenced below: */ #define _TDFX_NEW_RENDERSTATE (_DD_NEW_POINT_SMOOTH | \ _DD_NEW_LINE_STIPPLE | \ _DD_NEW_TRI_SMOOTH | \ _DD_NEW_FLATSHADE | \ _DD_NEW_TRI_UNFILLED | \ _DD_NEW_TRI_LIGHT_TWOSIDE | \ _DD_NEW_TRI_OFFSET | \ _DD_NEW_TRI_STIPPLE | \ _NEW_POLYGONSTIPPLE) static void tdfxChooseRenderState(struct gl_context *ctx) { TNLcontext *tnl = TNL_CONTEXT(ctx); tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); GLuint flags = ctx->_TriangleCaps; GLuint index = 0; if (0) { fxMesa->draw_point = tdfx_draw_point; fxMesa->draw_line = tdfx_draw_line; fxMesa->draw_triangle = tdfx_draw_triangle; index |= TDFX_FALLBACK_BIT; } if (flags & (ANY_FALLBACK_FLAGS|ANY_RASTER_FLAGS)) { if (flags & ANY_RASTER_FLAGS) { if (flags & DD_TRI_LIGHT_TWOSIDE) index |= TDFX_TWOSIDE_BIT; if (flags & DD_TRI_OFFSET) index |= TDFX_OFFSET_BIT; if (flags & DD_TRI_UNFILLED) index |= TDFX_UNFILLED_BIT; if (flags & DD_FLATSHADE) index |= TDFX_FLAT_BIT; } fxMesa->draw_point = tdfx_draw_point; fxMesa->draw_line = tdfx_draw_line; fxMesa->draw_triangle = tdfx_draw_triangle; /* Hook in fallbacks for specific primitives. * * DD_TRI_UNFILLED is here because the unfilled_tri functions use * fxMesa->draw_tri *always*, and thus can't use the multipass * approach to cliprects. * */ if (flags & (POINT_FALLBACK| LINE_FALLBACK| TRI_FALLBACK| DD_TRI_STIPPLE| DD_TRI_UNFILLED)) { if (flags & POINT_FALLBACK) fxMesa->draw_point = tdfx_fallback_point; if (flags & LINE_FALLBACK) fxMesa->draw_line = tdfx_fallback_line; if (flags & TRI_FALLBACK) fxMesa->draw_triangle = tdfx_fallback_tri; if ((flags & DD_TRI_STIPPLE) && !fxMesa->haveHwStipple) fxMesa->draw_triangle = tdfx_fallback_tri; index |= TDFX_FALLBACK_BIT; } } if (fxMesa->RenderIndex != index) { fxMesa->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 = tdfx_render_tab_verts; tnl->Driver.Render.PrimTabElts = tdfx_render_tab_elts; tnl->Driver.Render.ClippedLine = line; /* from tritmp.h */ tnl->Driver.Render.ClippedPolygon = tdfxFastRenderClippedPoly; } else { tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; tnl->Driver.Render.ClippedLine = tdfxRenderClippedLine; tnl->Driver.Render.ClippedPolygon = tdfxRenderClippedPoly; } } } /**********************************************************************/ /* Use multipass rendering for cliprects */ /**********************************************************************/ /* TODO: Benchmark this. * TODO: Use single back-buffer cliprect where possible. * NOTE: starts at 1, not zero! */ static GLboolean multipass_cliprect( struct gl_context *ctx, GLuint pass ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); if (pass >= fxMesa->numClipRects) return GL_FALSE; else { fxMesa->Glide.grClipWindow(fxMesa->pClipRects[pass].x1, fxMesa->screen_height - fxMesa->pClipRects[pass].y2, fxMesa->pClipRects[pass].x2, fxMesa->screen_height - fxMesa->pClipRects[pass].y1); return GL_TRUE; } } /**********************************************************************/ /* Runtime render state and callbacks */ /**********************************************************************/ static void tdfxRunPipeline( struct gl_context *ctx ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); if (fxMesa->new_state) { tdfxDDUpdateHwState( ctx ); } if (!fxMesa->Fallback && fxMesa->new_gl_state) { if (fxMesa->new_gl_state & _TDFX_NEW_RASTERSETUP) tdfxChooseVertexState( ctx ); if (fxMesa->new_gl_state & _TDFX_NEW_RENDERSTATE) tdfxChooseRenderState( ctx ); fxMesa->new_gl_state = 0; } _tnl_run_pipeline( ctx ); } static void tdfxRenderStart( struct gl_context *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); tdfxCheckTexSizes( ctx ); LOCK_HARDWARE(fxMesa); /* Make sure vertex format changes get uploaded before we start * sending triangles. */ if (fxMesa->dirty) { tdfxEmitHwStateLocked( fxMesa ); } if (fxMesa->numClipRects && !(fxMesa->RenderIndex & TDFX_FALLBACK_BIT)) { fxMesa->Glide.grClipWindow(fxMesa->pClipRects[0].x1, fxMesa->screen_height - fxMesa->pClipRects[0].y2, fxMesa->pClipRects[0].x2, fxMesa->screen_height - fxMesa->pClipRects[0].y1); if (fxMesa->numClipRects > 1) tnl->Driver.Render.Multipass = multipass_cliprect; else tnl->Driver.Render.Multipass = NULL; } else tnl->Driver.Render.Multipass = NULL; } /* Always called between RenderStart and RenderFinish --> We already * hold the lock. */ static void tdfxRasterPrimitive( struct gl_context *ctx, GLenum prim ) { tdfxContextPtr fxMesa = TDFX_CONTEXT( ctx ); FLUSH_BATCH( fxMesa ); fxMesa->raster_primitive = prim; tdfxUpdateCull(ctx); if ( fxMesa->dirty & TDFX_UPLOAD_CULL ) { fxMesa->Glide.grCullMode( fxMesa->CullMode ); fxMesa->dirty &= ~TDFX_UPLOAD_CULL; } tdfxUpdateStipple(ctx); if ( fxMesa->dirty & TDFX_UPLOAD_STIPPLE ) { fxMesa->Glide.grStipplePattern ( fxMesa->Stipple.Pattern ); fxMesa->Glide.grStippleMode ( fxMesa->Stipple.Mode ); fxMesa->dirty &= ~TDFX_UPLOAD_STIPPLE; } } /* Determine the rasterized primitive when not drawing unfilled * polygons. * * Used only for the default render stage which always decomposes * primitives to trianges/lines/points. For the accelerated stage, * which renders strips as strips, the equivalent calculations are * performed in tdfx_render.c. */ static void tdfxRenderPrimitive( struct gl_context *ctx, GLenum prim ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); GLuint rprim = reduced_prim[prim]; fxMesa->render_primitive = prim; if (rprim == GL_TRIANGLES && (ctx->_TriangleCaps & DD_TRI_UNFILLED)) return; if (fxMesa->raster_primitive != rprim) { tdfxRasterPrimitive( ctx, rprim ); } } static void tdfxRenderFinish( struct gl_context *ctx ) { tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); if (fxMesa->RenderIndex & TDFX_FALLBACK_BIT) _swrast_flush( ctx ); UNLOCK_HARDWARE(fxMesa); } /**********************************************************************/ /* Manage total rasterization fallbacks */ /**********************************************************************/ static char *fallbackStrings[] = { "3D/Rect/Cube Texture map", "glDrawBuffer(GL_FRONT_AND_BACK)", "Separate specular color", "glEnable/Disable(GL_STENCIL_TEST)", "glRenderMode(selection or feedback)", "glLogicOp()", "Texture env mode", "Texture border", "glColorMask", "blend mode", "line stipple", "Rasterization disable" }; static char *getFallbackString(GLuint bit) { int i = 0; while (bit > 1) { i++; bit >>= 1; } return fallbackStrings[i]; } void tdfxFallback( struct gl_context *ctx, GLuint bit, GLboolean mode ) { TNLcontext *tnl = TNL_CONTEXT(ctx); tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); GLuint oldfallback = fxMesa->Fallback; if (mode) { fxMesa->Fallback |= bit; if (oldfallback == 0) { /*printf("Go to software rendering, bit = 0x%x\n", bit);*/ FLUSH_BATCH(fxMesa); _swsetup_Wakeup( ctx ); fxMesa->RenderIndex = ~0; if (TDFX_DEBUG & DEBUG_VERBOSE_FALL) { fprintf(stderr, "Tdfx begin software fallback: 0x%x %s\n", bit, getFallbackString(bit)); } } } else { fxMesa->Fallback &= ~bit; if (oldfallback == bit) { /*printf("Go to hardware rendering, bit = 0x%x\n", bit);*/ _swrast_flush( ctx ); tnl->Driver.Render.Start = tdfxRenderStart; tnl->Driver.Render.PrimitiveNotify = tdfxRenderPrimitive; tnl->Driver.Render.Finish = tdfxRenderFinish; tnl->Driver.Render.BuildVertices = tdfxBuildVertices; fxMesa->new_gl_state |= (_TDFX_NEW_RENDERSTATE| _TDFX_NEW_RASTERSETUP); if (TDFX_DEBUG & DEBUG_VERBOSE_FALL) { fprintf(stderr, "Tdfx end software fallback: 0x%x %s\n", bit, getFallbackString(bit)); } } } } void tdfxDDInitTriFuncs( struct gl_context *ctx ) { TNLcontext *tnl = TNL_CONTEXT(ctx); tdfxContextPtr fxMesa = TDFX_CONTEXT(ctx); static int firsttime = 1; if (firsttime) { init_rast_tab(); firsttime = 0; } fxMesa->RenderIndex = ~0; tnl->Driver.RunPipeline = tdfxRunPipeline; tnl->Driver.Render.Start = tdfxRenderStart; tnl->Driver.Render.Finish = tdfxRenderFinish; tnl->Driver.Render.PrimitiveNotify = tdfxRenderPrimitive; tnl->Driver.Render.ResetLineStipple = _swrast_ResetLineStipple; tnl->Driver.Render.BuildVertices = tdfxBuildVertices; tnl->Driver.Render.Multipass = NULL; (void) tdfx_print_vertex; }