Files
third_party_mesa3d/src/mesa/drivers/glide/fxdd.c

633 lines
18 KiB
C
Raw Normal View History

1999-08-19 00:55:39 +00:00
/* -*- mode: C; tab-width:8; -*-
fxdd.c - 3Dfx VooDoo Mesa device driver functions
*/
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* See the file fxapi.c for more informations about authors
*
*/
#ifdef HAVE_CONFIG_H
#include "conf.h"
#endif
#if defined(FX)
#include "fxdrv.h"
#include "enums.h"
/**********************************************************************/
/***** Miscellaneous functions *****/
/**********************************************************************/
/* Enalbe/Disable dithering */
void fxDDDither(GLcontext *ctx, GLboolean enable)
{
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxDDDither()\n");
}
if(enable)
grDitherMode(GR_DITHER_4x4);
else
grDitherMode(GR_DITHER_DISABLE);
}
/* Return buffer size information */
void fxDDBufferSize(GLcontext *ctx, GLuint *width, GLuint *height)
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxDDBufferSize(...) Start\n");
}
*width=fxMesa->width;
*height=fxMesa->height;
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxDDBufferSize(...) End\n");
}
}
/* Set current drawing color */
static void fxDDSetColor(GLcontext *ctx, GLubyte red, GLubyte green,
GLubyte blue, GLubyte alpha )
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
GLubyte col[4];
ASSIGN_4V( col, red, green, blue, alpha );
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxDDSetColor(%d,%d,%d,%d)\n",red,green,blue,alpha);
}
fxMesa->color=FXCOLOR4(col);
}
/* Implements glClearColor() */
static void fxDDClearColor(GLcontext *ctx, GLubyte red, GLubyte green,
GLubyte blue, GLubyte alpha )
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
GLubyte col[4];
ASSIGN_4V( col, red, green, blue, 255 );
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxDDClearColor(%d,%d,%d,%d)\n",red,green,blue,alpha);
}
fxMesa->clearC=FXCOLOR4( col );
fxMesa->clearA=alpha;
}
/* Clear the color and/or depth buffers */
static GLbitfield fxDDClear(GLcontext *ctx, GLbitfield mask, GLboolean all,
GLint x, GLint y, GLint width, GLint height )
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
GLbitfield newmask;
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxDDClear(%d,%d,%d,%d)\n",x,y,width,height);
}
switch(mask & (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)) {
case (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT):
/* clear color and depth buffer */
if (ctx->Color.DrawDestMask & BACK_LEFT_BIT) {
grRenderBuffer(GR_BUFFER_BACKBUFFER);
grBufferClear(fxMesa->clearC, fxMesa->clearA,
(FxU16)(ctx->Depth.Clear*0xffff));
}
if (ctx->Color.DrawDestMask & FRONT_LEFT_BIT) {
grRenderBuffer(GR_BUFFER_FRONTBUFFER);
grBufferClear(fxMesa->clearC, fxMesa->clearA,
(FxU16)(ctx->Depth.Clear*0xffff));
}
newmask=mask & (~(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT));
break;
case (GL_COLOR_BUFFER_BIT):
/* clear color buffer */
if(ctx->Color.ColorMask) {
grDepthMask(FXFALSE);
if (ctx->Color.DrawDestMask & BACK_LEFT_BIT) {
grRenderBuffer(GR_BUFFER_BACKBUFFER);
grBufferClear(fxMesa->clearC, fxMesa->clearA, 0);
}
if (ctx->Color.DrawDestMask & FRONT_LEFT_BIT) {
grRenderBuffer(GR_BUFFER_FRONTBUFFER);
grBufferClear(fxMesa->clearC, fxMesa->clearA, 0);
}
if(ctx->Depth.Mask)
grDepthMask(FXTRUE);
}
newmask=mask & (~(GL_COLOR_BUFFER_BIT));
break;
case (GL_DEPTH_BUFFER_BIT):
/* clear depth buffer */
if(ctx->Depth.Mask) {
grColorMask(FXFALSE,FXFALSE);
grBufferClear(fxMesa->clearC, fxMesa->clearA,
(FxU16)(ctx->Depth.Clear*0xffff));
grColorMask(ctx->Color.ColorMask[RCOMP] ||
ctx->Color.ColorMask[GCOMP] ||
ctx->Color.ColorMask[BCOMP],
ctx->Color.ColorMask[ACOMP] && fxMesa->haveAlphaBuffer);
}
newmask=mask & (~(GL_DEPTH_BUFFER_BIT));
break;
default:
newmask=mask;
break;
}
return newmask;
}
/* Set the buffer used in double buffering */
static GLboolean fxDDSetBuffer(GLcontext *ctx, GLenum mode )
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxDDSetBuffer(%x)\n",mode);
}
if (mode == GL_FRONT_LEFT) {
fxMesa->currentFB = GR_BUFFER_FRONTBUFFER;
grRenderBuffer(fxMesa->currentFB);
return GL_TRUE;
}
else if (mode == GL_BACK_LEFT) {
fxMesa->currentFB = GR_BUFFER_BACKBUFFER;
grRenderBuffer(fxMesa->currentFB);
return GL_TRUE;
}
else {
return GL_FALSE;
}
}
static GLboolean fxDDDrawBitMap(GLcontext *ctx, GLint px, GLint py,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLubyte *bitmap)
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
FxU16 *p;
GrLfbInfo_t info;
const GLubyte *pb;
int x,y;
GLint r,g,b,a,scrwidth,scrheight,stride;
FxU16 color;
/* TODO: with a little work, these bitmap unpacking parameter restrictions
* could be removed.
*/
if((unpack->Alignment!=1) ||
(unpack->RowLength!=0) ||
(unpack->SkipPixels!=0) ||
(unpack->SkipRows!=0) ||
(unpack->SwapBytes) ||
(unpack->LsbFirst))
return GL_FALSE;
#define ISCLIPPED(rx) ( ((rx)<0) || ((rx)>=scrwidth) )
#define DRAWBIT(i) { \
if(!ISCLIPPED(x+px)) \
if( (*pb) & (1<<(i)) ) \
(*p)=color; \
p++; \
x++; \
if(x>=width) { \
pb++; \
break; \
} \
}
scrwidth=fxMesa->width;
scrheight=fxMesa->height;
if((px>=scrwidth) || (px+width<=0) || (py>=scrheight) || (py+height<=0))
return GL_TRUE;
pb=bitmap;
if(py<0) {
pb+=(height*(-py)) >> (3+1);
height+=py;
py=0;
}
if(py+height>=scrheight)
height-=(py+height)-scrheight;
info.size=sizeof(info);
if(!grLfbLock(GR_LFB_WRITE_ONLY,
fxMesa->currentFB,
GR_LFBWRITEMODE_565,
GR_ORIGIN_UPPER_LEFT,
FXFALSE,
&info)) {
#ifndef FX_SILENT
fprintf(stderr,"fx Driver: error locking the linear frame buffer\n");
#endif
return GL_TRUE;
}
r=(GLint)(ctx->Current.RasterColor[0]*255.0f);
g=(GLint)(ctx->Current.RasterColor[1]*255.0f);
b=(GLint)(ctx->Current.RasterColor[2]*255.0f);
a=(GLint)(ctx->Current.RasterColor[3]*255.0f);
color=(FxU16)
( ((FxU16)0xf8 & b) <<(11-3)) |
( ((FxU16)0xfc & g) <<(5-3+1)) |
( ((FxU16)0xf8 & r) >> 3);
stride=info.strideInBytes>>1;
/* This code is a bit slow... */
for(y=0;y<height;y++) {
p=((FxU16 *)info.lfbPtr)+px+((scrheight-(y+py))*stride);
for(x=0;;) {
DRAWBIT(7); DRAWBIT(6); DRAWBIT(5); DRAWBIT(4);
DRAWBIT(3); DRAWBIT(2); DRAWBIT(1); DRAWBIT(0);
pb++;
}
}
grLfbUnlock(GR_LFB_WRITE_ONLY,fxMesa->currentFB);
#undef ISCLIPPED
#undef DRAWBIT
return GL_TRUE;
}
static void fxDDFinish(GLcontext *ctx)
{
FX_grFlush();
}
static GLint fxDDGetParameteri(const GLcontext *ctx, GLint param)
{
switch(param) {
case DD_HAVE_HARDWARE_FOG:
return 1;
default:
fprintf(stderr,"fx Driver: internal error in fxDDGetParameteri(): %x\n",param);
fxCloseHardware();
exit(-1);
}
}
void fxDDSetNearFar(GLcontext *ctx, GLfloat n, GLfloat f)
{
FX_CONTEXT(ctx)->new_state |= FX_NEW_FOG;
ctx->Driver.RenderStart = fxSetupFXUnits;
}
/* KW: Put the word Mesa in the render string because quakeworld
* checks for this rather than doing a glGet(GL_MAX_TEXTURE_SIZE).
* Why?
*/
static const GLubyte *fxDDGetString(GLcontext *ctx, GLenum name)
{
static char *extensions="GL_EXT_blend_color GL_EXT_blend_minmax GL_EXT_blend_logic_op GL_EXT_blend_subtract GL_EXT_paletted_texture GL_EXT_point_parameters GL_EXT_polygon_offset GL_EXT_vertex_array GL_EXT_texture_object GL_EXT_texture3D GL_MESA_window_pos GL_MESA_resize_buffers GL_EXT_shared_texture_palette GL_EXT_rescale_normal GL_EXT_abgr GL_SGIS_texture_edge_clamp 3DFX_set_global_palette GL_FXMESA_global_texture_lod_bias";
static char buf[MAX_NUM_SST][64];
fxQueryHardware();
switch (name) {
case GL_RENDERER:
if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_VOODOO) {
sprintf(buf[glbCurrentBoard],"Mesa Glide v0.30 Voodoo_Graphics %d CARD/%d FB/%d TM/%d TMU/%s",
glbCurrentBoard,
(glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.sliDetect ?
(glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.fbRam*2) :
glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.fbRam),
glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.tmuConfig[GR_TMU0].tmuRam+
((glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.nTexelfx>1) ?
glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.tmuConfig[GR_TMU1].tmuRam :
0),
glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.nTexelfx,
(glbHWConfig.SSTs[glbCurrentBoard].sstBoard.VoodooConfig.sliDetect ? "SLI" : "NOSLI")
);
}
else {
if(glbHWConfig.SSTs[glbCurrentBoard].type==GR_SSTTYPE_SST96)
sprintf(buf[glbCurrentBoard],"Glide v0.30 Voodoo_Rush %d CARD/%d FB/%d TM/%d TMU/NOSLI",
glbCurrentBoard,
glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config.fbRam,
glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config.tmuConfig.tmuRam,
glbHWConfig.SSTs[glbCurrentBoard].sstBoard.SST96Config.nTexelfx
);
else
strcpy(buf[glbCurrentBoard],"Glide v0.30 UNKNOWN");
}
return (GLubyte *) buf[glbCurrentBoard];
case GL_EXTENSIONS:
return (GLubyte *) extensions;
default:
return NULL;
}
}
void fxDDInitExtensions( GLcontext *ctx )
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
gl_extensions_add( ctx, DEFAULT_ON, "3DFX_set_global_palette", 0 );
gl_extensions_add( ctx, DEFAULT_ON, "GL_FXMESA_global_texture_lod_bias", 0);
if (!fxMesa->emulateTwoTMUs)
gl_extensions_disable( ctx, "GL_ARB_multitexture" );
}
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* This is a no-op, since the z-buffer is in hardware */
static void fxAllocDepthBuffer(GLcontext *ctx)
{
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxAllocDepthBuffer()\n");
}
}
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* Check if the hardware supports the current context
*
* Performs similar work to fxDDChooseRenderState() - should be merged.
*/
static GLboolean fxIsInHardware(GLcontext *ctx)
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
if (!ctx->Hint.AllowDrawMem)
return GL_TRUE; /* you'll take it and like it */
if((ctx->RasterMask & STENCIL_BIT) ||
((ctx->Color.BlendEnabled) && (ctx->Color.BlendEquation!=GL_FUNC_ADD_EXT)) ||
((ctx->Color.ColorLogicOpEnabled) && (ctx->Color.LogicOp!=GL_COPY)) ||
(ctx->Light.Model.ColorControl==GL_SEPARATE_SPECULAR_COLOR) ||
(!((ctx->Color.ColorMask[RCOMP]==ctx->Color.ColorMask[GCOMP]) &&
(ctx->Color.ColorMask[GCOMP]==ctx->Color.ColorMask[BCOMP]) &&
(ctx->Color.ColorMask[ACOMP]==ctx->Color.ColorMask[ACOMP])))
)
return GL_FALSE;
/* Unsupported texture/multitexture cases */
if(fxMesa->emulateTwoTMUs) {
if((ctx->Enabled & (TEXTURE0_3D | TEXTURE1_3D)) ||
/* Not very well written ... */
((ctx->Enabled & (TEXTURE0_1D | TEXTURE1_1D)) &&
((ctx->Enabled & (TEXTURE0_2D | TEXTURE1_2D))!=(TEXTURE0_2D | TEXTURE1_2D)))
)
return GL_FALSE;
if((ctx->Texture.ReallyEnabled & TEXTURE0_2D) &&
(ctx->Texture.Unit[0].EnvMode==GL_BLEND))
return GL_FALSE;
if((ctx->Texture.ReallyEnabled & TEXTURE1_2D) &&
(ctx->Texture.Unit[1].EnvMode==GL_BLEND))
return GL_FALSE;
if (MESA_VERBOSE & (VERBOSE_DRIVER|VERBOSE_TEXTURE))
fprintf(stderr, "fxMesa: fxIsInHardware, envmode is %s/%s\n",
gl_lookup_enum_by_nr(ctx->Texture.Unit[0].EnvMode),
gl_lookup_enum_by_nr(ctx->Texture.Unit[1].EnvMode));
/* KW: This was wrong (I think) and I changed it... which doesn't mean
* it is now correct...
*/
if((ctx->Enabled & (TEXTURE0_1D | TEXTURE0_2D | TEXTURE0_3D)) &&
(ctx->Enabled & (TEXTURE1_1D | TEXTURE1_2D | TEXTURE1_3D)))
{
/* Can't use multipass to blend a multitextured triangle - fall
* back to software.
*/
if (!fxMesa->haveTwoTMUs && ctx->Color.BlendEnabled)
return GL_FALSE;
if ((ctx->Texture.Unit[0].EnvMode!=ctx->Texture.Unit[1].EnvMode) &&
(ctx->Texture.Unit[0].EnvMode!=GL_MODULATE) &&
(ctx->Texture.Unit[0].EnvMode!=GL_REPLACE)) /* q2, seems ok... */
{
if (MESA_VERBOSE&VERBOSE_DRIVER)
fprintf(stderr, "fxMesa: unsupported multitex env mode\n");
return GL_FALSE;
}
}
} else {
if((ctx->Enabled & (TEXTURE1_1D | TEXTURE1_2D | TEXTURE1_3D)) ||
/* Not very well written ... */
((ctx->Enabled & TEXTURE0_1D) &&
(!(ctx->Enabled & TEXTURE0_2D)))
)
return GL_FALSE;
if((ctx->Texture.ReallyEnabled & TEXTURE0_2D) &&
(ctx->Texture.Unit[0].EnvMode==GL_BLEND))
return GL_FALSE;
}
return GL_TRUE;
}
#define INTERESTED (~(NEW_MODELVIEW|NEW_PROJECTION|NEW_PROJECTION|NEW_TEXTURE_MATRIX|NEW_USER_CLIP|NEW_CLIENT_STATE|NEW_TEXTURE_ENABLE))
static void fxDDUpdateDDPointers(GLcontext *ctx)
{
fxMesaContext fxMesa=(fxMesaContext)ctx->DriverCtx;
GLuint new_state = ctx->NewState;
if (MESA_VERBOSE&(VERBOSE_DRIVER|VERBOSE_STATE))
fprintf(stderr,"fxmesa: fxDDUpdateDDPointers(...)\n");
if (new_state & (NEW_RASTER_OPS|NEW_TEXTURING))
fxMesa->is_in_hardware = fxIsInHardware(ctx);
if (fxMesa->is_in_hardware) {
if (fxMesa->new_state)
fxSetupFXUnits(ctx);
if(new_state & INTERESTED) {
fxDDChooseRenderState( ctx );
fxMesa->RenderVBTables=fxDDChooseRenderVBTables(ctx);
1999-08-26 14:50:49 +00:00
fxMesa->RenderVBClippedTab=fxMesa->RenderVBTables[0];
fxMesa->RenderVBCulledTab=fxMesa->RenderVBTables[1];
fxMesa->RenderVBRawTab=fxMesa->RenderVBTables[2];
1999-08-19 00:55:39 +00:00
ctx->Driver.RasterSetup=fxDDChooseSetupFunction(ctx);
}
ctx->Driver.PointsFunc=fxMesa->PointsFunc;
ctx->Driver.LineFunc=fxMesa->LineFunc;
ctx->Driver.TriangleFunc=fxMesa->TriangleFunc;
ctx->Driver.QuadFunc=fxMesa->QuadFunc;
}
ctx->Driver.AllocDepthBuffer=fxAllocDepthBuffer;
ctx->Driver.DepthTestSpan=fxDDDepthTestSpanGeneric;
ctx->Driver.DepthTestPixels=fxDDDepthTestPixelsGeneric;
ctx->Driver.ReadDepthSpanFloat=fxDDReadDepthSpanFloat;
ctx->Driver.ReadDepthSpanInt=fxDDReadDepthSpanInt;
ctx->Driver.RenderStart = 0;
}
void fxSetupDDPointers(GLcontext *ctx)
{
if (MESA_VERBOSE&VERBOSE_DRIVER) {
fprintf(stderr,"fxmesa: fxSetupDDPointers()\n");
}
ctx->Driver.UpdateState=fxDDUpdateDDPointers;
ctx->Driver.GetString=fxDDGetString;
ctx->Driver.Dither=fxDDDither;
ctx->Driver.NearFar=fxDDSetNearFar;
ctx->Driver.GetParameteri=fxDDGetParameteri;
ctx->Driver.ClearIndex=NULL;
ctx->Driver.ClearColor=fxDDClearColor;
ctx->Driver.Clear=fxDDClear;
ctx->Driver.Index=NULL;
ctx->Driver.Color=fxDDSetColor;
ctx->Driver.SetBuffer=fxDDSetBuffer;
ctx->Driver.GetBufferSize=fxDDBufferSize;
ctx->Driver.Bitmap=fxDDDrawBitMap;
ctx->Driver.DrawPixels=NULL;
ctx->Driver.Finish=fxDDFinish;
ctx->Driver.Flush=NULL;
ctx->Driver.RenderStart=NULL;
ctx->Driver.RenderFinish=NULL;
ctx->Driver.TexEnv=fxDDTexEnv;
ctx->Driver.TexImage=fxDDTexImg;
ctx->Driver.TexSubImage=fxDDTexSubImg;
ctx->Driver.TexParameter=fxDDTexParam;
ctx->Driver.BindTexture=fxDDTexBind;
ctx->Driver.DeleteTexture=fxDDTexDel;
ctx->Driver.UpdateTexturePalette=fxDDTexPalette;
ctx->Driver.UseGlobalTexturePalette=fxDDTexUseGlbPalette;
ctx->Driver.RectFunc=NULL;
ctx->Driver.AlphaFunc=fxDDAlphaFunc;
ctx->Driver.BlendFunc=fxDDBlendFunc;
ctx->Driver.DepthFunc=fxDDDepthFunc;
ctx->Driver.DepthMask=fxDDDepthMask;
ctx->Driver.ColorMask=fxDDColorMask;
ctx->Driver.Fogfv=fxDDFogfv;
ctx->Driver.Scissor=fxDDScissor;
ctx->Driver.FrontFace=fxDDFrontFace;
ctx->Driver.CullFace=fxDDCullFace;
ctx->Driver.ShadeModel=fxDDShadeModel;
ctx->Driver.Enable=fxDDEnable;
ctx->Driver.RegisterVB=fxDDRegisterVB;
ctx->Driver.UnregisterVB=fxDDUnregisterVB;
ctx->Driver.RegisterPipelineStages = fxDDRegisterPipelineStages;
ctx->Driver.OptimizeImmediatePipeline = 0; /* nothing done yet */
ctx->Driver.OptimizePrecalcPipeline = 0;
/* if (getenv("MESA_USE_FAST") || getenv("FX_USE_FAST")) */
/* ctx->Driver.OptimizePrecalcPipeline = fxDDOptimizePrecalcPipeline; */
if (!getenv("FX_NO_FAST"))
ctx->Driver.BuildPrecalcPipeline = fxDDBuildPrecalcPipeline;
ctx->Driver.TriangleCaps = DD_TRI_CULL|DD_TRI_OFFSET|DD_TRI_LIGHT_TWOSIDE;
fxSetupDDSpanPointers(ctx);
FX_CONTEXT(ctx)->render_index = 1; /* force an update */
fxDDUpdateDDPointers(ctx);
}
#else
/*
* Need this to provide at least one external definition.
*/
int gl_fx_dummy_function_dd(void)
{
return 0;
}
#endif /* FX */