diff options
Diffstat (limited to 'xc/lib/GL/mesa/src/drv/radeon')
30 files changed, 10227 insertions, 0 deletions
diff --git a/xc/lib/GL/mesa/src/drv/radeon/Imakefile b/xc/lib/GL/mesa/src/drv/radeon/Imakefile new file mode 100644 index 000000000..52787a5fc --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/Imakefile @@ -0,0 +1,386 @@ +XCOMM $XFree86: xc/lib/GL/mesa/src/drv/radeon/Imakefile,v 1.1 2001/01/08 01:07:26 martin Exp $ + +#include <Threads.tmpl> + +#define DoNormalLib NormalLibGlx +#define DoSharedLib SharedLibGlx +#define DoExtraLib SharedLibGlx +#define DoDebugLib DebugLibGlx +#define DoProfileLib ProfileLibGlx + +#if Malloc0ReturnsNull +ALLOC_DEFINES = -DMALLOC_0_RETURNS_NULL +#endif + +#ifdef i386Architecture +#if MesaUseMMX + MMX_DEFS = -DUSE_MMX_ASM +#endif +#if MesaUse3DNow + 3DNOW_DEFS = -DUSE_3DNOW_ASM +#endif +#if MesaUseKatmai + KATMAI_DEFS = -DUSE_KATMAI_ASM +#endif + ASM_DEFINES = -DUSE_X86_ASM $(MMX_DEFS) $(3DNOW_DEFS) $(KATMAI_DEFS) +#endif + +#if BuildXF86DRI + DRI_DEFINES = GlxDefines -DDRIVERTS + DRI_INCLUDES = -I../../../../dri \ + -I../../../../glx \ + -I../../../dri \ + -I$(TOP)/include \ + -I$(TOP)/include/GL \ + -I$(XF86OSSRC) \ + -I$(XF86COMSRC) \ + -I$(SERVERSRC)/GL/dri \ + -I$(XF86DRIVERSRC)/ati \ + -I../../../include \ + -I../.. \ + -I../../X \ + -I../common +#endif + +MESA_INCLUDES = -I. -I.. -I../../include \ + -I../../../../dri/drm + + DEFINES = $(ALLOC_DEFINES) $(DRI_DEFINES) $(ASM_DEFINES) + INCLUDES = -I$(XLIBSRC) -I$(EXTINCSRC) $(MESA_INCLUDES) $(DRI_INCLUDES) + + RADEONSRCS = radeon_context.c \ + radeon_dd.c \ + radeon_fastpath.c \ + radeon_eltpath.c \ + radeon_ioctl.c \ + radeon_lock.c \ + radeon_pipeline.c \ + radeon_screen.c \ + radeon_span.c \ + radeon_state.c \ + radeon_tex.c \ + radeon_tris.c \ + radeon_vb.c \ + radeon_xmesa.c + + RADEONOBJS = radeon_context.o \ + radeon_dd.o \ + radeon_fastpath.o \ + radeon_eltpath.o \ + radeon_ioctl.o \ + radeon_lock.o \ + radeon_pipeline.o \ + radeon_screen.o \ + radeon_span.o \ + radeon_state.o \ + radeon_tex.o \ + radeon_tris.o \ + radeon_vb.o \ + radeon_xmesa.o + +#if !GlxUseBuiltInDRIDriver + DRISRCS = ../../../dri/dri_mesa.c \ + ../../../../dri/dri_tmm.c + + DRIOBJS = ../../../dri/dri_mesa.o \ + ../../../../dri/dri_tmm.o + + DRMSRCS = ../../../../dri/drm/xf86drm.c \ + ../../../../dri/drm/xf86drmHash.c \ + ../../../../dri/drm/xf86drmRandom.c \ + ../../../../dri/drm/xf86drmSL.c \ + ../../../../dri/drm/xf86drmRadeon.c + + DRMOBJS = ../../../../dri/drm/xf86drm.o \ + ../../../../dri/drm/xf86drmHash.o \ + ../../../../dri/drm/xf86drmRandom.o \ + ../../../../dri/drm/xf86drmSL.o \ + ../../../../dri/drm/xf86drmRadeon.o + + MESASRCS = ../../aatriangle.c \ + ../../accum.c \ + ../../alpha.c \ + ../../alphabuf.c \ + ../../attrib.c \ + ../../bbox.c \ + ../../bitmap.c \ + ../../blend.c \ + ../../buffers.c \ + ../../clip.c \ + ../../colortab.c \ + ../../config.c \ + ../../context.c \ + ../../copypix.c \ + ../../cva.c \ + ../../debug_xform.c \ + ../../depth.c \ + ../../dlist.c \ + ../../drawpix.c \ + ../../enable.c \ + ../../enums.c \ + ../../eval.c \ + ../../extensions.c \ + ../../feedback.c \ + ../../fog.c \ + ../../get.c \ + ../../glapi.c \ + ../../glapinoop.c \ + ../../glthread.c \ + ../../hash.c \ + ../../image.c \ + ../../imaging.c \ + ../../light.c \ + ../../lines.c \ + ../../logic.c \ + ../../masking.c \ + ../../matrix.c \ + ../../mem.c \ + ../../mmath.c \ + ../../pb.c \ + ../../pipeline.c \ + ../../pixel.c \ + ../../pixeltex.c \ + ../../points.c \ + ../../polygon.c \ + ../../quads.c \ + ../../rastpos.c \ + ../../readpix.c \ + ../../rect.c \ + ../../scissor.c \ + ../../shade.c \ + ../../span.c \ + ../../stages.c \ + ../../state.c \ + ../../stencil.c \ + ../../teximage.c \ + ../../texobj.c \ + ../../texstate.c \ + ../../texture.c \ + ../../texutil.c \ + ../../translate.c \ + ../../triangle.c \ + ../../varray.c \ + ../../vb.c \ + ../../vbcull.c \ + ../../vbfill.c \ + ../../vbindirect.c \ + ../../vbrender.c \ + ../../vbxform.c \ + ../../vector.c \ + ../../vertices.c \ + ../../winpos.c \ + ../../xform.c \ + ../../zoom.c + + MESAOBJS = ../../aatriangle.o \ + ../../accum.o \ + ../../alpha.o \ + ../../alphabuf.o \ + ../../attrib.o \ + ../../bbox.o \ + ../../bitmap.o \ + ../../blend.o \ + ../../buffers.o \ + ../../clip.o \ + ../../colortab.o \ + ../../config.o \ + ../../context.o \ + ../../copypix.o \ + ../../cva.o \ + ../../debug_xform.o \ + ../../depth.o \ + ../../dlist.o \ + ../../drawpix.o \ + ../../enable.o \ + ../../enums.o \ + ../../eval.o \ + ../../extensions.o \ + ../../feedback.o \ + ../../fog.o \ + ../../get.o \ + ../../hash.o \ + ../../hint.o \ + ../../image.o \ + ../../imaging.o \ + ../../light.o \ + ../../lines.o \ + ../../logic.o \ + ../../masking.o \ + ../../matrix.o \ + ../../mem.o \ + ../../mmath.o \ + ../../pb.o \ + ../../pipeline.o \ + ../../pixel.o \ + ../../pixeltex.o \ + ../../points.o \ + ../../polygon.o \ + ../../quads.o \ + ../../rastpos.o \ + ../../readpix.o \ + ../../rect.o \ + ../../scissor.o \ + ../../shade.o \ + ../../span.o \ + ../../stages.o \ + ../../state.o \ + ../../stencil.o \ + ../../teximage.o \ + ../../texobj.o \ + ../../texstate.o \ + ../../texture.o \ + ../../texutil.o \ + ../../translate.o \ + ../../triangle.o \ + ../../varray.o \ + ../../vb.o \ + ../../vbcull.o \ + ../../vbfill.o \ + ../../vbindirect.o \ + ../../vbrender.o \ + ../../vbxform.o \ + ../../vector.o \ + ../../vertices.o \ + ../../winpos.o \ + ../../xform.o \ + ../../zoom.o + +#ifdef i386Architecture + X86_SRCS = ../../X86/common_x86.c \ + ../../X86/common_x86_asm.S \ + ../../X86/x86.c \ + ../../X86/x86_cliptest.S \ + ../../X86/x86_vertex.S \ + ../../X86/x86_xform_masked2.S \ + ../../X86/x86_xform_masked3.S \ + ../../X86/x86_xform_masked4.S \ + ../../X86/x86_xform_raw2.S \ + ../../X86/x86_xform_raw3.S \ + ../../X86/x86_xform_raw4.S + + X86_OBJS = ../../X86/common_x86.o \ + ../../X86/common_x86_asm.o \ + ../../X86/x86.o \ + ../../X86/x86_cliptest.o \ + ../../X86/x86_vertex.o \ + ../../X86/x86_xform_masked2.o \ + ../../X86/x86_xform_masked3.o \ + ../../X86/x86_xform_masked4.o \ + ../../X86/x86_xform_raw2.o \ + ../../X86/x86_xform_raw3.o \ + ../../X86/x86_xform_raw4.o + +#if MesaUseMMX + MMX_SRCS = ../../X86/mmx_blend.S + + MMX_OBJS = ../../X86/mmx_blend.o +#endif + +#if MesaUse3DNow + 3DNOW_SRCS = ../../X86/3dnow.c \ + ../../X86/3dnow_norm_raw.S \ + ../../X86/3dnow_vertex.S \ + ../../X86/3dnow_xform_masked1.S \ + ../../X86/3dnow_xform_masked2.S \ + ../../X86/3dnow_xform_masked3.S \ + ../../X86/3dnow_xform_masked4.S \ + ../../X86/3dnow_xform_raw1.S \ + ../../X86/3dnow_xform_raw2.S \ + ../../X86/3dnow_xform_raw3.S \ + ../../X86/3dnow_xform_raw4.S + + 3DNOW_OBJS = ../../X86/3dnow.o \ + ../../X86/3dnow_norm_raw.o \ + ../../X86/3dnow_vertex.o \ + ../../X86/3dnow_xform_masked1.o \ + ../../X86/3dnow_xform_masked2.o \ + ../../X86/3dnow_xform_masked3.o \ + ../../X86/3dnow_xform_masked4.o \ + ../../X86/3dnow_xform_raw1.o \ + ../../X86/3dnow_xform_raw2.o \ + ../../X86/3dnow_xform_raw3.o \ + ../../X86/3dnow_xform_raw4.o +#endif + +#if MesaUseKatmai + KATMAI_SRCS = ../../X86/katmai.c \ + ../../X86/katmai_norm_raw.S \ + ../../X86/katmai_vertex.S \ + ../../X86/katmai_xform_masked1.S \ + ../../X86/katmai_xform_masked2.S \ + ../../X86/katmai_xform_masked3.S \ + ../../X86/katmai_xform_masked4.S \ + ../../X86/katmai_xform_raw1.S \ + ../../X86/katmai_xform_raw2.S \ + ../../X86/katmai_xform_raw3.S \ + ../../X86/katmai_xform_raw4.S + + KATMAI_OBJS = ../../X86/katmai.o \ + ../../X86/katmai_norm_raw.o \ + ../../X86/katmai_vertex.o \ + ../../X86/katmai_xform_masked1.o \ + ../../X86/katmai_xform_masked2.o \ + ../../X86/katmai_xform_masked3.o \ + ../../X86/katmai_xform_masked4.o \ + ../../X86/katmai_xform_raw1.o \ + ../../X86/katmai_xform_raw2.o \ + ../../X86/katmai_xform_raw3.o \ + ../../X86/katmai_xform_raw4.o +#endif +#endif +#endif + +#ifdef GlxSoProf + LOSRCS = ../../../../lowpc.c + HISRCS = ../../../../highpc.c + + LOOBJS = ../../../../lowpc.o + HIOBJS = ../../../../highpc.o +#endif + + ASMSRCS = $(X86_SRCS) $(MMX_SRCS) $(3DNOW_SRCS) $(KATMAI_SRCS) + ASMOBJS = $(X86_OBJS) $(MMX_OBJS) $(3DNOW_OBJS) $(KATMAI_OBJS) + + COMMONSRCS = ../common/mm.c ../common/hwlog.c + COMMONOBJS = ../common/mm.o ../common/hwlog.o + + SRCS = $(LOSRCS) $(DRISRCS) $(DRMSRCS) $(MESASRCS) \ + $(ASMSRCS) $(COMMONSRCS) $(RADEONSRCS) $(HISRCS) + OBJS = $(LOOBJS) $(DRIOBJS) $(DRMOBJS) $(MESAOBJS) \ + $(ASMOBJS) $(COMMONOBJS) $(RADEONOBJS) $(HIOBJS) + +REQUIREDLIBS += MathLibrary +#if !GlxBuiltInRadeon +REQUIREDLIBS += -L../../../.. -lGL +#endif + + +#if !GlxUseBuiltInDRIDriver +#undef DoNormalLib NormalLibGlx +#undef DoExtraLib SharedLibGlx +#undef DoDebugLib DebugLibGlx +#undef DoProfileLib ProfileLibGlx +#endif + +#include <Library.tmpl> + +LibraryObjectRule() + +SubdirLibraryRule($(OBJS)) +NormalLintTarget($(SRCS)) + +#if !GlxUseBuiltInDRIDriver +LIBNAME = radeon_dri.so +ALL_OBJS = $(OBJS) +ALL_DEPS = DONE +SharedDepModuleTarget($(LIBNAME),$(ALL_DEPS),$(ALL_OBJS)) +InstallDynamicModule($(LIBNAME),$(MODULEDIR),dri) + +#ifdef GlxSoProf +SOPROF_LIBNAME = _radeon_dri_p +NormalDepLibraryTarget($(SOPROF_LIBNAME),$(ALL_DEPS),$(ALL_OBJS)) +InstallLibrary($(SOPROF_LIBNAME),$(MODULEDIR)/dri) +#endif +#endif + +DependTarget() diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_context.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_context.c new file mode 100644 index 000000000..9af8b5691 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_context.c @@ -0,0 +1,234 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_context.c,v 1.1 2001/01/08 01:07:26 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include <stdlib.h> + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_dd.h" +#include "radeon_state.h" +#include "radeon_span.h" +#include "radeon_tex.h" +#include "radeon_vb.h" +#include "radeon_pipeline.h" + +#include "context.h" +#include "simple_list.h" +#include "mem.h" + +#ifndef RADEON_DEBUG +int RADEON_DEBUG = (0 +/* | DEBUG_ALWAYS_SYNC */ +/* | DEBUG_VERBOSE_API */ +/* | DEBUG_VERBOSE_MSG */ +/* | DEBUG_VERBOSE_LRU */ +/* | DEBUG_VERBOSE_DRI */ +/* | DEBUG_VERBOSE_IOCTL */ +/* | DEBUG_VERBOSE_2D */ + ); +#endif + +/* Create the device specific context. + */ +GLboolean radeonCreateContext( Display *dpy, GLvisual *glVisual, + __DRIcontextPrivate *driContextPriv ) +{ + GLcontext *ctx = driContextPriv->mesaContext; + __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; + radeonContextPtr rmesa; + radeonScreenPtr radeonScreen; + int i; + + rmesa = (radeonContextPtr) CALLOC( sizeof(*rmesa) ); + if ( !rmesa ) return GL_FALSE; + + rmesa->glCtx = ctx; + rmesa->display = dpy; + + rmesa->driContext = driContextPriv; + rmesa->driScreen = sPriv; + rmesa->driDrawable = NULL; /* Set by XMesaMakeCurrent */ + + rmesa->hHWContext = driContextPriv->hHWContext; + rmesa->driHwLock = &sPriv->pSAREA->lock; + rmesa->driFd = sPriv->fd; + + radeonScreen = rmesa->radeonScreen = (radeonScreenPtr)(sPriv->private); + + rmesa->sarea = (RADEONSAREAPrivPtr)((char *)sPriv->pSAREA + + sizeof(XF86DRISAREARec)); + + rmesa->tmp_matrix = (GLfloat *) ALIGN_MALLOC( 16 * sizeof(GLfloat), 16 ); + if ( !rmesa->tmp_matrix ) { + FREE( rmesa ); + return GL_FALSE; + } + + make_empty_list( &rmesa->SwappedOut ); + + for ( i = 0 ; i < radeonScreen->numTexHeaps ; i++ ) { + rmesa->CurrentTexObj[i] = NULL; + make_empty_list( &rmesa->TexObjList[i] ); + rmesa->texHeap[i] = mmInit( 0, radeonScreen->texSize[i] ); + rmesa->lastTexAge[i] = -1; + } + rmesa->lastTexHeap = radeonScreen->numTexHeaps; + + rmesa->RenderIndex = -1; /* Impossible value */ + rmesa->OnFastPath = 0; + + rmesa->vert_buf = NULL; + rmesa->num_verts = 0; + + rmesa->elt_buf = NULL; + rmesa->retained_buf = NULL; + rmesa->vert_heap = radeonScreen->buffers->list->address; + + /* KW: Set the maximum texture size small enough that we can + * guarentee that both texture units can bind a maximal texture + * and have them both in on-card memory at once. (Kevin or + * Gareth: Please check these numbers are OK) + */ + if ( radeonScreen->texSize[0] < 2*1024*1024 ) { + ctx->Const.MaxTextureLevels = 9; + ctx->Const.MaxTextureSize = (1 << 8); + } else if ( radeonScreen->texSize[0] < 8*1024*1024 ) { + ctx->Const.MaxTextureLevels = 10; + ctx->Const.MaxTextureSize = (1 << 9); + } else { + ctx->Const.MaxTextureLevels = 11; + ctx->Const.MaxTextureSize = (1 << 10); + } + + /* FIXME: Support all available texture units... */ + ctx->Const.MaxTextureUnits = 2; + +#if ENABLE_PERF_BOXES + if (getenv("LIBGL_PERFORMANCE_BOXES")) + rmesa->boxes = 1; + else + rmesa->boxes = 0; +#endif + + ctx->DriverCtx = (void *)rmesa; + + radeonDDInitExtensions( ctx ); + + radeonDDInitDriverFuncs( ctx ); + radeonDDInitIoctlFuncs( ctx ); + radeonDDInitStateFuncs( ctx ); + radeonDDInitSpanFuncs( ctx ); + radeonDDInitTextureFuncs( ctx ); + + ctx->Driver.TriangleCaps = (DD_TRI_CULL | + DD_TRI_LIGHT_TWOSIDE | + DD_TRI_STIPPLE | + DD_TRI_OFFSET); + + /* Ask Mesa to clip fog coordinates for us. + */ + ctx->TriangleCaps |= DD_CLIP_FOG_COORD; + + if ( ctx->VB ) + radeonDDRegisterVB( ctx->VB ); + + if ( ctx->NrPipelineStages ) { + ctx->NrPipelineStages = + radeonDDRegisterPipelineStages( ctx->PipelineStage, + ctx->PipelineStage, + ctx->NrPipelineStages ); + } + + radeonDDInitState( rmesa ); + + driContextPriv->driverPrivate = (void *)rmesa; + + return GL_TRUE; +} + +/* Destroy the device specific context. + */ +void radeonDestroyContext( radeonContextPtr rmesa ) +{ + if ( rmesa ) { + radeonTexObjPtr t, next_t; + int i; + + for ( i = 0 ; i < rmesa->radeonScreen->numTexHeaps ; i++ ) { + foreach_s ( t, next_t, &rmesa->TexObjList[i] ) { + radeonDestroyTexObj( rmesa, t ); + } + mmDestroy( rmesa->texHeap[i] ); + } + + foreach_s ( t, next_t, &rmesa->SwappedOut ) { + radeonDestroyTexObj( rmesa, t ); + } + + ALIGN_FREE( rmesa->tmp_matrix ); + FREE( rmesa ); + } + +#if 0 + /* Use this to force shared object profiling. */ + glx_fini_prof(); +#endif +} + +/* Load the device specific context into the hardware. The actual + * setting of the hardware state is done in the radeonUpdateHWState(). + */ +radeonContextPtr radeonMakeCurrent( radeonContextPtr oldCtx, + radeonContextPtr newCtx, + __DRIdrawablePrivate *dPriv ) +{ + if ( oldCtx ) { + if ( oldCtx != newCtx ) { + newCtx->new_state |= RADEON_NEW_CONTEXT; + newCtx->dirty = RADEON_UPLOAD_ALL; + } + if ( oldCtx->driDrawable != dPriv ) { + newCtx->new_state |= RADEON_NEW_WINDOW | RADEON_NEW_CLIP; + } + } else { + newCtx->new_state |= RADEON_NEW_CONTEXT; + newCtx->dirty = RADEON_UPLOAD_ALL; + } + + newCtx->driDrawable = dPriv; + + return newCtx; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_context.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_context.h new file mode 100644 index 000000000..cae9d5b30 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_context.h @@ -0,0 +1,253 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_context.h,v 1.1 2001/01/08 01:07:26 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_CONTEXT_H__ +#define __RADEON_CONTEXT_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include <X11/Xlibint.h> + +#include "dri_mesaint.h" +#include "dri_tmm.h" + +#include "xf86drm.h" +#include "xf86drmRadeon.h" + +#include "types.h" + +#include "radeon_sarea.h" +#include "radeon_reg.h" + +struct radeon_context; +typedef struct radeon_context radeonContextRec; +typedef struct radeon_context *radeonContextPtr; + +#include "radeon_lock.h" +#include "radeon_texobj.h" +#include "radeon_screen.h" + +/* Flags for what context state needs to be updated */ +#define RADEON_NEW_ALPHA 0x0001 +#define RADEON_NEW_DEPTH 0x0002 +#define RADEON_NEW_FOG 0x0004 +#define RADEON_NEW_CLIP 0x0008 +#define RADEON_NEW_CULL 0x0010 +#define RADEON_NEW_MASKS 0x0020 +#define RADEON_NEW_WINDOW 0x0040 +#define RADEON_NEW_TEXTURE 0x0080 +#define RADEON_NEW_CONTEXT 0x0100 +#define RADEON_NEW_ALL 0x01ff + +/* Flags for software fallback cases */ +#define RADEON_FALLBACK_TEXTURE 0x0001 +#define RADEON_FALLBACK_DRAW_BUFFER 0x0002 +#define RADEON_FALLBACK_READ_BUFFER 0x0004 +#define RADEON_FALLBACK_STENCIL 0x0008 +#define RADEON_FALLBACK_RENDER_MODE 0x0010 +#define RADEON_FALLBACK_MULTIDRAW 0x0020 +#define RADEON_FALLBACK_LOGICOP 0x0040 + +typedef void (*radeon_interp_func)( GLfloat t, + GLfloat *result, + const GLfloat *in, + const GLfloat *out ); + +struct radeon_elt_tab { + void (*emit_unclipped_verts)( struct vertex_buffer *VB ); + + void (*build_tri_verts)( radeonContextPtr rmesa, + struct vertex_buffer *VB, + GLfloat *O, GLuint *elt ); + + void (*interp)( GLfloat t, GLfloat *O, + const GLfloat *I, const GLfloat *J ); + + void (*project_and_emit_verts)( radeonContextPtr rmesa, + const GLfloat *verts, + GLuint *elts, + GLuint nr ); +}; + +struct radeon_context { + GLcontext *glCtx; /* Mesa context */ + + /* Driver and hardware state management + */ + GLuint new_state; + GLuint dirty; /* Hardware state to be updated */ + radeon_context_regs_t setup; + + GLuint vertsize; + GLuint vc_format; + GLfloat depth_scale; + + CARD32 Color; /* Current draw color */ + CARD32 ClearColor; /* Color used to clear color buffer */ + CARD32 ClearDepth; /* Value used to clear depth buffer */ + CARD32 ClearStencil; /* Value used to clear stencil */ + + /* Map GL texture units onto hardware + */ + GLint multitex; + GLint tmu_source[RADEON_MAX_TEXTURE_UNITS]; + GLint tex_dest[RADEON_MAX_TEXTURE_UNITS]; + GLuint color_combine[RADEON_MAX_TEXTURE_UNITS]; + GLuint alpha_combine[RADEON_MAX_TEXTURE_UNITS]; + GLuint env_color[RADEON_MAX_TEXTURE_UNITS]; + GLuint lod_bias[RADEON_MAX_TEXTURE_UNITS]; + + /* Texture object bookkeeping + */ + radeonTexObjPtr CurrentTexObj[RADEON_MAX_TEXTURE_UNITS]; + radeonTexObj TexObjList[RADEON_NR_TEX_HEAPS]; + radeonTexObj SwappedOut; + memHeap_t *texHeap[RADEON_NR_TEX_HEAPS]; + GLint lastTexAge[RADEON_NR_TEX_HEAPS]; + GLint lastTexHeap; + + /* Current rendering state, fallbacks + */ + points_func PointsFunc; + line_func LineFunc; + triangle_func TriangleFunc; + quad_func QuadFunc; + + GLuint IndirectTriangles; + GLuint Fallback; + + /* Fast path + */ + GLuint SetupIndex; + GLuint SetupDone; + GLuint RenderIndex; + GLuint OnFastPath; + radeon_interp_func interp; + GLfloat *tmp_matrix; + + /* Vertex buffers + */ + drmBufPtr vert_buf; + GLuint vert_prim; + GLuint num_verts; + + /* Elt path + */ + drmBufPtr elt_buf, retained_buf; + GLushort *first_elt, *next_elt; + GLfloat *next_vert, *vert_heap; + GLushort next_vert_index; + GLushort first_vert_index; + GLuint elt_vertsize; + struct radeon_elt_tab *elt_tab; + GLfloat device_matrix[16]; + + /* Page flipping + */ + GLuint doPageFlip; + GLuint currentPage; + + /* Drawable, cliprect and scissor information + */ + GLenum DrawBuffer; /* Optimize draw buffer update */ + GLint drawOffset, drawPitch; + GLint readOffset, readPitch; + + GLuint numClipRects; /* Cliprects for the draw buffer */ + XF86DRIClipRectPtr pClipRects; + + GLuint scissor; + XF86DRIClipRectRec scissor_rect; /* Current software scissor */ + + /* Mirrors of some DRI state + */ + Display *display; /* X server display */ + + __DRIcontextPrivate *driContext; /* DRI context */ + __DRIscreenPrivate *driScreen; /* DRI screen */ + __DRIdrawablePrivate *driDrawable; /* DRI drawable bound to this ctx */ + + drmContext hHWContext; + drmLock *driHwLock; + int driFd; + + radeonScreenPtr radeonScreen; /* Screen private DRI data */ + RADEONSAREAPrivPtr sarea; /* Private SAREA data */ + + /* Performance counters + */ + GLuint boxes; /* Draw performance boxes */ + GLuint hardwareWentIdle; + GLuint c_clears; + GLuint c_drawWaits; + GLuint c_textureSwaps; + GLuint c_textureBytes; + GLuint c_vertexBuffers; +}; + +#define RADEON_CONTEXT(ctx) ((radeonContextPtr)(ctx->DriverCtx)) + + +extern GLboolean radeonCreateContext( Display *dpy, GLvisual *glVisual, + __DRIcontextPrivate *driContextPriv ); +extern void radeonDestroyContext( radeonContextPtr rmesa ); +extern radeonContextPtr radeonMakeCurrent( radeonContextPtr oldCtx, + radeonContextPtr newCtx, + __DRIdrawablePrivate *dPriv ); + + +/* ================================================================ + * Debugging: + */ +#define DO_DEBUG 0 +#define ENABLE_PERF_BOXES 0 + +#if DO_DEBUG +extern int RADEON_DEBUG; +#else +#define RADEON_DEBUG 0 +#endif + +#define DEBUG_ALWAYS_SYNC 0x01 +#define DEBUG_VERBOSE_API 0x02 +#define DEBUG_VERBOSE_MSG 0x04 +#define DEBUG_VERBOSE_LRU 0x08 +#define DEBUG_VERBOSE_DRI 0x10 +#define DEBUG_VERBOSE_IOCTL 0x20 +#define DEBUG_VERBOSE_2D 0x40 + +#endif +#endif /* __RADEON_CONTEXT_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_dd.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_dd.c new file mode 100644 index 000000000..52cf810cc --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_dd.c @@ -0,0 +1,217 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_dd.c,v 1.3 2001/01/21 21:19:09 tsi Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_vb.h" +#include "radeon_pipeline.h" +#include "radeon_dd.h" + +#include "extensions.h" +#if defined(USE_X86_ASM) || defined(USE_3DNOW_ASM) || defined(USE_KATMAI_ASM) +#include "X86/common_x86_asm.h" +#endif + +#define RADEON_DATE "20010105" + + +/* Return the width and height of the current color buffer. + */ +static void radeonDDGetBufferSize( GLcontext *ctx, + GLuint *width, GLuint *height ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + LOCK_HARDWARE( rmesa ); + *width = rmesa->driDrawable->w; + *height = rmesa->driDrawable->h; + UNLOCK_HARDWARE( rmesa ); +} + +/* Return various strings for glGetString(). + */ +static const GLubyte *radeonDDGetString( GLcontext *ctx, GLenum name ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + static char buffer[128]; + + switch ( name ) { + case GL_VENDOR: + return (GLubyte *)"VA Linux Systems, Inc."; + + case GL_RENDERER: + sprintf( buffer, "Mesa DRI Radeon " RADEON_DATE ); + + /* Append any chipset-specific information. None yet. + */ + + /* Append any AGP-specific information. + */ + switch ( rmesa->radeonScreen->AGPMode ) { + case 1: + strncat( buffer, " AGP 1x", 7 ); + break; + case 2: + strncat( buffer, " AGP 2x", 7 ); + break; + case 4: + strncat( buffer, " AGP 4x", 7 ); + break; + } + + /* Append any CPU-specific information. + */ +#ifdef USE_X86_ASM + if ( gl_x86_cpu_features ) { + strncat( buffer, " x86", 4 ); + } +#endif +#ifdef USE_3DNOW_ASM + if ( cpu_has_3dnow ) { + strncat( buffer, "/3DNow!", 7 ); + } +#endif +#ifdef USE_KATMAI_ASM + if ( cpu_has_xmm ) { + strncat( buffer, "/SSE", 4 ); + } +#endif + return (GLubyte *)buffer; + + default: + return NULL; + } +} + +/* Send all commands to the hardware. If vertex buffers or indirect + * buffers are in use, then we need to make sure they are sent to the + * hardware. All commands that are normally sent to the ring are + * already considered `flushed'. + */ +static void radeonDDFlush( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + +#if ENABLE_PERF_BOXES + if ( rmesa->boxes ) { + LOCK_HARDWARE( rmesa ); + radeonPerformanceBoxesLocked( rmesa ); + UNLOCK_HARDWARE( rmesa ); + } + + /* Log the performance counters if necessary */ + radeonPerformanceCounters( rmesa ); +#endif +} + +/* Make sure all commands have been sent to the hardware and have + * completed processing. + */ +static void radeonDDFinish( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + rmesa->c_drawWaits++; +#endif + + radeonDDFlush( ctx ); + radeonWaitForIdle( rmesa ); +} + +/* Return various parameters requested by Mesa (this is deprecated). + */ +static GLint radeonDDGetParameteri( const GLcontext *ctx, GLint param ) +{ + switch ( param ) { + case DD_HAVE_HARDWARE_FOG: + return 1; + default: + return 0; + } +} + +/* Initialize the extensions supported by this driver. + */ +void radeonDDInitExtensions( GLcontext *ctx ) +{ + gl_extensions_disable( ctx, "GL_ARB_imaging" ); + gl_extensions_disable( ctx, "GL_ARB_texture_compression" ); + gl_extensions_disable( ctx, "GL_ARB_texture_cube_map" ); + + gl_extensions_disable( ctx, "GL_EXT_blend_color" ); + gl_extensions_disable( ctx, "GL_EXT_blend_logic_op" ); + gl_extensions_disable( ctx, "GL_EXT_blend_minmax" ); + gl_extensions_disable( ctx, "GL_EXT_blend_subtract" ); + gl_extensions_disable( ctx, "GL_EXT_convolution" ); + gl_extensions_disable( ctx, "GL_EXT_paletted_texture" ); + gl_extensions_disable( ctx, "GL_EXT_point_parameters" ); + gl_extensions_disable( ctx, "GL_EXT_shared_texture_palette" ); + gl_extensions_enable( ctx, "GL_EXT_texture_env_combine" ); + gl_extensions_enable( ctx, "GL_EXT_texture_env_dot3" ); + + gl_extensions_disable( ctx, "GL_HP_occlusion_test" ); + + gl_extensions_disable( ctx, "GL_INGR_blend_func_separate" ); + + gl_extensions_disable( ctx, "GL_SGI_color_matrix" ); + gl_extensions_disable( ctx, "GL_SGI_color_table" ); + gl_extensions_disable( ctx, "GL_SGIX_pixel_texture" ); +} + +/* Initialize the driver's misc functions. + */ +void radeonDDInitDriverFuncs( GLcontext *ctx ) +{ + ctx->Driver.GetBufferSize = radeonDDGetBufferSize; + ctx->Driver.GetString = radeonDDGetString; + ctx->Driver.Finish = radeonDDFinish; + ctx->Driver.Flush = radeonDDFlush; + + ctx->Driver.Error = NULL; + ctx->Driver.GetParameteri = radeonDDGetParameteri; + + ctx->Driver.DrawPixels = NULL; + ctx->Driver.Bitmap = NULL; + + ctx->Driver.RegisterVB = radeonDDRegisterVB; + ctx->Driver.UnregisterVB = radeonDDUnregisterVB; + ctx->Driver.BuildPrecalcPipeline = radeonDDBuildPrecalcPipeline; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_dd.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_dd.h new file mode 100644 index 000000000..5e16e5e62 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_dd.h @@ -0,0 +1,46 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_dd.h,v 1.1 2001/01/08 01:07:26 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_DD_H__ +#define __RADEON_DD_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void radeonDDInitExtensions( GLcontext *ctx ); +extern void radeonDDInitDriverFuncs( GLcontext *ctx ); + +#endif +#endif diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_eltpath.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_eltpath.c new file mode 100644 index 000000000..6b2f36614 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_eltpath.c @@ -0,0 +1,504 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_eltpath.c,v 1.1 2001/01/08 01:07:26 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keithw@valinux.com> + * + */ + +#include <stdio.h> + +#include "radeon_context.h" +#include "radeon_pipeline.h" +#include "radeon_ioctl.h" +#include "radeon_tris.h" +#include "radeon_state.h" +#include "radeon_vb.h" + +#include "types.h" +#include "enums.h" +#include "cva.h" +#include "vertices.h" +#include "mmath.h" +#include "xform.h" + +/* Always use a full-sized stride for vertices. [FIXME] + * Stride in the buffers must be a quadword multiple. + */ +#define CLIP_STRIDE 10 + +static void fire_elts( radeonContextPtr rmesa ) +{ + GLuint vertsize = rmesa->vertsize; + + LOCK_HARDWARE( rmesa ); + + /* Fire queued elements and discard that buffer if its contents + * won't be referenced by future elements. + */ + if ( rmesa->elt_buf ) + { + GLuint retain = (rmesa->elt_buf == rmesa->retained_buf); + + if ( rmesa->first_elt != rmesa->next_elt ) { + radeonFireEltsLocked( rmesa, + ((GLuint)rmesa->first_elt - + (GLuint)rmesa->elt_buf->address), + ((GLuint)rmesa->next_elt - + (GLuint)rmesa->elt_buf->address), + !retain ); + } else if ( !retain ) { + radeonReleaseBufLocked( rmesa, rmesa->elt_buf ); + } + + rmesa->elt_buf = 0; + } + else if ( rmesa->vert_buf ) + { + radeonFlushVerticesLocked( rmesa ); + } + + radeonGetEltBufLocked( rmesa ); + + UNLOCK_HARDWARE( rmesa ); + + /* Give the compiler a chance to optimize the divisions. + */ + switch ( vertsize ) { + case 8: + rmesa->next_vert_index = (GLushort) + (((rmesa->elt_buf->idx + 1) * + RADEON_BUFFER_SIZE / (8 * sizeof(GLuint))) - 1); + rmesa->next_vert = (GLfloat *) + ((GLuint)rmesa->vert_heap + + rmesa->next_vert_index * 8 * sizeof(GLfloat)); + break; + + case 10: + rmesa->next_vert_index = (GLushort) + (((rmesa->elt_buf->idx + 1) * + RADEON_BUFFER_SIZE / (10 * sizeof(GLuint))) - 1); + rmesa->next_vert = (GLfloat *) + ((GLuint)rmesa->vert_heap + + rmesa->next_vert_index * 10 * sizeof(GLfloat)); + break; + } + + rmesa->first_elt = rmesa->next_elt = (GLushort *) + ((GLubyte *)rmesa->elt_buf->address + RADEON_INDEX_PRIM_OFFSET); + + rmesa->elt_vertsize = vertsize; +} + + +static void release_bufs( radeonContextPtr rmesa ) +{ + if ( rmesa->retained_buf && rmesa->retained_buf != rmesa->elt_buf ) + { + LOCK_HARDWARE( rmesa ); + if ( rmesa->first_elt != rmesa->next_elt ) { + radeonFireEltsLocked( rmesa, + ((GLuint)rmesa->first_elt - + (GLuint)rmesa->elt_buf->address), + ((GLuint)rmesa->next_elt - + (GLuint)rmesa->elt_buf->address), + 0 ); + + ALIGN_NEXT_ELT( rmesa ); + rmesa->first_elt = rmesa->next_elt; + } + + radeonReleaseBufLocked( rmesa, rmesa->retained_buf ); + UNLOCK_HARDWARE( rmesa ); + } + + rmesa->retained_buf = 0; +} + + + + +#define NEGATIVE( f ) (f < 0) +#define DIFFERENT_SIGNS( a, b ) ((a * b) < 0) +#define LINTERP( T, A, B ) ((A) + (T) * ((B) - (A))) + + +#define INTERP_RGBA( t, out, a, b ) { \ + GLuint i; \ + for ( i = 0 ; i < 4 ; i++ ) { \ + GLfloat fa = UBYTE_COLOR_TO_FLOAT_COLOR( a[i] ); \ + GLfloat fb = UBYTE_COLOR_TO_FLOAT_COLOR( b[i] ); \ + GLfloat fo = LINTERP( t, fa, fb ); \ + FLOAT_COLOR_TO_UBYTE_COLOR( out[i], fo ); \ + } \ +} + + +#define CLIP( SGN, V, PLANE ) \ +do { \ + if ( mask & PLANE ) { \ + GLuint *indata = inlist[in]; \ + GLuint *outdata = inlist[in ^= 1]; \ + GLuint nr = n; \ + GLfloat *J = verts[indata[nr-1]]; \ + GLfloat dpJ = (SGN J[V]) + J[3]; \ + \ + for ( i = n = 0 ; i < nr ; i++ ) { \ + GLuint elt_i = indata[i]; \ + GLfloat *I = verts[elt_i]; \ + GLfloat dpI = (SGN I[V]) + I[3]; \ + \ + if ( DIFFERENT_SIGNS( dpI, dpJ ) ) { \ + GLfloat *O = verts[next_vert]; \ + outdata[n++] = next_vert++; \ + \ + if ( NEGATIVE( dpI ) ) { \ + GLfloat t = dpI / (dpI - dpJ); \ + interp( t, O, I, J ); \ + } \ + else \ + { \ + GLfloat t = dpJ / (dpJ - dpI); \ + interp( t, O, J, I ); \ + } \ + } \ + \ + if ( !NEGATIVE( dpI ) ) \ + outdata[n++] = elt_i; \ + \ + J = I; \ + dpJ = dpI; \ + } \ + \ + if ( n < 3 ) return; \ + } \ +} while (0) + + +static void radeon_tri_clip( radeonContextPtr rmesa, + struct vertex_buffer *VB, + GLuint *elt, + GLubyte mask ) +{ + struct radeon_elt_tab *tab = rmesa->elt_tab; + radeon_interp_func interp = tab->interp; + GLuint vertsize = rmesa->vertsize; + GLuint inlist[2][VB_MAX_CLIPPED_VERTS]; + GLuint in = 0; + GLuint n = 3, next_vert = 3; + GLuint i; + GLfloat verts[VB_MAX_CLIPPED_VERTS][CLIP_STRIDE]; + + /* Build temporary vertices in clipspace. This is the potential + * downside to this path. + */ + tab->build_tri_verts( rmesa, VB, (GLfloat *)verts, elt ); + + inlist[0][0] = 0; + inlist[0][1] = 1; + inlist[0][2] = 2; + + CLIP( -, 0, CLIP_RIGHT_BIT ); + CLIP( +, 0, CLIP_LEFT_BIT ); + CLIP( -, 1, CLIP_TOP_BIT ); + CLIP( +, 1, CLIP_BOTTOM_BIT ); + CLIP( -, 2, CLIP_FAR_BIT ); + CLIP( +, 2, CLIP_NEAR_BIT ); + + + { + GLuint *out = inlist[in]; + GLint space = (GLint)((GLuint)rmesa->next_vert - + (GLuint)rmesa->next_elt); + + if ( space < (GLint)(n * (vertsize + 2) * sizeof(GLuint)) ) { + fire_elts( rmesa ); + } + + /* Project the new vertices and emit to dma buffers. Translate + * out values to physical addresses for setup dma. + */ + tab->project_and_emit_verts( rmesa, (GLfloat *)verts, out, n ); + + /* Convert the planar polygon to a list of triangles and emit to + * elt buffers. + */ + for ( i = 2 ; i < n ; i++ ) { + rmesa->next_elt[0] = (GLushort) out[0]; + rmesa->next_elt[1] = (GLushort) out[i-1]; + rmesa->next_elt[2] = (GLushort) out[i]; + rmesa->next_elt += 3; + } + } +} + + + + +/* Build a table of functions to clip each primitive type. These + * produce a list of elements in the appropriate 'reduced' primitive, + * ie (points, lines, triangles) containing all the clipped and + * unclipped primitives from the original list. + */ + +#define INIT( x ) + +#define TRI_THRESHOLD (GLint)(2 * sizeof(GLuint)) + +#define UNCLIPPED_VERT( x ) (GLushort)(rmesa->first_vert_index - x) + +#define TRIANGLE( e2, e1, e0 ) \ +do { \ + if ( (GLint)((GLuint)rmesa->next_vert - \ + (GLuint)rmesa->next_elt) < TRI_THRESHOLD ) { \ + fire_elts( rmesa ); \ + } \ + rmesa->next_elt[0] = UNCLIPPED_VERT( e2 ); \ + rmesa->next_elt[1] = UNCLIPPED_VERT( e1 ); \ + rmesa->next_elt[2] = UNCLIPPED_VERT( e0 ); \ + rmesa->next_elt += 3; \ +} while (0) + +#define CLIP_TRIANGLE( e2, e1, e0 ) \ +do { \ + GLubyte ormask = mask[e2] | mask[e1] | mask[e0]; \ + if ( ormask == 0 ) { \ + TRIANGLE( e2, e1, e0 ); \ + } else if ( (mask[e2] & mask[e1] & mask[e0]) == 0 ) { \ + out[0] = e2; \ + out[1] = e1; \ + out[2] = e0; \ + radeon_tri_clip( rmesa, VB, out, ormask ); \ + } \ +} while (0) + +#define LOCAL_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(VB->ctx); \ + GLuint *elt = VB->EltPtr->data; \ + GLuint out[VB_MAX_CLIPPED_VERTS]; \ + GLubyte *mask = VB->ClipMask; \ + (void) mask; (void) out; (void) elt; (void) rmesa; + + + +#define RENDER_POINTS( start, count ) +#define RENDER_LINE( i1, i0 ) +#define RENDER_TRI( i2, i1, i0, pv, parity ) \ +do { \ + GLuint e2 = elt[i2], e1 = elt[i1], e0 = elt[i0]; \ + if ( parity ) e2 = elt[i1], e1 = elt[i2]; \ + CLIP_TRIANGLE( e2, e1, e0 ); \ +} while (0) + +#define RENDER_QUAD( i3, i2, i1, i0, pv ) \ + CLIP_TRIANGLE( elt[i3], elt[i2], elt[i0] ); \ + CLIP_TRIANGLE( elt[i2], elt[i1], elt[i0] ) + +#define TAG(x) radeon_##x##_elt +#include "render_tmp.h" + + + +#define LOCAL_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(VB->ctx); \ + GLuint *elt = VB->EltPtr->data; \ + (void) elt; (void) rmesa; + +#define RENDER_POINTS( start, count ) +#define RENDER_LINE( i1, i0 ) +#define RENDER_TRI( i2, i1, i0, pv, parity ) \ +do { \ + GLuint e2 = elt[i2], e1 = elt[i1], e0 = elt[i0]; \ + if ( parity ) e2 = elt[i1], e1 = elt[i2]; \ + TRIANGLE( e2, e1, e0 ); \ +} while (0) + +#define RENDER_QUAD( i3, i2, i1, i0, pv ) \ + TRIANGLE( elt[i3], elt[i2], elt[i0] ); \ + TRIANGLE( elt[i2], elt[i1], elt[i0] ) + +#define TAG(x) radeon_##x##_elt_unclipped +#include "render_tmp.h" + + + + +static void refresh_projection_matrix( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLmatrix *mat = &ctx->Viewport.WindowMap; + GLfloat *m = rmesa->device_matrix; + + m[MAT_SX] = mat->m[MAT_SX]; + m[MAT_TX] = mat->m[MAT_TX]; + m[MAT_SY] = -mat->m[MAT_SY]; + m[MAT_TY] = -mat->m[MAT_TY]; + m[MAT_SZ] = mat->m[MAT_SZ]; + m[MAT_TZ] = mat->m[MAT_TZ]; +} + +#define CLIP_UBYTE_R 0 +#define CLIP_UBYTE_G 1 +#define CLIP_UBYTE_B 2 +#define CLIP_UBYTE_A 3 + + +#define TYPE (0) +#define TAG(x) x +#include "radeon_elttmp.h" + +#define TYPE (RADEON_RGBA_BIT) +#define TAG(x) x##_RGBA +#include "radeon_elttmp.h" + +#define TYPE (RADEON_TEX0_BIT) +#define TAG(x) x##_TEX0 +#include "radeon_elttmp.h" + +#define TYPE (RADEON_RGBA_BIT|RADEON_TEX0_BIT) +#define TAG(x) x##_RGBA_TEX0 +#include "radeon_elttmp.h" + +#define TYPE (RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT) +#define TAG(x) x##_RGBA_TEX0_TEX1 +#include "radeon_elttmp.h" + +#define TYPE (RADEON_TEX0_BIT|RADEON_TEX1_BIT) +#define TAG(x) x##_TEX0_TEX1 +#include "radeon_elttmp.h" + + +/* Very sparsely popluated array - fix the indices. + */ +static struct radeon_elt_tab radeonEltTab[RADEON_MAX_SETUPFUNC]; + +void radeonDDEltPathInit( void ) +{ + radeon_render_init_elt(); + radeon_render_init_elt_unclipped(); + + radeon_init_eltpath( &radeonEltTab[0] ); + radeon_init_eltpath_RGBA( &radeonEltTab[RADEON_RGBA_BIT] ); + radeon_init_eltpath_TEX0( &radeonEltTab[RADEON_TEX0_BIT] ); + radeon_init_eltpath_RGBA_TEX0( &radeonEltTab[(RADEON_RGBA_BIT | + RADEON_TEX0_BIT)] ); + radeon_init_eltpath_TEX0_TEX1( &radeonEltTab[(RADEON_TEX0_BIT | + RADEON_TEX1_BIT)] ); + radeon_init_eltpath_RGBA_TEX0_TEX1( &radeonEltTab[(RADEON_RGBA_BIT | + RADEON_TEX0_BIT | + RADEON_TEX1_BIT)] ); +} + +#define VALID_SETUP (RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT) + + + +/* Use a temporary array for device coordinates, so that we can easily + * tap into existing mesa assembly. Otherwise consider emitting + * device coordinates to dma buffers directly from the project/cliptest + * routine. (requires output stride, potential loss of writecombining + * efficiency?) + * + * This path is a lot closer to the standard vertex path in the + * initial stages than the original fastpath. A slightly more optimal + * path could be constructed, but would require us to write new + * assembly. + */ +void radeonDDEltPath( struct vertex_buffer *VB ) +{ + GLcontext *ctx = VB->ctx; + GLenum prim = ctx->CVA.elt_mode; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct radeon_elt_tab *tab = + &radeonEltTab[rmesa->SetupIndex & VALID_SETUP]; + GLint vertsize = rmesa->vertsize; + GLint space; + + VB->ClipPtr = TransformRaw( &VB->Clip, + &ctx->ModelProjectMatrix, + VB->ObjPtr ); + + refresh_projection_matrix( ctx ); + + VB->ClipAndMask = ~0; + VB->ClipOrMask = 0; + VB->Projected = gl_clip_tab[VB->ClipPtr->size]( VB->ClipPtr, + &VB->Win, + VB->ClipMask, + &VB->ClipOrMask, + &VB->ClipAndMask ); + + if ( VB->ClipAndMask ) + return; + + if ( rmesa->vert_buf ) + radeonFlushVertices( rmesa ); + + if ( rmesa->new_state ) + radeonDDUpdateHWState( ctx ); + + space = (GLint)((GLuint)rmesa->next_vert - + (GLuint)rmesa->next_elt); + + /* Allocate a single buffer to hold unclipped vertices. All + * unclipped vertices must be contiguous. + */ + if ( space < (GLint)(VB->Count * vertsize * sizeof(GLuint)) || + rmesa->vertsize != rmesa->elt_vertsize ) { + fire_elts( rmesa ); + } + + rmesa->retained_buf = rmesa->elt_buf; + + /* Emit unclipped vertices to the buffer. + */ + tab->emit_unclipped_verts( VB ); + + /* Emit indices and clipped vertices to one or more buffers. + */ + if ( VB->ClipOrMask ) { + rmesa->elt_tab = tab; + radeon_render_tab_elt[prim]( VB, 0, VB->EltPtr->count, 0 ); + } else { + radeon_render_tab_elt_unclipped[prim]( VB, 0, VB->EltPtr->count, 0 ); + } + + /* Send to hardware and release the elt buffer. + */ + release_bufs( rmesa ); + + /* This indicates that there is no cached data to reuse. + */ + VB->pipeline->data_valid = 0; + VB->pipeline->new_state = 0; + + FLUSH_BATCH( rmesa ); +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_elttmp.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_elttmp.h new file mode 100644 index 000000000..56c0ccedd --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_elttmp.h @@ -0,0 +1,246 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_elttmp.h,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keithw@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +/* Buffers fill from high addresses down with vertices and from low + * addresses up with elements. + */ + + +/* Emit the bulk of the vertices to the first dma buffer. Leave + * empty slots for clipped vertices so that we can still address + * vertices by index. + */ +static void TAG(emit_unclipped_verts)( struct vertex_buffer *VB ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(VB->ctx); + GLfloat *dev = VB->Projected->start; + GLubyte *color = VB->ColorPtr->start; + GLfloat *tex0_data = VB->TexCoordPtr[0]->start; + GLfloat *tex1_data = VB->TexCoordPtr[1]->start; + GLuint color_stride = VB->ColorPtr->stride; + GLuint tex0_stride = VB->TexCoordPtr[0]->stride; + GLuint tex1_stride = VB->TexCoordPtr[1]->stride; + GLuint buffer_stride = rmesa->vertsize; + + GLfloat *f = rmesa->next_vert; + GLuint count = VB->Count; + GLubyte *clipmask = VB->ClipMask; + + const GLfloat *m = rmesa->device_matrix; + const GLfloat sx = m[0], sy = m[5], sz = m[10]; + const GLfloat tx = m[12], ty = m[13], tz = m[14]; + GLuint i; + + rmesa->retained_buf = rmesa->elt_buf; + rmesa->first_vert_index = rmesa->next_vert_index; + + for ( i = 0 ; i < count ; f -= buffer_stride, i++ ) + { + if ( !clipmask[i] ) + { + f[0] = sx * dev[0] + tx; + f[1] = sy * dev[1] + ty; + f[2] = sz * dev[2] + tz; + f[3] = dev[3]; + + if ( TYPE & RADEON_RGBA_BIT ) { + *(GLuint *)&f[4] = *(GLuint *)color; + } + + if ( TYPE & RADEON_TEX0_BIT ) { + *(GLuint *)&f[6] = *(GLuint *)&tex0_data[0]; + *(GLuint *)&f[7] = *(GLuint *)&tex0_data[1]; + } + + if ( TYPE & RADEON_TEX1_BIT ) { + *(GLuint *)&f[8] = *(GLuint *)&tex1_data[0]; + *(GLuint *)&f[9] = *(GLuint *)&tex1_data[1]; + } + } + + STRIDE_F( dev, 16 ); + if ( TYPE & RADEON_RGBA_BIT ) color += color_stride; + if ( TYPE & RADEON_TEX0_BIT ) STRIDE_F( tex0_data, tex0_stride ); + if ( TYPE & RADEON_TEX1_BIT ) STRIDE_F( tex1_data, tex1_stride ); + } + + rmesa->next_vert = f; + rmesa->next_vert_index -= count; +} + + +/* Build three temporary clipspace vertex for clipping a triangle. + * Recreate from the VB data rather than trying to read back from + * uncached memory. + */ +static void TAG(build_tri_verts)( radeonContextPtr rmesa, + struct vertex_buffer *VB, + GLfloat *O, + GLuint *elt ) +{ + GLint i; + + for ( i = 0 ; i < 3 ; i++, O += CLIP_STRIDE ) { + GLfloat *clip = VB->Clip.start + elt[i]*4; + + O[0] = clip[0]; + O[1] = clip[1]; + O[2] = clip[2]; + O[3] = clip[3]; + + if ( TYPE & RADEON_RGBA_BIT ) { + GLubyte *color = VEC_ELT(VB->ColorPtr, GLubyte, elt[i]); + *(GLuint *)&O[4] = *(GLuint *)color; + } + + *(GLuint *)&O[5] = UNCLIPPED_VERT(elt[i]); + + if ( TYPE & RADEON_TEX0_BIT ) { + GLfloat *tex0_data = VEC_ELT(VB->TexCoordPtr[0], GLfloat, elt[i]); + *(GLuint *)&O[6] = *(GLuint *)&tex0_data[0]; + *(GLuint *)&O[7] = *(GLuint *)&tex0_data[1]; + } + + if ( TYPE & RADEON_TEX1_BIT ) { + GLfloat *tex1_data = VEC_ELT(VB->TexCoordPtr[1], GLfloat, elt[i]); + *(GLuint *)&O[8] = *(GLuint *)&tex1_data[0]; + *(GLuint *)&O[9] = *(GLuint *)&tex1_data[1]; + } + } +} + + +/* Interpolate between two of the vertices constructed above. + */ +static void TAG(interp)( GLfloat t, + GLfloat *O, + const GLfloat *I, + const GLfloat *J ) +{ + O[0] = LINTERP( t, I[0], J[0] ); + O[1] = LINTERP( t, I[1], J[1] ); + O[2] = LINTERP( t, I[2], J[2] ); + O[3] = LINTERP( t, I[3], J[3] ); + + if ( TYPE & RADEON_RGBA_BIT ) { + INTERP_RGBA( t, + ((GLubyte *)&(O[4])), + ((GLubyte *)&(I[4])), + ((GLubyte *)&(J[4])) ); + } + + *(GLuint *)&O[5] = ~0; /* note that this is a new vertex */ + + if ( TYPE & RADEON_TEX0_BIT ) { + O[6] = LINTERP( t, I[6], J[6] ); + O[7] = LINTERP( t, I[7], J[7] ); + } + + if ( TYPE & RADEON_TEX1_BIT ) { + O[8] = LINTERP( t, I[8], J[8] ); + O[9] = LINTERP( t, I[9], J[9] ); + } +} + + + +/* When clipping is complete, scan the final vertex list and emit any + * new ones to dma buffers. Update the element list to a format + * suitable for sending to hardware. + */ +static void TAG(project_and_emit_verts)( radeonContextPtr rmesa, + const GLfloat *verts, + GLuint *elt, + GLuint nr) +{ + GLfloat *O = rmesa->next_vert; + GLushort index = rmesa->next_vert_index; + GLuint buffer_stride = rmesa->vertsize; + + const GLfloat *m = rmesa->device_matrix; + const GLfloat sx = m[0], sy = m[5], sz = m[10]; + const GLfloat tx = m[12], ty = m[13], tz = m[14]; + GLuint i; + + for ( i = 0 ; i < nr ; i++ ) { + const GLfloat *I = &verts[elt[i] * CLIP_STRIDE]; + GLuint tmp = *(GLuint *)&I[5]; + + if ( (elt[i] = tmp) == ~0 ) { + GLfloat oow = 1.0 / I[3]; + + elt[i] = index--; + + O[0] = sx * I[0] * oow + tx; + O[1] = sy * I[1] * oow + ty; + O[2] = sz * I[2] * oow + tz; + O[3] = oow; + + if ( TYPE & RADEON_RGBA_BIT ) { + *(GLuint *)&O[4] = *(GLuint *)&I[4]; + } + + if ( TYPE & RADEON_TEX0_BIT ) { + *(GLuint *)&O[6] = *(GLuint *)&I[6]; + *(GLuint *)&O[7] = *(GLuint *)&I[7]; + } + + if ( TYPE & RADEON_TEX1_BIT ) { + *(GLuint *)&O[8] = *(GLuint *)&I[8]; + *(GLuint *)&O[9] = *(GLuint *)&I[9]; + } + + O -= buffer_stride; + } + } + + rmesa->next_vert = O; + rmesa->next_vert_index = index; +} + + + +static void TAG(radeon_init_eltpath)( struct radeon_elt_tab *tab ) +{ + tab->emit_unclipped_verts = TAG(emit_unclipped_verts); + tab->build_tri_verts = TAG(build_tri_verts); + tab->interp = TAG(interp); + tab->project_and_emit_verts = TAG(project_and_emit_verts); +} + +#undef TYPE +#undef TAG +#undef STRIDE diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_fastpath.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_fastpath.c new file mode 100644 index 000000000..1ff701435 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_fastpath.c @@ -0,0 +1,542 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_fastpath.c,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keithw@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_state.h" +#include "radeon_vb.h" +#include "radeon_pipeline.h" +#include "radeon_ioctl.h" +#include "radeon_tris.h" + +#include "mmath.h" +#include "cva.h" +#include "vertices.h" + + +struct radeon_fast_tab { + void (*build_vertices)( struct vertex_buffer *VB, GLuint do_cliptest ); + void (*interp)( GLfloat t, GLfloat *O, const GLfloat *I, const GLfloat *J ); +}; + +#define POINT(x) radeon_draw_point( rmesa, &vert[x], psize ) +#define LINE(x,y) radeon_draw_line( rmesa, &vert[x], &vert[y], lwidth ) +#define TRI(x,y,z) radeon_draw_triangle( rmesa, &vert[x], &vert[y], &vert[z] ) + + +/* Direct, and no clipping required. The clip funcs have not been + * written yet, so this is only useful for the fast path. + */ +#define RENDER_POINTS( start, count ) \ +do { \ + GLuint e; \ + for ( e = start ; e < count ; e++ ) \ + POINT( elt[e] ); \ +} while (0) + +#define RENDER_LINE( i1, i ) \ +do { \ + GLuint e1 = elt[i1], e = elt[i]; \ + LINE( e1, e ); \ +} while (0) + +#define RENDER_TRI( i2, i1, i, pv, parity ) \ +do { \ + GLuint e2 = elt[i2], e1 = elt[i1], e = elt[i]; \ + if ( parity ) { \ + GLuint tmp = e2; \ + e2 = e1; \ + e1 = tmp; \ + } \ + TRI( e2, e1, e ); \ +} while (0) + +#define RENDER_QUAD( i3, i2, i1, i, pv ) \ +do { \ + GLuint e3 = elt[i3], e2 = elt[i2], e1 = elt[i1], e = elt[i]; \ + TRI( e3, e2, e ); \ + TRI( e2, e1, e ); \ +} while (0) + +#define LOCAL_VARS \ + radeonVertexPtr vert = RADEON_DRIVER_DATA(VB)->verts; \ + const GLuint *elt = VB->EltPtr->data; \ + GLcontext *ctx = VB->ctx; \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + const GLfloat lwidth = ctx->Line.Width; \ + const GLfloat psize = ctx->Point.Size; \ + (void) lwidth; (void) psize; (void) vert; + +#define TAG(x) radeon_##x##_smooth_indirect +#include "render_tmp.h" + + + +#define NEGATIVE( f ) (f < 0) +#define DIFFERENT_SIGNS( a, b ) ((a * b) < 0) +#define LINTERP( T, A, B ) ((A) + (T) * ((B) - (A))) + + +#define INTERP_RGBA( t, out, a, b ) \ +do { \ + int i; \ + for ( i = 0 ; i < 4 ; i++ ) { \ + GLfloat fa = UBYTE_COLOR_TO_FLOAT_COLOR( a[i] ); \ + GLfloat fb = UBYTE_COLOR_TO_FLOAT_COLOR( b[i] ); \ + GLfloat fo = LINTERP( t, fa, fb ); \ + FLOAT_COLOR_TO_UBYTE_COLOR( out[i], fo ); \ + } \ +} while (0) + + +#define CLIP( SGN, V, PLANE ) \ +do { \ + if ( mask & PLANE ) { \ + GLuint *indata = inlist[in]; \ + GLuint *outdata = inlist[in ^= 1]; \ + GLuint nr = n; \ + GLfloat *J = verts[indata[nr-1]].f; \ + GLfloat dpJ = (SGN J[V]) + J[3]; \ + \ + inlist[0] = vlist1; \ + for ( i = n = 0 ; i < nr ; i++ ) { \ + GLuint elt_i = indata[i]; \ + GLfloat *I = verts[elt_i].f; \ + GLfloat dpI = (SGN I[V]) + I[3]; \ + \ + if ( DIFFERENT_SIGNS( dpI, dpJ ) ) { \ + GLfloat *O = verts[next_vert].f; \ + GLfloat t, *in, *out; \ + \ + if ( NEGATIVE( dpI ) ) { \ + t = dpI / (dpI - dpJ); \ + in = I; \ + out = J; \ + } else { \ + t = dpJ / (dpJ - dpI); \ + in = J; \ + out = I; \ + } \ + \ + interp( t, O, in, out ); \ + \ + clipmask[next_vert] = 0; \ + outdata[n++] = next_vert++; \ + } \ + \ + clipmask[elt_i] |= PLANE; /* don't set up */ \ + \ + if ( !NEGATIVE( dpI ) ) { \ + outdata[n++] = elt_i; \ + clipmask[elt_i] &= ~PLANE; /* set up after all */ \ + } \ + \ + J = I; \ + dpJ = dpI; \ + } \ + \ + if ( n < 3 ) return; \ + } \ +} while (0) + +#define LINE_CLIP( x, y, z, w, PLANE ) \ +do { \ + if ( mask & PLANE ) { \ + GLfloat dpI = DOT4V( I, x, y, z, w); \ + GLfloat dpJ = DOT4V( J, x, y, z, w); \ + \ + if ( DIFFERENT_SIGNS( dpI, dpJ ) ) { \ + GLfloat *O = verts[next_vert].f; \ + GLfloat t = dpI / (dpI - dpJ); \ + \ + interp( t, O, I, J ); \ + \ + clipmask[next_vert] = 0; \ + \ + if ( NEGATIVE( dpI ) ) { \ + clipmask[elts[0]] |= PLANE; \ + I = O; \ + elts[0] = next_vert++; \ + } else { \ + clipmask[elts[1]] |= PLANE; \ + J = O; \ + elts[1] = next_vert++; \ + } \ + } else if ( NEGATIVE( dpI ) ) return; \ + } \ +} while (0) + + +static __inline void radeon_tri_clip( GLuint **p_elts, + radeonVertexPtr verts, + GLubyte *clipmask, + GLuint *p_next_vert, + GLubyte mask, + radeon_interp_func interp ) +{ + GLuint *elts = *p_elts; + GLuint next_vert = *p_next_vert; + GLuint in = 0; + GLuint n = 3; + GLuint vlist1[VB_MAX_CLIPPED_VERTS]; + GLuint vlist2[VB_MAX_CLIPPED_VERTS]; + GLuint *inlist[2]; + GLuint *out; + GLuint i; + + inlist[0] = elts; + inlist[1] = vlist2; + + CLIP( -, 0, CLIP_RIGHT_BIT ); + CLIP( +, 0, CLIP_LEFT_BIT ); + CLIP( -, 1, CLIP_TOP_BIT ); + CLIP( +, 1, CLIP_BOTTOM_BIT ); + CLIP( -, 2, CLIP_FAR_BIT ); + CLIP( +, 2, CLIP_NEAR_BIT ); + + /* Convert the planar polygon to a list of triangles */ + out = inlist[in]; + + for ( i = 2 ; i < n ; i++ ) { + elts[0] = out[0]; + elts[1] = out[i-1]; + elts[2] = out[i]; + elts += 3; + } + + *p_next_vert = next_vert; + *p_elts = elts; +} + + +static __inline void radeon_line_clip( GLuint **p_elts, + radeonVertexPtr verts, + GLubyte *clipmask, + GLuint *p_next_vert, + GLubyte mask, + radeon_interp_func interp ) +{ + GLuint *elts = *p_elts; + GLfloat *I = verts[elts[0]].f; + GLfloat *J = verts[elts[1]].f; + GLuint next_vert = *p_next_vert; + + LINE_CLIP( 1, 0, 0, -1, CLIP_LEFT_BIT ); + LINE_CLIP( -1, 0, 0, 1, CLIP_RIGHT_BIT ); + LINE_CLIP( 0, 1, 0, -1, CLIP_TOP_BIT ); + LINE_CLIP( 0, -1, 0, 1, CLIP_BOTTOM_BIT ); + LINE_CLIP( 0, 0, 1, -1, CLIP_FAR_BIT ); + LINE_CLIP( 0, 0, -1, 1, CLIP_NEAR_BIT ); + + *p_next_vert = next_vert; + *p_elts += 2; +} + + + +#define CLIP_POINT( e ) \ +do { \ + if ( mask[e] ) *out++ = e; \ +} while (0) + +#define CLIP_LINE( e1, e0 ) \ +do { \ + GLubyte ormask = mask[e0] | mask[e1]; \ + out[0] = e1; \ + out[1] = e0; \ + out += 2; \ + if ( ormask ) { \ + out-=2; \ + if ( !(mask[e0] & mask[e1]) ) { \ + radeon_line_clip( &out, verts, mask, \ + &next_vert, ormask, interp ); \ + } \ + } \ +} while (0) + +#define CLIP_TRIANGLE( e2, e1, e0 ) \ +do { \ + GLubyte ormask; \ + out[0] = e2; \ + out[1] = e1; \ + out[2] = e0; \ + out += 3; \ + ormask = mask[e2] | mask[e1] | mask[e0]; \ + if ( ormask ) { \ + out -= 3; \ + if ( !(mask[e2] & mask[e1] & mask[e0]) ) { \ + radeon_tri_clip( &out, verts, mask, \ + &next_vert, ormask, interp ); \ + } \ + } \ +} while (0) + + + +/* Build a table of functions to clip each primitive type. These + * produce a list of elements in the appropriate 'reduced' primitive, + * ie (points, lines, triangles) containing all the clipped and + * unclipped primitives from the original list. + */ +#define LOCAL_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(VB->ctx); \ + radeonVertexBufferPtr rvb = RADEON_DRIVER_DATA(VB); \ + GLuint *elt = VB->EltPtr->data; \ + radeonVertexPtr verts = rvb->verts; \ + GLuint next_vert = rvb->last_vert; \ + GLuint *out = rvb->clipped_elements.data; \ + GLubyte *mask = VB->ClipMask; \ + radeon_interp_func interp = rmesa->interp; \ + (void) interp; (void) verts; + +#define POSTFIX \ + rvb->clipped_elements.count = out - rvb->clipped_elements.data; \ + rvb->last_vert = next_vert; + + +#define INIT( x ) + +#define RENDER_POINTS( start, count ) \ +do { \ + GLuint i; \ + for ( i = start; i < count ; i++ ) \ + CLIP_POINT( elt[i] ); \ +} while (0) + +#define RENDER_LINE( i1, i0 ) \ +do { \ + CLIP_LINE( elt[i1], elt[i0] ); \ +} while (0) + +#define RENDER_TRI( i2, i1, i0, pv, parity ) \ +do { \ + GLuint e2 = elt[i2], e1 = elt[i1], e0 = elt[i0]; \ + if ( parity ) e2 = elt[i1], e1 = elt[i2]; \ + CLIP_TRIANGLE( e2, e1, e0 ); \ +} while (0) + +#define RENDER_QUAD( i3, i2, i1, i0, pv ) \ +do { \ + CLIP_TRIANGLE( elt[i3], elt[i2], elt[i0] ); \ + CLIP_TRIANGLE( elt[i2], elt[i1], elt[i0] ); \ +} while (0) + +#define TAG(x) radeon_##x##_clip_elt +#include "render_tmp.h" + + + +/* Pack rgba and/or texture into the remaining half of a 32 byte vertex. + */ +#define CLIP_UBYTE_COLOR 4 +#define CLIP_UBYTE_R 0 +#define CLIP_UBYTE_G 1 +#define CLIP_UBYTE_B 2 +#define CLIP_UBYTE_A 3 +#define CLIP_S0 6 +#define CLIP_T0 7 +#define CLIP_S1 8 +#define CLIP_T1 9 + +#define TYPE (0) +#define TAG(x) x +#include "radeon_fasttmp.h" + +#define TYPE (RADEON_RGBA_BIT) +#define TAG(x) x##_RGBA +#include "radeon_fasttmp.h" + +#define TYPE (RADEON_TEX0_BIT) +#define TAG(x) x##_TEX0 +#include "radeon_fasttmp.h" + +#define TYPE (RADEON_RGBA_BIT | RADEON_TEX0_BIT) +#define TAG(x) x##_RGBA_TEX0 +#include "radeon_fasttmp.h" + +#define TYPE (RADEON_RGBA_BIT | RADEON_TEX0_BIT | RADEON_TEX1_BIT) +#define TAG(x) x##_RGBA_TEX0_TEX1 +#include "radeon_fasttmp.h" + +/* This one *could* get away with sneaking TEX1 into the color and + * specular slots, thus fitting inside a cache line. Would be even + * better to switch to a smaller vertex. + */ +#define TYPE (RADEON_TEX0_BIT | RADEON_TEX1_BIT) +#define TAG(x) x##_TEX0_TEX1 +#include "radeon_fasttmp.h" + + + +static void radeon_render_elements_direct( struct vertex_buffer *VB ) +{ + GLcontext *ctx = VB->ctx; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLenum prim = ctx->CVA.elt_mode; + GLuint nr = VB->EltPtr->count; + render_func func = radeon_render_tab_smooth_indirect[prim]; + GLuint p = 0; + + if ( rmesa->new_state ) + radeonDDUpdateHWState( ctx ); + + do { + func( VB, 0, nr, 0 ); + } while ( ctx->Driver.MultipassFunc && + ctx->Driver.MultipassFunc( VB, ++p ) ); +} + +/* GH: These should go away altogether on the Radeon. We should disable + * the viewport mapping entirely in Mesa and let the hardware do it in + * all cases. + */ +static void radeon_project_vertices( struct vertex_buffer *VB ) +{ + GLcontext *ctx = VB->ctx; + GLmatrix *mat = &ctx->Viewport.WindowMap; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonVertexBufferPtr rvb = RADEON_DRIVER_DATA(VB); + GLfloat *m = rmesa->tmp_matrix; + + m[MAT_SX] = mat->m[MAT_SX]; + m[MAT_TX] = mat->m[MAT_TX]; + m[MAT_SY] = -mat->m[MAT_SY]; + m[MAT_TY] = -mat->m[MAT_TY]; + m[MAT_SZ] = mat->m[MAT_SZ]; + m[MAT_TZ] = mat->m[MAT_TZ]; + + gl_project_v16( rvb->verts[VB->CopyStart].f, + rvb->verts[rvb->last_vert].f, + m, + 16 * 4 ); +} + +static void radeon_project_clipped_vertices( struct vertex_buffer *VB ) +{ + GLcontext *ctx = VB->ctx; + GLmatrix *mat = &ctx->Viewport.WindowMap; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonVertexBufferPtr rvb = RADEON_DRIVER_DATA(VB); + GLfloat *m = rmesa->tmp_matrix; + + m[MAT_SX] = mat->m[MAT_SX]; + m[MAT_TX] = mat->m[MAT_TX]; + m[MAT_SY] = -mat->m[MAT_SY]; + m[MAT_TY] = -mat->m[MAT_TY]; + m[MAT_SZ] = mat->m[MAT_SZ]; + m[MAT_TZ] = mat->m[MAT_TZ]; + + gl_project_clipped_v16( rvb->verts[VB->CopyStart].f, + rvb->verts[rvb->last_vert].f, + m, + 16 * 4, + VB->ClipMask + VB->CopyStart ); +} + +static struct radeon_fast_tab radeonFastTab[RADEON_MAX_SETUPFUNC]; + +void radeonDDFastPathInit( void ) +{ + radeon_render_init_clip_elt(); + radeon_render_init_smooth_indirect(); + + radeon_init_fastpath( &radeonFastTab[0] ); + radeon_init_fastpath_RGBA( &radeonFastTab[RADEON_RGBA_BIT] ); + radeon_init_fastpath_TEX0( &radeonFastTab[RADEON_TEX0_BIT] ); + radeon_init_fastpath_RGBA_TEX0( &radeonFastTab[(RADEON_RGBA_BIT | + RADEON_TEX0_BIT)] ); + radeon_init_fastpath_TEX0_TEX1( &radeonFastTab[(RADEON_TEX0_BIT | + RADEON_TEX1_BIT)] ); + radeon_init_fastpath_RGBA_TEX0_TEX1( &radeonFastTab[(RADEON_RGBA_BIT | + RADEON_TEX0_BIT | + RADEON_TEX1_BIT)] ); +} + +#define VALID_SETUP (RADEON_RGBA_BIT | RADEON_TEX0_BIT | RADEON_TEX1_BIT) + +void radeonDDFastPath( struct vertex_buffer *VB ) +{ + GLcontext *ctx = VB->ctx; + GLenum prim = ctx->CVA.elt_mode; + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + struct radeon_fast_tab *tab = + &radeonFastTab[rmesa->SetupIndex & VALID_SETUP]; + GLuint do_cliptest = 1; + + gl_prepare_arrays_cva( VB ); /* still need this */ + + if ( ( gl_reduce_prim[prim] == GL_TRIANGLES ) && + ( VB->Count < (RADEON_BUFFER_SIZE / (10 * sizeof(GLuint))) ) && + ( ctx->ModelProjectMatrix.flags & (MAT_FLAG_GENERAL | + MAT_FLAG_PERSPECTIVE) ) ) + { + radeonDDEltPath( VB ); + return; + } + + /* Reserve enough space for the pathological case */ + if ( VB->EltPtr->count * 12 > RADEON_DRIVER_DATA(VB)->size ) { + radeonDDResizeVB( VB, VB->EltPtr->count * 12 ); + do_cliptest = 1; + } + + tab->build_vertices( VB, do_cliptest ); /* object->clip space */ + + if ( rmesa->new_state ) + radeonDDUpdateHWState( ctx ); + + if ( VB->ClipOrMask ) { + if ( !VB->ClipAndMask ) { + render_func *clip = radeon_render_tab_clip_elt; + + rmesa->interp = tab->interp; + + clip[prim]( VB, 0, VB->EltPtr->count, 0 ); /* build new elts */ + + ctx->CVA.elt_mode = gl_reduce_prim[prim]; + VB->EltPtr = &(RADEON_DRIVER_DATA(VB)->clipped_elements); + + radeon_project_clipped_vertices( VB ); /* clip->device space */ + radeon_render_elements_direct( VB ); /* render using new list */ + } + } else { + radeon_project_vertices( VB ); /* clip->device space */ + radeon_render_elements_direct( VB ); /* render using orig list */ + } + + /* This indicates that there is no cached data to reuse */ + VB->pipeline->data_valid = 0; + VB->pipeline->new_state = 0; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_fasttmp.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_fasttmp.h new file mode 100644 index 000000000..dc444aa8a --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_fasttmp.h @@ -0,0 +1,185 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_fasttmp.h,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keithw@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +/* The first part of setup is applied to all vertices, clipped or + * unclipped. This data w!ill be used for clipping, and then all + * vertices with a zero clipmask will be projected to device space. + * + * This could be split into several loops, but - it seems that the + * large stride of the fxVertices makes cache issues the big + * performance factor, and that multiple loops mean multiple cache + * misses.... + */ +static void TAG(radeon_setup_full)( struct vertex_buffer *VB, + GLuint do_cliptest ) +{ + GLcontext *ctx = VB->ctx; + radeonVertexBufferPtr rvb = RADEON_DRIVER_DATA(VB); + const GLfloat *m = ctx->ModelProjectMatrix.m; + GLuint start = VB->CopyStart; + GLuint count = VB->Count; + + gl_xform_points3_v16_general( rvb->verts[start].f, + m, + VB->ObjPtr->start, + VB->ObjPtr->stride, + count - start ); + + if ( do_cliptest ) { + VB->ClipAndMask = ~0; + VB->ClipOrMask = 0; + gl_cliptest_points4_v16( rvb->verts[start].f, + rvb->verts[count].f, + &(VB->ClipOrMask), + &(VB->ClipAndMask), + VB->ClipMask + start ); + } + + /* These branches are all resolved at compile time. Hopefully all + * the pointers are valid addresses even when not enabled. + */ + if ( TYPE ) { + GLubyte *color = VB->ColorPtr->start; + GLfloat *tex0_data = VB->TexCoordPtr[0]->start; + GLfloat *tex1_data = VB->TexCoordPtr[1]->start; + + GLuint color_stride = VB->ColorPtr->stride; + GLuint tex0_stride = VB->TexCoordPtr[0]->stride; + GLuint tex1_stride = VB->TexCoordPtr[1]->stride; + + GLfloat *f = rvb->verts[start].f; + GLfloat *end = f + (16 * (count - start)); + + while ( f != end ) { + if ( TYPE & RADEON_RGBA_BIT ) { +#if defined (USE_X86_ASM) + /* GH: Finally! Some damned hardware manufacturer uses + * little-endian RGBA for vertex color... + */ + __asm__ ( "movl (%%ecx), %%eax \n" + "movl %%eax, 16(%%edi) \n" + : + : "c" (color), "D" (f) + : "%eax" ); +#else + *(GLuint *)(f+CLIP_UBYTE_COLOR) = *(GLuint *)color; +#endif + } + if ( TYPE & RADEON_TEX0_BIT ) { +#if defined (USE_X86_ASM) + __asm__ ( "movl (%%ecx), %%eax \n" + "movl %%eax, 24(%%edi) \n" + "movl 4(%%ecx), %%eax \n" + "movl %%eax, 28(%%edi)" + : + : "c" (tex0_data), "D" (f) + : "%eax" ); +#else + *(GLuint *)(f+CLIP_S0) = *(GLuint *)tex0_data; + *(GLuint *)(f+CLIP_T0) = *(GLuint *)(tex0_data+1); +#endif + } + if ( TYPE & RADEON_TEX1_BIT ) { + /* Hits a second cache line. + */ +#if defined (USE_X86_ASM) + __asm__ ( "movl (%%esi), %%eax \n" + "movl %%eax, 32(%%edi) \n" + "movl 4(%%esi), %%eax \n" + "movl %%eax, 36(%%edi)" + : + : "S" (tex1_data), "D" (f) + : "%eax" ); +#else + *(GLuint *)(f+CLIP_S1) = *(GLuint *)tex1_data; + *(GLuint *)(f+CLIP_T1) = *(GLuint *)(tex1_data+1); +#endif + } + if ( TYPE & RADEON_RGBA_BIT ) color += color_stride; + if ( TYPE & RADEON_TEX0_BIT ) STRIDE_F( tex0_data, tex0_stride ); + if ( TYPE & RADEON_TEX1_BIT ) STRIDE_F( tex1_data, tex1_stride ); + f += 16; + } + } + + rvb->clipped_elements.count = start; + rvb->last_vert = count; +} + + +/* Changed to just put the interp func instead of the whole clip + * routine into the header. Less code and better chance of doing some + * of this stuff in assembly. + */ +static void TAG(radeon_interp_vert)( GLfloat t, + GLfloat *O, + const GLfloat *I, + const GLfloat *J ) +{ + O[0] = LINTERP( t, I[0], J[0] ); + O[1] = LINTERP( t, I[1], J[1] ); + O[2] = LINTERP( t, I[2], J[2] ); + O[3] = LINTERP( t, I[3], J[3] ); + + if ( TYPE & RADEON_RGBA_BIT ) { + INTERP_RGBA( t, + ((GLubyte *)&(O[4])), + ((GLubyte *)&(I[4])), + ((GLubyte *)&(J[4])) ); + } + + if ( TYPE & RADEON_TEX0_BIT ) { + O[6] = LINTERP( t, I[6], J[6] ); + O[7] = LINTERP( t, I[7], J[7] ); + } + + if ( TYPE & RADEON_TEX1_BIT ) { + O[8] = LINTERP( t, I[8], J[8] ); + O[9] = LINTERP( t, I[9], J[9] ); + } +} + + +static void TAG(radeon_init_fastpath)( struct radeon_fast_tab *tab ) +{ + tab->build_vertices = TAG(radeon_setup_full); + tab->interp = TAG(radeon_interp_vert); +} + +#undef TYPE +#undef TAG +#undef SIZE diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c new file mode 100644 index 000000000..5273072e7 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c @@ -0,0 +1,703 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" + +#include "mem.h" + +#define RADEON_TIMEOUT 2048 +#define USE_IN_MEMORY_SCRATCH_REGS 0 + + +/* ============================================================= + * Hardware vertex buffer handling + */ + +/* Get a new VB from the pool of vertex buffers in AGP space. + */ +drmBufPtr radeonGetBufferLocked( radeonContextPtr rmesa ) +{ + int fd = rmesa->radeonScreen->driScreen->fd; + int index = 0; + int size = 0; + drmDMAReq dma; + drmBufPtr buf = NULL; + int to = 0; + int ret; + + dma.context = rmesa->hHWContext; + dma.send_count = 0; + dma.send_list = NULL; + dma.send_sizes = NULL; + dma.flags = 0; + dma.request_count = 1; + dma.request_size = RADEON_BUFFER_SIZE; + dma.request_list = &index; + dma.request_sizes = &size; + dma.granted_count = 0; + + while ( !buf && ( to++ < RADEON_TIMEOUT ) ) { + ret = drmDMA( fd, &dma ); + + if ( ret == 0 ) { + buf = &rmesa->radeonScreen->buffers->list[index]; + buf->used = 0; +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + rmesa->c_vertexBuffers++; +#endif + return buf; + } + } + + if ( !buf ) { + drmRadeonEngineReset( fd ); + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "Error: Could not get new VB... exiting\n" ); + exit( -1 ); + } + + return buf; +} + +static GLboolean intersect_rect( XF86DRIClipRectPtr out, + XF86DRIClipRectPtr a, + XF86DRIClipRectPtr b ) +{ + *out = *a; + if ( b->x1 > out->x1 ) out->x1 = b->x1; + if ( b->y1 > out->y1 ) out->y1 = b->y1; + if ( b->x2 < out->x2 ) out->x2 = b->x2; + if ( b->y2 < out->y2 ) out->y2 = b->y2; + if ( out->x1 >= out->x2 ) return GL_FALSE; + if ( out->y1 >= out->y2 ) return GL_FALSE; + return GL_TRUE; +} + +void radeonFlushVerticesLocked( radeonContextPtr rmesa ) +{ + XF86DRIClipRectPtr pbox = rmesa->pClipRects; + int nbox = rmesa->numClipRects; + drmBufPtr buffer = rmesa->vert_buf; + int count = rmesa->num_verts; + int prim = RADEON_TRIANGLES; + int fd = rmesa->driScreen->fd; + int i; + + rmesa->vert_buf = NULL; + rmesa->num_verts = 0; + + if ( !buffer ) + return; + + if ( rmesa->dirty & ~RADEON_UPLOAD_CLIPRECTS ) + radeonEmitHwStateLocked( rmesa ); + + if ( !nbox ) + count = 0; + + if ( nbox >= RADEON_NR_SAREA_CLIPRECTS ) + rmesa->dirty |= RADEON_UPLOAD_CLIPRECTS; + + if ( !count || !(rmesa->dirty & RADEON_UPLOAD_CLIPRECTS) ) + { + if ( nbox == 1 ) { + rmesa->sarea->nbox = 0; + } else { + rmesa->sarea->nbox = nbox; + } + + drmRadeonFlushVertexBuffer( fd, prim, buffer->idx, count, 1 ); + } + else + { + for ( i = 0 ; i < nbox ; ) { + int nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + int discard = 0; + + if ( rmesa->scissor ) { + rmesa->sarea->nbox = 0; + + for ( ; i < nr ; i++ ) { + *b = pbox[i]; + if ( intersect_rect( b, b, &rmesa->scissor_rect ) ) { + rmesa->sarea->nbox++; + b++; + } + } + + /* Culled? + */ + if ( !rmesa->sarea->nbox ) { + if ( nr < nbox ) continue; + count = 0; + } + } else { + rmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++) { + *b++ = pbox[i]; + } + } + + /* Finished with the buffer? + */ + if ( nr == nbox ) { + discard = 1; + } + + rmesa->sarea->dirty |= RADEON_UPLOAD_CLIPRECTS; + drmRadeonFlushVertexBuffer( fd, prim, buffer->idx, count, discard ); + } + } + + rmesa->dirty &= ~RADEON_UPLOAD_CLIPRECTS; +} + + + +/* ================================================================ + * Indexed vertex buffer handling + */ + +void radeonGetEltBufLocked( radeonContextPtr rmesa ) +{ + rmesa->elt_buf = radeonGetBufferLocked( rmesa ); +} + +void radeonFireEltsLocked( radeonContextPtr rmesa, + GLuint start, GLuint end, + GLuint discard ) +{ + XF86DRIClipRectPtr pbox = rmesa->pClipRects; + int nbox = rmesa->numClipRects; + drmBufPtr buffer = rmesa->elt_buf; + int prim = RADEON_TRIANGLES; + int fd = rmesa->driScreen->fd; + int i; + + if ( !buffer ) + return; + + if ( rmesa->dirty & ~RADEON_UPLOAD_CLIPRECTS ) + radeonEmitHwStateLocked( rmesa ); + + if ( !nbox ) + end = start; + + if ( nbox >= RADEON_NR_SAREA_CLIPRECTS ) + rmesa->dirty |= RADEON_UPLOAD_CLIPRECTS; + + if ( start == end || !(rmesa->dirty & RADEON_UPLOAD_CLIPRECTS) ) + { + if ( nbox == 1 ) { + rmesa->sarea->nbox = 0; + } else { + rmesa->sarea->nbox = nbox; + } + + drmRadeonFlushIndices( fd, prim, buffer->idx, start, end, discard ); + } + else + { + for ( i = 0 ; i < nbox ; ) { + int nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + int d = 0; + + if ( rmesa->scissor ) { + rmesa->sarea->nbox = 0; + + for ( ; i < nr ; i++ ) { + *b = pbox[i]; + if ( intersect_rect( b, b, &rmesa->scissor_rect ) ) { + rmesa->sarea->nbox++; + b++; + } + } + + /* Culled? + */ + if ( !rmesa->sarea->nbox ) { + if ( nr < nbox ) continue; + end = start; + } + } else { + rmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++) { + *b++ = pbox[i]; + } + } + + /* Finished with the buffer? + */ + if ( nr == nbox ) { + d = discard; + } + + rmesa->sarea->dirty |= RADEON_UPLOAD_CLIPRECTS; + drmRadeonFlushIndices( fd, prim, buffer->idx, start, end, discard ); + } + } + + rmesa->dirty &= ~RADEON_UPLOAD_CLIPRECTS; +} + +void radeonFlushEltsLocked( radeonContextPtr rmesa ) +{ + if ( rmesa->first_elt != rmesa->next_elt ) { + radeonFireEltsLocked( rmesa, + ((GLuint)rmesa->first_elt - + (GLuint)rmesa->elt_buf->address), + ((GLuint)rmesa->next_elt - + (GLuint)rmesa->elt_buf->address), + 0 ); + + ALIGN_NEXT_ELT( rmesa ); + rmesa->first_elt = rmesa->next_elt; + } +} + +void radeonReleaseBufLocked( radeonContextPtr rmesa, drmBufPtr buffer ) +{ + int fd = rmesa->driScreen->fd; + + if ( !buffer ) + return; + + drmRadeonFlushVertexBuffer( fd, RADEON_TRIANGLES, buffer->idx, 0, 1 ); +} + + +/* Allocate some space in the current vertex buffer. If the current + * buffer is full, flush it and grab another one. + */ +CARD32 *radeonAllocVertices( radeonContextPtr rmesa, GLuint count ) +{ + return radeonAllocVerticesInline( rmesa, count ); +} + + +/* ================================================================ + * Texture uploads + */ + +void radeonFireBlitLocked( radeonContextPtr rmesa, drmBufPtr buffer, + GLint offset, GLint pitch, GLint format, + GLint x, GLint y, GLint width, GLint height ) +{ + GLint ret; + + ret = drmRadeonTextureBlit( rmesa->driFd, buffer->idx, + offset, pitch, format, + x, y, width, height ); + + if ( ret ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "drmRadeonTextureBlit: return = %d\n", ret ); + exit( 1 ); + } +} + + +/* ================================================================ + * SwapBuffers with client-side throttling + */ + +#define RADEON_MAX_OUTSTANDING 2 + +/* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + * GH: We probably don't want a timeout here, as we can wait as + * long as we want for a frame to complete. If it never does, then + * the card has locked. + */ +#if USE_IN_MEMORY_SCRATCH_REGS +static int radeonWaitForFrameCompletion( radeonContextPtr rmesa ) +{ + RADEONSAREAPrivPtr sarea = rmesa->sarea; + __volatile__ CARD32 *scratch = rmesa->radeonScreen->scratch; + CARD32 frame; + int wait = 0; + + while ( 1 ) { + /* Read the frame counter from the in-memory copy of the scratch + * register. Nifty, eh? Should significantly reduce the bus + * traffic for SwapBuffers-limited apps (generally pretty trivial + * ones, but anyway). + */ + frame = scratch[0]; + if ( sarea->last_frame - frame <= RADEON_MAX_OUTSTANDING ) { + break; + } + wait++; + } + + return wait; +} +#else +static void delay( void ) { +/* Prevent an optimizing compiler from removing a spin loop */ +} + +static int radeonWaitForFrameCompletion( radeonContextPtr rmesa ) +{ + unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map; + RADEONSAREAPrivPtr sarea = rmesa->sarea; + CARD32 frame; + int wait = 0; + int i; + + while ( 1 ) { + frame = INREG( RADEON_LAST_FRAME_REG ); + if ( sarea->last_frame - frame <= RADEON_MAX_OUTSTANDING ) { + break; + } + wait++; + /* Spin in place a bit so we aren't hammering the bus */ + for ( i = 0 ; i < 1024 ; i++ ) { + delay(); + } + } + + return wait; +} +#endif + +/* Copy the back color buffer to the front color buffer. + */ +void radeonSwapBuffers( radeonContextPtr rmesa ) +{ + GLint nbox = rmesa->numClipRects; + GLint i; + GLint ret; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, rmesa->glCtx ); + } + + FLUSH_BATCH( rmesa ); + + LOCK_HARDWARE( rmesa ); + + /* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + */ + if ( !radeonWaitForFrameCompletion( rmesa ) ) { + rmesa->hardwareWentIdle = 1; + } else { + rmesa->hardwareWentIdle = 0; + } + + for ( i = 0 ; i < nbox ; ) { + GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox ); + XF86DRIClipRectPtr box = rmesa->pClipRects; + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + GLint n = 0; + + for ( ; i < nr ; i++ ) { + *b++ = *(XF86DRIClipRectRec *)&box[i]; + n++; + } + rmesa->sarea->nbox = n; + + ret = drmRadeonSwapBuffers( rmesa->driFd ); + + if ( ret ) { + fprintf( stderr, "drmRadeonSwapBuffers: return = %d\n", ret ); + UNLOCK_HARDWARE( rmesa ); + exit( 1 ); + } + } + + UNLOCK_HARDWARE( rmesa ); + + rmesa->new_state |= RADEON_NEW_CONTEXT; + rmesa->dirty |= (RADEON_UPLOAD_CONTEXT | + RADEON_UPLOAD_MASKS | + RADEON_UPLOAD_CLIPRECTS); + +#if ENABLE_PERF_BOXES + /* Log the performance counters if necessary */ + radeonPerformanceCounters( rmesa ); +#endif +} + +void radeonPageFlip( radeonContextPtr rmesa ) +{ + GLint ret; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "\n%s( %p ): page=%d\n\n", + __FUNCTION__, rmesa->glCtx, rmesa->currentPage ); + } + + FLUSH_BATCH( rmesa ); + + LOCK_HARDWARE( rmesa ); + + /* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + */ + if ( !radeonWaitForFrameCompletion( rmesa ) ) { + rmesa->hardwareWentIdle = 1; + } else { + rmesa->hardwareWentIdle = 0; + } + + /* The kernel will have been initialized to perform page flipping + * on a swapbuffers ioctl. + */ + ret = drmRadeonSwapBuffers( rmesa->driFd ); + + UNLOCK_HARDWARE( rmesa ); + + if ( ret ) { + fprintf( stderr, "drmRadeonSwapBuffers: return = %d\n", ret ); + exit( 1 ); + } + + if ( rmesa->currentPage == 0 ) { + rmesa->drawOffset = rmesa->radeonScreen->frontOffset; + rmesa->drawPitch = rmesa->radeonScreen->frontPitch; + rmesa->currentPage = 1; + } else { + rmesa->drawOffset = rmesa->radeonScreen->backOffset; + rmesa->drawPitch = rmesa->radeonScreen->backPitch; + rmesa->currentPage = 0; + } + + rmesa->setup.rb3d_coloroffset = rmesa->drawOffset; + rmesa->setup.rb3d_colorpitch = rmesa->drawPitch; + + rmesa->new_state |= RADEON_NEW_WINDOW; + + /* FIXME: Do we need this anymore? */ + rmesa->new_state |= RADEON_NEW_CONTEXT; + rmesa->dirty |= (RADEON_UPLOAD_CONTEXT | + RADEON_UPLOAD_MASKS | + RADEON_UPLOAD_CLIPRECTS); + +#if ENABLE_PERF_BOXES + /* Log the performance counters if necessary */ + radeonPerformanceCounters( rmesa ); +#endif +} + + +/* ================================================================ + * Buffer clear + */ +#define RADEON_MAX_CLEARS 256 + +static GLbitfield radeonDDClear( GLcontext *ctx, GLbitfield mask, + GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; + RADEONSAREAPrivPtr sarea = rmesa->sarea; +#if USE_IN_MEMORY_SCRATCH_REGS + __volatile__ CARD32 *scratch = rmesa->radeonScreen->scratch; +#else + unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map; +#endif + CARD32 clear; + GLuint flags = 0; + GLint ret, i; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s: all=%d cx=%d cy=%d cw=%d ch=%d\n", + __FUNCTION__, all, cx, cy, cw, ch ); + } + + FLUSH_BATCH( rmesa ); + + /* Update and emit any new state. We need to do this here to catch + * changes to the masks. + * FIXME: Just update the masks? + */ + if ( rmesa->new_state ) + radeonDDUpdateHWState( ctx ); + + if ( mask & DD_FRONT_LEFT_BIT ) { + flags |= DRM_RADEON_FRONT; + mask &= ~DD_FRONT_LEFT_BIT; + } + + if ( mask & DD_BACK_LEFT_BIT ) { + flags |= DRM_RADEON_BACK; + mask &= ~DD_BACK_LEFT_BIT; + } + + if ( mask & DD_DEPTH_BIT ) { + if ( ctx->Depth.Mask ) { + flags |= DRM_RADEON_DEPTH; + } + mask &= ~DD_DEPTH_BIT; + } +#if 0 + /* FIXME: Add stencil support */ + if ( mask & DD_STENCIL_BIT ) { + flags |= DRM_RADEON_DEPTH; + mask &= ~DD_STENCIL_BIT; + } +#endif + + if ( !flags ) + return mask; + + /* Flip top to bottom */ + cx += dPriv->x; + cy = dPriv->y + dPriv->h - cy - ch; + + LOCK_HARDWARE( rmesa ); + + /* Throttle the number of clear ioctls we do. + */ +#if USE_IN_MEMORY_SCRATCH_REGS + while ( 1 ) { + clear = scratch[2]; + if ( sarea->last_clear - clear <= RADEON_MAX_CLEARS ) { + break; + } + } +#else + while ( 1 ) { + clear = INREG( RADEON_LAST_CLEAR_REG ); + if ( sarea->last_clear - clear <= RADEON_MAX_CLEARS ) { + break; + } + /* Spin in place a bit so we aren't hammering the bus */ + for ( i = 0 ; i < 1024 ; i++ ) { + delay(); + } + } +#endif + + if ( rmesa->dirty & ~RADEON_UPLOAD_CLIPRECTS ) { + radeonEmitHwStateLocked( rmesa ); + } + + for ( i = 0 ; i < rmesa->numClipRects ; ) { + GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, rmesa->numClipRects ); + XF86DRIClipRectPtr box = rmesa->pClipRects; + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + GLint n = 0; + + if ( !all ) { + for ( ; i < nr ; i++ ) { + GLint x = box[i].x1; + GLint y = box[i].y1; + GLint w = box[i].x2 - x; + GLint h = box[i].y2 - y; + + if ( x < cx ) w -= cx - x, x = cx; + if ( y < cy ) h -= cy - y, y = cy; + if ( x + w > cx + cw ) w = cx + cw - x; + if ( y + h > cy + ch ) h = cy + ch - y; + if ( w <= 0 ) continue; + if ( h <= 0 ) continue; + + b->x1 = x; + b->y1 = y; + b->x2 = x + w; + b->y2 = y + h; + b++; + n++; + } + } else { + for ( ; i < nr ; i++ ) { + *b++ = *(XF86DRIClipRectRec *)&box[i]; + n++; + } + } + + rmesa->sarea->nbox = n; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_IOCTL ) { + fprintf( stderr, + "drmRadeonClear: flag 0x%x color %x depth %x nbox %d\n", + flags, + (GLuint)rmesa->ClearColor, + (GLuint)rmesa->ClearDepth, + rmesa->sarea->nbox ); + } + + ret = drmRadeonClear( rmesa->driFd, flags, + cx, cy, cw, ch, + rmesa->ClearColor, rmesa->ClearDepth ); + + if ( ret ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "drmRadeonClear: return = %d\n", ret ); + exit( 1 ); + } + } + + UNLOCK_HARDWARE( rmesa ); + + rmesa->dirty |= RADEON_UPLOAD_CLIPRECTS; + + return mask; +} + + +void radeonWaitForIdleLocked( radeonContextPtr rmesa ) +{ + int fd = rmesa->radeonScreen->driScreen->fd; + int to = 0; + int ret; + + do { + ret = drmRadeonWaitForIdleCP( fd ); + } while ( ( ret == -EBUSY ) && ( to++ < RADEON_TIMEOUT ) ); + + if ( ret < 0 ) { + drmRadeonEngineReset( fd ); + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "Error: Radeon timed out... exiting\n" ); + exit( -1 ); + } +} + + +void radeonDDInitIoctlFuncs( GLcontext *ctx ) +{ + ctx->Driver.Clear = radeonDDClear; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.h new file mode 100644 index 000000000..7b22a8766 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.h @@ -0,0 +1,161 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.h,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_IOCTL_H__ +#define __RADEON_IOCTL_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_dri.h" +#include "radeon_lock.h" + +#include "xf86drm.h" +#include "xf86drmRadeon.h" + +#define RADEON_BUFFER_MAX_DWORDS (RADEON_BUFFER_SIZE / sizeof(CARD32)) + + +extern drmBufPtr radeonGetBufferLocked( radeonContextPtr rmesa ); +extern void radeonFlushVerticesLocked( radeonContextPtr rmesa ); + +extern void radeonGetEltBufLocked( radeonContextPtr rmesa ); +extern void radeonFlushEltsLocked( radeonContextPtr rmesa ); +extern void radeonFireEltsLocked( radeonContextPtr rmesa, + GLuint start, GLuint end, + GLuint discard ); +extern void radeonReleaseBufLocked( radeonContextPtr rmesa, drmBufPtr buffer ); + +/* Make this available as both a regular and an inline function. + */ +extern CARD32 *radeonAllocVertices( radeonContextPtr rmesa, GLuint count ); + +static __inline CARD32 *radeonAllocVerticesInline( radeonContextPtr rmesa, + GLuint count ) +{ + int bytes = count * rmesa->vertsize * 4; + CARD32 *head; + + if ( !rmesa->vert_buf ) { + LOCK_HARDWARE( rmesa ); + + if ( rmesa->first_elt != rmesa->next_elt ) { + radeonFlushEltsLocked( rmesa ); + } + + rmesa->vert_buf = radeonGetBufferLocked( rmesa ); + + UNLOCK_HARDWARE( rmesa ); + } else if ( rmesa->vert_buf->used + bytes > rmesa->vert_buf->total ) { + LOCK_HARDWARE( rmesa ); + + radeonFlushVerticesLocked( rmesa ); + rmesa->vert_buf = radeonGetBufferLocked( rmesa ); + + UNLOCK_HARDWARE( rmesa ); + } + + head = (CARD32 *)((char *)rmesa->vert_buf->address + + rmesa->vert_buf->used); + + rmesa->vert_buf->used += bytes; + rmesa->num_verts += count; + return head; +} + +extern void radeonFireBlitLocked( radeonContextPtr rmesa, + drmBufPtr buffer, + GLint offset, GLint pitch, GLint format, + GLint x, GLint y, + GLint width, GLint height ); + +extern void radeonSwapBuffers( radeonContextPtr rmesa ); +extern void radeonPageFlip( radeonContextPtr rmesa ); + +extern void radeonWaitForIdleLocked( radeonContextPtr rmesa ); + + +extern void radeonDDInitIoctlFuncs( GLcontext *ctx ); + + +/* ================================================================ + * Helper macros: + */ + +#define FLUSH_BATCH( rmesa ) \ +do { \ + if ( RADEON_DEBUG & DEBUG_VERBOSE_IOCTL ) \ + fprintf( stderr, "FLUSH_BATCH in %s\n", __FUNCTION__ ); \ + if ( rmesa->vert_buf ) { \ + radeonFlushVertices( rmesa ); \ + } else if ( rmesa->next_elt != rmesa->first_elt ) { \ + radeonFlushElts( rmesa ); \ + } \ +} while (0) + +/* 64-bit align the next element address, and then make room for the + * next indexed prim packet header. + */ +#define ALIGN_NEXT_ELT( rmesa ) \ +do { \ + rmesa->next_elt = (GLushort *) \ + (((GLuint)rmesa->next_elt + 7) & ~0x7); \ + rmesa->next_elt = (GLushort *) \ + ((GLubyte *)rmesa->next_elt + RADEON_INDEX_PRIM_OFFSET); \ +} while (0) + +#define radeonFlushVertices( rmesa ) \ +do { \ + LOCK_HARDWARE( rmesa ); \ + radeonFlushVerticesLocked( rmesa ); \ + UNLOCK_HARDWARE( rmesa ); \ +} while (0) + +#define radeonFlushElts( rmesa ) \ +do { \ + LOCK_HARDWARE( rmesa ); \ + radeonFlushEltsLocked( rmesa ); \ + UNLOCK_HARDWARE( rmesa ); \ +} while (0) + +#define radeonWaitForIdle( rmesa ) \ +do { \ + LOCK_HARDWARE( rmesa ); \ + radeonWaitForIdleLocked( rmesa ); \ + UNLOCK_HARDWARE( rmesa ); \ +} while (0) + +#endif +#endif /* __RADEON_IOCTL_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c new file mode 100644 index 000000000..65658e997 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c @@ -0,0 +1,95 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_lock.h" +#include "radeon_tex.h" + +#if DEBUG_LOCKING +char *prevLockFile = NULL; +int prevLockLine = 0; +#endif + + +/* Update the hardware state. This is called if another context has + * grabbed the hardware lock, which includes the X server. This + * function also updates the driver's window state after the X server + * moves, resizes or restacks a window -- the change will be reflected + * in the drawable position and clip rects. Since the X server grabs + * the hardware lock when it changes the window state, this routine will + * automatically be called after such a change. + */ +void radeonGetLock( radeonContextPtr rmesa, GLuint flags ) +{ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; + __DRIscreenPrivate *sPriv = rmesa->driScreen; + RADEONSAREAPrivPtr sarea = rmesa->sarea; + int stamp = dPriv->lastStamp; + int i; + + drmGetLock( rmesa->driFd, rmesa->hHWContext, flags ); + + /* The window might have moved, so we might need to get new clip + * rects. + * + * NOTE: This releases and regrabs the hw lock to allow the X server + * to respond to the DRI protocol request for new drawable info. + * Since the hardware state depends on having the latest drawable + * clip rects, all state checking must be done _after_ this call. + */ + XMESA_VALIDATE_DRAWABLE_INFO( rmesa->display, sPriv, dPriv ); + + if ( stamp != dPriv->lastStamp ) { + rmesa->new_state |= RADEON_NEW_WINDOW | RADEON_NEW_CLIP; + rmesa->SetupDone = 0; + } + + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_CLIPRECTS; + + rmesa->numClipRects = dPriv->numClipRects; + rmesa->pClipRects = dPriv->pClipRects; + + if ( sarea->ctxOwner != rmesa->hHWContext ) { + sarea->ctxOwner = rmesa->hHWContext; + rmesa->dirty = RADEON_UPLOAD_ALL; + } + + for ( i = 0 ; i < rmesa->lastTexHeap ; i++ ) { + if ( sarea->texAge[i] != rmesa->lastTexAge[i] ) { + radeonAgeTextures( rmesa, i ); + } + } +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.h new file mode 100644 index 000000000..7cdb1b23d --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_lock.h @@ -0,0 +1,112 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_lock.h,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_LOCK_H__ +#define __RADEON_LOCK_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void radeonGetLock( radeonContextPtr rmesa, GLuint flags ); + +/* Turn DEBUG_LOCKING on to find locking conflicts. + */ +#define DEBUG_LOCKING 0 + +#if DEBUG_LOCKING +extern char *prevLockFile; +extern int prevLockLine; + +#define DEBUG_LOCK() \ + do { \ + prevLockFile = (__FILE__); \ + prevLockLine = (__LINE__); \ + } while (0) + +#define DEBUG_RESET() \ + do { \ + prevLockFile = 0; \ + prevLockLine = 0; \ + } while (0) + +#define DEBUG_CHECK_LOCK() \ + do { \ + if ( prevLockFile ) { \ + fprintf( stderr, \ + "LOCK SET!\n\tPrevious %s:%d\n\tCurrent: %s:%d\n", \ + prevLockFile, prevLockLine, __FILE__, __LINE__ ); \ + exit( 1 ); \ + } \ + } while (0) + +#else + +#define DEBUG_LOCK() +#define DEBUG_RESET() +#define DEBUG_CHECK_LOCK() + +#endif + +/* + * !!! We may want to separate locks from locks with validation. This + * could be used to improve performance for those things commands that + * do not do any drawing !!! + */ + +/* Lock the hardware and validate our state. + */ +#define LOCK_HARDWARE( rmesa ) \ + do { \ + char __ret = 0; \ + DEBUG_CHECK_LOCK(); \ + DRM_CAS( rmesa->driHwLock, rmesa->hHWContext, \ + (DRM_LOCK_HELD | rmesa->hHWContext), __ret ); \ + if ( __ret ) \ + radeonGetLock( rmesa, 0 ); \ + DEBUG_LOCK(); \ + } while (0) + +/* Unlock the hardware. + */ +#define UNLOCK_HARDWARE( rmesa ) \ + do { \ + DRM_UNLOCK( rmesa->driFd, \ + rmesa->driHwLock, \ + rmesa->hHWContext ); \ + DEBUG_RESET(); \ + } while (0) + +#endif +#endif /* __RADEON_LOCK_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.c new file mode 100644 index 000000000..fe0eb013e --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.c @@ -0,0 +1,168 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.c,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_vb.h" +#include "radeon_pipeline.h" + +#include "types.h" +#include "fog.h" + +static struct gl_pipeline_stage radeon_fast_stage = { + "Radeon Fast Path", + (PIPE_OP_VERT_XFORM | + PIPE_OP_RAST_SETUP_0 | + PIPE_OP_RAST_SETUP_1 | + PIPE_OP_RENDER), + PIPE_PRECALC, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + radeonDDFastPath +}; + +#define ILLEGAL_ENABLES (TEXTURE0_3D | \ + TEXTURE1_3D | \ + ENABLE_TEXMAT0 | \ + ENABLE_TEXMAT1 | \ + ENABLE_TEXGEN0 | \ + ENABLE_TEXGEN1 | \ + ENABLE_USERCLIP | \ + ENABLE_LIGHT | \ + ENABLE_FOG) + +/* Build the PRECALC pipeline with our stage, if possible. Otherwise, + * return GL_FALSE. + */ +GLboolean radeonDDBuildPrecalcPipeline( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_pipeline *pipe = &ctx->CVA.pre; + + if ( rmesa->RenderIndex == 0 && + (ctx->Enabled & ILLEGAL_ENABLES) == 0 && + (ctx->Array.Flags & (VERT_OBJ_234 | + VERT_TEX0_4 | + VERT_TEX1_4 | + VERT_ELT)) == (VERT_OBJ_23 | VERT_ELT) ) + { + pipe->stages[0] = &radeon_fast_stage; + pipe->stages[1] = 0; + pipe->new_inputs = ctx->RenderFlags & VERT_DATA; + pipe->ops = pipe->stages[0]->ops; + + rmesa->OnFastPath = GL_TRUE; + return GL_TRUE; + } + + if ( rmesa->OnFastPath ) { + rmesa->OnFastPath = GL_FALSE; + + ctx->CVA.VB->ClipOrMask = 0; + ctx->CVA.VB->ClipAndMask = CLIP_ALL_BITS; + ctx->Array.NewArrayState |= ctx->Array.Summary; + } + + return GL_FALSE; +} + + +/* Still do the normal fixup and copy-to-current, so this isn't so + * bad. + */ +#define ILLEGAL_INPUTS_IMM (VERT_OBJ_4 | \ + VERT_TEX0_4 | \ + VERT_TEX1_4 | \ + VERT_MATERIAL) + +static void radeonDDCheckRasterSetup( GLcontext *ctx, + struct gl_pipeline_stage *d ) +{ + d->type = PIPE_IMMEDIATE | PIPE_PRECALC; + d->inputs = ctx->RenderFlags; + + /* Radeon requires an extra input: + */ + if ( ctx->FogMode == FOG_FRAGMENT ) + d->inputs |= VERT_FOG_COORD; + + d->outputs = VERT_SETUP_FULL; + + if ( ctx->IndirectTriangles & DD_SW_SETUP ) + d->type = PIPE_IMMEDIATE; +} + + +GLuint radeonDDRegisterPipelineStages( struct gl_pipeline_stage *out, + const struct gl_pipeline_stage *in, + GLuint nr ) +{ + int i, o; + + for ( i = o = 0 ; i < nr ; i++ ) { + switch ( in[i].ops ) { + /* Completely replace Mesa's fog processing to generate fog + * coordinates instead of messing with colors. + */ + case PIPE_OP_FOG: + out[o] = gl_fog_coord_stage; + o++; + break; + + case PIPE_OP_RAST_SETUP_0: + out[o] = in[i]; + out[o].cva_state_change = (NEW_LIGHTING | + NEW_TEXTURING | + NEW_RASTER_OPS); + out[o].state_change = ~0; + out[o].check = radeonDDCheckPartialRasterSetup; + out[o].run = radeonDDPartialRasterSetup; + o++; + break; + + case PIPE_OP_RAST_SETUP_0 | PIPE_OP_RAST_SETUP_1: + out[o] = in[i]; + out[o].check = radeonDDCheckRasterSetup; + out[o].run = radeonDDDoRasterSetup; + o++; + break; + + default: + out[o++] = in[i]; + break; + } + } + + return o; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.h new file mode 100644 index 000000000..1af4e3eec --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.h @@ -0,0 +1,54 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_pipeline.h,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_PIPELINE_H__ +#define __RADEON_PIPELINE_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern GLboolean radeonDDBuildPrecalcPipeline( GLcontext *ctx ); +extern GLuint radeonDDRegisterPipelineStages( struct gl_pipeline_stage *out, + const struct gl_pipeline_stage *in, + GLuint nr ); + +extern void radeonDDFastPathInit( void ); +extern void radeonDDFastPath( struct vertex_buffer *VB ); + +extern void radeonDDEltPathInit( void ); +extern void radeonDDEltPath( struct vertex_buffer *VB ); + +#endif +#endif diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c new file mode 100644 index 000000000..e3cb90812 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c @@ -0,0 +1,220 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_dri.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_tris.h" +#include "radeon_vb.h" +#include "radeon_pipeline.h" + +#include "mem.h" + +#if 1 +/* Including xf86PciInfo.h introduces a bunch of errors... + */ +#define PCI_CHIP_RADEON_QD 0x5144 +#define PCI_CHIP_RADEON_QE 0x5145 +#define PCI_CHIP_RADEON_QF 0x5146 +#define PCI_CHIP_RADEON_QG 0x5147 +#endif + + +/* Create the device specific screen private data struct. + */ +radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ) +{ + radeonScreenPtr radeonScreen; + RADEONDRIPtr radeonDRIPriv = (RADEONDRIPtr)sPriv->pDevPriv; + + /* Check the DRI version */ + { + int major, minor, patch; + if ( XF86DRIQueryVersion( sPriv->display, &major, &minor, &patch ) ) { + if ( major != 3 || minor != 1 || patch < 0 ) { + char msg[128]; + sprintf( msg, "Radeon DRI driver expected DRI version 3.1.x but got version %d.%d.%d", major, minor, patch ); + __driMesaMessage( msg ); + return GL_FALSE; + } + } + } + + /* Check that the DDX driver version is compatible */ + if ( sPriv->ddxMajor != 4 || + sPriv->ddxMinor != 0 || + sPriv->ddxPatch < 0 ) { + char msg[128]; + sprintf( msg, "Radeon DRI driver expected DDX driver version 4.0.x but got version %d.%d.%d", sPriv->ddxMajor, sPriv->ddxMinor, sPriv->ddxPatch ); + __driMesaMessage( msg ); + return GL_FALSE; + } + + /* Check that the DRM driver version is compatible */ + if ( sPriv->drmMajor != 1 || + sPriv->drmMinor != 0 || + sPriv->drmPatch < 0 ) { + char msg[128]; + sprintf( msg, "Radeon DRI driver expected DRM driver version 2.1.x but got version %d.%d.%d", sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch ); + __driMesaMessage( msg ); + return GL_FALSE; + } + + /* Allocate the private area */ + radeonScreen = (radeonScreenPtr) CALLOC( sizeof(*radeonScreen) ); + if ( !radeonScreen ) return NULL; + + /* This is first since which regions we map depends on whether or + * not we are using a PCI card. + */ + radeonScreen->IsPCI = radeonDRIPriv->IsPCI; + + radeonScreen->mmio.handle = radeonDRIPriv->registerHandle; + radeonScreen->mmio.size = radeonDRIPriv->registerSize; + if ( drmMap( sPriv->fd, + radeonScreen->mmio.handle, + radeonScreen->mmio.size, + &radeonScreen->mmio.map ) ) { + FREE( radeonScreen ); + return NULL; + } + + radeonScreen->status.handle = radeonDRIPriv->statusHandle; + radeonScreen->status.size = radeonDRIPriv->statusSize; + if ( drmMap( sPriv->fd, + radeonScreen->status.handle, + radeonScreen->status.size, + &radeonScreen->status.map ) ) { + drmUnmap( radeonScreen->mmio.map, radeonScreen->mmio.size ); + FREE( radeonScreen ); + return NULL; + } + radeonScreen->scratch = (__volatile__ CARD32 *) + ((GLubyte *)radeonScreen->status.map + RADEON_SCRATCH_REG_OFFSET); + + radeonScreen->buffers = drmMapBufs( sPriv->fd ); + if ( !radeonScreen->buffers ) { + drmUnmap( radeonScreen->status.map, radeonScreen->status.size ); + drmUnmap( radeonScreen->mmio.map, radeonScreen->mmio.size ); + FREE( radeonScreen ); + return NULL; + } + + if ( !radeonScreen->IsPCI ) { + radeonScreen->agpTextures.handle = radeonDRIPriv->agpTexHandle; + radeonScreen->agpTextures.size = radeonDRIPriv->agpTexMapSize; + if ( drmMap( sPriv->fd, + radeonScreen->agpTextures.handle, + radeonScreen->agpTextures.size, + (drmAddressPtr)&radeonScreen->agpTextures.map ) ) { + drmUnmapBufs( radeonScreen->buffers ); + drmUnmap( radeonScreen->status.map, radeonScreen->status.size ); + drmUnmap( radeonScreen->mmio.map, radeonScreen->mmio.size ); + FREE( radeonScreen ); + return NULL; + } + } + + + switch ( radeonDRIPriv->deviceID ) { + case PCI_CHIP_RADEON_QD: + case PCI_CHIP_RADEON_QE: + case PCI_CHIP_RADEON_QF: + case PCI_CHIP_RADEON_QG: + radeonScreen->chipset = RADEON_CARD_TYPE_RADEON; + break; + default: + radeonScreen->chipset = RADEON_CARD_TYPE_RADEON; + break; + } + + radeonScreen->cpp = radeonDRIPriv->bpp / 8; + radeonScreen->AGPMode = radeonDRIPriv->AGPMode; + + radeonScreen->frontOffset = radeonDRIPriv->frontOffset; + radeonScreen->frontPitch = radeonDRIPriv->frontPitch; + radeonScreen->backOffset = radeonDRIPriv->backOffset; + radeonScreen->backPitch = radeonDRIPriv->backPitch; + radeonScreen->depthOffset = radeonDRIPriv->depthOffset; + radeonScreen->depthPitch = radeonDRIPriv->depthPitch; + + radeonScreen->texOffset[RADEON_CARD_HEAP] = radeonDRIPriv->textureOffset; + radeonScreen->texSize[RADEON_CARD_HEAP] = radeonDRIPriv->textureSize; + radeonScreen->logTexGranularity[RADEON_CARD_HEAP] = + radeonDRIPriv->log2TexGran; + + if ( radeonScreen->IsPCI ) { + radeonScreen->numTexHeaps = RADEON_NR_TEX_HEAPS - 1; + radeonScreen->texOffset[RADEON_AGP_HEAP] = 0; + radeonScreen->texSize[RADEON_AGP_HEAP] = 0; + radeonScreen->logTexGranularity[RADEON_AGP_HEAP] = 0; + } else { + radeonScreen->numTexHeaps = RADEON_NR_TEX_HEAPS; + radeonScreen->texOffset[RADEON_AGP_HEAP] = + radeonDRIPriv->agpTexOffset + RADEON_AGP_TEX_OFFSET; + radeonScreen->texSize[RADEON_AGP_HEAP] = radeonDRIPriv->agpTexMapSize; + radeonScreen->logTexGranularity[RADEON_AGP_HEAP] = + radeonDRIPriv->log2AGPTexGran; + } + + radeonScreen->driScreen = sPriv; + + radeonDDSetupInit(); + radeonDDTriangleFuncsInit(); + radeonDDFastPathInit(); + radeonDDEltPathInit(); + + return radeonScreen; +} + +/* Destroy the device specific screen private data struct. + */ +void radeonDestroyScreen( __DRIscreenPrivate *sPriv ) +{ + radeonScreenPtr radeonScreen = (radeonScreenPtr)sPriv->private; + + if ( !radeonScreen->IsPCI ) { + drmUnmap( radeonScreen->agpTextures.map, + radeonScreen->agpTextures.size ); + } + drmUnmapBufs( radeonScreen->buffers ); + drmUnmap( radeonScreen->status.map, radeonScreen->status.size ); + drmUnmap( radeonScreen->mmio.map, radeonScreen->mmio.size ); + + FREE( radeonScreen ); + sPriv->private = NULL; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h new file mode 100644 index 000000000..852e4f30a --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h @@ -0,0 +1,87 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h,v 1.1 2001/01/08 01:07:27 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_SCREEN_H__ +#define __RADEON_SCREEN_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_sarea.h" + +typedef struct { + drmHandle handle; /* Handle to the DRM region */ + drmSize size; /* Size of the DRM region */ + drmAddress map; /* Mapping of the DRM region */ +} radeonRegionRec, *radeonRegionPtr; + +typedef struct { + + GLint chipset; + GLint cpp; + GLint IsPCI; /* Current card is a PCI card */ + GLint AGPMode; + + GLuint frontOffset; + GLuint frontPitch; + GLuint backOffset; + GLuint backPitch; + + GLuint depthOffset; + GLuint depthPitch; + + /* Shared texture data */ + int numTexHeaps; + int texOffset[RADEON_NR_TEX_HEAPS]; + int texSize[RADEON_NR_TEX_HEAPS]; + int logTexGranularity[RADEON_NR_TEX_HEAPS]; + + radeonRegionRec mmio; + radeonRegionRec status; + radeonRegionRec agpTextures; + + drmBufMapPtr buffers; + + __volatile__ CARD32 *scratch; + + __DRIscreenPrivate *driScreen; + +} radeonScreenRec, *radeonScreenPtr; + +extern radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ); +extern void radeonDestroyScreen( __DRIscreenPrivate *sPriv ); + +#endif +#endif /* __RADEON_SCREEN_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_span.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_span.c new file mode 100644 index 000000000..74ce2c827 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_span.c @@ -0,0 +1,346 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.c,v 1.2 2001/01/16 05:10:58 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keithw@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_span.h" + +#define DBG 0 + +#define LOCAL_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + radeonScreenPtr radeonScreen = rmesa->radeonScreen; \ + __DRIscreenPrivate *sPriv = rmesa->driScreen; \ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \ + GLuint pitch = radeonScreen->frontPitch * radeonScreen->cpp; \ + GLuint height = dPriv->h; \ + char *buf = (char *)(sPriv->pFB + \ + rmesa->drawOffset + \ + (dPriv->x * radeonScreen->cpp) + \ + (dPriv->y * pitch)); \ + char *read_buf = (char *)(sPriv->pFB + \ + rmesa->readOffset + \ + (dPriv->x * radeonScreen->cpp) + \ + (dPriv->y * pitch)); \ + GLushort p; \ + (void) read_buf; (void) buf; (void) p + +#define LOCAL_DEPTH_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + radeonScreenPtr radeonScreen = rmesa->radeonScreen; \ + __DRIscreenPrivate *sPriv = rmesa->driScreen; \ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \ + GLuint height = dPriv->h; \ + GLuint xo = dPriv->x; \ + GLuint yo = dPriv->y; \ + char *buf = (char *)(sPriv->pFB + radeonScreen->depthOffset); \ + (void) buf + +#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS + +#define INIT_MONO_PIXEL( p ) p = rmesa->Color + +#define CLIPPIXEL( _x, _y ) \ + ((_x >= minx) && (_x < maxx) && (_y >= miny) && (_y < maxy)) + + +#define CLIPSPAN( _x, _y, _n, _x1, _n1, _i ) \ + if ((_y < miny) || (_y >= maxy)) { \ + _n1 = 0, _x1 = x; \ + } else { \ + _n1 = _n; \ + _x1 = _x; \ + if (_x1 < minx) _i += (minx - _x1), _x1 = minx; \ + if (_x1 + _n1 >= maxx) n1 -= (_x1 + n1 - maxx); \ + } + +#define Y_FLIP( _y ) (height - _y - 1) + + +#define HW_LOCK() \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + FLUSH_BATCH( rmesa ); \ + LOCK_HARDWARE( rmesa ); \ + radeonWaitForIdleLocked( rmesa ); + +#define HW_CLIPLOOP() \ + do { \ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \ + int _nc = dPriv->numClipRects; \ + \ + while ( _nc-- ) { \ + int minx = dPriv->pClipRects[_nc].x1 - dPriv->x; \ + int miny = dPriv->pClipRects[_nc].y1 - dPriv->y; \ + int maxx = dPriv->pClipRects[_nc].x2 - dPriv->x; \ + int maxy = dPriv->pClipRects[_nc].y2 - dPriv->y; + +#define HW_ENDCLIPLOOP() \ + } \ + } while (0) + +#define HW_UNLOCK() \ + UNLOCK_HARDWARE( rmesa ) + + + +/* ================================================================ + * Color buffer + */ + +/* 16 bit, RGB565 color spanline and pixel functions + */ +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)r & 0xf8) << 8) | \ + (((int)g & 0xfc) << 3) | \ + (((int)b & 0xf8) >> 3)) + +#define WRITE_PIXEL( _x, _y, p ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = p + +#define READ_RGBA( rgba, _x, _y ) \ + do { \ + GLushort p = *(GLushort *)(read_buf + _x*2 + _y*pitch); \ + rgba[0] = (p >> 8) & 0xf8; \ + rgba[1] = (p >> 3) & 0xfc; \ + rgba[2] = (p << 3) & 0xf8; \ + rgba[3] = 0xff; \ + if ( rgba[0] & 0x08 ) rgba[0] |= 0x07; \ + if ( rgba[1] & 0x04 ) rgba[1] |= 0x03; \ + if ( rgba[2] & 0x08 ) rgba[2] |= 0x07; \ + } while (0) + +#define TAG(x) radeon##x##_RGB565 +#include "spantmp.h" + +/* 32 bit, ARGB8888 color spanline and pixel functions + */ +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ + *(GLuint *)(buf + _x*4 + _y*pitch) = ((b << 0) | \ + (g << 8) | \ + (r << 16) | \ + (a << 24) ) + +#define WRITE_PIXEL( _x, _y, p ) \ + *(GLuint *)(buf + _x*4 + _y*pitch) = p + +#define READ_RGBA( rgba, _x, _y ) \ +do { \ + GLuint p = *(GLuint *)(read_buf + _x*4 + _y*pitch); \ + rgba[0] = (p >> 16) & 0xff; \ + rgba[1] = (p >> 8) & 0xff; \ + rgba[2] = (p >> 0) & 0xff; \ + rgba[3] = (p >> 24) & 0xff; \ +} while (0) + +#define TAG(x) radeon##x##_ARGB8888 +#include "spantmp.h" + + + +/* ================================================================ + * Depth buffer + */ + +/* The Radeon has depth tiling on all the time, so we have to convert + * the x,y coordinates into the memory bus address (mba) in the same + * manner as the engine. In each case, the linear block address (ba) + * is calculated, and then wired with x and y to produce the final + * memory address. + */ +static __inline GLuint radeon_mba_z16( radeonContextPtr rmesa, + GLint x, GLint y ) +{ + radeonScreenPtr radeonScreen = rmesa->radeonScreen; + GLuint pitch = radeonScreen->frontPitch; + GLuint ba, address = 0; /* a[0] = 0 */ + + ba = (y / 16) * (pitch / 32) + (x / 32); + + address |= (x & 0x7) << 1; /* a[1..3] = x[0..2] */ + address |= (y & 0x7) << 4; /* a[4..6] = y[0..2] */ + address |= (x & 0x8) << 4; /* a[7] = x[3] */ + address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ + address |= (y & 0x8) << 7; /* a[10] = y[3] */ + address |= ((x & 0x10) ^ (y & 0x10)) << 7; /* a[11] = x[4] ^ y[4] */ + address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */ + + return address; +} + +static GLuint radeon_mba_z32( radeonContextPtr rmesa, + GLint x, GLint y ) +{ + radeonScreenPtr radeonScreen = rmesa->radeonScreen; + GLuint pitch = radeonScreen->frontPitch; + GLuint ba, address = 0; /* a[0..1] = 0 */ + + ba = (y / 16) * (pitch / 16) + (x / 16); + + address |= (x & 0x7) << 2; /* a[2..4] = x[0..2] */ + address |= (y & 0x3) << 5; /* a[5..6] = y[0..1] */ + address |= + (((x & 0x10) >> 2) ^ (y & 0x4)) << 5; /* a[7] = x[4] ^ y[2] */ + address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ + + address |= (y & 0x8) << 7; /* a[10] = y[3] */ + address |= + (((x & 0x8) << 1) ^ (y & 0x10)) << 7; /* a[11] = x[3] ^ y[4] */ + address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */ + + return address; +} + + +/* 16-bit depth buffer functions + */ +#define WRITE_DEPTH( _x, _y, d ) \ + *(GLushort *)(buf + radeon_mba_z16( rmesa, _x+xo, _y+yo )) = d; + +#define READ_DEPTH( d, _x, _y ) \ + d = *(GLushort *)(buf + radeon_mba_z16( rmesa, _x+xo, _y+yo )); + +#define TAG(x) radeon##x##_16 +#include "depthtmp.h" + +/* 24 bit depth, 8 bit stencil depthbuffer functions + */ +#define WRITE_DEPTH( _x, _y, d ) \ +do { \ + GLuint offset = radeon_mba_z32( rmesa, _x+xo, _y+yo ); \ + GLuint tmp = *(GLuint *)(buf + offset); \ + tmp &= 0xff000000; \ + tmp |= ((d) & 0x00ffffff); \ + *(GLuint *)(buf + offset) = tmp; \ +} while (0) + +#define READ_DEPTH( d, _x, _y ) \ + d = *(GLuint *)(buf + radeon_mba_z32( rmesa, _x+xo, _y+yo )) & 0x00ffffff; + +#define TAG(x) radeon##x##_24_8 +#include "depthtmp.h" + + +/* ================================================================ + * Stencil buffer + */ + +/* 24 bit depth, 8 bit stencil depthbuffer functions + */ +#define WRITE_STENCIL( _x, _y, d ) \ +do { \ + GLuint offset = radeon_mba_z32( rmesa, _x+xo, _y+yo ); \ + GLuint tmp = *(GLuint *)(buf + offset); \ + tmp &= 0x00ffffff; \ + tmp |= (((d) & 0xff) << 24); \ + *(GLuint *)(buf + offset) = tmp; \ +} while (0) + +#define READ_STENCIL( d, _x, _y ) \ +do { \ + GLuint offset = radeon_mba_z32( rmesa, _x+xo, _y+yo ); \ + GLuint tmp = *(GLuint *)(buf + offset); \ + tmp &= 0xff000000; \ + d = tmp >> 24; \ +} while (0) + +#define TAG(x) radeon##x##_24_8 +#include "stenciltmp.h" + + + +void radeonDDInitSpanFuncs( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + switch ( rmesa->radeonScreen->cpp ) { + case 2: + ctx->Driver.WriteRGBASpan = radeonWriteRGBASpan_RGB565; + ctx->Driver.WriteRGBSpan = radeonWriteRGBSpan_RGB565; + ctx->Driver.WriteMonoRGBASpan = radeonWriteMonoRGBASpan_RGB565; + ctx->Driver.WriteRGBAPixels = radeonWriteRGBAPixels_RGB565; + ctx->Driver.WriteMonoRGBAPixels = radeonWriteMonoRGBAPixels_RGB565; + ctx->Driver.ReadRGBASpan = radeonReadRGBASpan_RGB565; + ctx->Driver.ReadRGBAPixels = radeonReadRGBAPixels_RGB565; + break; + + case 4: + ctx->Driver.WriteRGBASpan = radeonWriteRGBASpan_ARGB8888; + ctx->Driver.WriteRGBSpan = radeonWriteRGBSpan_ARGB8888; + ctx->Driver.WriteMonoRGBASpan = radeonWriteMonoRGBASpan_ARGB8888; + ctx->Driver.WriteRGBAPixels = radeonWriteRGBAPixels_ARGB8888; + ctx->Driver.WriteMonoRGBAPixels = radeonWriteMonoRGBAPixels_ARGB8888; + ctx->Driver.ReadRGBASpan = radeonReadRGBASpan_ARGB8888; + ctx->Driver.ReadRGBAPixels = radeonReadRGBAPixels_ARGB8888; + break; + + default: + break; + } + + switch ( rmesa->glCtx->Visual->DepthBits ) { + case 16: + ctx->Driver.ReadDepthSpan = radeonReadDepthSpan_16; + ctx->Driver.WriteDepthSpan = radeonWriteDepthSpan_16; + ctx->Driver.ReadDepthPixels = radeonReadDepthPixels_16; + ctx->Driver.WriteDepthPixels = radeonWriteDepthPixels_16; + break; + + case 24: + ctx->Driver.ReadDepthSpan = radeonReadDepthSpan_24_8; + ctx->Driver.WriteDepthSpan = radeonWriteDepthSpan_24_8; + ctx->Driver.ReadDepthPixels = radeonReadDepthPixels_24_8; + ctx->Driver.WriteDepthPixels = radeonWriteDepthPixels_24_8; + + ctx->Driver.ReadStencilSpan = radeonReadStencilSpan_24_8; + ctx->Driver.WriteStencilSpan = radeonWriteStencilSpan_24_8; + ctx->Driver.ReadStencilPixels = radeonReadStencilPixels_24_8; + ctx->Driver.WriteStencilPixels = radeonWriteStencilPixels_24_8; + break; + + default: + break; + } + + ctx->Driver.WriteCI8Span = NULL; + ctx->Driver.WriteCI32Span = NULL; + ctx->Driver.WriteMonoCISpan = NULL; + ctx->Driver.WriteCI32Pixels = NULL; + ctx->Driver.WriteMonoCIPixels = NULL; + ctx->Driver.ReadCI32Span = NULL; + ctx->Driver.ReadCI32Pixels = NULL; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_span.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_span.h new file mode 100644 index 000000000..241f11c1e --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_span.h @@ -0,0 +1,45 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.h,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_SPAN_H__ +#define __RADEON_SPAN_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void radeonDDInitSpanFuncs( GLcontext *ctx ); + +#endif +#endif diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_state.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_state.c new file mode 100644 index 000000000..8cec8ff52 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_state.c @@ -0,0 +1,1338 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.c,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keithw@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_tris.h" +#include "radeon_vb.h" +#include "radeon_tex.h" + +#include "mmath.h" +#include "pb.h" +#include "enums.h" + + +/* ============================================================= + * Alpha blending + */ + +static void radeonUpdateAlphaMode( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + CARD32 a = rmesa->setup.pp_misc; + CARD32 p = rmesa->setup.pp_cntl; + CARD32 b = rmesa->setup.rb3d_blendcntl; + CARD32 c = rmesa->setup.rb3d_cntl; + + if ( ctx->Color.AlphaEnabled ) { + GLubyte ref = ctx->Color.AlphaRef; + + a &= ~(RADEON_ALPHA_TEST_OP_MASK | RADEON_REF_ALPHA_MASK); + + switch ( ctx->Color.AlphaFunc ) { + case GL_NEVER: + a |= RADEON_ALPHA_TEST_FAIL; + break; + case GL_LESS: + a |= RADEON_ALPHA_TEST_LESS; + break; + case GL_LEQUAL: + a |= RADEON_ALPHA_TEST_LEQUAL; + break; + case GL_EQUAL: + a |= RADEON_ALPHA_TEST_EQUAL; + break; + case GL_GEQUAL: + a |= RADEON_ALPHA_TEST_GEQUAL; + break; + case GL_GREATER: + a |= RADEON_ALPHA_TEST_GREATER; + break; + case GL_NOTEQUAL: + a |= RADEON_ALPHA_TEST_NEQUAL; + break; + case GL_ALWAYS: + a |= RADEON_ALPHA_TEST_PASS; + break; + } + + a |= (ref & RADEON_REF_ALPHA_MASK); + p |= RADEON_ALPHA_TEST_ENABLE; + } else { + p &= ~RADEON_ALPHA_TEST_ENABLE; + } + + if ( ctx->Color.BlendEnabled ) { + b &= ~(RADEON_SRC_BLEND_MASK | RADEON_DST_BLEND_MASK); + + switch ( ctx->Color.BlendSrcRGB ) { + case GL_ZERO: + b |= RADEON_SRC_BLEND_GL_ZERO; + break; + case GL_ONE: + b |= RADEON_SRC_BLEND_GL_ONE; + break; + case GL_DST_COLOR: + b |= RADEON_SRC_BLEND_GL_DST_COLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR; + break; + case GL_SRC_ALPHA: + b |= RADEON_SRC_BLEND_GL_SRC_ALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + b |= RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA; + break; + case GL_DST_ALPHA: + b |= RADEON_SRC_BLEND_GL_DST_ALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA; + break; + case GL_SRC_ALPHA_SATURATE: + b |= RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE; + break; + } + + switch ( ctx->Color.BlendDstRGB ) { + case GL_ZERO: + b |= RADEON_DST_BLEND_GL_ZERO; + break; + case GL_ONE: + b |= RADEON_DST_BLEND_GL_ONE; + break; + case GL_SRC_COLOR: + b |= RADEON_DST_BLEND_GL_SRC_COLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR; + break; + case GL_SRC_ALPHA: + b |= RADEON_DST_BLEND_GL_SRC_ALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA; + break; + case GL_DST_ALPHA: + b |= RADEON_DST_BLEND_GL_DST_ALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + b |= RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA; + break; + } + + c |= RADEON_ALPHA_BLEND_ENABLE; + } else { + c &= ~RADEON_ALPHA_BLEND_ENABLE; + } + + if ( rmesa->setup.pp_misc != a ) { + rmesa->setup.pp_misc = a; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_MASKS; + } + if ( rmesa->setup.pp_cntl != p ) { + rmesa->setup.pp_cntl = p; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_MASKS; + } + if ( rmesa->setup.rb3d_blendcntl != b ) { + rmesa->setup.rb3d_blendcntl = b; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_MASKS; + } + if ( rmesa->setup.rb3d_cntl != c ) { + rmesa->setup.rb3d_cntl = c; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_MASKS; + } +} + +static void radeonDDAlphaFunc( GLcontext *ctx, GLenum func, GLclampf ref ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_ALPHA; +} + +static void radeonDDBlendEquation( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_ALPHA; +} + +static void radeonDDBlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_ALPHA; +} + +static void radeonDDBlendFuncSeparate( GLcontext *ctx, + GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_ALPHA; +} + + +/* ============================================================= + * Depth testing + */ + +static void radeonUpdateZMode( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + CARD32 z = rmesa->setup.rb3d_zstencilcntl; + CARD32 c = rmesa->setup.rb3d_cntl; + + if ( ctx->Depth.Test ) { + z &= ~RADEON_Z_TEST_MASK; + + switch ( ctx->Depth.Func ) { + case GL_NEVER: + z |= RADEON_Z_TEST_NEVER; + break; + case GL_ALWAYS: + z |= RADEON_Z_TEST_ALWAYS; + break; + case GL_LESS: + z |= RADEON_Z_TEST_LESS; + break; + case GL_LEQUAL: + z |= RADEON_Z_TEST_LEQUAL; + break; + case GL_EQUAL: + z |= RADEON_Z_TEST_EQUAL; + break; + case GL_GEQUAL: + z |= RADEON_Z_TEST_GEQUAL; + break; + case GL_GREATER: + z |= RADEON_Z_TEST_GREATER; + break; + case GL_NOTEQUAL: + z |= RADEON_Z_TEST_NEQUAL; + break; + } + + c |= RADEON_Z_ENABLE; + } else { + c &= ~RADEON_Z_ENABLE; + } + + if ( ctx->Depth.Mask ) { + z |= RADEON_Z_WRITE_ENABLE; + } else { + z &= ~RADEON_Z_WRITE_ENABLE; + } + + if ( rmesa->setup.rb3d_zstencilcntl != z ) { + rmesa->setup.rb3d_zstencilcntl = z; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } + if ( rmesa->setup.rb3d_cntl != c ) { + rmesa->setup.rb3d_cntl = c; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } +} + +static void radeonDDDepthFunc( GLcontext *ctx, GLenum func ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_DEPTH; +} + +static void radeonDDDepthMask( GLcontext *ctx, GLboolean flag ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_DEPTH; +} + +static void radeonDDClearDepth( GLcontext *ctx, GLclampd d ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + switch ( rmesa->setup.rb3d_zstencilcntl & RADEON_DEPTH_FORMAT_MASK ) { + case RADEON_DEPTH_FORMAT_16BIT_INT_Z: + rmesa->ClearDepth = d * 0x0000ffff; + break; + case RADEON_DEPTH_FORMAT_24BIT_INT_Z: + rmesa->ClearDepth = d * 0x00ffffff; + break; + } +} + + +/* ============================================================= + * Fog + */ + +static void radeonUpdateFogAttrib( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + CARD32 p = rmesa->setup.pp_cntl; + GLubyte c[4]; + CARD32 col; + + if ( ctx->FogMode == FOG_FRAGMENT ) { + p |= RADEON_FOG_ENABLE; + } else { + p &= ~RADEON_FOG_ENABLE; + } + + FLOAT_RGB_TO_UBYTE_RGB( c, ctx->Fog.Color ); + col = radeonPackColor( 4, c[0], c[1], c[2], 0 ); + + if ( rmesa->setup.pp_fog_color != col ) { + rmesa->setup.pp_fog_color = col; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } + if ( rmesa->setup.pp_cntl != p ) { + rmesa->setup.pp_cntl = p; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } +} + +static void radeonDDFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_FOG; +} + + +/* ============================================================= + * Clipping + */ + +static void radeonUpdateClipping( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if ( rmesa->driDrawable ) { + __DRIdrawablePrivate *drawable = rmesa->driDrawable; + int x = 0; + int y = 0; + int w = drawable->w - 1; + int h = drawable->h - 1; + + if ( ctx->Scissor.Enabled ) { + if ( ctx->Scissor.X > x ) { + x = ctx->Scissor.X; + } + if ( drawable->h - ctx->Scissor.Y - ctx->Scissor.Height > y ) { + y = drawable->h - ctx->Scissor.Y - ctx->Scissor.Height; + } + if ( ctx->Scissor.X + ctx->Scissor.Width - 1 < w ) { + w = ctx->Scissor.X + ctx->Scissor.Width - 1; + } + if ( drawable->h - ctx->Scissor.Y - 1 < h ) { + h = drawable->h - ctx->Scissor.Y - 1; + } + } + + rmesa->scissor_rect.x1 = x + rmesa->driDrawable->x; + rmesa->scissor_rect.y1 = y + rmesa->driDrawable->y; + rmesa->scissor_rect.x2 = w + rmesa->driDrawable->x; + rmesa->scissor_rect.y2 = h + rmesa->driDrawable->y; + + rmesa->dirty |= RADEON_UPLOAD_CLIPRECTS; + } +} + +static void radeonDDScissor( GLcontext *ctx, + GLint x, GLint y, GLsizei w, GLsizei h ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_CLIP; +} + + +/* ============================================================= + * Culling + */ + +static void radeonUpdateCull( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + CARD32 s = rmesa->setup.se_cntl; + + s &= ~RADEON_FFACE_CULL_DIR_MASK; + + switch ( ctx->Polygon.FrontFace ) { + case GL_CW: + s |= RADEON_FFACE_CULL_CW; + break; + case GL_CCW: + s |= RADEON_FFACE_CULL_CCW; + break; + } + + s |= RADEON_FFACE_SOLID | RADEON_BFACE_SOLID; + + if ( ctx->Polygon.CullFlag && ctx->PB->primitive == GL_POLYGON ) { + switch ( ctx->Polygon.CullFaceMode ) { + case GL_FRONT: + s &= ~RADEON_FFACE_SOLID; + break; + case GL_BACK: + s &= ~RADEON_BFACE_SOLID; + break; + case GL_FRONT_AND_BACK: + s &= ~(RADEON_FFACE_SOLID | RADEON_BFACE_SOLID); + break; + } + } + + if ( rmesa->setup.se_cntl != s ) { + rmesa->setup.se_cntl = s; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_SETUP; + } +} + +static void radeonDDCullFace( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_CULL; +} + +static void radeonDDFrontFace( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_CULL; +} + + +/* ============================================================= + * Masks + */ + +static void radeonUpdateMasks( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + GLuint mask = radeonPackColor( rmesa->radeonScreen->cpp, + ctx->Color.ColorMask[RCOMP], + ctx->Color.ColorMask[GCOMP], + ctx->Color.ColorMask[BCOMP], + ctx->Color.ColorMask[ACOMP] ); + + if ( rmesa->setup.rb3d_planemask != mask ) { + rmesa->setup.rb3d_planemask = mask; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_MASKS; + } +} + +static GLboolean radeonDDColorMask( GLcontext *ctx, + GLboolean r, GLboolean g, + GLboolean b, GLboolean a ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_MASKS; + + return GL_TRUE; +} + + +/* ============================================================= + * Rendering attributes + * + * We really don't want to recalculate all this every time we bind a + * texture. These things shouldn't change all that often, so it makes + * sense to break them out of the core texture state update routines. + */ + +static void radeonDDLightModelfv( GLcontext *ctx, GLenum pname, + const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if ( pname == GL_LIGHT_MODEL_COLOR_CONTROL ) { + CARD32 p = rmesa->setup.pp_cntl; + + FLUSH_BATCH( rmesa ); + + if ( ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR ) { + p |= RADEON_SPECULAR_ENABLE; + } else { + p &= ~RADEON_SPECULAR_ENABLE; + } + + if ( rmesa->setup.pp_cntl != p ) { + rmesa->setup.pp_cntl = p; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } + } +} + +static void radeonDDShadeModel( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + CARD32 s = rmesa->setup.se_cntl; + + s &= ~(RADEON_DIFFUSE_SHADE_MASK | + RADEON_ALPHA_SHADE_MASK | + RADEON_SPECULAR_SHADE_MASK | + RADEON_FOG_SHADE_MASK); + + switch ( mode ) { + case GL_FLAT: + s |= (RADEON_DIFFUSE_SHADE_FLAT | + RADEON_ALPHA_SHADE_FLAT | + RADEON_SPECULAR_SHADE_FLAT | + RADEON_FOG_SHADE_FLAT); + break; + case GL_SMOOTH: + s |= (RADEON_DIFFUSE_SHADE_GOURAUD | + RADEON_ALPHA_SHADE_GOURAUD | + RADEON_SPECULAR_SHADE_GOURAUD | + RADEON_FOG_SHADE_GOURAUD); + break; + default: + return; + } + + if ( rmesa->setup.se_cntl != s ) { + FLUSH_BATCH( rmesa ); + rmesa->setup.se_cntl = s; + + rmesa->new_state |= RADEON_NEW_CONTEXT; + rmesa->dirty |= RADEON_UPLOAD_SETUP; + } +} + + +/* ============================================================= + * Window position + */ + +void radeonUpdateWindow( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; + GLfloat xoffset = (GLfloat)dPriv->x; + GLfloat yoffset = (GLfloat)dPriv->y + dPriv->h; + const GLfloat one = 1.0; +#if 0 + CARD32 m = rmesa->setup.re_misc; + CARD32 sx, sy; +#endif + + rmesa->setup.se_vport_xscale = *(GLuint *)&one; + rmesa->setup.se_vport_xoffset = *(GLuint *)&xoffset; + rmesa->setup.se_vport_yscale = *(GLuint *)&one; + rmesa->setup.se_vport_yoffset = *(GLuint *)&yoffset; + rmesa->setup.se_vport_zscale = *(GLuint *)&rmesa->depth_scale; + rmesa->setup.se_vport_zoffset = 0x00000000; + +#if 0 + /* FIXME: This appears to be broken... + */ + m &= ~(RADEON_STIPPLE_X_OFFSET_MASK | + RADEON_STIPPLE_Y_OFFSET_MASK); + + sx = rmesa->driDrawable->x & RADEON_STIPPLE_COORD_MASK; + sy = rmesa->driDrawable->y & RADEON_STIPPLE_COORD_MASK; + + m |= ((sx << RADEON_STIPPLE_X_OFFSET_SHIFT) | + (sy << RADEON_STIPPLE_Y_OFFSET_SHIFT)); + + if ( rmesa->setup.re_misc != m ) { + rmesa->setup.re_misc = m; + rmesa->dirty |= RADEON_UPLOAD_MISC; + } +#endif + rmesa->dirty |= RADEON_UPLOAD_VIEWPORT; +} + + +/* ============================================================= + * Miscellaneous + */ + +static void radeonDDClearColor( GLcontext *ctx, + GLubyte r, GLubyte g, GLubyte b, GLubyte a ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + rmesa->ClearColor = radeonPackColor( rmesa->radeonScreen->cpp, + r, g, b, a ); +} + +static void radeonDDColor( GLcontext *ctx, + GLubyte r, GLubyte g, GLubyte b, GLubyte a ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + rmesa->Color = radeonPackColor( rmesa->radeonScreen->cpp, + r, g, b, a ); +} + +static void radeonDDLogicOpCode( GLcontext *ctx, GLenum opcode ) +{ + if ( ctx->Color.ColorLogicOpEnabled ) { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + + /* FIXME: We can do color logic ops. + */ + if ( opcode == GL_COPY ) { + rmesa->Fallback &= ~RADEON_FALLBACK_LOGICOP; + } else { + rmesa->Fallback |= RADEON_FALLBACK_LOGICOP; + } + } +} + +static GLboolean radeonDDSetDrawBuffer( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int found = GL_TRUE; + + FLUSH_BATCH( rmesa ); + + if ( rmesa->DrawBuffer != mode ) { + rmesa->DrawBuffer = mode; + rmesa->Fallback &= ~RADEON_FALLBACK_DRAW_BUFFER; + + switch ( mode ) { + case GL_FRONT_LEFT: + rmesa->drawOffset = rmesa->radeonScreen->frontOffset; + rmesa->drawPitch = rmesa->radeonScreen->frontPitch; + break; + case GL_BACK_LEFT: + rmesa->drawOffset = rmesa->radeonScreen->backOffset; + rmesa->drawPitch = rmesa->radeonScreen->backPitch; + break; + default: + rmesa->Fallback |= RADEON_FALLBACK_DRAW_BUFFER; + found = GL_FALSE; + break; + } + + rmesa->setup.rb3d_coloroffset = + (rmesa->drawOffset & RADEON_COLOROFFSET_MASK); + rmesa->setup.rb3d_colorpitch = rmesa->drawPitch; + + rmesa->new_state |= RADEON_NEW_WINDOW; + } + + return found; +} + +static void radeonDDSetReadBuffer( GLcontext *ctx, + GLframebuffer *colorBuffer, + GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + rmesa->Fallback &= ~RADEON_FALLBACK_READ_BUFFER; + + switch ( mode ) { + case GL_FRONT_LEFT: + rmesa->readOffset = rmesa->radeonScreen->frontOffset; + rmesa->readPitch = rmesa->radeonScreen->frontPitch; + break; + case GL_BACK_LEFT: + rmesa->readOffset = rmesa->radeonScreen->backOffset; + rmesa->readPitch = rmesa->radeonScreen->backPitch; + break; + default: + rmesa->Fallback |= RADEON_FALLBACK_READ_BUFFER; + break; + } +} + + +/* ============================================================= + * Polygon stipple + */ + +static void radeonDDPolygonStipple( GLcontext *ctx, const GLubyte *mask ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint *stipple = (GLuint *)mask; + + FLUSH_BATCH( rmesa ); + + if ( ctx->Polygon.StippleFlag && ctx->PB->primitive == GL_POLYGON ) { + rmesa->setup.pp_cntl |= RADEON_STIPPLE_ENABLE; + } else { + rmesa->setup.pp_cntl &= ~RADEON_STIPPLE_ENABLE; + } + + LOCK_HARDWARE( rmesa ); + + /* FIXME: Use window x,y offsets into stipple RAM. + */ + drmRadeonPolygonStipple( rmesa->driFd, stipple ); + + UNLOCK_HARDWARE( rmesa ); + + rmesa->new_state |= RADEON_NEW_CONTEXT; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; +} + + +/* ============================================================= + * State enable/disable + */ + +static void radeonDDEnable( GLcontext *ctx, GLenum cap, GLboolean state ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + switch ( cap ) { + case GL_ALPHA_TEST: + case GL_BLEND: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_ALPHA; + break; + + case GL_CULL_FACE: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_CULL; + break; + + case GL_DEPTH_TEST: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_DEPTH; + break; + + case GL_DITHER: + do { + CARD32 r = rmesa->setup.rb3d_cntl; + FLUSH_BATCH( rmesa ); + + if ( ctx->Color.DitherFlag ) { + r |= RADEON_DITHER_ENABLE; + } else { + r &= ~RADEON_DITHER_ENABLE; + } + + if ( rmesa->setup.rb3d_cntl != r ) { + rmesa->setup.rb3d_cntl = r; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } + } while (0); + break; + + case GL_FOG: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_FOG; + break; + + case GL_INDEX_LOGIC_OP: + case GL_COLOR_LOGIC_OP: + FLUSH_BATCH( rmesa ); + if ( state && ctx->Color.LogicOp != GL_COPY ) { + rmesa->Fallback |= RADEON_FALLBACK_LOGICOP; + } else { + rmesa->Fallback &= ~RADEON_FALLBACK_LOGICOP; + } + break; + + case GL_SCISSOR_TEST: + FLUSH_BATCH( rmesa ); + rmesa->scissor = state; + rmesa->new_state |= RADEON_NEW_CLIP; + break; + + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_TEXTURE; + break; + + case GL_POLYGON_STIPPLE: + if ( ctx->PB->primitive == GL_POLYGON ) { + FLUSH_BATCH( rmesa ); + if ( state ) { + rmesa->setup.pp_cntl |= RADEON_STIPPLE_ENABLE; + } else { + rmesa->setup.pp_cntl &= ~RADEON_STIPPLE_ENABLE; + } + rmesa->new_state |= RADEON_NEW_CONTEXT; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } + break; + + default: + return; + } +} + + +/* ============================================================= + * State initialization, management + */ + +static void radeonDDPrintDirty( const char *msg, GLuint state ) +{ + fprintf( stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", + msg, + state, + (state & RADEON_UPLOAD_CONTEXT) ? "context, " : "", + (state & RADEON_UPLOAD_VERTFMT) ? "vertfmt, " : "", + (state & RADEON_UPLOAD_LINE) ? "line, " : "", + (state & RADEON_UPLOAD_BUMPMAP) ? "bumpmap, " : "", + (state & RADEON_UPLOAD_MASKS) ? "masks, " : "", + (state & RADEON_UPLOAD_VIEWPORT) ? "viewport, " : "", + (state & RADEON_UPLOAD_SETUP) ? "setup, " : "", + (state & RADEON_UPLOAD_TCL) ? "tcl, " : "", + (state & RADEON_UPLOAD_MISC) ? "misc, " : "", + (state & RADEON_UPLOAD_TEX0) ? "tex0, " : "", + (state & RADEON_UPLOAD_TEX1) ? "tex1, " : "", + (state & RADEON_UPLOAD_TEX2) ? "tex2, " : "", + (state & RADEON_UPLOAD_TEX0IMAGES) ? "tex0 images, " : "", + (state & RADEON_UPLOAD_TEX1IMAGES) ? "tex1 images, " : "", + (state & RADEON_UPLOAD_TEX2IMAGES) ? "tex2 images, " : "", + (state & RADEON_UPLOAD_CLIPRECTS) ? "cliprects, " : "", + (state & RADEON_REQUIRE_QUIESCENCE) ? "quiescence, " : "" ); +} + +/* + * Load the current context's state into the hardware. + * + * NOTE: Be VERY careful about ensuring the context state is marked for + * upload, the only place it shouldn't be uploaded is when the setup + * state has changed in ReducedPrimitiveChange as this comes right after + * a state update. + * + * Blits of any type should always upload the context and masks after + * they are done. + */ +void radeonEmitHwStateLocked( radeonContextPtr rmesa ) +{ + RADEONSAREAPrivPtr sarea = rmesa->sarea; + radeon_context_regs_t *regs = &(rmesa->setup); + radeonTexObjPtr t0 = rmesa->CurrentTexObj[0]; + radeonTexObjPtr t1 = rmesa->CurrentTexObj[1]; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_MSG ) { + radeonDDPrintDirty( "radeonEmitHwStateLocked", rmesa->dirty ); + } + + if ( (rmesa->dirty & RADEON_UPLOAD_TEX0IMAGES) && t0 ) { + radeonUploadTexImages( rmesa, t0 ); + rmesa->dirty &= ~RADEON_UPLOAD_TEX0IMAGES; + } + if ( (rmesa->dirty & RADEON_UPLOAD_TEX1IMAGES) && t1 ) { + radeonUploadTexImages( rmesa, t1 ); + rmesa->dirty &= ~RADEON_UPLOAD_TEX1IMAGES; + } + if ( rmesa->dirty & RADEON_UPLOAD_TEX2IMAGES ) { + /* FIXME: Enable the third texture unit... */ + rmesa->dirty &= ~RADEON_UPLOAD_TEX2IMAGES; + } + + if ( rmesa->dirty & (RADEON_UPLOAD_CONTEXT | + RADEON_UPLOAD_VERTFMT | + RADEON_UPLOAD_LINE | + RADEON_UPLOAD_BUMPMAP | + RADEON_UPLOAD_MASKS | + RADEON_UPLOAD_VIEWPORT | + RADEON_UPLOAD_SETUP | + RADEON_UPLOAD_TCL | + RADEON_UPLOAD_MISC) ) { + memcpy( &sarea->ContextState, regs, sizeof(sarea->ContextState) ); + } + + /* Assemble the texture state, combining the texture object and + * texture environment state into the hardware texture unit state. + */ + if ( (rmesa->dirty & RADEON_UPLOAD_TEX0) && t0 ) { + radeon_texture_regs_t *tex = &sarea->TexState[0]; + + tex->pp_txfilter = t0->setup.pp_txfilter | rmesa->lod_bias[0] << 8; + tex->pp_txformat = t0->setup.pp_txformat | RADEON_TXF_ST_ROUTE_STQ0; + tex->pp_txoffset = t0->setup.pp_txoffset; + + tex->pp_txcblend = rmesa->color_combine[0]; + tex->pp_txablend = rmesa->alpha_combine[0]; + tex->pp_tfactor = rmesa->env_color[0]; + + tex->pp_border_color = t0->setup.pp_border_color; + } + + if ( (rmesa->dirty & RADEON_UPLOAD_TEX1) && t1 ) { + radeon_texture_regs_t *tex = &sarea->TexState[1]; + + tex->pp_txfilter = t1->setup.pp_txfilter | rmesa->lod_bias[1] << 8; + tex->pp_txformat = t1->setup.pp_txformat | RADEON_TXF_ST_ROUTE_STQ1; + tex->pp_txoffset = t1->setup.pp_txoffset; + + tex->pp_txcblend = rmesa->color_combine[1]; + tex->pp_txablend = rmesa->alpha_combine[1]; + tex->pp_tfactor = rmesa->env_color[1]; + + tex->pp_border_color = t1->setup.pp_border_color; + } + + if ( rmesa->dirty & RADEON_UPLOAD_TEX2 ) { + /* FIXME: Enable the third texture unit... */ + memset( &sarea->TexState[2], 0, sizeof(sarea->TexState[2]) ); + } + + sarea->vertsize = rmesa->vertsize; + sarea->vc_format = rmesa->vc_format; + + sarea->dirty |= rmesa->dirty; + rmesa->dirty &= RADEON_UPLOAD_CLIPRECTS; +} + +static void radeonDDPrintState( const char *msg, GLuint flags ) +{ + fprintf( stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n", + msg, + flags, + (flags & RADEON_NEW_CONTEXT) ? "context, " : "", + (flags & RADEON_NEW_ALPHA) ? "alpha, " : "", + (flags & RADEON_NEW_DEPTH) ? "depth, " : "", + (flags & RADEON_NEW_FOG) ? "fog, " : "", + (flags & RADEON_NEW_CLIP) ? "clip, " : "", + (flags & RADEON_NEW_TEXTURE) ? "texture, " : "", + (flags & RADEON_NEW_CULL) ? "cull, " : "", + (flags & RADEON_NEW_MASKS) ? "masks, " : "", + (flags & RADEON_NEW_WINDOW) ? "window, " : "" ); +} + +void radeonDDUpdateHWState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int new_state = rmesa->new_state; + + if ( new_state ) { + FLUSH_BATCH( rmesa ); + + rmesa->new_state = 0; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_MSG ) + radeonDDPrintState( "radeonUpdateHwState", new_state ); + + /* Update the various parts of the context's state. + */ + if ( new_state & RADEON_NEW_ALPHA ) + radeonUpdateAlphaMode( ctx ); + + if ( new_state & RADEON_NEW_DEPTH ) + radeonUpdateZMode( ctx ); + + if ( new_state & RADEON_NEW_FOG ) + radeonUpdateFogAttrib( ctx ); + + if ( new_state & RADEON_NEW_CLIP ) + radeonUpdateClipping( ctx ); + + if ( new_state & RADEON_NEW_CULL ) + radeonUpdateCull( ctx ); + + if ( new_state & RADEON_NEW_MASKS ) + radeonUpdateMasks( ctx ); + + if ( new_state & RADEON_NEW_WINDOW ) + radeonUpdateWindow( ctx ); + + if ( new_state & RADEON_NEW_TEXTURE ) + radeonUpdateTextureState( ctx ); + } +} + +/* This is called when Mesa switches between rendering triangle + * primitives (such as GL_POLYGON, GL_QUADS, GL_TRIANGLE_STRIP, etc), + * and lines, points and bitmaps. + * + * As the radeon uses triangles to render lines and points, it is + * necessary to turn off hardware culling when rendering these + * primitives. + */ +static void radeonDDReducedPrimitiveChange( GLcontext *ctx, GLenum prim ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + CARD32 s = rmesa->setup.se_cntl; + + s |= RADEON_FFACE_SOLID | RADEON_BFACE_SOLID; + + if ( ctx->Polygon.CullFlag && ctx->PB->primitive == GL_POLYGON ) { + switch ( ctx->Polygon.CullFaceMode ) { + case GL_FRONT: + s &= ~RADEON_FFACE_SOLID; + break; + case GL_BACK: + s &= ~RADEON_BFACE_SOLID; + break; + case GL_FRONT_AND_BACK: + s &= ~(RADEON_FFACE_SOLID | RADEON_BFACE_SOLID); + break; + } + } + + if ( rmesa->setup.se_cntl != s ) { + FLUSH_BATCH( rmesa ); + rmesa->setup.se_cntl = s; + + /* NOTE: Only upload the setup state, everything else has been + * uploaded by the usual means already. Also, note that this is + * an optimization (see comment in the kernel's radeon_state.c), + * which will not be necessary when/if we use the Radeon's + * native point/line support. + */ + rmesa->dirty |= RADEON_UPLOAD_SETUP; + } +} + + +#define INTERESTED (~(NEW_MODELVIEW | \ + NEW_PROJECTION | \ + NEW_TEXTURE_MATRIX | \ + NEW_USER_CLIP | \ + NEW_CLIENT_STATE)) + +void radeonDDUpdateState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if ( ctx->NewState & INTERESTED ) { + radeonDDChooseRenderState( ctx ); + radeonDDChooseRasterSetupFunc( ctx ); + } + + /* Need to do this here to detect texture fallbacks before + * setting triangle functions. + * GH: Do we need this anymore? The Radeon doesn't really have + * texturing fallbacks like the r128... + */ + if ( rmesa->new_state & RADEON_NEW_TEXTURE ) { + radeonDDUpdateHWState( ctx ); + } + + if ( !rmesa->Fallback ) { + ctx->IndirectTriangles &= ~DD_SW_RASTERIZE; + ctx->IndirectTriangles |= rmesa->IndirectTriangles; + + ctx->Driver.PointsFunc = rmesa->PointsFunc; + ctx->Driver.LineFunc = rmesa->LineFunc; + ctx->Driver.TriangleFunc = rmesa->TriangleFunc; + ctx->Driver.QuadFunc = rmesa->QuadFunc; + } +} + + +/* Initialize the context's hardware state. + */ +void radeonDDInitState( radeonContextPtr rmesa ) +{ + GLuint color_fmt, depth_fmt; + + switch ( rmesa->radeonScreen->cpp ) { + case 2: + color_fmt = RADEON_COLOR_FORMAT_RGB565; + break; + case 4: + color_fmt = RADEON_COLOR_FORMAT_ARGB8888; + break; + default: + fprintf( stderr, "Error: Unsupported pixel depth... exiting\n" ); + exit( -1 ); + } + + rmesa->ClearColor = 0x00000000; + + switch ( rmesa->glCtx->Visual->DepthBits ) { + case 16: + rmesa->ClearDepth = 0x0000ffff; + depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z; + rmesa->depth_scale = 1.0 / (GLfloat)0xffff; + break; + case 24: + rmesa->ClearDepth = 0x00ffffff; + depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z; + rmesa->depth_scale = 1.0 / (GLfloat)0xffffff; + break; + default: + fprintf( stderr, "Error: Unsupported depth %d... exiting\n", + rmesa->glCtx->Visual->DepthBits ); + exit( -1 ); + } + + rmesa->RenderIndex = RADEON_FALLBACK_BIT; + rmesa->PointsFunc = NULL; + rmesa->LineFunc = NULL; + rmesa->TriangleFunc = NULL; + rmesa->QuadFunc = NULL; + + rmesa->IndirectTriangles = 0; + rmesa->Fallback = 0; + + if ( rmesa->glCtx->Visual->DBflag ) { + rmesa->DrawBuffer = GL_BACK_LEFT; + rmesa->drawOffset = rmesa->readOffset = rmesa->radeonScreen->backOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->radeonScreen->backPitch; + } else { + rmesa->DrawBuffer = GL_FRONT_LEFT; + rmesa->drawOffset = rmesa->readOffset = rmesa->radeonScreen->frontOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->radeonScreen->frontPitch; + } + + /* Harware state: + */ + rmesa->setup.pp_misc = (RADEON_ALPHA_TEST_PASS | + RADEON_CHROMA_FUNC_FAIL | + RADEON_CHROMA_KEY_NEAREST | + RADEON_SHADOW_FUNC_EQUAL | + RADEON_SHADOW_PASS_1 | + RADEON_RIGHT_HAND_CUBE_OGL); + + rmesa->setup.pp_fog_color = ((0x00000000 & RADEON_FOG_COLOR_MASK) | + RADEON_FOG_VERTEX | + RADEON_FOG_USE_DEPTH); + + rmesa->setup.re_solid_color = 0x00000000; + + rmesa->setup.rb3d_blendcntl = (RADEON_SRC_BLEND_GL_ONE | + RADEON_DST_BLEND_GL_ZERO ); + + rmesa->setup.rb3d_depthoffset = rmesa->radeonScreen->depthOffset; + + rmesa->setup.rb3d_depthpitch = ((rmesa->radeonScreen->depthPitch & + RADEON_DEPTHPITCH_MASK) | + RADEON_DEPTH_ENDIAN_NO_SWAP); + + rmesa->setup.rb3d_zstencilcntl = (depth_fmt | + RADEON_Z_TEST_LESS | + RADEON_STENCIL_TEST_ALWAYS | + RADEON_STENCIL_S_FAIL_KEEP | + RADEON_STENCIL_ZPASS_KEEP | + RADEON_STENCIL_ZFAIL_KEEP | + RADEON_Z_WRITE_ENABLE); + + rmesa->setup.pp_cntl = (RADEON_SCISSOR_ENABLE | + RADEON_ANTI_ALIAS_NONE); + + rmesa->setup.rb3d_cntl = (RADEON_PLANE_MASK_ENABLE | + color_fmt | + RADEON_ZBLOCK16); + + rmesa->setup.rb3d_coloroffset = (rmesa->drawOffset & + RADEON_COLOROFFSET_MASK); + + rmesa->setup.re_width_height = ((0x7ff << RADEON_RE_WIDTH_SHIFT) | + (0x7ff << RADEON_RE_HEIGHT_SHIFT)); + + rmesa->setup.rb3d_colorpitch = ((rmesa->drawPitch & + RADEON_COLORPITCH_MASK) | + RADEON_COLOR_ENDIAN_NO_SWAP); + + rmesa->setup.se_cntl = (RADEON_FFACE_CULL_CW | + RADEON_BFACE_SOLID | + RADEON_FFACE_SOLID | + RADEON_FLAT_SHADE_VTX_LAST | + RADEON_DIFFUSE_SHADE_GOURAUD | + RADEON_ALPHA_SHADE_GOURAUD | + RADEON_SPECULAR_SHADE_GOURAUD | + RADEON_FOG_SHADE_GOURAUD | + RADEON_VPORT_XY_XFORM_ENABLE | + RADEON_VPORT_Z_XFORM_ENABLE | + RADEON_VTX_PIX_CENTER_OGL | + RADEON_ROUND_MODE_TRUNC | + RADEON_ROUND_PREC_8TH_PIX); + + rmesa->setup.se_coord_fmt = (RADEON_VTX_XY_PRE_MULT_1_OVER_W0 | + RADEON_VTX_Z_PRE_MULT_1_OVER_W0 | + RADEON_TEX1_W_ROUTING_USE_Q1); + + rmesa->setup.re_line_pattern = ((0x0000 & RADEON_LINE_PATTERN_MASK) | + (0 << RADEON_LINE_REPEAT_COUNT_SHIFT) | + (0 << RADEON_LINE_PATTERN_START_SHIFT) | + RADEON_LINE_PATTERN_LITTLE_BIT_ORDER); + + rmesa->setup.re_line_state = ((0 << RADEON_LINE_CURRENT_PTR_SHIFT) | + (0 << RADEON_LINE_CURRENT_COUNT_SHIFT)); + + rmesa->setup.se_line_width = 0x0000000; + + rmesa->setup.pp_lum_matrix = 0x00000000; + + rmesa->setup.pp_rot_matrix_0 = 0x00000000; + rmesa->setup.pp_rot_matrix_1 = 0x00000000; + + rmesa->setup.rb3d_stencilrefmask = ((0x00 << RADEON_STENCIL_REF_SHIFT) | + (0xff << RADEON_STENCIL_MASK_SHIFT) | + (0xff << RADEON_STENCIL_WRITEMASK_SHIFT)); + + rmesa->setup.rb3d_ropcntl = 0x00000000; + rmesa->setup.rb3d_planemask = 0xffffffff; + + rmesa->setup.se_vport_xscale = 0x00000000; + rmesa->setup.se_vport_xoffset = 0x00000000; + rmesa->setup.se_vport_yscale = 0x00000000; + rmesa->setup.se_vport_yoffset = 0x00000000; + rmesa->setup.se_vport_zscale = 0x00000000; + rmesa->setup.se_vport_zoffset = 0x00000000; + + rmesa->setup.se_cntl_status = (RADEON_VC_NO_SWAP | + RADEON_TCL_BYPASS); + +#ifdef TCL_ENABLE + /* FIXME: Obviously these need to be properly initialized */ + rmesa->setup.se_tcl_material_emmissive.red = 0x00000000; + rmesa->setup.se_tcl_material_emmissive.green = 0x00000000; + rmesa->setup.se_tcl_material_emmissive.blue = 0x00000000; + rmesa->setup.se_tcl_material_emmissive.alpha = 0x00000000; + + rmesa->setup.se_tcl_material_ambient.red = 0x00000000; + rmesa->setup.se_tcl_material_ambient.green = 0x00000000; + rmesa->setup.se_tcl_material_ambient.blue = 0x00000000; + rmesa->setup.se_tcl_material_ambient.alpha = 0x00000000; + + rmesa->setup.se_tcl_material_diffuse.red = 0x00000000; + rmesa->setup.se_tcl_material_diffuse.green = 0x00000000; + rmesa->setup.se_tcl_material_diffuse.blue = 0x00000000; + rmesa->setup.se_tcl_material_diffuse.alpha = 0x00000000; + + rmesa->setup.se_tcl_material_specular.red = 0x00000000; + rmesa->setup.se_tcl_material_specular.green = 0x00000000; + rmesa->setup.se_tcl_material_specular.blue = 0x00000000; + rmesa->setup.se_tcl_material_specular.alpha = 0x00000000; + + rmesa->setup.se_tcl_shininess = 0x00000000; + rmesa->setup.se_tcl_output_vtx_fmt = 0x00000000; + rmesa->setup.se_tcl_output_vtx_sel = 0x00000000; + rmesa->setup.se_tcl_matrix_select_0 = 0x00000000; + rmesa->setup.se_tcl_matrix_select_1 = 0x00000000; + rmesa->setup.se_tcl_ucp_vert_blend_ctl = 0x00000000; + rmesa->setup.se_tcl_texture_proc_ctl = 0x00000000; + rmesa->setup.se_tcl_light_model_ctl = 0x00000000; + for ( i = 0 ; i < 4 ; i++ ) { + rmesa->setup.se_tcl_per_light_ctl[i] = 0x00000000; + } +#endif + + rmesa->setup.re_top_left = ((0 << RADEON_RE_LEFT_SHIFT) | + (0 << RADEON_RE_TOP_SHIFT) ); + + rmesa->setup.re_misc = ((0 << RADEON_STIPPLE_X_OFFSET_SHIFT) | + (0 << RADEON_STIPPLE_Y_OFFSET_SHIFT) | + RADEON_STIPPLE_LITTLE_BIT_ORDER); + + rmesa->env_color[0] = 0x00000000; + rmesa->env_color[1] = 0x00000000; + rmesa->env_color[2] = 0x00000000; + + rmesa->new_state = RADEON_NEW_ALL; +} + +/* Initialize the driver's state functions. + */ +void radeonDDInitStateFuncs( GLcontext *ctx ) +{ + ctx->Driver.UpdateState = radeonDDUpdateState; + + ctx->Driver.ClearIndex = NULL; + ctx->Driver.ClearColor = radeonDDClearColor; + ctx->Driver.Index = NULL; + ctx->Driver.Color = radeonDDColor; + ctx->Driver.SetDrawBuffer = radeonDDSetDrawBuffer; + ctx->Driver.SetReadBuffer = radeonDDSetReadBuffer; + + ctx->Driver.IndexMask = NULL; + ctx->Driver.ColorMask = radeonDDColorMask; + ctx->Driver.LogicOp = NULL; + ctx->Driver.Dither = NULL; + + ctx->Driver.NearFar = NULL; + + ctx->Driver.RenderStart = radeonDDUpdateHWState; + ctx->Driver.RenderFinish = NULL; + ctx->Driver.RasterSetup = NULL; + + ctx->Driver.RenderVBClippedTab = NULL; + ctx->Driver.RenderVBCulledTab = NULL; + ctx->Driver.RenderVBRawTab = NULL; + + ctx->Driver.ReducedPrimitiveChange = radeonDDReducedPrimitiveChange; + ctx->Driver.MultipassFunc = NULL; + + ctx->Driver.AlphaFunc = radeonDDAlphaFunc; + ctx->Driver.BlendEquation = radeonDDBlendEquation; + ctx->Driver.BlendFunc = radeonDDBlendFunc; + ctx->Driver.BlendFuncSeparate = radeonDDBlendFuncSeparate; + ctx->Driver.ClearDepth = radeonDDClearDepth; + ctx->Driver.CullFace = radeonDDCullFace; + ctx->Driver.FrontFace = radeonDDFrontFace; + ctx->Driver.DepthFunc = radeonDDDepthFunc; + ctx->Driver.DepthMask = radeonDDDepthMask; + ctx->Driver.DepthRange = NULL; + ctx->Driver.Enable = radeonDDEnable; + ctx->Driver.Fogfv = radeonDDFogfv; + ctx->Driver.Hint = NULL; + ctx->Driver.Lightfv = NULL; + ctx->Driver.LightModelfv = radeonDDLightModelfv; + ctx->Driver.LogicOpcode = radeonDDLogicOpCode; + ctx->Driver.PolygonMode = NULL; + ctx->Driver.PolygonStipple = radeonDDPolygonStipple; + ctx->Driver.Scissor = radeonDDScissor; + ctx->Driver.ShadeModel = radeonDDShadeModel; + ctx->Driver.ClearStencil = NULL; + ctx->Driver.StencilFunc = NULL; + ctx->Driver.StencilMask = NULL; + ctx->Driver.StencilOp = NULL; + ctx->Driver.Viewport = NULL; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_state.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_state.h new file mode 100644 index 000000000..9a368d989 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_state.h @@ -0,0 +1,55 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.h,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_STATE_H__ +#define __RADEON_STATE_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_context.h" + +extern void radeonDDInitState( radeonContextPtr rmesa ); +extern void radeonDDInitStateFuncs( GLcontext *ctx ); + +extern void radeonDDUpdateState( GLcontext *ctx ); +extern void radeonDDUpdateHWState( GLcontext *ctx ); + +extern void radeonUpdateWindow( GLcontext *ctx ); + +extern void radeonEmitHwStateLocked( radeonContextPtr rmesa ); + +#endif +#endif diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c new file mode 100644 index 000000000..32709537b --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c @@ -0,0 +1,2253 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c,v 1.2 2001/01/16 05:10:59 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_vb.h" +#include "radeon_tex.h" + +#include "mmath.h" +#include "simple_list.h" +#include "enums.h" +#include "mem.h" + + +static void radeonSetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap ) +{ + t->setup.pp_txfilter &= ~(RADEON_CLAMP_S_MASK | RADEON_CLAMP_T_MASK); + + switch ( swrap ) { + case GL_REPEAT: + t->setup.pp_txfilter |= RADEON_CLAMP_S_WRAP; + break; + case GL_CLAMP: + t->setup.pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST; + break; + case GL_CLAMP_TO_EDGE: + t->setup.pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST; + break; + } + + switch ( twrap ) { + case GL_REPEAT: + t->setup.pp_txfilter |= RADEON_CLAMP_T_WRAP; + break; + case GL_CLAMP: + t->setup.pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST; + break; + case GL_CLAMP_TO_EDGE: + t->setup.pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST; + break; + } +} + +static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf ) +{ + t->setup.pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK); + + switch ( minf ) { + case GL_NEAREST: + t->setup.pp_txfilter |= RADEON_MIN_FILTER_NEAREST; + break; + case GL_LINEAR: + t->setup.pp_txfilter |= RADEON_MIN_FILTER_LINEAR; + break; + case GL_NEAREST_MIPMAP_NEAREST: + t->setup.pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST; + break; + case GL_LINEAR_MIPMAP_NEAREST: + t->setup.pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + t->setup.pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + t->setup.pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR; + break; + } + + switch ( magf ) { + case GL_NEAREST: + t->setup.pp_txfilter |= RADEON_MAG_FILTER_NEAREST; + break; + case GL_LINEAR: + t->setup.pp_txfilter |= RADEON_MAG_FILTER_LINEAR; + break; + } +} + +static void radeonSetTexBorderColor( radeonTexObjPtr t, GLubyte c[4] ) +{ + t->setup.pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] ); +} + + +/* Allocate and initialize hardware state associated with texture `t'. + */ +static radeonTexObjPtr radeonCreateTexObj( radeonContextPtr rmesa, + struct gl_texture_object *tObj ) +{ + radeonTexObjPtr t; + struct gl_texture_image *image; + GLint log2Width, log2Height, log2Size, log2MinSize; + GLint totalSize; + GLint texelsPerDword = 0, blitWidth = 0, blitPitch = 0; + GLint x, y, width, height; + GLint i; + GLuint txformat, txalpha; + + image = tObj->Image[0]; + if ( !image ) + return NULL; + + t = (radeonTexObjPtr) CALLOC( sizeof(*t) ); + if ( !t ) + return NULL; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) + fprintf( stderr, "%s( %p )\n", __FUNCTION__, tObj ); + + switch ( image->Format ) { + case GL_RGBA: + if ( image->IntFormat != GL_RGBA4 && + ( image->IntFormat == GL_RGBA8 || + rmesa->radeonScreen->cpp == 4 ) ) { + t->texelBytes = 4; + txformat = RADEON_TXF_32BPP_ARGB8888; + } else { + t->texelBytes = 2; + txformat = RADEON_TXF_16BPP_ARGB4444; + } + txalpha = RADEON_TXF_ALPHA_IN_MAP; + break; + + case GL_RGB: + if ( image->IntFormat != GL_RGB5 && + ( image->IntFormat == GL_RGB8 || + rmesa->radeonScreen->cpp == 4 ) ) { + t->texelBytes = 4; + txformat = RADEON_TXF_32BPP_ARGB8888; + } else { + t->texelBytes = 2; + txformat = RADEON_TXF_16BPP_RGB565; + } + txalpha = 0; + break; + + case GL_ALPHA: + case GL_LUMINANCE_ALPHA: + t->texelBytes = 2; + txformat = RADEON_TXF_16BPP_AI88; + txalpha = RADEON_TXF_ALPHA_IN_MAP; + break; + + case GL_LUMINANCE: + t->texelBytes = 2; + txformat = RADEON_TXF_16BPP_AI88; + txalpha = 0; + break; + + case GL_INTENSITY: + t->texelBytes = 1; + txformat = RADEON_TXF_8BPP_I; + txalpha = 0; + break; + + case GL_COLOR_INDEX: + default: + fprintf( stderr, "%s: bad image->Format\n", __FUNCTION__ ); + FREE( t ); + return NULL; + } + + /* Calculate dimensions in log domain. + */ + for ( i = 1, log2Height = 0 ; i < image->Height ; i *= 2 ) { + log2Height++; + } + for ( i = 1, log2Width = 0 ; i < image->Width ; i *= 2 ) { + log2Width++; + } + if ( image->Width > image->Height ) { + log2Size = log2Width; + } else { + log2Size = log2Height; + } + + t->dirty_images = 0; + + /* The Radeon has a 64-byte minimum pitch for all blits. We + * calculate the equivalent number of texels to simplify the + * calculation of the texture image area. + */ + switch ( t->texelBytes ) { + case 1: + texelsPerDword = 4; + blitPitch = 64; + break; + case 2: + texelsPerDword = 2; + blitPitch = 32; + break; + case 4: + texelsPerDword = 1; + blitPitch = 16; + break; + } + + /* Select the larger of the two widths for our global texture image + * coordinate space. As the Radeon has very strict offset rules, we + * can't upload mipmaps directly and have to reference their location + * from the aligned start of the whole image. + */ + blitWidth = MAX2( image->Width, blitPitch ); + + /* Calculate mipmap offsets and dimensions. + */ + totalSize = 0; + x = 0; + y = 0; + + for ( i = 0 ; i <= log2Size ; i++ ) { + GLuint size; + + image = tObj->Image[i]; + if ( !image ) + break; + + width = image->Width; + height = image->Height; + + /* Texture images have a minimum pitch of 32 bytes (half of the + * 64-byte minimum pitch for blits). For images that have a + * width smaller than this, we must pad each texture image + * scanline out to this amount. + */ + if ( width < blitPitch / 2 ) { + width = blitPitch / 2; + } + + size = width * height * t->texelBytes; + totalSize += size; + + t->dirty_images |= (1 << i); + + while ( width < blitWidth && height > 1 ) { + width *= 2; + height /= 2; + } + + t->image[i].x = x; + t->image[i].y = y; + + t->image[i].width = width; + t->image[i].height = height; + + t->image[i].dwords = size / sizeof(CARD32); + + /* While blits must have a pitch of at least 64 bytes, mipmaps + * must be aligned on a 32-byte boundary (just like each texture + * image scanline). + */ + if ( width >= blitWidth ) { + y += height; + } else { + x += width; + if ( x >= blitWidth ) { + x = 0; + y++; + } + } + + if ( 0 ) + fprintf( stderr, "level=%d p=%d %dx%d -> %dx%d at (%d,%d) %d dwords\n", + i, blitWidth, image->Width, image->Height, + t->image[i].width, t->image[i].height, + t->image[i].x, t->image[i].y, + t->image[i].dwords ); + } + + log2MinSize = log2Size - i + 1; + + /* Align the total size of texture memory block. + */ + totalSize = (totalSize + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; + + t->totalSize = totalSize; + + t->bound = 0; + t->heap = 0; + t->tObj = tObj; + + t->memBlock = NULL; + t->bufAddr = 0; + + /* Hardware state: + */ + t->setup.pp_txfilter = ((log2Size << RADEON_MAX_MIP_LEVEL_SHIFT) | + RADEON_BORDER_MODE_OGL); + + t->setup.pp_txformat = (txformat | txalpha | + (log2Width << RADEON_TXF_WIDTH_SHIFT) | + (log2Height << RADEON_TXF_HEIGHT_SHIFT) | + RADEON_TXF_ENDIAN_NO_SWAP | + RADEON_TXF_PERSPECTIVE_ENABLE); + + t->setup.pp_txoffset = 0x00000000; + t->setup.pp_txcblend = 0x00000000; + t->setup.pp_txablend = 0x00000000; + t->setup.pp_tfactor = 0x00000000; + t->setup.pp_border_color = 0x00000000; + + radeonSetTexWrap( t, tObj->WrapS, tObj->WrapT ); + radeonSetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); + radeonSetTexBorderColor( t, tObj->BorderColor ); + + tObj->DriverData = t; + + make_empty_list( t ); + + return t; +} + +/* Destroy hardware state associated with texture `t'. + */ +void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ) +{ +#if ENABLE_PERF_BOXES + /* Bump the performace counter */ + rmesa->c_textureSwaps++; +#endif + if ( !t ) return; + + if ( t->memBlock ) { + mmFreeMem( t->memBlock ); + t->memBlock = NULL; + } + + if ( t->tObj ) + t->tObj->DriverData = NULL; + if ( t->bound ) + rmesa->CurrentTexObj[t->bound-1] = NULL; + + remove_from_list( t ); + FREE( t ); +} + +/* Keep track of swapped out texture objects. + */ +static void radeonSwapOutTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ) +{ +#if ENABLE_PERF_BOXES + /* Bump the performace counter */ + rmesa->c_textureSwaps++; +#endif + if ( t->memBlock ) { + mmFreeMem( t->memBlock ); + t->memBlock = NULL; + } + + t->dirty_images = ~0; + move_to_tail( &rmesa->SwappedOut, t ); +} + +/* Print out debugging information about texture LRU. + */ +void radeonPrintLocalLRU( radeonContextPtr rmesa, int heap ) +{ + radeonTexObjPtr t; + int sz = 1 << (rmesa->radeonScreen->logTexGranularity[heap]); + + fprintf( stderr, "\nLocal LRU, heap %d:\n", heap ); + + foreach ( t, &rmesa->TexObjList[heap] ) { + if (!t->tObj) { + fprintf( stderr, "Placeholder %d at 0x%x sz 0x%x\n", + t->memBlock->ofs / sz, + t->memBlock->ofs, + t->memBlock->size ); + } else { + fprintf( stderr, "Texture (bound %d) at 0x%x sz 0x%x\n", + t->bound, + t->memBlock->ofs, + t->memBlock->size ); + } + } + + fprintf( stderr, "\n" ); +} + +void radeonPrintGlobalLRU( radeonContextPtr rmesa, int heap ) +{ + radeon_tex_region_t *list = rmesa->sarea->texList[heap]; + int i, j; + + fprintf( stderr, "\nGlobal LRU, heap %d list %p:\n", heap, list ); + + for ( i = 0, j = RADEON_NR_TEX_REGIONS ; i < RADEON_NR_TEX_REGIONS ; i++ ) { + fprintf( stderr, "list[%d] age %d next %d prev %d\n", + j, list[j].age, list[j].next, list[j].prev ); + j = list[j].next; + if ( j == RADEON_NR_TEX_REGIONS ) break; + } + + if ( j != RADEON_NR_TEX_REGIONS ) { + fprintf( stderr, "Loop detected in global LRU\n" ); + for ( i = 0 ; i < RADEON_NR_TEX_REGIONS ; i++ ) { + fprintf( stderr, "list[%d] age %d next %d prev %d\n", + i, list[i].age, list[i].next, list[i].prev ); + } + } + + fprintf( stderr, "\n" ); +} + +/* Reset the global texture LRU. + */ +static void radeonResetGlobalLRU( radeonContextPtr rmesa, int heap ) +{ + radeon_tex_region_t *list = rmesa->sarea->texList[heap]; + int sz = 1 << rmesa->radeonScreen->logTexGranularity[heap]; + int i; + + /* + * (Re)initialize the global circular LRU list. The last element in + * the array (RADEON_NR_TEX_REGIONS) is the sentinal. Keeping it at + * the end of the array allows it to be addressed rationally when + * looking up objects at a particular location in texture memory. + */ + for ( i = 0 ; (i+1) * sz <= rmesa->radeonScreen->texSize[heap] ; i++ ) { + list[i].prev = i-1; + list[i].next = i+1; + list[i].age = 0; + } + + i--; + list[0].prev = RADEON_NR_TEX_REGIONS; + list[i].prev = i-1; + list[i].next = RADEON_NR_TEX_REGIONS; + list[RADEON_NR_TEX_REGIONS].prev = i; + list[RADEON_NR_TEX_REGIONS].next = 0; + rmesa->sarea->texAge[heap] = 0; +} + +/* Update the local and glock texture LRUs. + */ +static void radeonUpdateTexLRU(radeonContextPtr rmesa, radeonTexObjPtr t ) +{ + int heap = t->heap; + radeon_tex_region_t *list = rmesa->sarea->texList[heap]; + int sz = rmesa->radeonScreen->logTexGranularity[heap]; + int start = t->memBlock->ofs >> sz; + int end = (t->memBlock->ofs + t->memBlock->size-1) >> sz; + int i; + + rmesa->lastTexAge[heap] = ++rmesa->sarea->texAge[heap]; + + if ( !t->memBlock ) { + fprintf( stderr, "no memblock\n\n" ); + return; + } + + /* Update our local LRU */ + move_to_head( &rmesa->TexObjList[heap], t ); + + /* Update the global LRU */ + for ( i = start ; i <= end ; i++ ) { + list[i].in_use = 1; + list[i].age = rmesa->lastTexAge[heap]; + + /* remove_from_list(i) */ + list[(CARD32)list[i].next].prev = list[i].prev; + list[(CARD32)list[i].prev].next = list[i].next; + + /* insert_at_head(list, i) */ + list[i].prev = RADEON_NR_TEX_REGIONS; + list[i].next = list[RADEON_NR_TEX_REGIONS].next; + list[(CARD32)list[RADEON_NR_TEX_REGIONS].next].prev = i; + list[RADEON_NR_TEX_REGIONS].next = i; + } + + if ( 0 ) { + radeonPrintGlobalLRU( rmesa, t->heap ); + radeonPrintLocalLRU( rmesa, t->heap ); + } +} + +/* Update our notion of what textures have been changed since we last + * held the lock. This pertains to both our local textures and the + * textures belonging to other clients. Keep track of other client's + * textures by pushing a placeholder texture onto the LRU list -- these + * are denoted by (tObj == NULL). + */ +static void radeonTexturesGone( radeonContextPtr rmesa, int heap, + int offset, int size, int in_use ) +{ + radeonTexObjPtr t, tmp; + + foreach_s ( t, tmp, &rmesa->TexObjList[heap] ) { + if ( t->memBlock->ofs >= offset + size || + t->memBlock->ofs + t->memBlock->size <= offset ) + continue; + + /* It overlaps - kick it out. Need to hold onto the currently + * bound objects, however. + */ + if ( t->bound ) { + radeonSwapOutTexObj( rmesa, t ); + } else { + radeonDestroyTexObj( rmesa, t ); + } + } + + if ( in_use ) { + t = (radeonTexObjPtr) CALLOC( sizeof(*t) ); + if ( !t ) return; + + t->memBlock = mmAllocMem( rmesa->texHeap[heap], size, 0, offset ); + if ( !t->memBlock ) { + fprintf( stderr, "Couldn't alloc placeholder sz %x ofs %x\n", + (int)size, (int)offset ); + mmDumpMemInfo( rmesa->texHeap[heap] ); + return; + } + insert_at_head( &rmesa->TexObjList[heap], t ); + } +} + +/* Update our client's shared texture state. If another client has + * modified a region in which we have textures, then we need to figure + * out which of our textures has been removed, and update our global + * LRU. + */ +void radeonAgeTextures( radeonContextPtr rmesa, int heap ) +{ + RADEONSAREAPrivPtr sarea = rmesa->sarea; + + if ( sarea->texAge[heap] != rmesa->lastTexAge[heap] ) { + int sz = 1 << rmesa->radeonScreen->logTexGranularity[heap]; + int nr = 0; + int idx; + + for ( idx = sarea->texList[heap][RADEON_NR_TEX_REGIONS].prev ; + idx != RADEON_NR_TEX_REGIONS && nr < RADEON_NR_TEX_REGIONS ; + idx = sarea->texList[heap][idx].prev, nr++ ) + { + /* If switching texturing schemes, then the SAREA might not + * have been properly cleared, so we need to reset the + * global texture LRU. + */ + if ( idx * sz > rmesa->radeonScreen->texSize[heap] ) { + nr = RADEON_NR_TEX_REGIONS; + break; + } + + if ( sarea->texList[heap][idx].age > rmesa->lastTexAge[heap] ) { + radeonTexturesGone( rmesa, heap, idx * sz, sz, + sarea->texList[heap][idx].in_use ); + } + } + + if ( nr == RADEON_NR_TEX_REGIONS ) { + radeonTexturesGone( rmesa, heap, 0, + rmesa->radeonScreen->texSize[heap], 0 ); + radeonResetGlobalLRU( rmesa, heap ); + } + + rmesa->dirty |= (RADEON_UPLOAD_CONTEXT | + RADEON_UPLOAD_TEX0IMAGES | + RADEON_UPLOAD_TEX1IMAGES); + rmesa->lastTexAge[heap] = sarea->texAge[heap]; + } +} + + +/* ================================================================ + * Texture image conversions + */ + +/* Convert a block of Mesa-formatted texture to an 8bpp hardware format. + */ +static void radeonConvertTexture8bpp( CARD32 *dst, + struct gl_texture_image *image, + int x, int y, int width, int height, + int pitch ) +{ + CARD8 *src; + int i, j; + + if ( width < 4 ) { + width = 4; + } + +#define ALIGN_DST \ + do { \ + if ( width < 32 ) { \ + dst += ((32 - width) / 4); \ + } \ + } while (0) + + switch ( image->Format ) { + case GL_INTENSITY: + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x); + for ( j = width >> 2 ; j ; j-- ) { + *dst++ = src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); + src += 4; + } + ALIGN_DST; + } + break; + + case GL_COLOR_INDEX: + default: + fprintf( stderr, "%s: unsupported format 0x%x\n", + __FUNCTION__, image->Format ); + break; + } +} +#undef ALIGN_DST + +/* Convert a block of Mesa-formatted texture to a 16bpp hardware format. + */ +static void radeonConvertTexture16bpp( CARD32 *dst, + struct gl_texture_image *image, + int x, int y, int width, int height, + int pitch ) +{ + CARD8 *src; + int i, j; + + if ( width < 2 ) { + width = 2; + } + +#define ALIGN_DST \ + do { \ + if ( width < 16 ) { \ + dst += ((16 - width) / 2); \ + } \ + } while (0) + + switch ( image->Format ) { + case GL_RGBA: + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x) * 4; + for ( j = width >> 1 ; j ; j-- ) { + *dst++ = ((RADEONPACKCOLOR4444( src[0], src[1], src[2], src[3] )) | + (RADEONPACKCOLOR4444( src[4], src[5], src[6], src[7] ) << 16)); + src += 8; + } + ALIGN_DST; + } + break; + + case GL_RGB: + { + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x) * 3; + for ( j = width >> 1 ; j ; j-- ) { + *dst++ = ((RADEONPACKCOLOR565( src[0], src[1], src[2] )) | + (RADEONPACKCOLOR565( src[3], src[4], src[5] ) << 16)); + src += 6; + } + ALIGN_DST; + } + } + break; + + case GL_ALPHA: + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x); + for ( j = width >> 1 ; j ; j-- ) { + *dst++ = ((RADEONPACKCOLOR88( 0x00, src[0] )) | + (RADEONPACKCOLOR88( 0x00, src[1] ) << 16)); + src += 2; + } + ALIGN_DST; + } + break; + + case GL_LUMINANCE: + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x); + for ( j = width >> 1 ; j ; j-- ) { + *dst++ = ((RADEONPACKCOLOR88( src[0], 0xff )) | + (RADEONPACKCOLOR88( src[1], 0xff ) << 16)); + src += 2; + } + ALIGN_DST; + } + break; + + case GL_LUMINANCE_ALPHA: + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x) * 2; + for ( j = width >> 1 ; j ; j-- ) { + *dst++ = ((RADEONPACKCOLOR88( src[0], src[1] )) | + (RADEONPACKCOLOR88( src[2], src[3] ) << 16)); + src += 4; + } + ALIGN_DST; + } + break; + + default: + fprintf( stderr, "%s: unsupported format 0x%x\n", + __FUNCTION__, image->Format ); + break; + } +} +#undef ALIGN_DST + +/* Convert a block of Mesa-formatted texture to a 32bpp hardware format. + */ +static void radeonConvertTexture32bpp( CARD32 *dst, + struct gl_texture_image *image, + int x, int y, int width, int height, + int pitch ) +{ + CARD8 *src; + int i, j; + +#define ALIGN_DST \ + do { \ + if ( width < 8 ) { \ + dst += (8 - width); \ + } \ + } while (0) + + switch ( image->Format ) { + case GL_RGBA: + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x) * 4; + for ( j = width ; j ; j-- ) { + *dst++ = RADEONPACKCOLOR8888( src[0], src[1], src[2], src[3] ); + src += 4; + } + ALIGN_DST; + } + break; + + case GL_RGB: + for ( i = 0 ; i < height ; i++ ) { + src = (CARD8 *)image->Data + ((y + i) * pitch + x) * 3; + for ( j = width ; j ; j-- ) { + *dst++ = RADEONPACKCOLOR8888( src[0], src[1], src[2], 0xff ); + src += 3; + } + ALIGN_DST; + } + break; + + default: + fprintf( stderr, "%s: unsupported format 0x%x\n", + __FUNCTION__, image->Format ); + break; + } +} + +/* Upload the texture image associated with texture `t' at level `level' + * at the address relative to `start'. + */ +static void radeonUploadSubImage( radeonContextPtr rmesa, + radeonTexObjPtr t, GLint level, + GLint x, GLint y, GLint width, GLint height ) +{ + struct gl_texture_image *image; + GLint texelsPerDword = 0; + GLint imageX, imageY, imageWidth, imageHeight; + GLint blitX, blitY, blitWidth, blitHeight; + GLint imageRows, blitRows; + GLint remaining ; + GLint format, dwords; + CARD32 pitch, offset; + drmBufPtr buffer; + CARD32 *dst; + + /* Ensure we have a valid texture to upload */ + if ( ( level < 0 ) || ( level >= RADEON_MAX_TEXTURE_LEVELS ) ) + return; + + image = t->tObj->Image[level]; + if ( !image ) + return; + + switch ( t->texelBytes ) { + case 1: + texelsPerDword = 4; + break; + case 2: + texelsPerDword = 2; + break; + case 4: + texelsPerDword = 1; + break; + } + + format = t->setup.pp_txformat & RADEON_TXF_FORMAT_MASK; + + imageX = 0; + imageY = 0; + imageWidth = image->Width; + imageHeight = image->Height; + + blitX = t->image[level].x; + blitY = t->image[level].y; + blitWidth = t->image[level].width; + blitHeight = t->image[level].height; + + dwords = t->image[level].dwords; + offset = t->bufAddr; + pitch = (t->image[0].width * t->texelBytes) / 64; + +#if ENABLE_PERF_BOXES + /* Bump the performace counter */ + rmesa->c_textureBytes += (dwords << 2); +#endif + + if ( RADEON_DEBUG & DEBUG_VERBOSE_MSG ) { + fprintf( stderr, " upload image: %d,%d at %d,%d\n", + imageWidth, imageHeight, imageX, imageY ); + fprintf( stderr, " upload blit: %d,%d at %d,%d\n", + blitWidth, blitHeight, blitX, blitY ); + fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d " + "level: %d format: %x\n", + (GLuint)offset, (GLuint)pitch, dwords, level, format ); + } + + /* Subdivide the texture if required */ + if ( dwords <= RADEON_BUFFER_MAX_DWORDS / 2 ) { + imageRows = imageHeight; + blitRows = blitHeight; + } else { + imageRows = (RADEON_BUFFER_MAX_DWORDS * texelsPerDword)/(2 * imageWidth); + blitRows = (RADEON_BUFFER_MAX_DWORDS * texelsPerDword) / (2 * blitWidth); + } + + for ( remaining = imageHeight ; + remaining > 0 ; + remaining -= imageRows, imageY += imageRows, blitY += blitRows ) + { + if ( remaining >= imageRows ) { + imageHeight = imageRows; + blitHeight = blitRows; + } else { + imageHeight = remaining; + blitHeight = blitRows; + } + dwords = blitWidth * blitHeight / texelsPerDword; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_MSG ) { + fprintf( stderr, " blitting: %d,%d at %d,%d\n", + imageWidth, imageHeight, imageX, imageY ); + fprintf( stderr, " %d,%d at %d,%d - %d dwords\n", + blitWidth, blitHeight, blitX, blitY, dwords ); + } + + /* Grab the indirect buffer for the texture blit */ + buffer = radeonGetBufferLocked( rmesa ); + + dst = (CARD32 *)((char *)buffer->address + RADEON_HOSTDATA_BLIT_OFFSET); + + /* Actually do the texture conversion */ + switch ( t->texelBytes ) { + case 1: + radeonConvertTexture8bpp( dst, image, + imageX, imageY, imageWidth, imageHeight, + imageWidth ); + break; + case 2: + radeonConvertTexture16bpp( dst, image, + imageX, imageY, imageWidth, imageHeight, + imageWidth ); + break; + case 4: + radeonConvertTexture32bpp( dst, image, + imageX, imageY, imageWidth, imageHeight, + imageWidth ); + break; + } + + radeonFireBlitLocked( rmesa, buffer, + offset, pitch, format, + blitX, blitY, blitWidth, blitHeight ); + } + + rmesa->new_state |= RADEON_NEW_CONTEXT; + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_MASKS; +} + +/* Upload the texture images associated with texture `t'. This might + * require removing our own and/or other client's texture objects to + * make room for these images. + */ +/* NOTE: This function is only called while holding the hardware lock */ +int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t ) +{ + int i; + int heap; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %p )\n", + __FUNCTION__, rmesa->glCtx, t ); + } + + if ( !t ) + return 0; + + /* Choose the heap appropriately */ + heap = t->heap = RADEON_CARD_HEAP; +#if 0 + if ( !rmesa->radeonScreen->IsPCI && + t->totalSize > rmesa->radeonScreen->texSize[heap] ) { + heap = t->heap = RADEON_AGP_HEAP; + } +#endif + + /* Do we need to eject LRU texture objects? */ + if ( !t->memBlock ) { + /* Allocate a memory block on a 4k boundary (1<<12 == 4096) */ + t->memBlock = mmAllocMem( rmesa->texHeap[heap], + t->totalSize, 12, 0 ); + +#if 0 + /* Try AGP before kicking anything out of local mem */ + if ( !t->memBlock && heap == RADEON_CARD_HEAP ) { + t->memBlock = mmAllocMem( rmesa->texHeap[RADEON_AGP_HEAP], + t->totalSize, 12, 0 ); + + if ( t->memBlock ) + heap = t->heap = RADEON_AGP_HEAP; + } +#endif + + /* Kick out textures until the requested texture fits */ + while ( !t->memBlock ) { + if ( rmesa->TexObjList[heap].prev->bound ) { + fprintf( stderr, + "radeonUploadTexImages: ran into bound texture\n" ); + return -1; + } + if ( rmesa->TexObjList[heap].prev == + &rmesa->TexObjList[heap] ) { + if ( rmesa->radeonScreen->IsPCI ) { + fprintf( stderr, "radeonUploadTexImages: upload texture " + "failure on local texture heaps, sz=%d\n", + t->totalSize ); + return -1; +#if 0 + } else if ( heap == RADEON_CARD_HEAP ) { + heap = t->heap = RADEON_AGP_HEAP; + continue; +#endif + } else { + fprintf( stderr, "radeonUploadTexImages: upload texture " + "failure on both local and AGP texture heaps, " + "sz=%d\n", + t->totalSize ); + return -1; + } + } + + radeonDestroyTexObj( rmesa, rmesa->TexObjList[heap].prev ); + + t->memBlock = mmAllocMem( rmesa->texHeap[heap], + t->totalSize, 12, 0 ); + } + + /* Set the base offset of the texture image */ + t->bufAddr = rmesa->radeonScreen->texOffset[heap] + t->memBlock->ofs; + + t->setup.pp_txoffset = t->bufAddr; +#if 0 + /* Fix AGP texture offsets */ + if ( heap == RADEON_AGP_HEAP ) { + t->setup.pp_tx_offset += RADEON_AGP_TEX_OFFSET + + rmesa->radeonScreen->agpTexOffset; + } +#endif + + /* Force loading the new state into the hardware */ + switch ( t->bound ) { + case 1: + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_TEX0; + break; + + case 2: + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_TEX1; + break; + + default: + return -1; + } + } + + /* Let the world know we've used this memory recently */ + radeonUpdateTexLRU( rmesa, t ); + + /* Upload any images that are new */ + if ( t->dirty_images ) { + int num_levels = ((t->setup.pp_txfilter & RADEON_MAX_MIP_LEVEL_MASK) >> + RADEON_MAX_MIP_LEVEL_SHIFT); + + for ( i = 0 ; i <= num_levels ; i++ ) { + if ( t->dirty_images & (1 << i) ) { + radeonUploadSubImage( rmesa, t, i, 0, 0, + t->image[i].width, t->image[i].height ); + } + } + + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; + } + + t->dirty_images = 0; + return 0; +} + + +/* ================================================================ + * Texture combine functions + */ + +#define RADEON_DISABLE 0 +#define RADEON_REPLACE 1 +#define RADEON_MODULATE 2 +#define RADEON_DECAL 3 +#define RADEON_BLEND 4 +#define RADEON_ADD 5 +#define RADEON_MAX_COMBFUNC 6 + +static GLuint radeon_color_combine[][RADEON_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00802800 + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800142 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T0_COLOR | + RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x008c2d42 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T0_COLOR | + RADEON_COLOR_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x008c2902 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_TFACTOR_COLOR | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00812802 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 1: + */ + { + /* Disable combiner stage + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00803000 + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T1_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800182 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T1_COLOR | + RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x008c3582 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T1_COLOR | + RADEON_COLOR_ARG_C_T1_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x008c3102 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_TFACTOR_COLOR | + RADEON_COLOR_ARG_C_T1_COLOR | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00813002 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T1_COLOR | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 2: + */ + { + /* Disable combiner stage + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00803800 + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T2_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x008001c2 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T2_COLOR | + RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x008c3dc2 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T2_COLOR | + RADEON_COLOR_ARG_C_T2_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x008c3902 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_TFACTOR_COLOR | + RADEON_COLOR_ARG_C_T2_COLOR | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00813802 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T2_COLOR | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + } +}; + +static GLuint radeon_alpha_combine[][RADEON_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00800500 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_T0_ALPHA | + RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x00800100 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 1: + */ + { + /* Disable combiner stage + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00800600 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T1_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800061 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_T1_ALPHA | + RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x00800100 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x00800061 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_C_T1_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00800061 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T1_ALPHA | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 2: + */ + { + /* Disable combiner stage + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00800700 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T2_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800071 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_T2_ALPHA | + RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x00800100 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x00800071 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_C_T2_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00800021 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T2_ALPHA | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + } +}; + + +/* GL_EXT_texture_env_combine support + */ + +/* The color tables have combine functions for GL_SRC_COLOR, + * GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. + */ +static GLuint radeon_texture_color[][RADEON_MAX_TEXTURE_UNITS] = +{ + { + RADEON_COLOR_ARG_A_T0_COLOR, + RADEON_COLOR_ARG_A_T1_COLOR, + RADEON_COLOR_ARG_A_T2_COLOR + }, + { + RADEON_COLOR_ARG_A_T0_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T1_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T2_COLOR | RADEON_COMP_ARG_A + }, + { + RADEON_COLOR_ARG_A_T0_ALPHA, + RADEON_COLOR_ARG_A_T1_ALPHA, + RADEON_COLOR_ARG_A_T2_ALPHA + }, + { + RADEON_COLOR_ARG_A_T0_ALPHA | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T1_ALPHA | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T2_ALPHA | RADEON_COMP_ARG_A + }, +}; + +static GLuint radeon_tfactor_color[] = +{ + RADEON_COLOR_ARG_A_TFACTOR_COLOR, + RADEON_COLOR_ARG_A_TFACTOR_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_TFACTOR_ALPHA, + RADEON_COLOR_ARG_A_TFACTOR_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_primary_color[] = +{ + RADEON_COLOR_ARG_A_DIFFUSE_COLOR, + RADEON_COLOR_ARG_A_DIFFUSE_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_DIFFUSE_ALPHA, + RADEON_COLOR_ARG_A_DIFFUSE_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_previous_color[] = +{ + RADEON_COLOR_ARG_A_CURRENT_COLOR, + RADEON_COLOR_ARG_A_CURRENT_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_CURRENT_ALPHA, + RADEON_COLOR_ARG_A_CURRENT_ALPHA | RADEON_COMP_ARG_A +}; + +/* The alpha tables only have GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. + */ +static GLuint radeon_texture_alpha[][RADEON_MAX_TEXTURE_UNITS] = +{ + { + RADEON_ALPHA_ARG_A_T0_ALPHA, + RADEON_ALPHA_ARG_A_T1_ALPHA, + RADEON_ALPHA_ARG_A_T2_ALPHA + }, + { + RADEON_ALPHA_ARG_A_T0_ALPHA | RADEON_COMP_ARG_A, + RADEON_ALPHA_ARG_A_T1_ALPHA | RADEON_COMP_ARG_A, + RADEON_ALPHA_ARG_A_T2_ALPHA | RADEON_COMP_ARG_A + }, +}; + +static GLuint radeon_tfactor_alpha[] = +{ + RADEON_ALPHA_ARG_A_TFACTOR_ALPHA, + RADEON_ALPHA_ARG_A_TFACTOR_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_primary_alpha[] = +{ + RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA, + RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_previous_alpha[] = +{ + RADEON_ALPHA_ARG_A_CURRENT_ALPHA, + RADEON_ALPHA_ARG_A_CURRENT_ALPHA | RADEON_COMP_ARG_A +}; + + +/* Extract the arg from slot A, shift it into the correct argument slot + * and set the corresponding complement bit. + */ +#define RADEON_COLOR_ARG( n, arg ) \ +do { \ + color_combine |= \ + ((color_arg[n] & RADEON_COLOR_ARG_MASK) \ + << RADEON_COLOR_ARG_##arg##_SHIFT); \ + color_combine |= \ + ((color_arg[n] >> RADEON_COMP_ARG_SHIFT) \ + << RADEON_COMP_ARG_##arg##_SHIFT); \ +} while (0) + +#define RADEON_ALPHA_ARG( n, arg ) \ +do { \ + alpha_combine |= \ + ((alpha_arg[n] & RADEON_ALPHA_ARG_MASK) \ + << RADEON_ALPHA_ARG_##arg##_SHIFT); \ + alpha_combine |= \ + ((alpha_arg[n] >> RADEON_COMP_ARG_SHIFT) \ + << RADEON_COMP_ARG_##arg##_SHIFT); \ +} while (0) + + +/* ================================================================ + * Texture unit state management + */ + +static void radeonUpdateTextureEnv( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int source = rmesa->tmu_source[unit]; + struct gl_texture_object *tObj; + struct gl_texture_unit *texUnit; + GLuint enabled; + GLuint color_combine, alpha_combine; + GLuint color_arg[3], alpha_arg[3]; + GLuint i, numColorArgs = 0, numAlphaArgs = 0; + GLuint op; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %d )\n", + __FUNCTION__, ctx, unit ); + } + + enabled = (ctx->Texture.ReallyEnabled >> (source * 4)) & TEXTURE0_ANY; + if ( enabled != TEXTURE0_2D && enabled != TEXTURE0_1D ) + return; + + /* Only update the hardware texture state if the texture is current, + * complete and enabled. + */ + texUnit = &ctx->Texture.Unit[source]; + tObj = texUnit->Current; + if ( !tObj || !tObj->Complete ) + return; + + if ( ( tObj != texUnit->CurrentD[2] ) && + ( tObj != texUnit->CurrentD[1] ) ) + return; + + /* Set the texture environment state. Isn't this nice and clean? + * The Radeon will automagically set the texture alpha to 0xff when + * the texture format does not include an alpha component. This + * reduces the amount of special-casing we have to do, alpha-only + * textures being a notable exception. + */ + switch ( texUnit->EnvMode ) { + case GL_REPLACE: + switch ( tObj->Image[0]->Format ) { + case GL_RGBA: + case GL_RGB: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_REPLACE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE]; + break; + case GL_COLOR_INDEX: + default: + return; + } + break; + + case GL_MODULATE: + switch ( tObj->Image[0]->Format ) { + case GL_RGBA: + case GL_RGB: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_MODULATE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_COLOR_INDEX: + default: + return; + } + break; + + case GL_DECAL: + switch ( tObj->Image[0]->Format ) { + case GL_RGBA: + case GL_RGB: + color_combine = radeon_color_combine[unit][RADEON_DECAL]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + case GL_COLOR_INDEX: + default: + return; + } + break; + + case GL_BLEND: + switch ( tObj->Image[0]->Format ) { + case GL_RGBA: + case GL_RGB: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_BLEND]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_BLEND]; + alpha_combine = radeon_alpha_combine[unit][RADEON_BLEND]; + break; + case GL_COLOR_INDEX: + default: + return; + } + break; + + case GL_ADD: + switch ( tObj->Image[0]->Format ) { + case GL_RGBA: + case GL_RGB: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_ADD]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_ADD]; + alpha_combine = radeon_alpha_combine[unit][RADEON_ADD]; + break; + case GL_COLOR_INDEX: + default: + return; + } + break; + + case GL_COMBINE_EXT: + /* Step 0: + * Calculate how many arguments we need to process. + */ + switch ( texUnit->CombineModeRGB ) { + case GL_REPLACE: + numColorArgs = 1; + break; + case GL_MODULATE: + case GL_ADD: + case GL_ADD_SIGNED_EXT: + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + numColorArgs = 2; + break; + case GL_INTERPOLATE_EXT: + numColorArgs = 3; + break; + default: + return; + } + + switch ( texUnit->CombineModeA ) { + case GL_REPLACE: + numAlphaArgs = 1; + break; + case GL_MODULATE: + case GL_ADD: + case GL_ADD_SIGNED_EXT: + numAlphaArgs = 2; + break; + case GL_INTERPOLATE_EXT: + numAlphaArgs = 3; + break; + default: + return; + } + + /* Step 1: + * Extract the color and alpha combine function arguments. + */ + for ( i = 0 ; i < numColorArgs ; i++ ) { + op = texUnit->CombineOperandRGB[i] - GL_SRC_COLOR; + switch ( texUnit->CombineSourceRGB[i] ) { + case GL_TEXTURE: + color_arg[i] = radeon_texture_color[op][unit]; + break; + case GL_CONSTANT_EXT: + color_arg[i] = radeon_tfactor_color[op]; + break; + case GL_PRIMARY_COLOR_EXT: + color_arg[i] = radeon_primary_color[op]; + break; + case GL_PREVIOUS_EXT: + color_arg[i] = radeon_previous_color[op]; + break; + default: + return; + } + } + + for ( i = 0 ; i < numAlphaArgs ; i++ ) { + op = texUnit->CombineOperandA[i] - GL_SRC_ALPHA; + switch ( texUnit->CombineSourceA[i] ) { + case GL_TEXTURE: + alpha_arg[i] = radeon_texture_alpha[op][unit]; + break; + case GL_CONSTANT_EXT: + alpha_arg[i] = radeon_tfactor_alpha[op]; + break; + case GL_PRIMARY_COLOR_EXT: + alpha_arg[i] = radeon_primary_alpha[op]; + break; + case GL_PREVIOUS_EXT: + alpha_arg[i] = radeon_previous_alpha[op]; + break; + default: + return; + } + } + + /* Step 2: + * Build up the color and alpha combine functions. + */ + switch ( texUnit->CombineModeRGB ) { + case GL_REPLACE: + color_combine = (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, C ); + break; + case GL_MODULATE: + color_combine = (RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, B ); + break; + case GL_ADD: + color_combine = (RADEON_COLOR_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + break; + case GL_ADD_SIGNED_EXT: + color_combine = (RADEON_COLOR_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADDSIGNED | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + break; + case GL_INTERPOLATE_EXT: + color_combine = (RADEON_BLEND_CTL_BLEND | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, B ); + RADEON_COLOR_ARG( 1, A ); + RADEON_COLOR_ARG( 2, C ); + break; + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + color_combine = (RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_DOT3 | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, B ); + break; + default: + return; + } + + switch ( texUnit->CombineModeA ) { + case GL_REPLACE: + alpha_combine = (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, C ); + break; + case GL_MODULATE: + alpha_combine = (RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, B ); + break; + case GL_ADD: + alpha_combine = (RADEON_ALPHA_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + break; + case GL_ADD_SIGNED_EXT: + alpha_combine = (RADEON_ALPHA_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADDSIGNED | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + break; + case GL_INTERPOLATE_EXT: + alpha_combine = (RADEON_BLEND_CTL_BLEND | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, B ); + RADEON_ALPHA_ARG( 1, A ); + RADEON_ALPHA_ARG( 2, C ); + break; + default: + return; + } + + if ( texUnit->CombineModeRGB == GL_DOT3_RGB_EXT ) { + alpha_combine |= RADEON_DOT_ALPHA_DONT_REPLICATE; + } + + /* Step 3: + * Apply the scale factor. The EXT extension has a somewhat + * unnecessary restriction that the scale must be 4x. The ARB + * extension will likely drop this and we can just apply the + * scale factors regardless. + */ + if ( texUnit->CombineModeRGB != GL_DOT3_RGB_EXT && + texUnit->CombineModeRGB != GL_DOT3_RGBA_EXT ) { + color_combine |= (texUnit->CombineScaleShiftRGB << 21); + alpha_combine |= (texUnit->CombineScaleShiftA << 21); + } else { + color_combine |= RADEON_SCALE_4X; + alpha_combine |= RADEON_SCALE_4X; + } + + /* All done! + */ + break; + + default: + return; + } + + rmesa->color_combine[source] = color_combine; + rmesa->alpha_combine[source] = alpha_combine; +} + +static void radeonUpdateTextureObject( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int source = rmesa->tmu_source[unit]; + struct gl_texture_object *tObj; + radeonTexObjPtr t; + GLuint enabled; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %d )\n", + __FUNCTION__, ctx, unit ); + } + + enabled = (ctx->Texture.ReallyEnabled >> (source * 4)) & TEXTURE0_ANY; + if ( enabled != TEXTURE0_2D && enabled != TEXTURE0_1D ) { + if ( enabled ) + rmesa->Fallback |= RADEON_FALLBACK_TEXTURE; + return; + } + + /* Only update the hardware texture state if the texture is current, + * complete and enabled. + */ + tObj = ctx->Texture.Unit[source].Current; + if ( !tObj || !tObj->Complete ) + return; + + if ( ( tObj != ctx->Texture.Unit[source].CurrentD[2] ) && + ( tObj != ctx->Texture.Unit[source].CurrentD[1] ) ) + return; + + if ( !tObj->DriverData ) { + /* If this is the first time the texture has been used, then create + * a new texture object for it. + */ + radeonCreateTexObj( rmesa, tObj ); + + if ( !tObj->DriverData ) { + /* Can't create a texture object... */ + fprintf( stderr, "%s: texture object creation failed!\n", + __FUNCTION__ ); + rmesa->Fallback |= RADEON_FALLBACK_TEXTURE; + return; + } + } + + /* We definately have a valid texture now */ + t = tObj->DriverData; + + /* Force the texture unit state to be loaded into the hardware */ + rmesa->dirty |= RADEON_UPLOAD_CONTEXT | (RADEON_UPLOAD_TEX0 << unit); + + /* Force any texture images to be loaded into the hardware */ + if ( t->dirty_images ) + rmesa->dirty |= (RADEON_UPLOAD_TEX0IMAGES << unit); + + /* Bind to the given texture unit */ + rmesa->CurrentTexObj[unit] = t; + t->bound = unit + 1; + + if ( t->memBlock ) + radeonUpdateTexLRU( rmesa, t ); + + switch ( unit ) { + case 0: + rmesa->setup.pp_cntl |= (RADEON_TEX_0_ENABLE | + RADEON_TEX_BLEND_0_ENABLE); + break; + case 1: + rmesa->setup.pp_cntl |= (RADEON_TEX_1_ENABLE | + RADEON_TEX_BLEND_1_ENABLE); + break; + } +} + +void radeonUpdateTextureState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p ) en=0x%x\n", + __FUNCTION__, ctx, ctx->Texture.ReallyEnabled ); + } + + /* Clear any texturing fallbacks */ + rmesa->Fallback &= ~RADEON_FALLBACK_TEXTURE; + + /* Unbind any currently bound textures */ + if ( rmesa->CurrentTexObj[0] ) rmesa->CurrentTexObj[0]->bound = 0; + if ( rmesa->CurrentTexObj[1] ) rmesa->CurrentTexObj[1]->bound = 0; + rmesa->CurrentTexObj[0] = NULL; + rmesa->CurrentTexObj[1] = NULL; + + if ( ctx->Enabled & (TEXTURE0_3D|TEXTURE1_3D) ) + rmesa->Fallback |= RADEON_FALLBACK_TEXTURE; + + /* Disable all texturing until it is known to be good */ + rmesa->setup.pp_cntl &= ~(RADEON_TEX_ENABLE_MASK | + RADEON_TEX_BLEND_ENABLE_MASK); + + radeonUpdateTextureObject( ctx, 0 ); + radeonUpdateTextureEnv( ctx, 0 ); + + if ( rmesa->multitex ) { + radeonUpdateTextureObject( ctx, 1 ); + radeonUpdateTextureEnv( ctx, 1 ); + } + + rmesa->dirty |= RADEON_UPLOAD_CONTEXT; +} + + +/* ================================================================ + * DD interface texturing functions + * + * FIXME: Many of these are deprecated -- we should move to the new + * single-copy texture interface. + */ +#define SCALED_FLOAT_TO_BYTE( x, scale ) \ + ((((GLint)((256.0F / scale) * (x))) - 1) / 2) + +static void radeonDDTexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_texture_unit *texUnit; + GLuint source; + GLubyte c[4]; + GLuint col; + GLfloat bias; + GLubyte b; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s )\n", + __FUNCTION__, gl_lookup_enum_by_nr( pname ) ); + } + + switch ( pname ) { + case GL_TEXTURE_ENV_MODE: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= RADEON_NEW_TEXTURE | RADEON_NEW_ALPHA; + break; + + case GL_TEXTURE_ENV_COLOR: + source = rmesa->tmu_source[ctx->Texture.CurrentUnit]; + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + FLOAT_RGBA_TO_UBYTE_RGBA( c, texUnit->EnvColor ); + col = radeonPackColor( 4, c[0], c[1], c[2], c[3] ); + if ( rmesa->env_color[source] != col ) { + FLUSH_BATCH( rmesa ); + rmesa->env_color[source] = col; + + rmesa->new_state |= RADEON_NEW_TEXTURE; + } + break; + + case GL_TEXTURE_LOD_BIAS_EXT: + /* The Radeon's LOD bias is a signed 2's complement value with a + * range of -1.0 <= bias < 4.0. We break this into two linear + * functions, one mapping [-1.0,0.0] to [-128,0] and one mapping + * [0.0,4.0] to [0,127]. + */ + source = rmesa->tmu_source[ctx->Texture.CurrentUnit]; + bias = CLAMP( *param, -1.0, 4.0 ); + if ( bias == 0 ) { + b = 0; + } else if ( bias > 0 ) { + b = (GLubyte) SCALED_FLOAT_TO_BYTE( bias, 4.0 ); + } else { + b = (GLubyte) SCALED_FLOAT_TO_BYTE( bias, 1.0 ); + } + if ( rmesa->lod_bias[source] != (GLuint)b ) { + FLUSH_BATCH( rmesa ); + rmesa->lod_bias[source] = (GLuint)b; + + rmesa->new_state |= RADEON_NEW_TEXTURE; + } + break; + + default: + return; + } +} + +static void radeonDDTexImage( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, GLint level, + GLint internalFormat, + const struct gl_texture_image *image ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonTexObjPtr t; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) + fprintf( stderr, "%s( %p, level %d )\n", __FUNCTION__, tObj, level ); + + if ( ( target != GL_TEXTURE_2D ) && + ( target != GL_TEXTURE_1D ) ) + return; + + if ( level >= RADEON_MAX_TEXTURE_LEVELS ) + return; + + t = (radeonTexObjPtr)tObj->DriverData; + if ( t ) { + if ( t->bound ) FLUSH_BATCH( rmesa ); + + /* Destroy the old texture, and upload a new one. The actual + * uploading of the texture image occurs in the UploadSubImage + * function. + */ + radeonDestroyTexObj( rmesa, t ); + rmesa->new_state |= RADEON_NEW_TEXTURE; + } +} + +static void radeonDDTexSubImage( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLint internalFormat, + const struct gl_texture_image *image ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonTexObjPtr t; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, level %d ) size: %d,%d of %d,%d\n", + __FUNCTION__, tObj, level, width, height, + image->Width, image->Height ); + } + + if ( ( target != GL_TEXTURE_2D ) && + ( target != GL_TEXTURE_1D ) ) + return; + + if ( level >= RADEON_MAX_TEXTURE_LEVELS ) + return; + + t = (radeonTexObjPtr)tObj->DriverData; + if ( t ) { + if ( t->bound ) FLUSH_BATCH( rmesa ); + +#if 0 + /* FIXME: Only upload textures if we already have space in the heap. + */ + LOCK_HARDWARE( rmesa ); + radeonUploadSubImage( rmesa, t, level, + xoffset, yoffset, width, height ); + UNLOCK_HARDWARE( rmesa ); +#else + radeonDestroyTexObj( rmesa, t ); +#endif + /* Update the context state */ + rmesa->new_state |= RADEON_NEW_TEXTURE; + } +} + +static void radeonDDTexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, + GLenum pname, const GLfloat *params ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s )\n", + __FUNCTION__, gl_lookup_enum_by_nr( pname ) ); + } + + /* If we don't have a hardware texture, it will be automatically + * created with current state before it is used, so we don't have + * to do anything now. + */ + if ( !t || !t->bound ) + return; + + if ( ( target != GL_TEXTURE_2D ) && + ( target != GL_TEXTURE_1D ) ) + return; + + switch ( pname ) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + if ( t->bound ) FLUSH_BATCH( rmesa ); + radeonSetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + if ( t->bound ) FLUSH_BATCH( rmesa ); + radeonSetTexWrap( t, tObj->WrapS, tObj->WrapT ); + break; + + case GL_TEXTURE_BORDER_COLOR: + if ( t->bound ) FLUSH_BATCH( rmesa ); + radeonSetTexBorderColor( t, tObj->BorderColor ); + break; + + default: + return; + } + + rmesa->new_state |= RADEON_NEW_TEXTURE; +} + +static void radeonDDBindTexture( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLint unit = ctx->Texture.CurrentUnit; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p ) unit=%d\n", + __FUNCTION__, tObj, ctx->Texture.CurrentUnit ); + } + + FLUSH_BATCH( rmesa ); + + if ( rmesa->CurrentTexObj[unit] ) { + rmesa->CurrentTexObj[unit]->bound = 0; + rmesa->CurrentTexObj[unit] = NULL; + } + + rmesa->new_state |= RADEON_NEW_TEXTURE; +} + +static void radeonDDDeleteTexture( GLcontext *ctx, + struct gl_texture_object *tObj ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData; + + if ( t ) { + if ( t->bound ) { + FLUSH_BATCH( rmesa ); + + rmesa->CurrentTexObj[t->bound-1] = 0; + rmesa->new_state |= RADEON_NEW_TEXTURE; + } + + radeonDestroyTexObj( rmesa, t ); + tObj->DriverData = NULL; + } +} + +static GLboolean radeonDDIsTextureResident( GLcontext *ctx, + struct gl_texture_object *tObj ) +{ + radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData; + + return ( t && t->memBlock ); +} + + + +void radeonDDInitTextureFuncs( GLcontext *ctx ) +{ + ctx->Driver.TexEnv = radeonDDTexEnv; + ctx->Driver.TexImage = radeonDDTexImage; + ctx->Driver.TexSubImage = radeonDDTexSubImage; + ctx->Driver.TexParameter = radeonDDTexParameter; + ctx->Driver.BindTexture = radeonDDBindTexture; + ctx->Driver.DeleteTexture = radeonDDDeleteTexture; + ctx->Driver.UpdateTexturePalette = NULL; + ctx->Driver.ActiveTexture = NULL; + ctx->Driver.IsTextureResident = radeonDDIsTextureResident; + ctx->Driver.PrioritizeTexture = NULL; +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_tex.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_tex.h new file mode 100644 index 000000000..2534335aa --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_tex.h @@ -0,0 +1,96 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.h,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_TEX_H__ +#define __RADEON_TEX_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void radeonUpdateTextureState( GLcontext *ctx ); + +extern int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t ); + +extern void radeonAgeTextures( radeonContextPtr rmesa, int heap ); +extern void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ); + +extern void radeonPrintLocalLRU( radeonContextPtr rmesa, int heap ); +extern void radeonPrintGlobalLRU( radeonContextPtr rmesa, int heap ); + +extern void radeonDDInitTextureFuncs( GLcontext *ctx ); + + +/* ================================================================ + * Color conversion macros: + */ + +#define RADEONPACKCOLOR332( r, g, b ) \ + (((r) & 0xe0) | (((g) & 0xe0) >> 3) | (((b) & 0xc0) >> 6)) + +#define RADEONPACKCOLOR1555( r, g, b, a ) \ + ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \ + ((a) ? 0x8000 : 0)) + +#define RADEONPACKCOLOR565( r, g, b ) \ + ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3)) + +#define RADEONPACKCOLOR88( i, a ) \ + (((a) << 8) | (i)) + +#define RADEONPACKCOLOR888( r, g, b ) \ + (((r) << 16) | ((g) << 8) | (b)) + +#define RADEONPACKCOLOR8888( r, g, b, a ) \ + (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) + +#define RADEONPACKCOLOR4444( r, g, b, a ) \ + ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4)) + +static __inline__ CARD32 radeonPackColor( GLuint cpp, + GLubyte r, GLubyte g, + GLubyte b, GLubyte a ) +{ + switch ( cpp ) { + case 2: + return RADEONPACKCOLOR565( r, g, b ); + case 4: + return RADEONPACKCOLOR8888( r, g, b, a ); + default: + return 0; + } +} + +#endif +#endif /* __RADEON_TEX_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_texobj.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_texobj.h new file mode 100644 index 000000000..45368e076 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_texobj.h @@ -0,0 +1,87 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_texobj.h,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_TEXOBJ_H__ +#define __RADEON_TEXOBJ_H__ + +#include "radeon_sarea.h" +#include "mm.h" + +/* Handle the Radeon's tightly packed mipmaps and strict offset, + * pitch rules for blits by assigning each mipmap a set of + * coordinates that can be used for a hostdata blit. + */ +typedef struct { + GLuint x; /* Blit coordinates */ + GLuint y; + GLuint width; /* Blit dimensions */ + GLuint height; + GLuint dwords; /* Size of image level */ +} radeonTexImage; + +typedef struct radeon_tex_obj radeonTexObj, *radeonTexObjPtr; + +/* Texture object in locally shared texture space. + */ +struct radeon_tex_obj { + radeonTexObjPtr next, prev; + + struct gl_texture_object *tObj; /* Mesa texture object */ + + PMemBlock memBlock; /* Memory block containing texture */ + CARD32 bufAddr; /* Offset to start of locally + shared texture block */ + + CARD32 dirty_images; /* Flags for whether or not + images need to be uploaded to + local or AGP texture space */ + + GLint bound; /* Texture unit currently bound to */ + GLint heap; /* Texture heap currently stored in */ + + radeonTexImage image[RADEON_MAX_TEXTURE_LEVELS]; /* Image data for all + mipmap levels */ + + GLint totalSize; /* Total size of the texture + including all mipmap levels */ + GLint texelBytes; /* Number of bytes per texel */ + + GLboolean hasAlpha; + + radeon_texture_regs_t setup; /* Setup regs for texture */ +}; + +#endif /* __RADEON_TEXOBJ_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_tris.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_tris.c new file mode 100644 index 000000000..bbc766129 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_tris.c @@ -0,0 +1,209 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tris.c,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_vb.h" +#include "radeon_tris.h" +#include "radeon_state.h" + +#include "pipeline.h" +#include "vbindirect.h" + +static struct { + points_func points; + line_func line; + triangle_func triangle; + quad_func quad; +} rast_tab[RADEON_MAX_TRIFUNC]; + +#define RADEON_COLOR( to, from ) \ +do { \ + *(GLuint *)(to) = *(GLuint *)(from); \ +} while (0) + + +static void radeon_null_quad( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint v3, GLuint pv ) +{ +} +static void radeon_null_triangle( GLcontext *ctx, GLuint v0, + GLuint v1, GLuint v2, GLuint pv ) +{ +} +static void radeon_null_line( GLcontext *ctx, + GLuint v1, GLuint v2, GLuint pv ) +{ +} +static void radeon_null_points( GLcontext *ctx, GLuint first, GLuint last ) +{ +} + +static void radeonPrintRenderState( const char *msg, GLuint state ) +{ + fprintf( stderr, "%s: (0x%x) %s%s%s%s%s\n", + msg, state, + (state & RADEON_FLAT_BIT) ? "flat, " : "", + (state & RADEON_OFFSET_BIT) ? "offset, " : "", + (state & RADEON_TWOSIDE_BIT) ? "twoside, " : "", + (state & RADEON_NODRAW_BIT) ? "no-draw, " : "", + (state & RADEON_FALLBACK_BIT) ? "fallback" : "" ); +} + +#define IND (0) +#define TAG(x) x +#include "radeon_tritmp.h" + +#define IND (RADEON_FLAT_BIT) +#define TAG(x) x##_flat +#include "radeon_tritmp.h" + +#define IND (RADEON_OFFSET_BIT) +#define TAG(x) x##_offset +#include "radeon_tritmp.h" + +#define IND (RADEON_OFFSET_BIT | RADEON_FLAT_BIT) +#define TAG(x) x##_offset_flat +#include "radeon_tritmp.h" + +#define IND (RADEON_TWOSIDE_BIT) +#define TAG(x) x##_twoside +#include "radeon_tritmp.h" + +#define IND (RADEON_TWOSIDE_BIT | RADEON_FLAT_BIT) +#define TAG(x) x##_twoside_flat +#include "radeon_tritmp.h" + +#define IND (RADEON_TWOSIDE_BIT | RADEON_OFFSET_BIT) +#define TAG(x) x##_twoside_offset +#include "radeon_tritmp.h" + +#define IND (RADEON_TWOSIDE_BIT | RADEON_OFFSET_BIT | RADEON_FLAT_BIT) +#define TAG(x) x##_twoside_offset_flat +#include "radeon_tritmp.h" + + +void radeonDDTriangleFuncsInit( void ) +{ + GLint i; + + init(); + init_flat(); + init_offset(); + init_offset_flat(); + init_twoside(); + init_twoside_flat(); + init_twoside_offset(); + init_twoside_offset_flat(); + + for ( i = 0 ; i < RADEON_MAX_TRIFUNC ; i++ ) { + if ( i & RADEON_NODRAW_BIT ) { + rast_tab[i].points = radeon_null_points; + rast_tab[i].line = radeon_null_line; + rast_tab[i].triangle = radeon_null_triangle; + rast_tab[i].quad = radeon_null_quad; + } + } +} + + +/* FIXME: Only enable software fallback for stencil in 16 bpp mode after + * we have hardware stencil support. + */ +#define ALL_FALLBACK (DD_SELECT | DD_FEEDBACK | DD_STENCIL) +#define POINT_FALLBACK (ALL_FALLBACK | DD_POINT_SMOOTH | DD_POINT_ATTEN) +#define LINE_FALLBACK (ALL_FALLBACK | DD_LINE_SMOOTH | DD_LINE_STIPPLE) +#define TRI_FALLBACK (ALL_FALLBACK | DD_TRI_SMOOTH | DD_TRI_UNFILLED) +#define ANY_FALLBACK (POINT_FALLBACK | LINE_FALLBACK | TRI_FALLBACK) +#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE | DD_TRI_OFFSET | DD_Z_NEVER) + +/* Setup the Point, Line, Triangle and Quad functions based on the + * current rendering state. Wherever possible, use the hardware to + * render the primitive. Otherwise, fallback to software rendering. + */ +void radeonDDChooseRenderState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint flags = ctx->TriangleCaps; + GLuint index = 0; + + if ( rmesa->Fallback ) { + rmesa->RenderIndex = RADEON_FALLBACK_BIT; + return; + } + + if ( flags & ANY_RASTER_FLAGS ) { + if ( flags & DD_FLATSHADE ) index |= RADEON_FLAT_BIT; + if ( flags & DD_TRI_LIGHT_TWOSIDE ) index |= RADEON_TWOSIDE_BIT; + if ( flags & DD_TRI_OFFSET ) index |= RADEON_OFFSET_BIT; + if ( flags & DD_Z_NEVER ) index |= RADEON_NODRAW_BIT; + } + + rmesa->PointsFunc = rast_tab[index].points; + rmesa->LineFunc = rast_tab[index].line; + rmesa->TriangleFunc = rast_tab[index].triangle; + rmesa->QuadFunc = rast_tab[index].quad; + + rmesa->RenderIndex = index; + rmesa->IndirectTriangles = 0; + + if ( flags & ANY_FALLBACK ) { + if ( flags & POINT_FALLBACK ) { + rmesa->RenderIndex |= RADEON_FALLBACK_BIT; + rmesa->PointsFunc = 0; + rmesa->IndirectTriangles |= DD_POINT_SW_RASTERIZE; + } + + if ( flags & LINE_FALLBACK ) { + rmesa->RenderIndex |= RADEON_FALLBACK_BIT; + rmesa->LineFunc = 0; + rmesa->IndirectTriangles |= DD_LINE_SW_RASTERIZE; + } + + if ( flags & TRI_FALLBACK ) { + rmesa->RenderIndex |= RADEON_FALLBACK_BIT; + rmesa->TriangleFunc = 0; + rmesa->QuadFunc = 0; + rmesa->IndirectTriangles |= (DD_TRI_SW_RASTERIZE | + DD_QUAD_SW_RASTERIZE); + } + } + + if ( 0 ) { + gl_print_tri_caps( "tricaps", ctx->TriangleCaps ); + radeonPrintRenderState( "radeon render state", rmesa->RenderIndex ); + } +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_tris.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_tris.h new file mode 100644 index 000000000..57fadaeca --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_tris.h @@ -0,0 +1,316 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tris.h,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_TRIS_H__ +#define __RADEON_TRIS_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_vb.h" + +extern void radeonDDChooseRenderState( GLcontext *ctx ); +extern void radeonDDTriangleFuncsInit( void ); + +#define RADEON_ANTIALIAS_BIT 0x00 /* GH: Do we need this? */ +#define RADEON_FLAT_BIT 0x01 +#define RADEON_OFFSET_BIT 0x02 +#define RADEON_TWOSIDE_BIT 0x04 +#define RADEON_NODRAW_BIT 0x08 +#define RADEON_FALLBACK_BIT 0x10 +#define RADEON_MAX_TRIFUNC 0x20 + + +static __inline void radeon_draw_triangle( radeonContextPtr rmesa, + radeonVertexPtr v0, + radeonVertexPtr v1, + radeonVertexPtr v2 ) +{ + GLuint vertsize = rmesa->vertsize; + CARD32 *vb = radeonAllocVerticesInline( rmesa, 3 ); + GLuint j; + +#if defined (USE_X86_ASM) + /* GH: We can safely assume the vertex stride is some number of + * dwords, and thus a "rep movsd" is okay. The vb pointer is + * automagically updated with this instruction, so we don't have + * to manually take care of incrementing it. + */ + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "D" ((long)vb), "S" ((long)v0) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)v1) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)v2) + : "memory" ); +#else + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v0->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v1->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v2->ui[j]; +#endif +} + +static __inline void radeon_draw_quad( radeonContextPtr rmesa, + radeonVertexPtr v0, + radeonVertexPtr v1, + radeonVertexPtr v2, + radeonVertexPtr v3 ) +{ + GLuint vertsize = rmesa->vertsize; + CARD32 *vb = radeonAllocVerticesInline( rmesa, 6 ); + GLuint j; + +#if defined (USE_X86_ASM) + /* GH: We can safely assume the vertex stride is some number of + * dwords, and thus a "rep movsd" is okay. The vb pointer is + * automagically updated with this instruction, so we don't have + * to manually take care of incrementing it. + */ + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "D" ((long)vb), "S" ((long)v0) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)v1) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)v3) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)v1) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)v2) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)v3) + : "memory" ); +#else + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v0->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v1->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v3->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v1->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v2->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = v3->ui[j]; +#endif +} + +static __inline void radeon_draw_line( radeonContextPtr rmesa, + radeonVertexPtr tmp0, + radeonVertexPtr tmp1, + GLfloat width ) +{ +#if 1 + GLuint vertsize = rmesa->vertsize; + CARD32 *vb = radeonAllocVerticesInline( rmesa, 6 ); + GLfloat dx, dy, ix, iy; + GLuint j; + + dx = tmp0->v.x - tmp1->v.x; + dy = tmp0->v.y - tmp1->v.y; + + ix = width * .5; iy = 0; + + if ((ix<.5) && (ix>0.1)) ix = .5; /* I want to see lines with width + 0.5 also */ + + if (dx * dx > dy * dy) { + iy = ix; ix = 0; + } + + *(float *)&vb[0] = tmp0->v.x - ix; + *(float *)&vb[1] = tmp0->v.y - iy; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp0->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp1->v.x + ix; + *(float *)&vb[1] = tmp1->v.y + iy; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp1->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp0->v.x + ix; + *(float *)&vb[1] = tmp0->v.y + iy; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp0->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp0->v.x - ix; + *(float *)&vb[1] = tmp0->v.y - iy; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp0->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp1->v.x - ix; + *(float *)&vb[1] = tmp1->v.y - iy; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp1->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp1->v.x + ix; + *(float *)&vb[1] = tmp1->v.y + iy; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp1->ui[j]; +#else + GLuint vertsize = rmesa->vertsize; + CARD32 *vb = radeonAllocVerticesInline( rmesa, RADEON_LINES, 2 ); + GLuint j; + +#if defined (USE_X86_ASM) + /* GH: We can safely assume the vertex stride is some number of + * dwords, and thus a "rep movsd" is okay. The vb pointer is + * automagically updated with this instruction, so we don't have + * to manually take care of incrementing it. + */ + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "D" ((long)vb), "S" ((long)tmp0) + : "memory" ); + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "S" ((long)tmp1) + : "memory" ); +#else + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = tmp0->ui[j]; + + vb += vertsize; + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = tmp1->ui[j]; +#endif +#endif +} + +static __inline void radeon_draw_point( radeonContextPtr rmesa, + radeonVertexPtr tmp, GLfloat sz ) +{ +#if 1 + GLuint vertsize = rmesa->vertsize; + CARD32 *vb = radeonAllocVerticesInline( rmesa, 6 ); + GLuint j; + + *(float *)&vb[0] = tmp->v.x - sz; + *(float *)&vb[1] = tmp->v.y - sz; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp->v.x + sz; + *(float *)&vb[1] = tmp->v.y - sz; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp->v.x + sz; + *(float *)&vb[1] = tmp->v.y + sz; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp->v.x + sz; + *(float *)&vb[1] = tmp->v.y + sz; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp->v.x - sz; + *(float *)&vb[1] = tmp->v.y + sz; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp->ui[j]; + vb += vertsize; + + *(float *)&vb[0] = tmp->v.x - sz; + *(float *)&vb[1] = tmp->v.y - sz; + for (j = 2 ; j < vertsize ; j++) + vb[j] = tmp->ui[j]; + +#else + int vertsize = rmesa->vertsize; + CARD32 *vb = radeonAllocVerticesInline( rmesa, RADEON_3_VERTEX_POINTS, 1 ); + int j; + +#if defined (USE_X86_ASM) + /* GH: We can safely assume the vertex stride is some number of + * dwords, and thus a "rep movsd" is okay. The vb pointer is + * automagically updated with this instruction, so we don't have + * to manually take care of incrementing it. + */ + __asm__ __volatile__( "rep ; movsl" + : "=%c" (j) + : "0" (vertsize), "D" ((long)vb), "S" ((long)tmp) + : "memory" ); +#else + for ( j = 0 ; j < vertsize ; j++ ) + vb[j] = tmp->ui[j]; +#endif +#endif +} + +#endif +#endif /* __RADEON_TRIS_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_tritmp.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_tritmp.h new file mode 100644 index 000000000..ffa0d4746 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_tritmp.h @@ -0,0 +1,336 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tritmp.h,v 1.1 2001/01/08 01:07:28 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +static __inline void TAG(triangle)( GLcontext *ctx, + GLuint e0, GLuint e1, GLuint e2, + GLuint pv ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct vertex_buffer *VB = ctx->VB; + radeonVertexPtr verts = RADEON_DRIVER_DATA(VB)->verts; + radeonVertexPtr v[3]; + +#if (IND & RADEON_OFFSET_BIT) + GLfloat offset; + GLfloat z[3]; +#endif + +#if (IND & RADEON_TWOSIDE_BIT) + GLuint c[3]; +#endif + + v[0] = &verts[e0]; + v[1] = &verts[e1]; + v[2] = &verts[e2]; + +#if (IND & RADEON_TWOSIDE_BIT) + c[0] = v[0]->ui[4]; + c[1] = v[1]->ui[4]; + c[2] = v[2]->ui[4]; +#endif + +#if (IND & (RADEON_TWOSIDE_BIT | RADEON_OFFSET_BIT)) + { + GLfloat ex = v[0]->v.x - v[2]->v.x; + GLfloat ey = v[0]->v.y - v[2]->v.y; + GLfloat fx = v[1]->v.x - v[2]->v.x; + GLfloat fy = v[1]->v.y - v[2]->v.y; + GLfloat cc = ex*fy - ey*fx; + +#if (IND & RADEON_TWOSIDE_BIT) + { + GLuint facing = ( cc > 0.0 ) ^ ctx->Polygon.FrontBit; + GLubyte (*vbcolor)[4] = VB->Color[facing]->data; + if ( IND & RADEON_FLAT_BIT ) { + RADEON_COLOR( (char *)&v[0]->ui[4], vbcolor[pv] ); + v[2]->ui[4] = v[1]->ui[4] = v[0]->ui[4]; + } else { + RADEON_COLOR( (char *)&v[0]->ui[4], vbcolor[e0] ); + RADEON_COLOR( (char *)&v[1]->ui[4], vbcolor[e1] ); + RADEON_COLOR( (char *)&v[2]->ui[4], vbcolor[e2] ); + } + } +#endif + +#if (IND & RADEON_OFFSET_BIT) + { + offset = ctx->Polygon.OffsetUnits * rmesa->depth_scale; + z[0] = v[0]->v.z; + z[1] = v[1]->v.z; + z[2] = v[2]->v.z; + if ( cc * cc > 1e-16 ) { + GLfloat ez = z[0] - z[2]; + GLfloat fz = z[1] - z[2]; + GLfloat a = ey*fz - ez*fy; + GLfloat b = ez*fx - ex*fz; + GLfloat ic = 1.0 / cc; + GLfloat ac = a * ic; + GLfloat bc = b * ic; + if ( ac < 0.0f ) ac = -ac; + if ( bc < 0.0f ) bc = -bc; + offset += MAX2( ac, bc ) * ctx->Polygon.OffsetFactor; + } + v[0]->v.z += offset; + v[1]->v.z += offset; + v[2]->v.z += offset; + } +#endif + } +#endif + + radeon_draw_triangle( rmesa, v[0], v[1], v[2] ); + +#if (IND & RADEON_OFFSET_BIT) + v[0]->v.z = z[0]; + v[1]->v.z = z[1]; + v[2]->v.z = z[2]; +#endif + +#if (IND & RADEON_TWOSIDE_BIT) + v[0]->ui[4] = c[0]; + v[1]->ui[4] = c[1]; + v[2]->ui[4] = c[2]; +#endif +} + + +static void TAG(quad)( GLcontext *ctx, + GLuint e0, GLuint e1, GLuint e2, GLuint e3, + GLuint pv ) +{ +#if 0 + TAG(triangle)( ctx, e0, e1, e3, pv ); + TAG(triangle)( ctx, e1, e2, e3, pv ); +#else + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct vertex_buffer *VB = ctx->VB; + radeonVertexPtr verts = RADEON_DRIVER_DATA(VB)->verts; + radeonVertexPtr v[4]; + +#if (IND & RADEON_OFFSET_BIT) + GLfloat offset; + GLfloat z[4]; +#endif + +#if (IND & RADEON_TWOSIDE_BIT) + int c[4]; +#endif + + v[0] = &verts[e0]; + v[1] = &verts[e1]; + v[2] = &verts[e2]; + v[3] = &verts[e3]; + +#if (IND & RADEON_TWOSIDE_BIT) + c[0] = v[0]->ui[4]; + c[1] = v[1]->ui[4]; + c[2] = v[2]->ui[4]; + c[3] = v[3]->ui[4]; +#endif + +#if (IND & (RADEON_TWOSIDE_BIT | RADEON_OFFSET_BIT)) + { + GLfloat ex = v[0]->v.x - v[2]->v.x; + GLfloat ey = v[0]->v.y - v[2]->v.y; + GLfloat fx = v[1]->v.x - v[2]->v.x; + GLfloat fy = v[1]->v.y - v[2]->v.y; + GLfloat cc = ex*fy - ey*fx; + +#if (IND & RADEON_TWOSIDE_BIT) + { + GLuint facing = ( cc > 0.0 ) ^ ctx->Polygon.FrontBit; + GLubyte (*vbcolor)[4] = VB->Color[facing]->data; + if ( IND & RADEON_FLAT_BIT ) { + RADEON_COLOR( (char *)&v[0]->ui[4], vbcolor[pv] ); + v[3]->ui[4] = v[2]->ui[4] = v[1]->ui[4] = v[0]->ui[4]; + } else { + RADEON_COLOR( (char *)&v[0]->ui[4], vbcolor[e0] ); + RADEON_COLOR( (char *)&v[1]->ui[4], vbcolor[e1] ); + RADEON_COLOR( (char *)&v[2]->ui[4], vbcolor[e2] ); + RADEON_COLOR( (char *)&v[3]->ui[4], vbcolor[e3] ); + } + } +#endif + +#if (IND & RADEON_OFFSET_BIT) + { + offset = ctx->Polygon.OffsetUnits * rmesa->depth_scale; + z[0] = v[0]->v.z; + z[1] = v[1]->v.z; + z[2] = v[2]->v.z; + z[3] = v[3]->v.z; + if ( cc * cc > 1e-16 ) { + GLfloat ez = z[0] - z[2]; + GLfloat fz = z[1] - z[2]; + GLfloat a = ey*fz - ez*fy; + GLfloat b = ez*fx - ex*fz; + GLfloat ic = 1.0 / cc; + GLfloat ac = a * ic; + GLfloat bc = b * ic; + if ( ac < 0.0f ) ac = -ac; + if ( bc < 0.0f ) bc = -bc; + offset += MAX2( ac, bc ) * ctx->Polygon.OffsetFactor; + } + v[0]->v.z += offset; + v[1]->v.z += offset; + v[2]->v.z += offset; + v[3]->v.z += offset; + } +#endif + } +#endif + + radeon_draw_quad( rmesa, v[0], v[1], v[2], v[3] ); + +#if (IND & RADEON_OFFSET_BIT) + v[0]->v.z = z[0]; + v[1]->v.z = z[1]; + v[2]->v.z = z[2]; + v[3]->v.z = z[3]; +#endif + +#if (IND & RADEON_TWOSIDE_BIT) + v[0]->ui[4] = c[0]; + v[1]->ui[4] = c[1]; + v[2]->ui[4] = c[2]; + v[3]->ui[4] = c[3]; +#endif +#endif +} + + +static void TAG(line)( GLcontext *ctx, + GLuint e0, GLuint e1, + GLuint pv ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct vertex_buffer *VB = ctx->VB; + radeonVertexPtr verts = RADEON_DRIVER_DATA(VB)->verts; + GLfloat width = ctx->Line.Width; + radeonVertexPtr v[2]; + +#if (IND & RADEON_OFFSET_BIT) + GLfloat offset; + GLfloat z[2]; +#endif +#if (IND & RADEON_TWOSIDE_BIT) + int c[2]; +#endif + + v[0] = &verts[e0]; + v[1] = &verts[e1]; + +#if (IND & RADEON_TWOSIDE_BIT) + c[0] = v[0]->ui[4]; + c[1] = v[1]->ui[4]; +#endif + +#if (IND & RADEON_TWOSIDE_BIT) + { + GLubyte (*vbcolor)[4] = ctx->VB->ColorPtr->data; + if ( IND & RADEON_FLAT_BIT ) { + RADEON_COLOR( (char *)&v[0]->ui[4], vbcolor[pv] ); + v[1]->ui[4] = v[0]->ui[4]; + } else { + RADEON_COLOR( (char *)&v[0]->ui[4], vbcolor[e0] ); + RADEON_COLOR( (char *)&v[1]->ui[4], vbcolor[e1] ); + } + } +#endif + +#if (IND & RADEON_OFFSET_BIT) + offset = ctx->LineZoffset * rmesa->depth_scale; + z[0] = v[0]->v.z; + z[1] = v[1]->v.z; + v[0]->v.z += offset; + v[1]->v.z += offset; +#endif + + radeon_draw_line( rmesa, v[0], v[1], width ); + +#if (IND & RADEON_OFFSET_BIT) + v[0]->v.z = z[0]; + v[1]->v.z = z[1]; +#endif + +#if (IND & RADEON_TWOSIDE_BIT) + v[0]->ui[4] = c[0]; + v[1]->ui[4] = c[1]; +#endif +} + + +static void TAG(points)( GLcontext *ctx, + GLuint first, GLuint last ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct vertex_buffer *VB = ctx->VB; + radeonVertexPtr verts = RADEON_DRIVER_DATA(VB)->verts; + GLfloat size = ctx->Point.Size * 0.5; + int i; + + for ( i = first ; i < last ; i++ ) { + if ( VB->ClipMask[i] == 0 ) { + if ( IND & (RADEON_TWOSIDE_BIT|RADEON_OFFSET_BIT) ) { + radeonVertex tmp0 = verts[i]; + + if ( IND & RADEON_TWOSIDE_BIT ) { + GLubyte (*vbcolor)[4] = VB->ColorPtr->data; + RADEON_COLOR( (char *)&tmp0.v.color, vbcolor[i] ); + } + if ( IND & RADEON_OFFSET_BIT ) { + GLfloat offset = ctx->PointZoffset * rmesa->depth_scale; + tmp0.v.z += offset; + } + radeon_draw_point( rmesa, &tmp0, size ); + } else { + radeon_draw_point( rmesa, &verts[i], size ); + } + } + } +} + + +static void TAG(init)( void ) +{ + rast_tab[IND].points = TAG(points); + rast_tab[IND].line = TAG(line); + rast_tab[IND].triangle = TAG(triangle); + rast_tab[IND].quad = TAG(quad); +} + +#undef IND +#undef TAG diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_vb.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_vb.c new file mode 100644 index 000000000..bdf19b2d6 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_vb.c @@ -0,0 +1,483 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_vb.c,v 1.2 2001/01/11 03:36:55 tsi Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_vb.h" + +#include "mem.h" +#include "stages.h" + +#define TEX0 \ +do { \ + v->v.tu0 = tc0[i][0]; \ + v->v.tv0 = tc0[i][1]; \ +} while (0) + +#define TEX1 \ +do { \ + v->v.tu1 = tc1[i][0]; \ + v->v.tv1 = tc1[i][1]; \ +} while (0) + +#define SPC \ +do { \ + GLubyte *spec = &(VB->Spec[0][i][0]); \ + v->v.specular.red = spec[0]; \ + v->v.specular.green = spec[1]; \ + v->v.specular.blue = spec[2]; \ +} while (0) + +#define FOG \ +do { \ + GLubyte *spec = &(VB->Spec[0][i][0]); \ + v->v.specular.alpha = spec[3]; \ +} while (0) + +#define COL \ +do { \ + GLubyte *col = &(VB->Color[0]->data[i][0]); \ + v->ui[4] = *(GLuint *)col; \ +} while (0) + +#define TEX0_4 \ +do { \ + if ( VB->TexCoordPtr[0]->size == 4 ) { \ + GLfloat (*tc)[4] = VB->TexCoordPtr[0]->data; \ + v = &(RADEON_DRIVER_DATA(VB)->verts[start]); \ + for ( i = start ; i < end ; i++, v++ ) { \ + float oow = 1.0 / tc[i][3]; \ + v->v.rhw *= tc[i][3]; \ + v->v.tu0 *= oow; \ + v->v.tv0 *= oow; \ + } \ + } \ +} while (0) + +#ifdef USE_RHW2 + +#define TEX1_4 \ +do { \ + if ( VB->TexCoordPtr[1]->size == 4 ) { \ + GLfloat (*tc)[4] = VB->TexCoordPtr[1]->data; \ + v = &(RADEON_DRIVER_DATA(VB)->verts[start]); \ + for ( i = start ; i < end ; i++, v++ ) { \ + float oow = 1.0 / tc[i][3]; \ + v->v.rhw2 *= tc[i][3]; \ + v->v.tu1 *= oow; \ + v->v.tv1 *= oow; \ + } \ + } \ +} while (0) + +#define COORD \ +do { \ + GLfloat *win = VB->Win.data[i]; \ + v->v.x = win[0]; \ + v->v.y = - win[1]; \ + v->v.z = win[2]; \ + v->v.rhw = v->v.rhw2 = win[3]; \ +} while (0) + +#else /* USE_RHW2 */ + +#define TEX1_4 + +#define COORD \ +do { \ + GLfloat *win = VB->Win.data[i]; \ + v->v.x = win[0]; \ + v->v.y = - win[1]; \ + v->v.z = win[2]; \ + v->v.rhw = win[3]; \ +} while (0) \ + +#endif /* USE_RHW2 */ + +#define NOP + + +#define SETUPFUNC(name,win,col,tex0,tex1,tex0_4,tex1_4,spec,fog) \ +static void name( struct vertex_buffer *VB, GLuint start, GLuint end ) \ +{ \ + radeonContextPtr rmesa = RADEON_CONTEXT(VB->ctx); \ + radeonVertexPtr v; \ + GLfloat (*tc0)[4]; \ + GLfloat (*tc1)[4]; \ + GLint i; \ + \ + gl_import_client_data( VB, VB->ctx->RenderFlags, \ + (VB->ClipOrMask \ + ? VEC_WRITABLE | VEC_GOOD_STRIDE \ + : VEC_GOOD_STRIDE) ); \ + \ + tc0 = VB->TexCoordPtr[rmesa->tmu_source[0]]->data; \ + tc1 = VB->TexCoordPtr[rmesa->tmu_source[1]]->data; \ + \ + v = &(RADEON_DRIVER_DATA(VB)->verts[start]); \ + \ + if ( VB->ClipOrMask == 0 ) { \ + for ( i = start ; i < end ; i++, v++ ) { \ + win; \ + col; \ + spec; \ + fog; \ + tex0; \ + tex1; \ + } \ + } else { \ + for ( i = start ; i < end ; i++, v++ ) { \ + if ( VB->ClipMask[i] == 0 ) { \ + win; \ + spec; \ + fog; \ + tex0; \ + tex1; \ + } \ + col; \ + } \ + } \ + tex0_4; \ + tex1_4; \ +} + + +SETUPFUNC(rs_wt0, COORD, NOP, TEX0, NOP, TEX0_4, NOP, NOP, NOP) +SETUPFUNC(rs_wt0t1, COORD, NOP, TEX0, TEX1, TEX0_4, TEX1_4, NOP, NOP) +SETUPFUNC(rs_wft0, COORD, NOP, TEX0, NOP, TEX0_4, NOP, NOP, FOG) +SETUPFUNC(rs_wft0t1, COORD, NOP, TEX0, TEX1, TEX0_4, TEX1_4, NOP, FOG) +SETUPFUNC(rs_wg, COORD, COL, NOP, NOP, NOP, NOP, NOP, NOP) +SETUPFUNC(rs_wgs, COORD, COL, NOP, NOP, NOP, NOP, SPC, NOP) +SETUPFUNC(rs_wgt0, COORD, COL, TEX0, NOP, TEX0_4, NOP, NOP, NOP) +SETUPFUNC(rs_wgt0t1, COORD, COL, TEX0, TEX1, TEX0_4, TEX1_4, NOP, NOP) +SETUPFUNC(rs_wgst0, COORD, COL, TEX0, NOP, TEX0_4, NOP, SPC, NOP) +SETUPFUNC(rs_wgst0t1, COORD, COL, TEX0, TEX1, TEX0_4, TEX1_4, SPC, NOP) +SETUPFUNC(rs_wgf, COORD, COL, NOP, NOP, NOP, NOP, NOP, FOG) +SETUPFUNC(rs_wgfs, COORD, COL, NOP, NOP, NOP, NOP, SPC, FOG) +SETUPFUNC(rs_wgft0, COORD, COL, TEX0, NOP, TEX0_4, NOP, NOP, FOG) +SETUPFUNC(rs_wgft0t1, COORD, COL, TEX0, TEX1, TEX0_4, TEX1_4, NOP, FOG) +SETUPFUNC(rs_wgfst0, COORD, COL, TEX0, NOP, TEX0_4, NOP, SPC, FOG) +SETUPFUNC(rs_wgfst0t1, COORD, COL, TEX0, TEX1, TEX0_4, TEX1_4, SPC, FOG) + +SETUPFUNC(rs_t0, NOP, NOP, TEX0, NOP, TEX0_4, NOP, NOP, NOP) +SETUPFUNC(rs_t0t1, NOP, NOP, TEX0, TEX1, TEX0_4, TEX1_4, NOP, NOP) +SETUPFUNC(rs_f, NOP, NOP, NOP, NOP, NOP, NOP, NOP, FOG) +SETUPFUNC(rs_ft0, NOP, NOP, TEX0, NOP, TEX0_4, NOP, NOP, FOG) +SETUPFUNC(rs_ft0t1, NOP, NOP, TEX0, TEX1, TEX0_4, TEX1_4, NOP, FOG) +SETUPFUNC(rs_g, NOP, COL, NOP, NOP, NOP, NOP, NOP, NOP) +SETUPFUNC(rs_gs, NOP, COL, NOP, NOP, NOP, NOP, SPC, NOP) +SETUPFUNC(rs_gt0, NOP, COL, TEX0, NOP, TEX0_4, NOP, NOP, NOP) +SETUPFUNC(rs_gt0t1, NOP, COL, TEX0, TEX1, TEX0_4, TEX1_4, NOP, NOP) +SETUPFUNC(rs_gst0, NOP, COL, TEX0, NOP, TEX0_4, NOP, SPC, NOP) +SETUPFUNC(rs_gst0t1, NOP, COL, TEX0, TEX1, TEX0_4, TEX1_4, SPC, NOP) +SETUPFUNC(rs_gf, NOP, COL, NOP, NOP, NOP, NOP, NOP, FOG) +SETUPFUNC(rs_gfs, NOP, COL, NOP, NOP, NOP, NOP, SPC, FOG) +SETUPFUNC(rs_gft0, NOP, COL, TEX0, NOP, TEX0_4, NOP, NOP, FOG) +SETUPFUNC(rs_gft0t1, NOP, COL, TEX0, TEX1, TEX0_4, TEX1_4, NOP, FOG) +SETUPFUNC(rs_gfst0, NOP, COL, TEX0, NOP, TEX0_4, NOP, SPC, FOG) +SETUPFUNC(rs_gfst0t1, NOP, COL, TEX0, TEX1, TEX0_4, TEX1_4, SPC, FOG) + + +static void rs_invalid( struct vertex_buffer *VB, GLuint start, GLuint end ) +{ + fprintf( stderr, "radeonRasterSetup(): invalid setup function\n" ); +} + +typedef void (*setupFunc)( struct vertex_buffer *, GLuint, GLuint ); +static setupFunc setup_func[RADEON_MAX_SETUPFUNC]; + + +void radeonDDSetupInit( void ) +{ + GLint i; + + for ( i = 0 ; i < RADEON_MAX_SETUPFUNC ; i++ ) { + setup_func[i] = rs_invalid; + } + + /* Functions to build vertices from scratch + */ + setup_func[RADEON_WIN_BIT|RADEON_TEX0_BIT] = rs_wt0; + setup_func[RADEON_WIN_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_wt0t1; + setup_func[RADEON_WIN_BIT|RADEON_FOG_BIT|RADEON_TEX0_BIT] = rs_wft0; + setup_func[RADEON_WIN_BIT|RADEON_FOG_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_wft0t1; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT] = rs_wg; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT] = rs_wgs; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT] = rs_wgt0; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_wgt0t1; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT] = rs_wgst0; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_wgst0t1; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_FOG_BIT] = rs_wgf; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_SPEC_BIT] = rs_wgfs; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_TEX0_BIT] = rs_wgft0; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_wgft0t1; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT] = rs_wgfst0; + setup_func[RADEON_WIN_BIT|RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_wgfst0t1; + + /* Repair functions + */ + setup_func[RADEON_TEX0_BIT] = rs_t0; + setup_func[RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_t0t1; + setup_func[RADEON_FOG_BIT] = rs_f; + setup_func[RADEON_FOG_BIT|RADEON_TEX0_BIT] = rs_ft0; + setup_func[RADEON_FOG_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_ft0t1; + setup_func[RADEON_RGBA_BIT] = rs_g; + setup_func[RADEON_RGBA_BIT|RADEON_SPEC_BIT] = rs_gs; + setup_func[RADEON_RGBA_BIT|RADEON_TEX0_BIT] = rs_gt0; + setup_func[RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_gt0t1; + setup_func[RADEON_RGBA_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT] = rs_gst0; + setup_func[RADEON_RGBA_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_gst0t1; + setup_func[RADEON_RGBA_BIT|RADEON_FOG_BIT] = rs_gf; + setup_func[RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_SPEC_BIT] = rs_gfs; + setup_func[RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_TEX0_BIT] = rs_gft0; + setup_func[RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_gft0t1; + setup_func[RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT] = rs_gfst0; + setup_func[RADEON_RGBA_BIT|RADEON_FOG_BIT|RADEON_SPEC_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT] = rs_gfst0t1; +} + + +void radeonPrintSetupFlags( char *msg, GLuint flags ) +{ + fprintf( stderr, "%s: %d %s%s%s%s%s%s\n", + msg, + (int)flags, + (flags & RADEON_WIN_BIT) ? " xyzw," : "", + (flags & RADEON_RGBA_BIT) ? " rgba," : "", + (flags & RADEON_SPEC_BIT) ? " spec," : "", + (flags & RADEON_FOG_BIT) ? " fog," : "", + (flags & RADEON_TEX0_BIT) ? " tex-0," : "", + (flags & RADEON_TEX1_BIT) ? " tex-1," : "" ); +} + + +/* Initialize the vertex buffer setup functions based on the current + * rendering state. + */ +void radeonDDChooseRasterSetupFunc( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + GLint index = RADEON_WIN_BIT | RADEON_RGBA_BIT; + + rmesa->vertsize = 8; + rmesa->vc_format = RADEON_TEX0_VERTEX_FORMAT; + rmesa->tmu_source[0] = 0; + rmesa->tmu_source[1] = 1; + rmesa->tex_dest[0] = RADEON_TEX0_BIT; + rmesa->tex_dest[1] = RADEON_TEX1_BIT; + rmesa->multitex = 0; + + if ( ctx->Texture.ReallyEnabled & ENABLE_TEX0 ) { + index |= RADEON_TEX0_BIT; + } + + if ( ctx->Texture.ReallyEnabled & ENABLE_TEX1 ) { + if ( ctx->Texture.ReallyEnabled & ENABLE_TEX0 ) { + rmesa->multitex = 1; + rmesa->vertsize = 10; + rmesa->vc_format = RADEON_TEX1_VERTEX_FORMAT; + index |= RADEON_TEX1_BIT; + } else { + /* Just a funny way of doing single texturing. + */ + rmesa->tmu_source[0] = 1; + rmesa->tex_dest[1] = RADEON_TEX0_BIT; + index |= RADEON_TEX0_BIT; + } + } + + if ( ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR ) + index |= RADEON_SPEC_BIT; + + if ( ctx->Fog.Enabled ) + index |= RADEON_FOG_BIT; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_MSG ) { + radeonPrintSetupFlags( "full setup function", index ); + } + + rmesa->new_state |= RADEON_NEW_TEXTURE; + rmesa->SetupIndex = index; + + ctx->Driver.RasterSetup = setup_func[index]; +} + +/* Check to see if any updates of the vertex buffer entries are needed. + */ +void radeonDDCheckPartialRasterSetup( GLcontext *ctx, + struct gl_pipeline_stage *s ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLint tmp = rmesa->SetupDone; + + s->type = 0; + rmesa->SetupDone = 0; + + if ( (ctx->Array.Summary & VERT_OBJ_ANY) == 0 ) + return; + + if ( ctx->IndirectTriangles ) + return; + + rmesa->SetupDone = tmp; +} + +/* Repair existing precalculated vertices with new data. + */ +void radeonDDPartialRasterSetup( struct vertex_buffer *VB ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(VB->ctx); + GLuint new = VB->pipeline->new_outputs; + GLuint available = VB->pipeline->outputs; + GLuint index = 0; + + if ( new & VERT_WIN ) { + new = available; + index |= RADEON_WIN_BIT | RADEON_FOG_BIT; + } + + if ( new & VERT_RGBA ) + index |= RADEON_RGBA_BIT | RADEON_SPEC_BIT; + + if ( new & VERT_TEX0_ANY ) + index |= RADEON_TEX0_BIT; + + if ( new & VERT_TEX1_ANY ) + index |= rmesa->tex_dest[1]; + + if ( new & VERT_FOG_COORD ) + index |= RADEON_FOG_BIT; + + rmesa->SetupDone &= ~index; + index &= rmesa->SetupIndex; + rmesa->SetupDone |= index; + + if ( RADEON_DEBUG & DEBUG_VERBOSE_MSG ) + radeonPrintSetupFlags( "partial setup function", index ); + + if ( index ) + setup_func[index]( VB, VB->Start, VB->Count ); +} + +void radeonDDDoRasterSetup( struct vertex_buffer *VB ) +{ + GLcontext *ctx = VB->ctx; + + if ( VB->Type == VB_CVA_PRECALC ) { + radeonDDPartialRasterSetup( VB ); + } else if ( ctx->Driver.RasterSetup ) { + ctx->Driver.RasterSetup( VB, VB->CopyStart, VB->Count ); + } +} + + +/* ================================================================ + * Hardware-format vertex buffers + */ + +void radeonDDResizeVB( struct vertex_buffer *VB, GLuint size ) +{ + radeonVertexBufferPtr rvb = RADEON_DRIVER_DATA(VB); + + while ( rvb->size < size ) + rvb->size *= 2; + + ALIGN_FREE( rvb->vert_store ); + rvb->vert_store = ALIGN_MALLOC( sizeof(radeonVertex) * rvb->size, 32 ); + if ( !rvb->vert_store ) { + fprintf( stderr, "Cannot allocate vertex store! Exiting...\n" ); + exit( 1 ); + } + + rvb->verts = (radeonVertexPtr)rvb->vert_store; + + gl_vector1ui_free( &rvb->clipped_elements ); + gl_vector1ui_alloc( &rvb->clipped_elements, VEC_WRITABLE, rvb->size, 32 ); + if ( !rvb->clipped_elements.start ) { + fprintf( stderr, "Cannot allocate clipped elements! Exiting...\n" ); + exit( 1 ); + } + + ALIGN_FREE( VB->ClipMask ); + VB->ClipMask = (GLubyte *)ALIGN_MALLOC( sizeof(GLubyte) * rvb->size, 32 ); + if ( !VB->ClipMask ) { + fprintf( stderr, "Cannot allocate clipmask! Exiting...\n" ); + exit( 1 ); + } +} + +void radeonDDRegisterVB( struct vertex_buffer *VB ) +{ + radeonVertexBufferPtr rvb; + + rvb = (radeonVertexBufferPtr)CALLOC( sizeof(*rvb) ); + + rvb->size = VB->Size * 2; + rvb->vert_store = ALIGN_MALLOC( sizeof(radeonVertex) * rvb->size, 32 ); + if ( !rvb->vert_store ) { + fprintf( stderr, "Cannot allocate vertex store! Exiting...\n" ); + exit( 1 ); + } + + rvb->verts = (radeonVertexPtr)rvb->vert_store; + + gl_vector1ui_alloc( &rvb->clipped_elements, VEC_WRITABLE, rvb->size, 32 ); + if ( !rvb->clipped_elements.start ) { + fprintf( stderr, "Cannot allocate clipped elements! Exiting...\n" ); + exit( 1 ); + } + + ALIGN_FREE( VB->ClipMask ); + VB->ClipMask = (GLubyte *)ALIGN_MALLOC( sizeof(GLubyte) * rvb->size, 32 ); + if ( !VB->ClipMask ) { + fprintf( stderr, "Cannot allocate clipmask! Exiting...\n" ); + exit( 1 ); + } + + VB->driver_data = rvb; +} + +void radeonDDUnregisterVB( struct vertex_buffer *VB ) +{ + radeonVertexBufferPtr rvb = RADEON_DRIVER_DATA(VB); + + if ( rvb ) { + if ( rvb->vert_store ) ALIGN_FREE( rvb->vert_store ); + gl_vector1ui_free( &rvb->clipped_elements ); + FREE( rvb ); + VB->driver_data = 0; + } +} diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_vb.h b/xc/lib/GL/mesa/src/drv/radeon/radeon_vb.h new file mode 100644 index 000000000..bd809efbb --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_vb.h @@ -0,0 +1,136 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_vb.h,v 1.1 2001/01/08 01:07:29 martin Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_VB_H__ +#define __RADEON_VB_H__ + +#ifdef GLX_DIRECT_RENDERING + +/* FIXME: This is endian-specific */ +typedef struct { + GLubyte red; + GLubyte green; + GLubyte blue; + GLubyte alpha; +} radeon_color_t; + +/* The vertex structure. The final tu1/tv1 values are only used in + * multitexture modes, and the rhw2 value is currently never used. + */ +typedef struct { + GLfloat x, y, z; /* Coordinates in screen space */ + GLfloat rhw; /* Reciprocal homogeneous w */ + radeon_color_t color; /* Diffuse color */ + radeon_color_t specular; /* Specular color (alpha is fog) */ + GLfloat tu0, tv0; /* Texture 0 coordinates */ + GLfloat tu1, tv1; /* Texture 1 coordinates */ + GLfloat rhw2; /* Reciprocal homogeneous w2 */ +} radeon_vertex; + +/* Format of vertices in radeon_vertex struct: + */ +#define RADEON_TEX0_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_W0 | \ + RADEON_CP_VC_FRMT_PKCOLOR | \ + RADEON_CP_VC_FRMT_PKSPEC | \ + RADEON_CP_VC_FRMT_ST0) + +#define RADEON_TEX1_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_W0 | \ + RADEON_CP_VC_FRMT_PKCOLOR | \ + RADEON_CP_VC_FRMT_PKSPEC | \ + RADEON_CP_VC_FRMT_ST0 | \ + RADEON_CP_VC_FRMT_ST1) + +#if 0 +#define RADEON_PROJ_TEX1_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_W0 | \ + RADEON_CP_VC_FRMT_PKCOLOR | \ + RADEON_CP_VC_FRMT_PKSPEC | \ + RADEON_CP_VC_FRMT_ST0 | \ + RADEON_CP_VC_FRMT_ST1 | \ + RADEON_CP_VC_FRMT_Q1) +#endif + + +/* The fastpath code still expects a 16-float stride vertex. + */ +union radeon_vertex_t { + radeon_vertex v; + GLfloat f[16]; + GLuint ui[16]; +}; + +typedef union radeon_vertex_t radeonVertex; +typedef union radeon_vertex_t *radeonVertexPtr; + +typedef struct { + radeonVertexPtr verts; + GLvector1ui clipped_elements; + GLint last_vert; + void *vert_store; + GLuint size; +} *radeonVertexBufferPtr; + +#define RADEON_DRIVER_DATA(vb) ((radeonVertexBufferPtr)((vb)->driver_data)) + +#define RADEON_WIN_BIT 0x01 +#define RADEON_RGBA_BIT 0x02 +#define RADEON_FOG_BIT 0x04 +#define RADEON_SPEC_BIT 0x08 +#define RADEON_TEX0_BIT 0x10 +#define RADEON_TEX1_BIT 0x20 +#define RADEON_MAX_SETUPFUNC 0x40 + +extern void radeonDDChooseRasterSetupFunc( GLcontext *ctx ); +extern void radeonPrintSetupFlags( char *msg, GLuint flags ); + +extern void radeonDDCheckPartialRasterSetup( GLcontext *ctx, + struct gl_pipeline_stage *s ); +extern void radeonDDPartialRasterSetup( struct vertex_buffer *VB ); +extern void radeonDDDoRasterSetup( struct vertex_buffer *VB ); + +extern void radeonDDResizeVB( struct vertex_buffer *VB, GLuint size ); +extern void radeonDDRegisterVB( struct vertex_buffer *VB ); +extern void radeonDDUnregisterVB( struct vertex_buffer *VB ); + +extern void radeonDDSetupInit( void ); + +#endif +#endif /* __RADEON_VB_H__ */ diff --git a/xc/lib/GL/mesa/src/drv/radeon/radeon_xmesa.c b/xc/lib/GL/mesa/src/drv/radeon/radeon_xmesa.c new file mode 100644 index 000000000..1f24b8409 --- /dev/null +++ b/xc/lib/GL/mesa/src/drv/radeon/radeon_xmesa.c @@ -0,0 +1,314 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_xmesa.c,v 1.2 2001/01/23 18:14:39 alanh Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifdef GLX_DIRECT_RENDERING + +/* Radeon Mesa driver includes */ +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_tex.h" + +/* Mesa src includes */ +#include "context.h" +#include "simple_list.h" +#include "mmath.h" + +extern void __driRegisterExtensions( void ); + +static radeonContextPtr radeonCtx = NULL; + + +/* Initialize the driver specific screen private data. + */ +GLboolean XMesaInitDriver( __DRIscreenPrivate *sPriv ) +{ + sPriv->private = (void *) radeonCreateScreen( sPriv ); + + /* Check the DRI version */ + { + int major, minor, patch; + if (XF86DRIQueryVersion(sPriv->display, &major, &minor, &patch)) { + if (major != 3 || minor != 1 || patch < 0) { + char msg[1000]; + sprintf(msg, "RADEON DRI driver expected DRI version 3.1.x but got version %d.%d.%d", major, minor, patch); + __driMesaMessage(msg); + return GL_FALSE; + } + } + } + + /* Check that the DDX driver version is compatible */ + if (sPriv->ddxMajor != 4 || + sPriv->ddxMinor != 0 || + sPriv->ddxPatch < 0) { + char msg[1000]; + sprintf(msg, "RADEON DRI driver expected DDX driver version 4.0.x but got version %d.%d.%d", sPriv->ddxMajor, sPriv->ddxMinor, sPriv->ddxPatch); + __driMesaMessage(msg); + return GL_FALSE; + } + + /* Check that the DRM driver version is compatible */ + if (sPriv->drmMajor != 1 || + sPriv->drmMinor != 0 || + sPriv->drmPatch < 0) { + char msg[1000]; + sprintf(msg, "RADEON DRI driver expected DRM driver version 1.0.x but got version %d.%d.%d", sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch); + __driMesaMessage(msg); + return GL_FALSE; + } + + if ( !sPriv->private ) { + radeonDestroyScreen( sPriv ); + return GL_FALSE; + } + + return GL_TRUE; +} + +/* Reset the driver specific screen private data. + */ +void XMesaResetDriver( __DRIscreenPrivate *sPriv ) +{ + radeonDestroyScreen( sPriv ); +} + +/* Create and initialize the Mesa and driver specific visual data. + */ +GLvisual *XMesaCreateVisual( Display *dpy, + __DRIscreenPrivate *driScrnPriv, + const XVisualInfo *visinfo, + const __GLXvisualConfig *config ) +{ + /* Drivers may change the args to _mesa_create_visual() in order to + * setup special visuals. + */ + return _mesa_create_visual( config->rgba, + config->doubleBuffer, + config->stereo, + _mesa_bitcount( visinfo->red_mask ), + _mesa_bitcount( visinfo->green_mask ), + _mesa_bitcount( visinfo->blue_mask ), + config->alphaSize, + 0, /* index bits */ + config->depthSize, + config->stencilSize, + config->accumRedSize, + config->accumGreenSize, + config->accumBlueSize, + config->accumAlphaSize, + 0 /* num samples */); +} + +/* Create and initialize the Mesa and driver specific context data. + */ +GLboolean XMesaCreateContext( Display *dpy, GLvisual *mesaVis, + __DRIcontextPrivate *driContextPriv ) +{ + return radeonCreateContext( dpy, mesaVis, driContextPriv ); +} + +/* Destroy the Mesa and driver specific context data. + */ +void XMesaDestroyContext( __DRIcontextPrivate *driContextPriv ) +{ + radeonContextPtr rmesa = (radeonContextPtr)driContextPriv->driverPrivate; + + if ( rmesa == (void *)radeonCtx) radeonCtx = NULL; + radeonDestroyContext( rmesa ); +} + +/* Create and initialize the Mesa and driver specific pixmap buffer + * data. + */ +GLframebuffer *XMesaCreateWindowBuffer( Display *dpy, + __DRIscreenPrivate *driScrnPriv, + __DRIdrawablePrivate *driDrawPriv, + GLvisual *mesaVis ) +{ + return gl_create_framebuffer( mesaVis, + GL_FALSE, /* software depth buffer? */ + mesaVis->StencilBits > 0, + mesaVis->AccumRedBits > 0, + GL_FALSE /* software alpha buffer? */ ); +} + +/* Create and initialize the Mesa and driver specific pixmap buffer + * data. + */ +GLframebuffer *XMesaCreatePixmapBuffer( Display *dpy, + __DRIscreenPrivate *driScrnPriv, + __DRIdrawablePrivate *driDrawPriv, + GLvisual *mesaVis ) +{ +#if 0 + /* Different drivers may have different combinations of hardware and + * software ancillary buffers. + */ + return gl_create_framebuffer( mesaVis, + GL_FALSE, /* software depth buffer? */ + mesaVis->StencilBits > 0, + mesaVis->AccumRedBits > 0, + mesaVis->AlphaBits > 0 ); +#else + return NULL; /* not implemented yet */ +#endif +} + +/* Copy the back color buffer to the front color buffer. + */ +void XMesaSwapBuffers( __DRIdrawablePrivate *driDrawPriv ) +{ + /* FIXME: This assumes buffer is currently bound to a context. This + * needs to be able to swap buffers when not currently bound. Also, + * this needs to swap according to buffer, and NOT according to + * context! + */ + if ( radeonCtx == NULL ) return; + + /* Only swap buffers when a back buffer exists. + */ + if ( radeonCtx->glCtx->Visual->DBflag ) { + FLUSH_VB( radeonCtx->glCtx, "swap buffers" ); + if ( !radeonCtx->doPageFlip ) { + radeonSwapBuffers( radeonCtx ); + } else { + radeonPageFlip( radeonCtx ); + } + } +} + +/* Force the context `c' to be the current context and associate with it + * buffer `b'. + */ +GLboolean XMesaMakeCurrent( __DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv ) +{ + if ( driContextPriv ) { + radeonContextPtr rmesa = (radeonContextPtr)driContextPriv->driverPrivate; + + radeonCtx = radeonMakeCurrent( radeonCtx, rmesa, driDrawPriv ); + + gl_make_current2( radeonCtx->glCtx, + driDrawPriv->mesaBuffer, + driReadPriv->mesaBuffer ); + + if ( radeonCtx->driDrawable != driDrawPriv ) { + radeonCtx->driDrawable = driDrawPriv; + radeonCtx->dirty = RADEON_UPLOAD_ALL; + } + + /* GH: We need this to correctly calculate the window offset + * and aux scissor rects. + */ + radeonCtx->new_state = RADEON_NEW_WINDOW | RADEON_NEW_CLIP; + + if ( !radeonCtx->glCtx->Viewport.Width ) { + gl_Viewport( radeonCtx->glCtx, 0, 0, driDrawPriv->w, driDrawPriv->h ); + } + } else { + gl_make_current( 0, 0 ); + radeonCtx = NULL; + } + + return GL_TRUE; +} + +/* Force the context `c' to be unbound from its buffer. + */ +GLboolean XMesaUnbindContext( __DRIcontextPrivate *driContextPriv ) +{ + return GL_TRUE; +} + +/* This function is called by libGL.so as soon as libGL.so is loaded. + * This is where we'd register new extension functions with the dispatcher. + */ +void __driRegisterExtensions( void ) +{ +} + +/* Initialize the fullscreen mode. + */ +GLboolean +XMesaOpenFullScreen( __DRIcontextPrivate *driContextPriv ) +{ + radeonContextPtr rmesa = (radeonContextPtr)driContextPriv->driverPrivate; + GLint ret; + + /* FIXME: Do we need to check this? + */ + if ( !radeonCtx->glCtx->Visual->DBflag ) + return GL_TRUE; + + LOCK_HARDWARE( rmesa ); + radeonWaitForIdleLocked( rmesa ); + + /* Ignore errors. If this fails, we simply don't do page flipping. + */ + ret = drmRadeonFullScreen( rmesa->driFd, GL_TRUE ); + + UNLOCK_HARDWARE( rmesa ); + + rmesa->doPageFlip = ( ret == 0 ); + + return GL_TRUE; +} + +/* Shut down the fullscreen mode. + */ +GLboolean +XMesaCloseFullScreen( __DRIcontextPrivate *driContextPriv ) +{ + radeonContextPtr rmesa = (radeonContextPtr)driContextPriv->driverPrivate; + + LOCK_HARDWARE( rmesa ); + radeonWaitForIdleLocked( rmesa ); + + /* Don't care if this fails, we're not page flipping anymore. + */ + drmRadeonFullScreen( rmesa->driFd, GL_FALSE ); + + UNLOCK_HARDWARE( rmesa ); + + rmesa->doPageFlip = GL_FALSE; + rmesa->currentPage = 0; + + return GL_TRUE; +} + +#endif |