diff options
author | Luc Verhaegen <libv@skynet.be> | 2010-03-09 07:31:48 +0100 |
---|---|---|
committer | Luc Verhaegen <libv@skynet.be> | 2010-03-09 07:31:48 +0100 |
commit | 6f692a811778c3481b404e9c9a2d68504c39af08 (patch) | |
tree | a1ee6fe7581f8127dcadbf7d4189491718dc3cb6 /src | |
parent | 5dee9b7b19c1aa3a13618b08bc24f00677b5364b (diff) |
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 23 | ||||
-rw-r--r-- | src/mach64_context.c | 361 | ||||
-rw-r--r-- | src/mach64_context.h | 364 | ||||
-rw-r--r-- | src/mach64_dd.c | 134 | ||||
-rw-r--r-- | src/mach64_dd.h | 36 | ||||
-rw-r--r-- | src/mach64_ioctl.c | 932 | ||||
-rw-r--r-- | src/mach64_ioctl.h | 148 | ||||
-rw-r--r-- | src/mach64_lock.c | 96 | ||||
-rw-r--r-- | src/mach64_lock.h | 104 | ||||
-rw-r--r-- | src/mach64_native_vb.c | 257 | ||||
-rw-r--r-- | src/mach64_native_vbtmp.h | 562 | ||||
-rw-r--r-- | src/mach64_reg.h | 406 | ||||
-rw-r--r-- | src/mach64_screen.c | 557 | ||||
-rw-r--r-- | src/mach64_screen.h | 78 | ||||
-rw-r--r-- | src/mach64_span.c | 169 | ||||
-rw-r--r-- | src/mach64_span.h | 41 | ||||
-rw-r--r-- | src/mach64_state.c | 1189 | ||||
-rw-r--r-- | src/mach64_state.h | 47 | ||||
-rw-r--r-- | src/mach64_tex.c | 567 | ||||
-rw-r--r-- | src/mach64_tex.h | 89 | ||||
-rw-r--r-- | src/mach64_texmem.c | 506 | ||||
-rw-r--r-- | src/mach64_texstate.c | 525 | ||||
-rw-r--r-- | src/mach64_tris.c | 1924 | ||||
-rw-r--r-- | src/mach64_tris.h | 43 | ||||
-rw-r--r-- | src/mach64_vb.c | 642 | ||||
-rw-r--r-- | src/mach64_vb.h | 77 | ||||
-rw-r--r-- | src/mach64_vbtmp.h | 770 | ||||
-rw-r--r-- | src/server/mach64_dri.h | 126 |
28 files changed, 10768 insertions, 5 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index aa854c5..5591852 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,20 @@ AM_CFLAGS = -DIN_DRI_DRIVER -DGLX_DIRECT_RENDERING -DGLX_INDIRECT_RENDERING -xxx_dri_la_LTLIBRARIES = xxx_dri.la -xxx_dri_la_CFLAGS = $(AM_CFLAGS) $(DRM_CFLAGS) $(DRI_CFLAGS) -Iserver -xxx_dri_la_LDFLAGS = -module -noprefix -lm -ldl $(DRM_LIBS) $(DRI_LIBS) -xxx_dri_ladir = @libdir@/dri -xxx_dri_la_SOURCES = \ +mach64_dri_la_LTLIBRARIES = mach64_dri.la +mach64_dri_la_CFLAGS = $(AM_CFLAGS) $(DRM_CFLAGS) $(DRI_CFLAGS) -Iserver +mach64_dri_la_LDFLAGS = -module -noprefix -avoid-version -lm -ldl \ + $(DRM_LIBS) $(DRI_LIBS) +mach64_dri_ladir = @libdir@/dri +mach64_dri_la_SOURCES = \ + mach64_context.c \ + mach64_ioctl.c \ + mach64_screen.c \ + mach64_span.c \ + mach64_state.c \ + mach64_tex.c \ + mach64_texmem.c \ + mach64_texstate.c \ + mach64_tris.c \ + mach64_vb.c \ + mach64_dd.c \ + mach64_lock.c diff --git a/src/mach64_context.c b/src/mach64_context.c new file mode 100644 index 0000000..ad661e1 --- /dev/null +++ b/src/mach64_context.c @@ -0,0 +1,361 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * Jos�Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "glheader.h" +#include "context.h" +#include "simple_list.h" +#include "imports.h" +#include "matrix.h" +#include "extensions.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "vbo/vbo.h" + +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" + +#include "drivers/common/driverfuncs.h" + +#include "mach64_context.h" +#include "mach64_ioctl.h" +#include "mach64_dd.h" +#include "mach64_span.h" +#include "mach64_state.h" +#include "mach64_tex.h" +#include "mach64_tris.h" +#include "mach64_vb.h" + +#include "utils.h" +#include "vblank.h" + +#define need_GL_ARB_multisample +#define need_GL_ARB_vertex_buffer_object +#include "extension_helper.h" + +#ifndef MACH64_DEBUG +int MACH64_DEBUG = (0); +#endif + +static const struct dri_debug_control debug_control[] = +{ + { "sync", DEBUG_ALWAYS_SYNC }, + { "api", DEBUG_VERBOSE_API }, + { "msg", DEBUG_VERBOSE_MSG }, + { "lru", DEBUG_VERBOSE_LRU }, + { "dri", DEBUG_VERBOSE_DRI }, + { "ioctl", DEBUG_VERBOSE_IOCTL }, + { "prims", DEBUG_VERBOSE_PRIMS }, + { "count", DEBUG_VERBOSE_COUNT }, + { "nowait", DEBUG_NOWAIT }, + { "fall", DEBUG_VERBOSE_FALLBACK }, + { NULL, 0 } +}; + +const struct dri_extension card_extensions[] = +{ + { "GL_ARB_multisample", GL_ARB_multisample_functions }, + { "GL_ARB_multitexture", NULL }, + { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions }, + { "GL_EXT_texture_edge_clamp", NULL }, + { "GL_MESA_ycbcr_texture", NULL }, + { "GL_SGIS_generate_mipmap", NULL }, + { NULL, NULL } +}; + + +/* Create the device specific context. + */ +GLboolean mach64CreateContext( const __GLcontextModes *glVisual, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate ) +{ + GLcontext *ctx, *shareCtx; + __DRIscreenPrivate *driScreen = driContextPriv->driScreenPriv; + struct dd_function_table functions; + mach64ContextPtr mmesa; + mach64ScreenPtr mach64Screen; + int i, heap; + GLuint *c_textureSwapsPtr = NULL; + +#if DO_DEBUG + MACH64_DEBUG = driParseDebugString(getenv("MACH64_DEBUG"), debug_control); +#endif + + /* Allocate the mach64 context */ + mmesa = (mach64ContextPtr) CALLOC( sizeof(*mmesa) ); + if ( !mmesa ) + return GL_FALSE; + + /* Init default driver functions then plug in our Mach64-specific functions + * (the texture functions are especially important) + */ + _mesa_init_driver_functions( &functions ); + mach64InitDriverFuncs( &functions ); + mach64InitIoctlFuncs( &functions ); + mach64InitTextureFuncs( &functions ); + + /* Allocate the Mesa context */ + if (sharedContextPrivate) + shareCtx = ((mach64ContextPtr) sharedContextPrivate)->glCtx; + else + shareCtx = NULL; + mmesa->glCtx = _mesa_create_context(glVisual, shareCtx, + &functions, (void *)mmesa); + if (!mmesa->glCtx) { + FREE(mmesa); + return GL_FALSE; + } + driContextPriv->driverPrivate = mmesa; + ctx = mmesa->glCtx; + + mmesa->driContext = driContextPriv; + mmesa->driScreen = driScreen; + mmesa->driDrawable = NULL; + mmesa->hHWContext = driContextPriv->hHWContext; + mmesa->driHwLock = &driScreen->pSAREA->lock; + mmesa->driFd = driScreen->fd; + + mach64Screen = mmesa->mach64Screen = (mach64ScreenPtr)driScreen->private; + + /* Parse configuration files */ + driParseConfigFiles (&mmesa->optionCache, &mach64Screen->optionCache, + mach64Screen->driScreen->myNum, "mach64"); + + mmesa->sarea = (drm_mach64_sarea_t *)((char *)driScreen->pSAREA + + sizeof(drm_sarea_t)); + + mmesa->CurrentTexObj[0] = NULL; + mmesa->CurrentTexObj[1] = NULL; + + (void) memset( mmesa->texture_heaps, 0, sizeof( mmesa->texture_heaps ) ); + make_empty_list( &mmesa->swapped ); + + mmesa->firstTexHeap = mach64Screen->firstTexHeap; + mmesa->lastTexHeap = mach64Screen->firstTexHeap + mach64Screen->numTexHeaps; + + for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) { + mmesa->texture_heaps[i] = driCreateTextureHeap( i, mmesa, + mach64Screen->texSize[i], + 6, /* align to 64-byte boundary, use 12 for page-size boundary */ + MACH64_NR_TEX_REGIONS, + (drmTextureRegionPtr)mmesa->sarea->tex_list[i], + &mmesa->sarea->tex_age[i], + &mmesa->swapped, + sizeof( mach64TexObj ), + (destroy_texture_object_t *) mach64DestroyTexObj ); + +#if ENABLE_PERF_BOXES + c_textureSwapsPtr = & mmesa->c_textureSwaps; +#endif + driSetTextureSwapCounterLocation( mmesa->texture_heaps[i], + c_textureSwapsPtr ); + } + + mmesa->RenderIndex = -1; /* Impossible value */ + mmesa->vert_buf = NULL; + mmesa->num_verts = 0; + mmesa->new_state = MACH64_NEW_ALL; + mmesa->dirty = MACH64_UPLOAD_ALL; + + /* 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 memory (on-card or AGP) at once. + * Test for 2 textures * bytes/texel * size * size. There's no + * need to account for mipmaps since we only upload one level. + */ + + ctx->Const.MaxTextureUnits = 2; + ctx->Const.MaxTextureImageUnits = 2; + ctx->Const.MaxTextureCoordUnits = 2; + + heap = mach64Screen->IsPCI ? MACH64_CARD_HEAP : MACH64_AGP_HEAP; + + driCalculateMaxTextureLevels( & mmesa->texture_heaps[heap], + 1, + & ctx->Const, + mach64Screen->cpp, + 10, /* max 2D texture size is 1024x1024 */ + 0, /* 3D textures unsupported. */ + 0, /* cube textures unsupported. */ + 0, /* texture rectangles unsupported. */ + 1, /* mipmapping unsupported. */ + GL_TRUE, /* need to have both textures in + either local or AGP memory */ + 0 ); + +#if ENABLE_PERF_BOXES + mmesa->boxes = ( getenv( "LIBGL_PERFORMANCE_BOXES" ) != NULL ); +#endif + + /* Allocate the vertex buffer + */ + mmesa->vert_buf = ALIGN_MALLOC(MACH64_BUFFER_SIZE, 32); + if ( !mmesa->vert_buf ) + return GL_FALSE; + mmesa->vert_used = 0; + mmesa->vert_total = MACH64_BUFFER_SIZE; + + /* Initialize the software rasterizer and helper modules. + */ + _swrast_CreateContext( ctx ); + _vbo_CreateContext( ctx ); + _tnl_CreateContext( ctx ); + _swsetup_CreateContext( ctx ); + + /* Install the customized pipeline: + */ +/* _tnl_destroy_pipeline( ctx ); */ +/* _tnl_install_pipeline( ctx, mach64_pipeline ); */ + + /* Configure swrast and T&L to match hardware characteristics: + */ + _swrast_allow_pixel_fog( ctx, GL_FALSE ); + _swrast_allow_vertex_fog( ctx, GL_TRUE ); + _tnl_allow_pixel_fog( ctx, GL_FALSE ); + _tnl_allow_vertex_fog( ctx, GL_TRUE ); + + driInitExtensions( ctx, card_extensions, GL_TRUE ); + + mach64InitVB( ctx ); + mach64InitTriFuncs( ctx ); + mach64DDInitStateFuncs( ctx ); + mach64DDInitSpanFuncs( ctx ); + mach64DDInitState( mmesa ); + + mmesa->do_irqs = (mmesa->mach64Screen->irq && !getenv("MACH64_NO_IRQS")); + + mmesa->vblank_flags = (mmesa->do_irqs) + ? driGetDefaultVBlankFlags(&mmesa->optionCache) : VBLANK_FLAG_NO_IRQ; + + driContextPriv->driverPrivate = (void *)mmesa; + + if (driQueryOptionb(&mmesa->optionCache, "no_rast")) { + fprintf(stderr, "disabling 3D acceleration\n"); + FALLBACK(mmesa, MACH64_FALLBACK_DISABLE, 1); + } + + return GL_TRUE; +} + +/* Destroy the device specific context. + */ +void mach64DestroyContext( __DRIcontextPrivate *driContextPriv ) +{ + mach64ContextPtr mmesa = (mach64ContextPtr) driContextPriv->driverPrivate; + + assert(mmesa); /* should never be null */ + if ( mmesa ) { + GLboolean release_texture_heaps; + + release_texture_heaps = (mmesa->glCtx->Shared->RefCount == 1); + + _swsetup_DestroyContext( mmesa->glCtx ); + _tnl_DestroyContext( mmesa->glCtx ); + _vbo_DestroyContext( mmesa->glCtx ); + _swrast_DestroyContext( mmesa->glCtx ); + + if (release_texture_heaps) { + /* This share group is about to go away, free our private + * texture object data. + */ + int i; + + for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) { + driDestroyTextureHeap( mmesa->texture_heaps[i] ); + mmesa->texture_heaps[i] = NULL; + } + + assert( is_empty_list( & mmesa->swapped ) ); + } + + mach64FreeVB( mmesa->glCtx ); + + /* Free the vertex buffer */ + if ( mmesa->vert_buf ) + ALIGN_FREE( mmesa->vert_buf ); + + /* free the Mesa context */ + mmesa->glCtx->DriverCtx = NULL; + _mesa_destroy_context(mmesa->glCtx); + + FREE( mmesa ); + } +} + +/* Force the context `c' to be the current context and associate with it + * buffer `b'. + */ +GLboolean +mach64MakeCurrent( __DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv ) +{ + if ( driContextPriv ) { + GET_CURRENT_CONTEXT(ctx); + mach64ContextPtr oldMach64Ctx = ctx ? MACH64_CONTEXT(ctx) : NULL; + mach64ContextPtr newMach64Ctx = (mach64ContextPtr) driContextPriv->driverPrivate; + + if ( newMach64Ctx != oldMach64Ctx ) { + newMach64Ctx->new_state |= MACH64_NEW_CONTEXT; + newMach64Ctx->dirty = MACH64_UPLOAD_ALL; + } + + + driDrawableInitVBlank( driDrawPriv, newMach64Ctx->vblank_flags, + &newMach64Ctx->vbl_seq ); + + if ( newMach64Ctx->driDrawable != driDrawPriv ) { + newMach64Ctx->driDrawable = driDrawPriv; + mach64CalcViewport( newMach64Ctx->glCtx ); + } + + _mesa_make_current( newMach64Ctx->glCtx, + (GLframebuffer *) driDrawPriv->driverPrivate, + (GLframebuffer *) driReadPriv->driverPrivate ); + + + newMach64Ctx->new_state |= MACH64_NEW_CLIP; + } else { + _mesa_make_current( NULL, NULL, NULL ); + } + + return GL_TRUE; +} + + +/* Force the context `c' to be unbound from its buffer. + */ +GLboolean +mach64UnbindContext( __DRIcontextPrivate *driContextPriv ) +{ + return GL_TRUE; +} diff --git a/src/mach64_context.h b/src/mach64_context.h new file mode 100644 index 0000000..8d89452 --- /dev/null +++ b/src/mach64_context.h @@ -0,0 +1,364 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * Jos�Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#ifndef __MACH64_CONTEXT_H__ +#define __MACH64_CONTEXT_H__ + +#include "dri_util.h" +#include "drm.h" +#include "mach64_drm.h" + +#include "mtypes.h" + +#include "mach64_reg.h" + +#include "texmem.h" + +struct mach64_context; +typedef struct mach64_context mach64ContextRec; +typedef struct mach64_context *mach64ContextPtr; + +#include "mach64_lock.h" +#include "mach64_screen.h" + +/* Experimental driver options */ +#define MACH64_CLIENT_STATE_EMITS 0 + +/* Performace monitoring */ +#define ENABLE_PERF_BOXES 1 + +/* Native vertex format */ +#define MACH64_NATIVE_VTXFMT 1 + +/* Flags for what context state needs to be updated: + */ +#define MACH64_NEW_ALPHA 0x0001 +#define MACH64_NEW_DEPTH 0x0002 +#define MACH64_NEW_FOG 0x0004 +#define MACH64_NEW_CLIP 0x0008 +#define MACH64_NEW_CULL 0x0010 +#define MACH64_NEW_MASKS 0x0020 +#define MACH64_NEW_RENDER_UNUSED 0x0040 +#define MACH64_NEW_WINDOW 0x0080 +#define MACH64_NEW_TEXTURE 0x0100 +#define MACH64_NEW_CONTEXT 0x0200 +#define MACH64_NEW_ALL 0x03ff + +/* Flags for software fallback cases: + */ +#define MACH64_FALLBACK_TEXTURE 0x0001 +#define MACH64_FALLBACK_DRAW_BUFFER 0x0002 +#define MACH64_FALLBACK_READ_BUFFER 0x0004 +#define MACH64_FALLBACK_STENCIL 0x0008 +#define MACH64_FALLBACK_RENDER_MODE 0x0010 +#define MACH64_FALLBACK_LOGICOP 0x0020 +#define MACH64_FALLBACK_SEP_SPECULAR 0x0040 +#define MACH64_FALLBACK_BLEND_EQ 0x0080 +#define MACH64_FALLBACK_BLEND_FUNC 0x0100 +#define MACH64_FALLBACK_DISABLE 0x0200 + +#define CARD32 GLuint /* KW: For building in mesa tree */ + +#if MACH64_NATIVE_VTXFMT + +/* The vertex structures. + */ + +/* The size of this union is not of relevence: + */ +union mach64_vertex_t { + GLfloat f[16]; + GLuint ui[16]; + GLushort us2[16][2]; + GLubyte ub4[16][4]; +}; + +typedef union mach64_vertex_t mach64Vertex, *mach64VertexPtr; + +#else + +/* Use the templated vertex format: + */ +#define TAG(x) mach64##x +#include "tnl_dd/t_dd_vertex.h" +#undef TAG + +#endif /* MACH64_NATIVE_VTXFMT */ + +/* Subpixel offsets for window coordinates: + * These are enough to fix most glean tests except polygonOffset. + * There are also still some gaps that show in e.g. the tunnel Mesa demo + * or the lament xscreensaver hack. + */ +#define SUBPIXEL_X (0.0125F) +#define SUBPIXEL_Y (0.15F) + + +typedef void (*mach64_tri_func)( mach64ContextPtr, + mach64Vertex *, + mach64Vertex *, + mach64Vertex * ); + +typedef void (*mach64_line_func)( mach64ContextPtr, + mach64Vertex *, + mach64Vertex * ); + +typedef void (*mach64_point_func)( mach64ContextPtr, + mach64Vertex * ); + +struct mach64_texture_object { + driTextureObject base; + + GLuint bufAddr; + + GLint heap; /* same as base.heap->heapId */ + + /* For communicating values from mach64AllocTexObj(), mach64SetTexImages() + * to mach64UpdateTextureUnit(). Alternately, we can use the tObj values or + * set the context registers directly. + */ + GLint widthLog2; + GLint heightLog2; + GLint maxLog2; + + GLint hasAlpha; + GLint textureFormat; + + GLboolean BilinearMin; + GLboolean BilinearMag; + GLboolean ClampS; + GLboolean ClampT; +}; + +typedef struct mach64_texture_object mach64TexObj, *mach64TexObjPtr; + +struct mach64_context { + GLcontext *glCtx; + + /* Driver and hardware state management + */ + GLuint new_state; + GLuint dirty; /* Hardware state to be updated */ + drm_mach64_context_regs_t setup; + + GLuint NewGLState; + GLuint Fallback; + GLuint SetupIndex; + GLuint SetupNewInputs; + GLuint RenderIndex; + GLfloat hw_viewport[16]; + GLfloat depth_scale; + GLuint vertex_size; + GLuint vertex_stride_shift; + GLuint vertex_format; + GLuint num_verts; + GLubyte *verts; + + CARD32 Color; /* Current draw color */ + CARD32 ClearColor; /* Color used to clear color buffer */ + CARD32 ClearDepth; /* Value used to clear depth buffer */ + + /* Map GL texture units onto hardware + */ + GLint multitex; + GLint tmu_source[2]; + GLint tex_dest[2]; + + /* Texture object bookkeeping + */ + mach64TexObjPtr CurrentTexObj[2]; + + GLint firstTexHeap, lastTexHeap; + driTexHeap *texture_heaps[MACH64_NR_TEX_HEAPS]; + driTextureObject swapped; + + /* Fallback rasterization functions + */ + mach64_point_func draw_point; + mach64_line_func draw_line; + mach64_tri_func draw_tri; + + /* Culling */ + GLfloat backface_sign; + + /* DMA buffers + */ + void *vert_buf; + size_t vert_total; + unsigned vert_used; + + GLuint hw_primitive; + GLenum render_primitive; + + /* Visual, drawable, cliprect and scissor information + */ + GLint drawOffset, drawPitch; + GLint drawX, drawY; /* origin of drawable in draw buffer */ + GLint readOffset, readPitch; + + GLuint numClipRects; /* Cliprects for the draw buffer */ + drm_clip_rect_t *pClipRects; + + GLint scissor; + drm_clip_rect_t ScissorRect; /* Current software scissor */ + + /* Mirrors of some DRI state + */ + __DRIcontextPrivate *driContext; /* DRI context */ + __DRIscreenPrivate *driScreen; /* DRI screen */ + __DRIdrawablePrivate *driDrawable; /* DRI drawable bound to this ctx */ + + unsigned int lastStamp; /* mirror driDrawable->lastStamp */ + + drm_context_t hHWContext; + drm_hw_lock_t *driHwLock; + int driFd; + + mach64ScreenPtr mach64Screen; /* Screen private DRI data */ + drm_mach64_sarea_t *sarea; /* Private SAREA data */ + + GLuint hardwareWentIdle; + +#if ENABLE_PERF_BOXES + /* Performance counters + */ + GLuint boxes; /* Draw performance boxes */ + GLuint c_clears; + GLuint c_drawWaits; + GLuint c_textureSwaps; + GLuint c_textureBytes; + GLuint c_agpTextureBytes; + GLuint c_texsrc_agp; + GLuint c_texsrc_card; + GLuint c_vertexBuffers; +#endif + + /* VBI + */ + GLuint vbl_seq; + GLuint vblank_flags; + GLuint do_irqs; + + /* Configuration cache + */ + driOptionCache optionCache; +}; + +#define MACH64_CONTEXT(ctx) ((mach64ContextPtr)(ctx->DriverCtx)) + + +extern GLboolean mach64CreateContext( const __GLcontextModes *glVisual, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate ); + +extern void mach64DestroyContext( __DRIcontextPrivate * ); + +extern GLboolean mach64MakeCurrent( __DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv ); + +extern GLboolean mach64UnbindContext( __DRIcontextPrivate *driContextPriv ); + +/* ================================================================ + * Byte ordering + */ +#if MESA_LITTLE_ENDIAN == 1 +#define LE32_IN( x ) ( *(GLuint *)(x) ) +#define LE32_IN_FLOAT( x ) ( *(GLfloat *)(x) ) +#define LE32_OUT( x, y ) do { *(GLuint *)(x) = (y); } while (0) +#define LE32_OUT_FLOAT( x, y ) do { *(GLfloat *)(x) = (y); } while (0) +#else +#include <byteswap.h> +#define LE32_IN( x ) bswap_32( *(GLuint *)(x) ) +#define LE32_IN_FLOAT( x ) \ +({ \ + GLuint __tmp = bswap_32( *(GLuint *)(x) ); \ + *(GLfloat *)&__tmp; \ +}) +#define LE32_OUT( x, y ) do { *(GLuint *)(x) = bswap_32( y ); } while (0) +#define LE32_OUT_FLOAT( x, y ) \ +do { \ + GLuint __tmp; \ + *(GLfloat *)&__tmp = (y); \ + *(GLuint *)(x) = bswap_32( __tmp ); \ +} while (0) +#endif + +/* ================================================================ + * DMA buffers + */ + +#define DMALOCALS CARD32 *buf=NULL; int requested=0; int outcount=0 + +/* called while locked for interleaved client-side state emits */ +#define DMAGETPTR( dwords ) \ +do { \ + requested = (dwords); \ + buf = (CARD32 *)mach64AllocDmaLocked( mmesa, ((dwords)*4) ); \ + outcount = 0; \ +} while(0) + +#define DMAOUTREG( reg, val ) \ +do { \ + LE32_OUT( &buf[outcount++], ADRINDEX( reg ) ); \ + LE32_OUT( &buf[outcount++], ( val ) ); \ +} while(0) + +#define DMAADVANCE() \ +do { \ + if (outcount < requested) { \ + mmesa->vert_used -= (requested - outcount) * 4; \ + } \ +} while(0) + +/* ================================================================ + * Debugging: + */ + +#define DO_DEBUG 1 + +#if DO_DEBUG +extern int MACH64_DEBUG; +#else +#define MACH64_DEBUG 0 +#endif + +#define DEBUG_ALWAYS_SYNC 0x001 +#define DEBUG_VERBOSE_API 0x002 +#define DEBUG_VERBOSE_MSG 0x004 +#define DEBUG_VERBOSE_LRU 0x008 +#define DEBUG_VERBOSE_DRI 0x010 +#define DEBUG_VERBOSE_IOCTL 0x020 +#define DEBUG_VERBOSE_PRIMS 0x040 +#define DEBUG_VERBOSE_COUNT 0x080 +#define DEBUG_NOWAIT 0x100 +#define DEBUG_VERBOSE_FALLBACK 0x200 +#endif /* __MACH64_CONTEXT_H__ */ diff --git a/src/mach64_dd.c b/src/mach64_dd.c new file mode 100644 index 0000000..17e8d74 --- /dev/null +++ b/src/mach64_dd.c @@ -0,0 +1,134 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "mach64_context.h" +#include "mach64_ioctl.h" +#include "mach64_state.h" +#include "mach64_vb.h" +#include "mach64_dd.h" + +#include "context.h" +#include "utils.h" +#include "framebuffer.h" + +#define DRIVER_DATE "20051019" + +/* Return the current color buffer size. + */ +static void mach64DDGetBufferSize( GLframebuffer *buffer, + GLuint *width, GLuint *height ) +{ + GET_CURRENT_CONTEXT(ctx); + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + LOCK_HARDWARE( mmesa ); + *width = mmesa->driDrawable->w; + *height = mmesa->driDrawable->h; + UNLOCK_HARDWARE( mmesa ); +} + +/* Return various strings for glGetString(). + */ +static const GLubyte *mach64DDGetString( GLcontext *ctx, GLenum name ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + static char buffer[128]; + unsigned offset; + const char * card_name = "Mach64 [Rage Pro]"; + GLuint agp_mode = mmesa->mach64Screen->IsPCI ? 0 : + mmesa->mach64Screen->AGPMode; + + switch ( name ) { + case GL_VENDOR: + return (GLubyte*)"Gareth Hughes, Leif Delgass, José Fonseca"; + + case GL_RENDERER: + + offset = driGetRendererString( buffer, card_name, DRIVER_DATE, + agp_mode ); + 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 mach64DDFlush( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + LOCK_HARDWARE( mmesa ); + FLUSH_DMA_LOCKED( mmesa ); + UNLOCK_HARDWARE( mmesa ); + +#if ENABLE_PERF_BOXES + if ( mmesa->boxes ) { + LOCK_HARDWARE( mmesa ); + mach64PerformanceBoxesLocked( mmesa ); + UNLOCK_HARDWARE( mmesa ); + } + + /* Log the performance counters if necessary */ + mach64PerformanceCounters( mmesa ); +#endif +} + +/* Make sure all commands have been sent to the hardware and have + * completed processing. + */ +static void mach64DDFinish( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + mmesa->c_drawWaits++; +#endif + + mach64DDFlush( ctx ); + mach64WaitForIdle( mmesa ); +} + +/* Initialize the driver's misc functions. + */ +void mach64InitDriverFuncs( struct dd_function_table *functions ) +{ + functions->GetBufferSize = mach64DDGetBufferSize; + functions->GetString = mach64DDGetString; + functions->Finish = mach64DDFinish; + functions->Flush = mach64DDFlush; + +} diff --git a/src/mach64_dd.h b/src/mach64_dd.h new file mode 100644 index 0000000..74cf1d3 --- /dev/null +++ b/src/mach64_dd.h @@ -0,0 +1,36 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * + */ + +#ifndef __MACH64_DD_H__ +#define __MACH64_DD_H__ + +extern void mach64InitDriverFuncs( struct dd_function_table *functions ); + +#endif diff --git a/src/mach64_ioctl.c b/src/mach64_ioctl.c new file mode 100644 index 0000000..36e7d3c --- /dev/null +++ b/src/mach64_ioctl.c @@ -0,0 +1,932 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * Jos�Fonseca <j_r_fonseca@yahoo.co.uk> + */ +#include <errno.h> + +#include "mach64_context.h" +#include "mach64_state.h" +#include "mach64_ioctl.h" +#include "mach64_tex.h" + +#include "imports.h" +#include "macros.h" + +#include "swrast/swrast.h" + +#include "vblank.h" + +#define MACH64_TIMEOUT 10 /* the DRM already has a timeout, so keep this small */ + + +/* ============================================================= + * Hardware vertex buffer handling + */ + +/* Get a new VB from the pool of vertex buffers in AGP space. + */ +drmBufPtr mach64GetBufferLocked( mach64ContextPtr mmesa ) +{ + int fd = mmesa->mach64Screen->driScreen->fd; + int index = 0; + int size = 0; + drmDMAReq dma; + drmBufPtr buf = NULL; + int to = 0; + int ret; + + dma.context = mmesa->hHWContext; + dma.send_count = 0; + dma.send_list = NULL; + dma.send_sizes = NULL; + dma.flags = 0; + dma.request_count = 1; + dma.request_size = MACH64_BUFFER_SIZE; + dma.request_list = &index; + dma.request_sizes = &size; + dma.granted_count = 0; + + while ( !buf && ( to++ < MACH64_TIMEOUT ) ) { + ret = drmDMA( fd, &dma ); + + if ( ret == 0 ) { + buf = &mmesa->mach64Screen->buffers->list[index]; + buf->used = 0; +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + mmesa->c_vertexBuffers++; +#endif + return buf; + } + } + + if ( !buf ) { + drmCommandNone( fd, DRM_MACH64_RESET ); + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "Error: Could not get new VB... exiting\n" ); + exit( -1 ); + } + + return buf; +} + +void mach64FlushVerticesLocked( mach64ContextPtr mmesa ) +{ + drm_clip_rect_t *pbox = mmesa->pClipRects; + int nbox = mmesa->numClipRects; + void *buffer = mmesa->vert_buf; + int count = mmesa->vert_used; + int prim = mmesa->hw_primitive; + int fd = mmesa->driScreen->fd; + drm_mach64_vertex_t vertex; + int i; + + mmesa->num_verts = 0; + mmesa->vert_used = 0; + + if ( !count ) + return; + + if ( mmesa->dirty & ~MACH64_UPLOAD_CLIPRECTS ) + mach64EmitHwStateLocked( mmesa ); + + if ( !nbox ) + count = 0; + + if ( nbox > MACH64_NR_SAREA_CLIPRECTS ) + mmesa->dirty |= MACH64_UPLOAD_CLIPRECTS; + + if ( !count || !(mmesa->dirty & MACH64_UPLOAD_CLIPRECTS) ) { + int to = 0; + int ret; + + /* FIXME: Is this really necessary */ + if ( nbox == 1 ) + mmesa->sarea->nbox = 0; + else + mmesa->sarea->nbox = nbox; + + vertex.prim = prim; + vertex.buf = buffer; + vertex.used = count; + vertex.discard = 1; + do { + ret = drmCommandWrite( fd, DRM_MACH64_VERTEX, + &vertex, sizeof(drm_mach64_vertex_t) ); + } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) ); + if ( ret ) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "Error flushing vertex buffer: return = %d\n", ret ); + exit( -1 ); + } + + } else { + + for ( i = 0 ; i < nbox ; ) { + int nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS, nbox ); + drm_clip_rect_t *b = mmesa->sarea->boxes; + int discard = 0; + int to = 0; + int ret; + + mmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++ ) { + *b++ = pbox[i]; + } + + /* Finished with the buffer? + */ + if ( nr == nbox ) { + discard = 1; + } + + mmesa->sarea->dirty |= MACH64_UPLOAD_CLIPRECTS; + + vertex.prim = prim; + vertex.buf = buffer; + vertex.used = count; + vertex.discard = discard; + do { + ret = drmCommandWrite( fd, DRM_MACH64_VERTEX, + &vertex, sizeof(drm_mach64_vertex_t) ); + } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) ); + if ( ret ) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "Error flushing vertex buffer: return = %d\n", ret ); + exit( -1 ); + } + } + } + + mmesa->dirty &= ~MACH64_UPLOAD_CLIPRECTS; +} + +/* ================================================================ + * Texture uploads + */ + +void mach64FireBlitLocked( mach64ContextPtr mmesa, void *buffer, + GLint offset, GLint pitch, GLint format, + GLint x, GLint y, GLint width, GLint height ) +{ + drm_mach64_blit_t blit; + int to = 0; + int ret; + + blit.buf = buffer; + blit.offset = offset; + blit.pitch = pitch; + blit.format = format; + blit.x = x; + blit.y = y; + blit.width = width; + blit.height = height; + + do { + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_BLIT, + &blit, sizeof(drm_mach64_blit_t) ); + } while ( ( ret == -EAGAIN ) && ( to++ < MACH64_TIMEOUT ) ); + + if ( ret ) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_BLIT: return = %d\n", ret ); + exit( -1 ); + } +} + + +/* ================================================================ + * SwapBuffers with client-side throttling + */ +static void delay( void ) { +/* Prevent an optimizing compiler from removing a spin loop */ +} + +/* Throttle the frame rate -- only allow MACH64_MAX_QUEUED_FRAMES + * pending swap buffers requests 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. + */ +static int mach64WaitForFrameCompletion( mach64ContextPtr mmesa ) +{ + int fd = mmesa->driFd; + int i; + int wait = 0; + int frames; + + while ( 1 ) { + drm_mach64_getparam_t gp; + int ret; + + if ( mmesa->sarea->frames_queued < MACH64_MAX_QUEUED_FRAMES ) { + break; + } + + if (MACH64_DEBUG & DEBUG_NOWAIT) { + return 1; + } + + gp.param = MACH64_PARAM_FRAMES_QUEUED; + gp.value = &frames; /* also copied into sarea->frames_queued by DRM */ + + ret = drmCommandWriteRead( fd, DRM_MACH64_GETPARAM, &gp, sizeof(gp) ); + + if ( ret ) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_GETPARAM: return = %d\n", ret ); + exit( -1 ); + } + + /* Spin in place a bit so we aren't hammering the register */ + wait++; + + for ( i = 0 ; i < 1024 ; i++ ) { + delay(); + } + + } + + return wait; +} + +/* Copy the back color buffer to the front color buffer. + */ +void mach64CopyBuffer( const __DRIdrawablePrivate *dPriv ) +{ + mach64ContextPtr mmesa; + GLint nbox, i, ret; + drm_clip_rect_t *pbox; + GLboolean missed_target; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + mmesa = (mach64ContextPtr) dPriv->driContextPriv->driverPrivate; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "\n********************************\n" ); + fprintf( stderr, "\n%s( %p )\n\n", + __FUNCTION__, mmesa->glCtx ); + fflush( stderr ); + } + + /* Flush any outstanding vertex buffers */ + FLUSH_BATCH( mmesa ); + + LOCK_HARDWARE( mmesa ); + + /* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + */ + if ( !mach64WaitForFrameCompletion( mmesa ) ) { + mmesa->hardwareWentIdle = 1; + } else { + mmesa->hardwareWentIdle = 0; + } + +#if ENABLE_PERF_BOXES + if ( mmesa->boxes ) { + mach64PerformanceBoxesLocked( mmesa ); + } +#endif + + UNLOCK_HARDWARE( mmesa ); + driWaitForVBlank( dPriv, &mmesa->vbl_seq, mmesa->vblank_flags, &missed_target ); + LOCK_HARDWARE( mmesa ); + + /* use front buffer cliprects */ + nbox = dPriv->numClipRects; + pbox = dPriv->pClipRects; + + for ( i = 0 ; i < nbox ; ) { + GLint nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS , nbox ); + drm_clip_rect_t *b = mmesa->sarea->boxes; + GLint n = 0; + + for ( ; i < nr ; i++ ) { + *b++ = pbox[i]; + n++; + } + mmesa->sarea->nbox = n; + + ret = drmCommandNone( mmesa->driFd, DRM_MACH64_SWAP ); + + if ( ret ) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_SWAP: return = %d\n", ret ); + exit( -1 ); + } + } + + if ( MACH64_DEBUG & DEBUG_ALWAYS_SYNC ) { + mach64WaitForIdleLocked( mmesa ); + } + + UNLOCK_HARDWARE( mmesa ); + + mmesa->dirty |= (MACH64_UPLOAD_CONTEXT | + MACH64_UPLOAD_MISC | + MACH64_UPLOAD_CLIPRECTS); + +#if ENABLE_PERF_BOXES + /* Log the performance counters if necessary */ + mach64PerformanceCounters( mmesa ); +#endif +} + +#if ENABLE_PERF_BOXES +/* ================================================================ + * Performance monitoring + */ + +void mach64PerformanceCounters( mach64ContextPtr mmesa ) +{ + + if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) { + /* report performance counters */ + fprintf( stderr, "mach64CopyBuffer: vertexBuffers:%i drawWaits:%i clears:%i\n", + mmesa->c_vertexBuffers, mmesa->c_drawWaits, mmesa->c_clears ); + } + + mmesa->c_vertexBuffers = 0; + mmesa->c_drawWaits = 0; + mmesa->c_clears = 0; + + if ( mmesa->c_textureSwaps || mmesa->c_textureBytes || mmesa->c_agpTextureBytes ) { + if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) { + fprintf( stderr, " textureSwaps:%i textureBytes:%i agpTextureBytes:%i\n", + mmesa->c_textureSwaps, mmesa->c_textureBytes, mmesa->c_agpTextureBytes ); + } + mmesa->c_textureSwaps = 0; + mmesa->c_textureBytes = 0; + mmesa->c_agpTextureBytes = 0; + } + + mmesa->c_texsrc_agp = 0; + mmesa->c_texsrc_card = 0; + + if (MACH64_DEBUG & DEBUG_VERBOSE_COUNT) + fprintf( stderr, "---------------------------------------------------------\n" ); +} + + +void mach64PerformanceBoxesLocked( mach64ContextPtr mmesa ) +{ + GLint ret; + drm_mach64_clear_t clear; + GLint x, y, w, h; + GLuint color; + GLint nbox; + GLint x1, y1, x2, y2; + drm_clip_rect_t *b = mmesa->sarea->boxes; + + /* save cliprects */ + nbox = mmesa->sarea->nbox; + x1 = b[0].x1; + y1 = b[0].y1; + x2 = b[0].x2; + y2 = b[0].y2; + + /* setup a single cliprect and call the clear ioctl for each box */ + mmesa->sarea->nbox = 1; + + w = h = 8; + x = mmesa->drawX; + y = mmesa->drawY; + b[0].x1 = x; + b[0].x2 = x + w; + b[0].y1 = y; + b[0].y2 = y + h; + + clear.flags = MACH64_BACK; + clear.clear_depth = 0; + + /* Red box if DDFinish was called to wait for rendering to complete */ + if ( mmesa->c_drawWaits ) { + color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 0, 0 ); + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + + } + + x += w; + b[0].x1 = x; + b[0].x2 = x + w; + + /* draw a green box if we had to wait for previous frame(s) to complete */ + if ( !mmesa->hardwareWentIdle ) { + color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 255, 0, 0 ); + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + + } + + x += w; + w = 20; + b[0].x1 = x; + + /* show approx. ratio of AGP/card textures used - Blue = AGP, Purple = Card */ + if ( mmesa->c_texsrc_agp || mmesa->c_texsrc_card ) { + color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 0, 255, 0 ); + w = ((GLfloat)mmesa->c_texsrc_agp / (GLfloat)(mmesa->c_texsrc_agp + mmesa->c_texsrc_card))*20; + if (w > 1) { + + b[0].x2 = x + w; + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + } + + x += w; + w = 20 - w; + + if (w > 1) { + b[0].x1 = x; + b[0].x2 = x + w; + + color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 255, 0 ); + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + } + } + + x += w; + w = 8; + b[0].x1 = x; + b[0].x2 = x + w; + + /* Yellow box if we swapped textures */ + if ( mmesa->c_textureSwaps ) { + color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 255, 0, 0 ); + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + + } + + h = 4; + x += 8; + b[0].x1 = x; + b[0].y2 = y + h; + + /* Purple bar for card memory texture blits/uploads */ + if ( mmesa->c_textureBytes ) { + color = mach64PackColor( mmesa->mach64Screen->cpp, 255, 0, 255, 0 ); + w = mmesa->c_textureBytes / 16384; + if ( w <= 0 ) + w = 1; + if (w > (mmesa->driDrawable->w - 44)) + w = mmesa->driDrawable->w - 44; + + b[0].x2 = x + w; + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + } + + /* Blue bar for AGP memory texture blits/uploads */ + if ( mmesa->c_agpTextureBytes ) { + color = mach64PackColor( mmesa->mach64Screen->cpp, 0, 0, 255, 0 ); + w = mmesa->c_agpTextureBytes / 16384; + if ( w <= 0 ) + w = 1; + if (w > (mmesa->driDrawable->w - 44)) + w = mmesa->driDrawable->w - 44; + + y += 4; + b[0].x2 = x + w; + b[0].y1 = y; + b[0].y2 = y + h; + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + } + + /* Pink bar for number of vertex buffers used */ + if ( mmesa->c_vertexBuffers ) { + color = mach64PackColor( mmesa->mach64Screen->cpp, 196, 128, 128, 0 ); + + w = mmesa->c_vertexBuffers; + if (w > (mmesa->driDrawable->w)) + w = mmesa->driDrawable->w; + + h = 8; + x = mmesa->drawX; + y = mmesa->drawY + 8; + b[0].x1 = x; + b[0].x2 = x + w; + b[0].y1 = y; + b[0].y2 = y + h; + + clear.x = x; + clear.y = y; + clear.w = w; + clear.h = h; + clear.clear_color = color; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if (ret < 0) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + } + + /* restore cliprects */ + mmesa->sarea->nbox = nbox; + b[0].x1 = x1; + b[0].y1 = y1; + b[0].x2 = x2; + b[0].y2 = y2; + +} + +#endif + +/* ================================================================ + * Buffer clear + */ + +static void mach64DDClear( GLcontext *ctx, GLbitfield mask ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); + __DRIdrawablePrivate *dPriv = mmesa->driDrawable; + drm_mach64_clear_t clear; + GLuint flags = 0; + GLint i; + GLint ret; + GLint cx, cy, cw, ch; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "mach64DDClear\n"); + } + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + mmesa->c_clears++; +#endif + + FLUSH_BATCH( mmesa ); + + /* The only state changes we care about here are the RGBA colormask + * and scissor/clipping. We'll just update that state, if needed. + */ + if ( mmesa->new_state & (MACH64_NEW_MASKS | MACH64_NEW_CLIP) ) { + const GLuint save_state = mmesa->new_state; + mmesa->new_state &= (MACH64_NEW_MASKS | MACH64_NEW_CLIP); + mach64DDUpdateHWState( ctx ); + mmesa->new_state = save_state & ~(MACH64_NEW_MASKS | MACH64_NEW_CLIP); + } + + if ( mask & BUFFER_BIT_FRONT_LEFT ) { + flags |= MACH64_FRONT; + mask &= ~BUFFER_BIT_FRONT_LEFT; + } + + if ( mask & BUFFER_BIT_BACK_LEFT ) { + flags |= MACH64_BACK; + mask &= ~BUFFER_BIT_BACK_LEFT; + } + + if ( ( mask & BUFFER_BIT_DEPTH ) && ctx->Depth.Mask ) { + flags |= MACH64_DEPTH; + mask &= ~BUFFER_BIT_DEPTH; + } + + if ( mask ) + _swrast_Clear( ctx, mask ); + + if ( !flags ) + return; + + LOCK_HARDWARE( mmesa ); + + /* compute region after locking: */ + cx = ctx->DrawBuffer->_Xmin; + cy = ctx->DrawBuffer->_Ymin; + cw = ctx->DrawBuffer->_Xmax - cx; + ch = ctx->DrawBuffer->_Ymax - cy; + + /* Flip top to bottom */ + cx += mmesa->drawX; + cy = mmesa->drawY + dPriv->h - cy - ch; + + /* HACK? + */ + if ( mmesa->dirty & ~MACH64_UPLOAD_CLIPRECTS ) { + mach64EmitHwStateLocked( mmesa ); + } + + for ( i = 0 ; i < mmesa->numClipRects ; ) { + int nr = MIN2( i + MACH64_NR_SAREA_CLIPRECTS, mmesa->numClipRects ); + drm_clip_rect_t *box = mmesa->pClipRects; + drm_clip_rect_t *b = mmesa->sarea->boxes; + GLint n = 0; + + if (cw != dPriv->w || ch != dPriv->h) { + /* clear subregion */ + 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 { + /* clear whole window */ + for ( ; i < nr ; i++ ) { + *b++ = box[i]; + n++; + } + } + + mmesa->sarea->nbox = n; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_IOCTL ) { + fprintf( stderr, + "DRM_MACH64_CLEAR: flag 0x%x color %x depth %x nbox %d\n", + flags, + (GLuint)mmesa->ClearColor, + (GLuint)mmesa->ClearDepth, + mmesa->sarea->nbox ); + } + + clear.flags = flags; + clear.x = cx; + clear.y = cy; + clear.w = cw; + clear.h = ch; + clear.clear_color = mmesa->ClearColor; + clear.clear_depth = mmesa->ClearDepth; + + ret = drmCommandWrite( mmesa->driFd, DRM_MACH64_CLEAR, + &clear, sizeof(drm_mach64_clear_t) ); + + if ( ret ) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "DRM_MACH64_CLEAR: return = %d\n", ret ); + exit( -1 ); + } + } + + UNLOCK_HARDWARE( mmesa ); + + mmesa->dirty |= (MACH64_UPLOAD_CONTEXT | + MACH64_UPLOAD_MISC | + MACH64_UPLOAD_CLIPRECTS); + +} + + +void mach64WaitForIdleLocked( mach64ContextPtr mmesa ) +{ + int fd = mmesa->driFd; + int to = 0; + int ret; + + do { + ret = drmCommandNone( fd, DRM_MACH64_IDLE ); + } while ( ( ret == -EBUSY ) && ( to++ < MACH64_TIMEOUT ) ); + + if ( ret < 0 ) { + drmCommandNone( fd, DRM_MACH64_RESET ); + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "Error: Mach64 timed out... exiting\n" ); + exit( -1 ); + } +} + +/* Flush the DMA queue to the hardware */ +void mach64FlushDMALocked( mach64ContextPtr mmesa ) +{ + int fd = mmesa->driFd; + int ret; + + ret = drmCommandNone( fd, DRM_MACH64_FLUSH ); + + if ( ret < 0 ) { + drmCommandNone( fd, DRM_MACH64_RESET ); + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "Error flushing DMA... exiting\n" ); + exit( -1 ); + } + + mmesa->dirty |= (MACH64_UPLOAD_CONTEXT | + MACH64_UPLOAD_MISC | + MACH64_UPLOAD_CLIPRECTS); + +} + +/* For client-side state emits - currently unused */ +void mach64UploadHwStateLocked( mach64ContextPtr mmesa ) +{ + drm_mach64_sarea_t *sarea = mmesa->sarea; + + drm_mach64_context_regs_t *regs = &sarea->context_state; + unsigned int dirty = sarea->dirty; + CARD32 offset = ((regs->tex_size_pitch & 0xf0) >> 2); + + DMALOCALS; + + DMAGETPTR( 19*2 ); + + if ( dirty & MACH64_UPLOAD_MISC ) { + DMAOUTREG( MACH64_DP_MIX, regs->dp_mix ); + DMAOUTREG( MACH64_DP_SRC, regs->dp_src ); + DMAOUTREG( MACH64_CLR_CMP_CNTL, regs->clr_cmp_cntl ); + DMAOUTREG( MACH64_GUI_TRAJ_CNTL, regs->gui_traj_cntl ); + DMAOUTREG( MACH64_SC_LEFT_RIGHT, regs->sc_left_right ); + DMAOUTREG( MACH64_SC_TOP_BOTTOM, regs->sc_top_bottom ); + sarea->dirty &= ~MACH64_UPLOAD_MISC; + } + + if ( dirty & MACH64_UPLOAD_DST_OFF_PITCH ) { + DMAOUTREG( MACH64_DST_OFF_PITCH, regs->dst_off_pitch ); + sarea->dirty &= ~MACH64_UPLOAD_DST_OFF_PITCH; + } + if ( dirty & MACH64_UPLOAD_Z_OFF_PITCH ) { + DMAOUTREG( MACH64_Z_OFF_PITCH, regs->z_off_pitch ); + sarea->dirty &= ~MACH64_UPLOAD_Z_OFF_PITCH; + } + if ( dirty & MACH64_UPLOAD_Z_ALPHA_CNTL ) { + DMAOUTREG( MACH64_Z_CNTL, regs->z_cntl ); + DMAOUTREG( MACH64_ALPHA_TST_CNTL, regs->alpha_tst_cntl ); + sarea->dirty &= ~MACH64_UPLOAD_Z_ALPHA_CNTL; + } + if ( dirty & MACH64_UPLOAD_SCALE_3D_CNTL ) { + DMAOUTREG( MACH64_SCALE_3D_CNTL, regs->scale_3d_cntl ); + sarea->dirty &= ~MACH64_UPLOAD_SCALE_3D_CNTL; + } + if ( dirty & MACH64_UPLOAD_DP_FOG_CLR ) { + DMAOUTREG( MACH64_DP_FOG_CLR, regs->dp_fog_clr ); + sarea->dirty &= ~MACH64_UPLOAD_DP_FOG_CLR; + } + if ( dirty & MACH64_UPLOAD_DP_WRITE_MASK ) { + DMAOUTREG( MACH64_DP_WRITE_MASK, regs->dp_write_mask ); + sarea->dirty &= ~MACH64_UPLOAD_DP_WRITE_MASK; + } + if ( dirty & MACH64_UPLOAD_DP_PIX_WIDTH ) { + DMAOUTREG( MACH64_DP_PIX_WIDTH, regs->dp_pix_width ); + sarea->dirty &= ~MACH64_UPLOAD_DP_PIX_WIDTH; + } + if ( dirty & MACH64_UPLOAD_SETUP_CNTL ) { + DMAOUTREG( MACH64_SETUP_CNTL, regs->setup_cntl ); + sarea->dirty &= ~MACH64_UPLOAD_SETUP_CNTL; + } + + if ( dirty & MACH64_UPLOAD_TEXTURE ) { + DMAOUTREG( MACH64_TEX_SIZE_PITCH, regs->tex_size_pitch ); + DMAOUTREG( MACH64_TEX_CNTL, regs->tex_cntl ); + DMAOUTREG( MACH64_SECONDARY_TEX_OFF, regs->secondary_tex_off ); + DMAOUTREG( MACH64_TEX_0_OFF + offset, regs->tex_offset ); + sarea->dirty &= ~MACH64_UPLOAD_TEXTURE; + } + +#if 0 + if ( dirty & MACH64_UPLOAD_CLIPRECTS ) { + DMAOUTREG( MACH64_SC_LEFT_RIGHT, regs->sc_left_right ); + DMAOUTREG( MACH64_SC_TOP_BOTTOM, regs->sc_top_bottom ); + sarea->dirty &= ~MACH64_UPLOAD_CLIPRECTS; + } +#endif + + sarea->dirty = 0; + + DMAADVANCE(); +} + +void mach64InitIoctlFuncs( struct dd_function_table *functions ) +{ + functions->Clear = mach64DDClear; +} diff --git a/src/mach64_ioctl.h b/src/mach64_ioctl.h new file mode 100644 index 0000000..52fe863 --- /dev/null +++ b/src/mach64_ioctl.h @@ -0,0 +1,148 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#ifndef __MACH64_IOCTL_H__ +#define __MACH64_IOCTL_H__ + +#include "mach64_dri.h" +#include "mach64_reg.h" +#include "mach64_lock.h" + +#define MACH64_BUFFER_MAX_DWORDS (MACH64_BUFFER_SIZE / sizeof(CARD32)) + + +extern drmBufPtr mach64GetBufferLocked( mach64ContextPtr mmesa ); +extern void mach64FlushVerticesLocked( mach64ContextPtr mmesa ); +extern void mach64FlushDMALocked( mach64ContextPtr mmesa ); +extern void mach64UploadHwStateLocked( mach64ContextPtr mmesa ); + +static __inline void *mach64AllocDmaLow( mach64ContextPtr mmesa, int bytes ) +{ + CARD32 *head; + + if ( mmesa->vert_used + bytes > mmesa->vert_total ) { + LOCK_HARDWARE( mmesa ); + mach64FlushVerticesLocked( mmesa ); + UNLOCK_HARDWARE( mmesa ); + } + + head = (CARD32 *)((char *)mmesa->vert_buf + mmesa->vert_used); + mmesa->vert_used += bytes; + + return head; +} + +static __inline void *mach64AllocDmaLocked( mach64ContextPtr mmesa, int bytes ) +{ + CARD32 *head; + + if ( mmesa->vert_used + bytes > mmesa->vert_total ) { + mach64FlushVerticesLocked( mmesa ); + } + + head = (CARD32 *)((char *)mmesa->vert_buf + mmesa->vert_used); + mmesa->vert_used += bytes; + + return head; +} + +extern void mach64FireBlitLocked( mach64ContextPtr mmesa, void *buffer, + GLint offset, GLint pitch, GLint format, + GLint x, GLint y, GLint width, GLint height ); + +extern void mach64CopyBuffer( const __DRIdrawablePrivate *dPriv ); +#if ENABLE_PERF_BOXES +extern void mach64PerformanceCounters( mach64ContextPtr mmesa ); +extern void mach64PerformanceBoxesLocked( mach64ContextPtr mmesa ); +#endif +extern void mach64WaitForIdleLocked( mach64ContextPtr mmesa ); + +extern void mach64InitIoctlFuncs( struct dd_function_table *functions ); + +/* ================================================================ + * Helper macros: + */ + +#define FLUSH_BATCH( mmesa ) \ +do { \ + if ( MACH64_DEBUG & DEBUG_VERBOSE_IOCTL ) \ + fprintf( stderr, "FLUSH_BATCH in %s\n", __FUNCTION__ ); \ + if ( mmesa->vert_used ) { \ + mach64FlushVertices( mmesa ); \ + } \ +} while (0) + +/* According to a comment in ATIMach64Sync (atimach64.c) in the DDX: + * + * "For VTB's and later, the first CPU read of the framebuffer will return + * zeroes [...] This appears to be due to some kind of engine + * caching of framebuffer data I haven't found any way of disabling, or + * otherwise circumventing." + */ +#define FINISH_DMA_LOCKED( mmesa ) \ +do { \ + CARD32 _tmp; \ + if ( MACH64_DEBUG & DEBUG_VERBOSE_IOCTL ) \ + fprintf( stderr, "FINISH_DMA_LOCKED in %s\n", __FUNCTION__ ); \ + if ( mmesa->vert_used ) { \ + mach64FlushVerticesLocked( mmesa ); \ + } \ + mach64WaitForIdleLocked( mmesa ); \ + /* pre-read framebuffer to counter caching problem */ \ + _tmp = *(volatile CARD32 *)mmesa->driScreen->pFB; \ +} while (0) + +#define FLUSH_DMA_LOCKED( mmesa ) \ +do { \ + if ( MACH64_DEBUG & DEBUG_VERBOSE_IOCTL ) \ + fprintf( stderr, "FLUSH_DMA_LOCKED in %s\n", __FUNCTION__ ); \ + if ( mmesa->vert_used ) { \ + mach64FlushVerticesLocked( mmesa ); \ + } \ + mach64FlushDMALocked( mmesa ); \ +} while (0) + +#define mach64FlushVertices( mmesa ) \ +do { \ + LOCK_HARDWARE( mmesa ); \ + mach64FlushVerticesLocked( mmesa ); \ + UNLOCK_HARDWARE( mmesa ); \ +} while (0) + +#define mach64WaitForIdle( mmesa ) \ +do { \ + LOCK_HARDWARE( mmesa ); \ + mach64WaitForIdleLocked( mmesa ); \ + UNLOCK_HARDWARE( mmesa ); \ +} while (0) + + +#endif /* __MACH64_IOCTL_H__ */ diff --git a/src/mach64_lock.c b/src/mach64_lock.c new file mode 100644 index 0000000..b73e350 --- /dev/null +++ b/src/mach64_lock.c @@ -0,0 +1,96 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "mach64_context.h" +#include "mach64_state.h" +#include "mach64_lock.h" +#include "mach64_tex.h" +#include "drirenderbuffer.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 mach64GetLock( mach64ContextPtr mmesa, GLuint flags ) +{ + __DRIdrawablePrivate *dPriv = mmesa->driDrawable; + __DRIscreenPrivate *sPriv = mmesa->driScreen; + drm_mach64_sarea_t *sarea = mmesa->sarea; + int i; + + drmGetLock( mmesa->driFd, mmesa->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. + */ + DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv ); + + if ( mmesa->lastStamp != dPriv->lastStamp ) { + mmesa->lastStamp = dPriv->lastStamp; + if (mmesa->glCtx->DrawBuffer->_ColorDrawBufferMask[0] == BUFFER_BIT_BACK_LEFT) + mach64SetCliprects( mmesa->glCtx, GL_BACK_LEFT ); + else + mach64SetCliprects( mmesa->glCtx, GL_FRONT_LEFT ); + driUpdateFramebufferSize( mmesa->glCtx, dPriv ); + mach64CalcViewport( mmesa->glCtx ); + } + + mmesa->dirty |= (MACH64_UPLOAD_CONTEXT + | MACH64_UPLOAD_MISC + | MACH64_UPLOAD_CLIPRECTS); + + /* EXA render acceleration uses the texture engine, so restore it */ + mmesa->dirty |= (MACH64_UPLOAD_TEXTURE); + + if ( sarea->ctx_owner != mmesa->hHWContext ) { + sarea->ctx_owner = mmesa->hHWContext; + mmesa->dirty = MACH64_UPLOAD_ALL; + } + + for ( i = mmesa->firstTexHeap ; i < mmesa->lastTexHeap ; i++ ) { + DRI_AGE_TEXTURES( mmesa->texture_heaps[i] ); + } +} diff --git a/src/mach64_lock.h b/src/mach64_lock.h new file mode 100644 index 0000000..973880e --- /dev/null +++ b/src/mach64_lock.h @@ -0,0 +1,104 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * + */ + +#ifndef __MACH64_LOCK_H__ +#define __MACH64_LOCK_H__ + +extern void mach64GetLock( mach64ContextPtr mmesa, GLuint flags ); + + +/* Turn DEBUG_LOCKING on to find locking conflicts. + */ +#define DEBUG_LOCKING 1 + +#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( mmesa ) \ + do { \ + char __ret = 0; \ + DEBUG_CHECK_LOCK(); \ + DRM_CAS( mmesa->driHwLock, mmesa->hHWContext, \ + (DRM_LOCK_HELD | mmesa->hHWContext), __ret ); \ + if ( __ret ) \ + mach64GetLock( mmesa, 0 ); \ + DEBUG_LOCK(); \ + } while (0) + +/* Unlock the hardware. + */ +#define UNLOCK_HARDWARE( mmesa ) \ + do { \ + DRM_UNLOCK( mmesa->driFd, \ + mmesa->driHwLock, \ + mmesa->hHWContext ); \ + DEBUG_RESET(); \ + } while (0) + +#endif /* __MACH64_LOCK_H__ */ diff --git a/src/mach64_native_vb.c b/src/mach64_native_vb.c new file mode 100644 index 0000000..81bcf80 --- /dev/null +++ b/src/mach64_native_vb.c @@ -0,0 +1,257 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL 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. + * + * Original authors: + * Keith Whitwell <keithw@valinux.com> + * + * Adapted to Mach64 by: + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "math/m_translate.h" + +#ifndef LOCALVARS +#define LOCALVARS +#endif + +void TAG(translate_vertex)(GLcontext *ctx, + const VERTEX *src, + SWvertex *dst) +{ + LOCALVARS + GLuint format = GET_VERTEX_FORMAT(); + UNVIEWPORT_VARS; + CARD32 *p = (CARD32 *)src + 10 - mmesa->vertex_size; + + dst->win[3] = 1.0; + + switch ( format ) { + case TEX1_VERTEX_FORMAT: +#ifdef MACH64_PREMULT_TEXCOORDS + { + float rhw = 1.0 / LE32_IN_FLOAT( p + 2 ); + + dst->attrib[FRAG_ATTRIB_TEX1][0] = rhw*LE32_IN_FLOAT( p++ ); + dst->attrib[FRAG_ATTRIB_TEX1][1] = rhw*LE32_IN_FLOAT( p++ ); + } +#else + dst->attrib[FRAG_ATTRIB_TEX1][0] = LE32_IN_FLOAT( p++ ); + dst->attrib[FRAG_ATTRIB_TEX1][1] = LE32_IN_FLOAT( p++ ); +#endif + dst->attrib[FRAG_ATTRIB_TEX1][3] = 1.0; + p++; + + case TEX0_VERTEX_FORMAT: +#ifdef MACH64_PREMULT_TEXCOORDS + { + float rhw = 1.0 / LE32_IN_FLOAT( p + 2 ); + + dst->attrib[FRAG_ATTRIB_TEX0][0] = rhw*LE32_IN_FLOAT( p++ ); + dst->attrib[FRAG_ATTRIB_TEX0][1] = rhw*LE32_IN_FLOAT( p++ ); + } +#else + dst->attrib[FRAG_ATTRIB_TEX0][0] = LE32_IN_FLOAT( p++ ); + dst->attrib[FRAG_ATTRIB_TEX0][1] = LE32_IN_FLOAT( p++ ); +#endif + dst->attrib[FRAG_ATTRIB_TEX0][3] = 1.0; + dst->win[3] = LE32_IN_FLOAT( p++ ); + + case NOTEX_VERTEX_FORMAT: + dst->specular[2] = ((GLubyte *)p)[0]; + dst->specular[1] = ((GLubyte *)p)[1]; + dst->specular[0] = ((GLubyte *)p)[2]; + dst->attrib[FRAG_ATTRIB_FOGC][0] = ((GLubyte *)p)[3]; + p++; + + case TINY_VERTEX_FORMAT: + dst->win[2] = UNVIEWPORT_Z( LE32_IN( p++ ) ); + + dst->color[2] = ((GLubyte *)p)[0]; + dst->color[1] = ((GLubyte *)p)[1]; + dst->color[0] = ((GLubyte *)p)[2]; + dst->color[3] = ((GLubyte *)p)[3]; + p++; + + { + GLuint xy = LE32_IN( p ); + + dst->win[0] = UNVIEWPORT_X( (GLfloat)(GLshort)( xy >> 16 ) ); + dst->win[1] = UNVIEWPORT_Y( (GLfloat)(GLshort)( xy & 0xffff ) ); + } + } + + assert( p + 1 - (CARD32 *)src == 10 ); + + dst->pointSize = ctx->Point._Size; +} + + + +void TAG(print_vertex)( GLcontext *ctx, const VERTEX *v ) +{ + LOCALVARS + GLuint format = GET_VERTEX_FORMAT(); + CARD32 *p = (CARD32 *)v + 10 - mmesa->vertex_size; + + switch ( format ) { + case TEX1_VERTEX_FORMAT: + { + GLfloat u, v, w; +#ifdef MACH64_PREMULT_TEXCOORDS + float rhw = 1.0 / LE32_IN_FLOAT( p + 2 ); + + u = rhw*LE32_IN_FLOAT( p++ ); + v = rhw*LE32_IN_FLOAT( p++ ); +#else + u = LE32_IN_FLOAT( p++ ); + v = LE32_IN_FLOAT( p++ ); +#endif + w = LE32_IN_FLOAT( p++ ); + fprintf( stderr, "u1 %f v1 %f w1 %f\n", u, v, w ); + } + + case TEX0_VERTEX_FORMAT: + { + GLfloat u, v, w; +#ifdef MACH64_PREMULT_TEXCOORDS + float rhw = 1.0 / LE32_IN_FLOAT( p + 2 ); + + u = rhw*LE32_IN_FLOAT( p++ ); + v = rhw*LE32_IN_FLOAT( p++ ); +#else + u = LE32_IN_FLOAT( p++ ); + v = LE32_IN_FLOAT( p++ ); +#endif + w = LE32_IN_FLOAT( p++ ); + fprintf( stderr, "u0 %f v0 %f w0 %f\n", u, v, w ); + } + + case NOTEX_VERTEX_FORMAT: + { + GLubyte r, g, b, a; + + b = ((GLubyte *)p)[0]; + g = ((GLubyte *)p)[1]; + r = ((GLubyte *)p)[2]; + a = ((GLubyte *)p)[3]; + p++; + fprintf(stderr, "spec: r %d g %d b %d a %d\n", r, g, b, a); + } + + case TINY_VERTEX_FORMAT: + { + GLuint xy; + GLfloat x, y, z; + GLubyte r, g, b, a; + + z = LE32_IN( p++ ) / 65536.0; + + b = ((GLubyte *)p)[0]; + g = ((GLubyte *)p)[1]; + r = ((GLubyte *)p)[2]; + a = ((GLubyte *)p)[3]; + p++; + xy = LE32_IN( p ); + x = (GLfloat)(GLshort)( xy >> 16 ) / 4.0; + y = (GLfloat)(GLshort)( xy & 0xffff ) / 4.0; + + fprintf(stderr, "x %f y %f z %f\n", x, y, z); + fprintf(stderr, "r %d g %d b %d a %d\n", r, g, b, a); + } + } + + assert( p + 1 - (CARD32 *)v == 10 ); + + fprintf(stderr, "\n"); +} + +/* Interpolate the elements of the VB not included in typical hardware + * vertices. + * + * NOTE: All these arrays are guarenteed by tnl to be writeable and + * have good stride. + */ +#ifndef INTERP_QUALIFIER +#define INTERP_QUALIFIER static +#endif + +#define GET_COLOR(ptr, idx) ((ptr)->data[idx]) + + +INTERP_QUALIFIER void TAG(interp_extras)( GLcontext *ctx, + GLfloat t, + GLuint dst, GLuint out, GLuint in, + GLboolean force_boundary ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + if (VB->ColorPtr[1]) { + assert(VB->ColorPtr[1]->stride == 4 * sizeof(GLfloat)); + + INTERP_4F( t, + GET_COLOR(VB->ColorPtr[1], dst), + GET_COLOR(VB->ColorPtr[1], out), + GET_COLOR(VB->ColorPtr[1], in) ); + + if (VB->SecondaryColorPtr[1]) { + INTERP_3F( t, + GET_COLOR(VB->SecondaryColorPtr[1], dst), + GET_COLOR(VB->SecondaryColorPtr[1], out), + GET_COLOR(VB->SecondaryColorPtr[1], in) ); + } + } + + if (VB->EdgeFlag) { + VB->EdgeFlag[dst] = VB->EdgeFlag[out] || force_boundary; + } + + INTERP_VERTEX(ctx, t, dst, out, in, force_boundary); +} + +INTERP_QUALIFIER void TAG(copy_pv_extras)( GLcontext *ctx, + GLuint dst, GLuint src ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + if (VB->ColorPtr[1]) { + COPY_4FV( GET_COLOR(VB->ColorPtr[1], dst), + GET_COLOR(VB->ColorPtr[1], src) ); + + if (VB->SecondaryColorPtr[1]) { + COPY_4FV( GET_COLOR(VB->SecondaryColorPtr[1], dst), + GET_COLOR(VB->SecondaryColorPtr[1], src) ); + } + } + + COPY_PV_VERTEX(ctx, dst, src); +} + + +#undef INTERP_QUALIFIER +#undef GET_COLOR + +#undef IND +#undef TAG diff --git a/src/mach64_native_vbtmp.h b/src/mach64_native_vbtmp.h new file mode 100644 index 0000000..f64b808 --- /dev/null +++ b/src/mach64_native_vbtmp.h @@ -0,0 +1,562 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL 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. + * + * Original authors: + * Keith Whitwell <keithw@valinux.com> + * + * Adapted to Mach64 by: + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + + +/* DO_XYZW: Emit xyz and maybe w coordinates. + * DO_RGBA: Emit color. + * DO_SPEC: Emit specular color. + * DO_FOG: Emit fog coordinate in specular alpha. + * DO_TEX0: Emit tex0 u,v coordinates. + * DO_TEX1: Emit tex1 u,v coordinates. + * DO_PTEX: Emit tex0,1 q coordinates where possible. + * + * Additionally, this template assumes it is emitting *transformed* + * vertices; the modifications to emit untransformed vertices (ie. to + * t&l hardware) are probably too great to cooexist with the code + * already in this file. + */ + +#define VIEWPORT_X(x) ((GLint) ((s[0] * (x) + s[12]) * 4.0)) +#define VIEWPORT_Y(y) ((GLint) ((s[5] * (y) + s[13]) * 4.0)) +#define VIEWPORT_Z(z) (((GLuint) (s[10] * (z) + s[14])) << 15) + +#ifndef LOCALVARS +#define LOCALVARS +#endif + +static void TAG(emit)( GLcontext *ctx, + GLuint start, GLuint end, + void *dest, + GLuint stride ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; +#if DO_TEX1 + GLfloat (*tc1)[4]; + GLuint tc1_stride; +#if DO_PTEX + GLuint tc1_size; +#endif +#endif +#if DO_TEX0 + GLfloat (*tc0)[4]; + GLuint tc0_stride; +#if DO_PTEX + GLuint tc0_size; +#endif +#endif +#if DO_SPEC + GLfloat (*spec)[4]; + GLuint spec_stride; +#endif +#if DO_FOG + GLfloat (*fog)[4]; + GLuint fog_stride; +#endif +#if DO_RGBA + GLfloat (*col)[4]; + GLuint col_stride; +#endif + GLfloat (*coord)[4]; + GLuint coord_stride; + VERTEX *v = (VERTEX *)dest; + const GLfloat *s = GET_VIEWPORT_MAT(); +#if DO_TEX1 || DO_TEX0 || DO_XYZW + const GLubyte *mask = VB->ClipMask; +#endif + int i; + +#if !DO_XYZW + (void) s; /* Quiet compiler */ +#endif +/* fprintf(stderr, "%s(big) importable %d %d..%d\n", */ +/* __FUNCTION__, VB->importable_data, start, end); */ + +#if DO_TEX1 + { + const GLuint t1 = GET_TEXSOURCE(1); + tc1 = VB->TexCoordPtr[t1]->data; + tc1_stride = VB->TexCoordPtr[t1]->stride; +#if DO_PTEX + tc1_size = VB->TexCoordPtr[t1]->size; +#endif + } +#endif + +#if DO_TEX0 + { + const GLuint t0 = GET_TEXSOURCE(0); + tc0 = VB->TexCoordPtr[t0]->data; + tc0_stride = VB->TexCoordPtr[t0]->stride; +#if DO_PTEX + tc0_size = VB->TexCoordPtr[t0]->size; +#endif + } +#endif + +#if DO_SPEC + if (VB->SecondaryColorPtr[0]) { + spec = VB->SecondaryColorPtr[0]->data; + spec_stride = VB->SecondaryColorPtr[0]->stride; + } else { + spec = (GLfloat (*)[4])ctx->Current.Attrib[VERT_ATTRIB_COLOR1]; + spec_stride = 0; + } +#endif + +#if DO_FOG + if (VB->FogCoordPtr) { + fog = VB->FogCoordPtr->data; + fog_stride = VB->FogCoordPtr->stride; + } else { + static GLfloat tmp[4] = {0, 0, 0, 0}; + fog = &tmp; + fog_stride = 0; + } +#endif + +#if DO_RGBA + col = VB->ColorPtr[0]->data; + col_stride = VB->ColorPtr[0]->stride; +#endif + + coord = VB->NdcPtr->data; + coord_stride = VB->NdcPtr->stride; + + if (start) { +#if DO_TEX1 + STRIDE_4F(tc1, start * tc1_stride); +#endif +#if DO_TEX0 + STRIDE_4F(tc0, start * tc0_stride); +#endif +#if DO_SPEC + STRIDE_4F(spec, start * spec_stride); +#endif +#if DO_FOG + STRIDE_4F(fog, start * fog_stride); +#endif +#if DO_RGBA + STRIDE_4F(col, start * col_stride); +#endif + STRIDE_4F(coord, start * coord_stride); + } + + for (i=start; i < end; i++, v = (VERTEX *)((GLubyte *)v + stride)) { + CARD32 *p = (CARD32 *)v; +#if DO_TEX1 || DO_TEX0 + GLfloat w; + + if (mask[i] == 0) { + /* unclipped */ + w = coord[0][3]; + } else { + /* clipped */ + w = 1.0; + } +#endif + +#if DO_TEX1 +#if DO_PTEX + if (tc1_size == 4) { +#ifdef MACH64_PREMULT_TEXCOORDS + LE32_OUT_FLOAT( p++, w*tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ + LE32_OUT_FLOAT( p++, w*tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ + LE32_OUT_FLOAT( p++, w*tc1[0][3] ); /* VERTEX_?_SECONDARY_W */ +#else /* !MACH64_PREMULT_TEXCOORDS */ + float rhw = 1.0 / tc1[0][3]; + LE32_OUT_FLOAT( p++, rhw*tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ + LE32_OUT_FLOAT( p++, rhw*tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ + LE32_OUT_FLOAT( p++, w*tc1[0][3] ); /* VERTEX_?_SECONDARY_W */ +#endif /* !MACH64_PREMULT_TEXCOORDS */ + } else { +#endif /* DO_PTEX */ +#ifdef MACH64_PREMULT_TEXCOORDS + LE32_OUT_FLOAT( p++, w*tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ + LE32_OUT_FLOAT( p++, w*tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ + LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_SECONDARY_W */ +#else /* !MACH64_PREMULT_TEXCOORDS */ + LE32_OUT_FLOAT( p++, tc1[0][0] ); /* VERTEX_?_SECONDARY_S */ + LE32_OUT_FLOAT( p++, tc1[0][1] ); /* VERTEX_?_SECONDARY_T */ + LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_SECONDARY_W */ +#endif /* !MACH64_PREMULT_TEXCOORDS */ +#if DO_PTEX + } +#endif /* DO_PTEX */ + STRIDE_4F(tc1, tc1_stride); +#else /* !DO_TEX1 */ + p += 3; +#endif /* !DO_TEX1 */ + +#if DO_TEX0 +#if DO_PTEX + if (tc0_size == 4) { +#ifdef MACH64_PREMULT_TEXCOORDS + LE32_OUT_FLOAT( p++, w*tc0[0][0] ); /* VERTEX_?_S */ + LE32_OUT_FLOAT( p++, w*tc0[0][1] ); /* VERTEX_?_T */ + LE32_OUT_FLOAT( p++, w*tc0[0][3] ); /* VERTEX_?_W */ +#else /* !MACH64_PREMULT_TEXCOORDS */ + float rhw = 1.0 / tc0[0][3]; + LE32_OUT_FLOAT( p++, rhw*tc0[0][0] ); /* VERTEX_?_S */ + LE32_OUT_FLOAT( p++, rhw*tc0[0][1] ); /* VERTEX_?_T */ + LE32_OUT_FLOAT( p++, w*tc0[0][3] ); /* VERTEX_?_W */ +#endif /* !MACH64_PREMULT_TEXCOORDS */ + } else { +#endif /* DO_PTEX */ +#ifdef MACH64_PREMULT_TEXCOORDS + LE32_OUT_FLOAT( p++, w*tc0[0][0] ); /* VERTEX_?_S */ + LE32_OUT_FLOAT( p++, w*tc0[0][1] ); /* VERTEX_?_T */ + LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_W */ +#else /* !MACH64_PREMULT_TEXCOORDS */ + LE32_OUT_FLOAT( p++, tc0[0][0] ); /* VERTEX_?_S */ + LE32_OUT_FLOAT( p++, tc0[0][1] ); /* VERTEX_?_T */ + LE32_OUT_FLOAT( p++, w ); /* VERTEX_?_W */ +#endif /* !MACH64_PREMULT_TEXCOORDS */ +#if DO_PTEX + } +#endif /* DO_PTEX */ + STRIDE_4F(tc0, tc0_stride); +#else /* !DO_TEX0 */ + p += 3; +#endif /* !DO_TEX0 */ + +#if DO_SPEC + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[0], spec[0][2]); /* VERTEX_?_SPEC_B */ + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[1], spec[0][1]); /* VERTEX_?_SPEC_G */ + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[2], spec[0][0]); /* VERTEX_?_SPEC_R */ + + STRIDE_4F(spec, spec_stride); +#endif +#if DO_FOG + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[3], fog[0][0]); /* VERTEX_?_SPEC_A */ + /* ((GLubyte *)p)[3] = fog[0][0] * 255.0; */ + STRIDE_4F(fog, fog_stride); +#endif + p++; + +#if DO_XYZW + if (mask[i] == 0) { + /* unclipped */ + LE32_OUT( p++, VIEWPORT_Z( coord[0][2] ) ); /* VERTEX_?_Z */ + } else { +#endif + p++; +#if DO_XYZW + } +#endif + +#if DO_RGBA + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[0], col[0][2]); + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[1], col[0][1]); + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[2], col[0][0]); + UNCLAMPED_FLOAT_TO_UBYTE(((GLubyte *)p)[3], col[0][3]); + p++; + STRIDE_4F(col, col_stride); +#else + p++; +#endif + +#if DO_XYZW + if (mask[i] == 0) { + /* unclipped */ + LE32_OUT( p, + (VIEWPORT_X( coord[0][0] ) << 16) | /* VERTEX_?_X */ + (VIEWPORT_Y( coord[0][1] ) & 0xffff) ); /* VERTEX_?_Y */ + + if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { + fprintf( stderr, "%s: vert %d: %.2f %.2f %.2f %x\n", + __FUNCTION__, + i, + (LE32_IN( p ) >> 16)/4.0, + (LE32_IN( p ) & 0xffff)/4.0, + LE32_IN( p - 2 )/65536.0, + *(GLuint *)(p - 1) ); + } + } +#endif +#if DO_TEX1 || DO_TEX0 || DO_XYZW + STRIDE_4F(coord, coord_stride); +#endif + + assert( p + 1 - (CARD32 *)v == 10 ); + } +} + +#if DO_XYZW && DO_RGBA + +static GLboolean TAG(check_tex_sizes)( GLcontext *ctx ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + /* Force 'missing' texcoords to something valid. + */ + if (DO_TEX1 && VB->TexCoordPtr[0] == 0) + VB->TexCoordPtr[0] = VB->TexCoordPtr[1]; + + if (DO_PTEX) + return GL_TRUE; + + /* No hardware support for projective texture. Can fake it for + * TEX0 only. + */ + if ((DO_TEX1 && VB->TexCoordPtr[GET_TEXSOURCE(1)]->size == 4)) { + PTEX_FALLBACK(); + return GL_FALSE; + } + + if (DO_TEX0 && VB->TexCoordPtr[GET_TEXSOURCE(0)]->size == 4) { + if (DO_TEX1) { + PTEX_FALLBACK(); + } + return GL_FALSE; + } + + return GL_TRUE; +} + + +static void TAG(interp)( GLcontext *ctx, + GLfloat t, + GLuint edst, GLuint eout, GLuint ein, + GLboolean force_boundary ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLubyte *ddverts = GET_VERTEX_STORE(); + GLuint size = GET_VERTEX_SIZE(); + const GLfloat *dstclip = VB->ClipPtr->data[edst]; + GLfloat w; + const GLfloat *s = GET_VIEWPORT_MAT(); + + CARD32 *dst = (CARD32 *)(ddverts + (edst * size)); + CARD32 *in = (CARD32 *)(ddverts + (ein * size)); + CARD32 *out = (CARD32 *)(ddverts + (eout * size)); + + (void)s; + + w = (dstclip[3] == 0.0F) ? 1.0 : (1.0 / dstclip[3]); + +#if DO_TEX1 + { + GLfloat temp; +#if DO_PTEX + GLfloat wout = VB->NdcPtr->data[eout][3]; + GLfloat win = VB->NdcPtr->data[ein][3]; + GLfloat qout = LE32_IN_FLOAT( out + 2 ) / wout; + GLfloat qin = LE32_IN_FLOAT( in + 2 ) / win; + GLfloat qdst, rqdst; + + INTERP_F( t, qdst, qout, qin ); + rqdst = 1.0 / qdst; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_SECONDARY_S */ + dst++; out++; in++; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_SECONDARY_T */ + dst++; out++; in++; + + LE32_OUT_FLOAT( dst, w*rqdst ); /* VERTEX_?_SECONDARY_W */ + dst++; out++; in++; +#else /* !DO_PTEX */ +#ifdef MACH64_PREMULT_TEXCOORDS + GLfloat qout = w / LE32_IN_FLOAT( out + 2 ); + GLfloat qin = w / LE32_IN_FLOAT( in + 2 ); + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_S */ + dst++; out++; in++; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_T */ + dst++; out++; in++; +#else /* !MACH64_PREMULT_TEXCOORDS */ + INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_S */ + dst++; out++; in++; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_SECONDARY_T */ + dst++; out++; in++; +#endif /* !MACH64_PREMULT_TEXCOORDS */ + LE32_OUT_FLOAT( dst, w ); /* VERTEX_?_SECONDARY_W */ + dst++; out++; in++; +#endif /* !DO_PTEX */ + } +#else /* !DO_TEX1 */ + dst += 3; out += 3; in += 3; +#endif /* !DO_TEX1 */ + +#if DO_TEX0 + { + GLfloat temp; +#if DO_PTEX + GLfloat wout = VB->NdcPtr->data[eout][3]; + GLfloat win = VB->NdcPtr->data[ein][3]; + GLfloat qout = LE32_IN_FLOAT( out + 2 ) / wout; + GLfloat qin = LE32_IN_FLOAT( in + 2 ) / win; + GLfloat qdst, rqdst; + + INTERP_F( t, qdst, qout, qin ); + rqdst = 1.0 / qdst; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_S */ + dst++; out++; in++; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp*rqdst ); /* VERTEX_?_T */ + dst++; out++; in++; + + LE32_OUT_FLOAT( dst, w*rqdst ); /* VERTEX_?_W */ + dst++; out++; in++; +#else /* !DO_PTEX */ +#ifdef MACH64_PREMULT_TEXCOORDS + GLfloat qout = w / LE32_IN_FLOAT( out + 2 ); + GLfloat qin = w / LE32_IN_FLOAT( in + 2 ); + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_S */ + dst++; out++; in++; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ) * qout, LE32_IN_FLOAT( in ) * qin ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_T */ + dst++; out++; in++; +#else /* !MACH64_PREMULT_TEXCOORDS */ + INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_S */ + dst++; out++; in++; + + INTERP_F( t, temp, LE32_IN_FLOAT( out ), LE32_IN_FLOAT( in ) ); + LE32_OUT_FLOAT( dst, temp ); /* VERTEX_?_T */ + dst++; out++; in++; +#endif /* !MACH64_PREMULT_TEXCOORDS */ + LE32_OUT_FLOAT( dst, w ); /* VERTEX_?_W */ + dst++; out++; in++; +#endif /* !DO_PTEX */ + } +#else /* !DO_TEX0 */ + dst += 3; out += 3; in += 3; +#endif /* !DO_TEX0 */ + +#if DO_SPEC + INTERP_UB( t, ((GLubyte *)dst)[0], ((GLubyte *)out)[0], ((GLubyte *)in)[0] ); /* VERTEX_?_SPEC_B */ + INTERP_UB( t, ((GLubyte *)dst)[1], ((GLubyte *)out)[1], ((GLubyte *)in)[1] ); /* VERTEX_?_SPEC_G */ + INTERP_UB( t, ((GLubyte *)dst)[2], ((GLubyte *)out)[2], ((GLubyte *)in)[2] ); /* VERTEX_?_SPEC_R */ +#endif + +#if DO_FOG + INTERP_UB( t, ((GLubyte *)dst)[3], ((GLubyte *)out)[3], ((GLubyte *)in)[3] ); /* VERTEX_?_SPEC_A */ +#endif /* DO_FOG */ + + dst++; out++; in++; + + LE32_OUT( dst, VIEWPORT_Z( dstclip[2] * w ) ); /* VERTEX_?_Z */ + dst++; out++; in++; + + INTERP_UB( t, ((GLubyte *)dst)[0], ((GLubyte *)out)[0], ((GLubyte *)in)[0] ); /* VERTEX_?_B */ + INTERP_UB( t, ((GLubyte *)dst)[1], ((GLubyte *)out)[1], ((GLubyte *)in)[1] ); /* VERTEX_?_G */ + INTERP_UB( t, ((GLubyte *)dst)[2], ((GLubyte *)out)[2], ((GLubyte *)in)[2] ); /* VERTEX_?_R */ + INTERP_UB( t, ((GLubyte *)dst)[3], ((GLubyte *)out)[3], ((GLubyte *)in)[3] ); /* VERTEX_?_A */ + dst++; /*out++; in++;*/ + + LE32_OUT( dst, + (VIEWPORT_X( dstclip[0] * w ) << 16) | /* VERTEX_?_X */ + (VIEWPORT_Y( dstclip[1] * w ) & 0xffff) ); /* VERTEX_?_Y */ + + assert( dst + 1 - (CARD32 *)(ddverts + (edst * size)) == 10 ); + assert( in + 2 - (CARD32 *)(ddverts + (ein * size)) == 10 ); + assert( out + 2 - (CARD32 *)(ddverts + (eout * size)) == 10 ); + + if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { + fprintf( stderr, "%s: dst vert: %.2f %.2f %.2f %x\n", + __FUNCTION__, + (GLshort)(LE32_IN( dst ) >> 16)/4.0, + (GLshort)(LE32_IN( dst ) & 0xffff)/4.0, + LE32_IN( dst - 2 )/65536.0, + *(GLuint *)(dst - 1) ); + } +} + +#endif /* DO_RGBA && DO_XYZW */ + + +static void TAG(copy_pv)( GLcontext *ctx, GLuint edst, GLuint esrc ) +{ +#if DO_SPEC || DO_FOG || DO_RGBA + LOCALVARS + GLubyte *verts = GET_VERTEX_STORE(); + GLuint size = GET_VERTEX_SIZE(); + GLuint *dst = (GLuint *)(verts + (edst * size)); + GLuint *src = (GLuint *)(verts + (esrc * size)); +#endif + +#if DO_SPEC || DO_FOG + dst[6] = src[6]; /* VERTEX_?_SPEC_ARGB */ +#endif + +#if DO_RGBA + dst[8] = src[8]; /* VERTEX_?_ARGB */ +#endif +} + +static void TAG(init)( void ) +{ + setup_tab[IND].emit = TAG(emit); + +#if DO_XYZW && DO_RGBA + setup_tab[IND].check_tex_sizes = TAG(check_tex_sizes); + setup_tab[IND].interp = TAG(interp); +#endif + + setup_tab[IND].copy_pv = TAG(copy_pv); + +#if DO_TEX1 + setup_tab[IND].vertex_format = TEX1_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 10; +#elif DO_TEX0 + setup_tab[IND].vertex_format = TEX0_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 7; +#elif DO_SPEC || DO_FOG + setup_tab[IND].vertex_format = NOTEX_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 4; +#else + setup_tab[IND].vertex_format = TINY_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 3; +#endif + +} + + +#undef IND +#undef TAG diff --git a/src/mach64_reg.h b/src/mach64_reg.h new file mode 100644 index 0000000..abbba29 --- /dev/null +++ b/src/mach64_reg.h @@ -0,0 +1,406 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#ifndef __MACH64_REG_H__ +#define __MACH64_REG_H__ + +/* + * Not sure how this compares with the G200, but the Rage Pro has two + * banks of registers, with bank 0 at (aperture base + memmap offset - 1KB) + * and bank 1 at (aperture base + memmap offset - 2KB). But, to send them + * via DMA, we need to encode them as memory map select rather than physical + * offsets. + */ +#define DWMREG0 0x0400 +#define DWMREG0_END 0x07ff +#define DWMREG1 0x0000 +#define DWMREG1_END 0x03ff + +#define ISREG0(r) ( ( (r) >= DWMREG0 ) && ( (r) <= DWMREG0_END ) ) +#define ADRINDEX0(r) ( ((r) - DWMREG0) >> 2 ) +#define ADRINDEX1(r) ( ( ((r) - DWMREG1) >> 2 ) | 0x0100 ) +#define ADRINDEX(r) ( ISREG0(r) ? ADRINDEX0(r) : ADRINDEX1(r) ) + +#define MMREG0 0x0000 +#define MMREG0_END 0x00ff + +#define ISMMREG0(r) ( ( (r) >= MMREG0 ) && ( (r) <= MMREG0_END ) ) +#define MMSELECT0(r) ( ((r)<<2) + DWMREG0 ) +#define MMSELECT1(r) ( ( (((r) & 0xff)<<2) + DWMREG1 ) ) +#define MMSELECT(r) ( ISMMREG0(r) ? MMSELECT0(r) : MMSELECT1(r) ) + +/* FIXME: If register reads are necessary, we should account for endianess here */ +#define MACH64_BASE(reg) ((CARD32)(mmesa->mach64Screen->mmio.map)) +#define MACH64_ADDR(reg) (MACH64_BASE(reg) + reg) + +#define MACH64_DEREF(reg) *(__volatile__ CARD32 *)MACH64_ADDR(reg) +#define MACH64_READ(reg) MACH64_DEREF(reg) + + +/* ================================================================ + * Registers + */ + +#define MACH64_ALPHA_TST_CNTL 0x0550 +# define MACH64_ALPHA_TEST_EN (1 << 0) +# define MACH64_ALPHA_TEST_MASK (7 << 4) +# define MACH64_ALPHA_TEST_NEVER (0 << 4) +# define MACH64_ALPHA_TEST_LESS (1 << 4) +# define MACH64_ALPHA_TEST_LEQUAL (2 << 4) +# define MACH64_ALPHA_TEST_EQUAL (3 << 4) +# define MACH64_ALPHA_TEST_GEQUAL (4 << 4) +# define MACH64_ALPHA_TEST_GREATER (5 << 4) +# define MACH64_ALPHA_TEST_NOTEQUAL (6 << 4) +# define MACH64_ALPHA_TEST_ALWAYS (7 << 4) +# define MACH64_ALPHA_MOD_MSB (1 << 7) +# define MACH64_ALPHA_DST_MASK (7 << 8) +# define MACH64_ALPHA_DST_ZERO (0 << 8) +# define MACH64_ALPHA_DST_ONE (1 << 8) +# define MACH64_ALPHA_DST_SRCALPHA (4 << 8) +# define MACH64_ALPHA_DST_INVSRCALPHA (5 << 8) +# define MACH64_ALPHA_DST_DSTALPHA (6 << 8) +# define MACH64_ALPHA_DST_INVDSTALPHA (7 << 8) +# define MACH64_ALPHA_TST_SRC_TEXEL (0 << 12) +# define MACH64_ALPHA_TST_SRC_SRCALPHA (1 << 12) +# define MACH64_REF_ALPHA_MASK (0xff << 16) +# define MACH64_REF_ALPHA_SHIFT 16 +# define MACH64_COMPOSITE_SHADOW (1 << 30) +# define MACH64_SPECULAR_LIGHT_EN (1 << 31) + +#define MACH64_BUS_CNTL 0x04a0 +# define MACH64_BUS_MSTR_RESET (1 << 1) +# define MACH64_BUS_FLUSH_BUF (1 << 2) +# define MACH64_BUS_MASTER_DIS (1 << 6) +# define MACH64_BUS_EXT_REG_EN (1 << 27) + +#define MACH64_COMPOSITE_SHADOW_ID 0x0798 + +#define MACH64_CLR_CMP_CLR 0x0700 +#define MACH64_CLR_CMP_CNTL 0x0708 +#define MACH64_CLR_CMP_MASK 0x0704 + +#define MACH64_DP_BKGD_CLR 0x06c0 +#define MACH64_DP_FOG_CLR 0x06c4 +#define MACH64_DP_FGRD_BKGD_CLR 0x06e0 +#define MACH64_DP_FRGD_CLR 0x06c4 +#define MACH64_DP_FGRD_CLR_MIX 0x06dc + +#define MACH64_DP_MIX 0x06d4 +# define BKGD_MIX_NOT_D (0 << 0) +# define BKGD_MIX_ZERO (1 << 0) +# define BKGD_MIX_ONE (2 << 0) +# define MACH64_BKGD_MIX_D (3 << 0) +# define BKGD_MIX_NOT_S (4 << 0) +# define BKGD_MIX_D_XOR_S (5 << 0) +# define BKGD_MIX_NOT_D_XOR_S (6 << 0) +# define MACH64_BKGD_MIX_S (7 << 0) +# define BKGD_MIX_NOT_D_OR_NOT_S (8 << 0) +# define BKGD_MIX_D_OR_NOT_S (9 << 0) +# define BKGD_MIX_NOT_D_OR_S (10 << 0) +# define BKGD_MIX_D_OR_S (11 << 0) +# define BKGD_MIX_D_AND_S (12 << 0) +# define BKGD_MIX_NOT_D_AND_S (13 << 0) +# define BKGD_MIX_D_AND_NOT_S (14 << 0) +# define BKGD_MIX_NOT_D_AND_NOT_S (15 << 0) +# define BKGD_MIX_D_PLUS_S_DIV2 (23 << 0) +# define FRGD_MIX_NOT_D (0 << 16) +# define FRGD_MIX_ZERO (1 << 16) +# define FRGD_MIX_ONE (2 << 16) +# define FRGD_MIX_D (3 << 16) +# define FRGD_MIX_NOT_S (4 << 16) +# define FRGD_MIX_D_XOR_S (5 << 16) +# define FRGD_MIX_NOT_D_XOR_S (6 << 16) +# define MACH64_FRGD_MIX_S (7 << 16) +# define FRGD_MIX_NOT_D_OR_NOT_S (8 << 16) +# define FRGD_MIX_D_OR_NOT_S (9 << 16) +# define FRGD_MIX_NOT_D_OR_S (10 << 16) +# define FRGD_MIX_D_OR_S (11 << 16) +# define FRGD_MIX_D_AND_S (12 << 16) +# define FRGD_MIX_NOT_D_AND_S (13 << 16) +# define FRGD_MIX_D_AND_NOT_S (14 << 16) +# define FRGD_MIX_NOT_D_AND_NOT_S (15 << 16) +# define FRGD_MIX_D_PLUS_S_DIV2 (23 << 16) + +#define MACH64_DP_PIX_WIDTH 0x06d0 +# define MACH64_COMPOSITE_PIX_WIDTH_MASK (0xf << 4) +# define MACH64_HOST_TRIPLE_ENABLE (1 << 13) +# define MACH64_BYTE_ORDER_MSB_TO_LSB (0 << 24) +# define MACH64_BYTE_ORDER_LSB_TO_MSB (1 << 24) +# define MACH64_SCALE_PIX_WIDTH_MASK (0xf << 28) + +#define MACH64_DP_SRC 0x06d8 +# define MACH64_BKGD_SRC_BKGD_CLR (0 << 0) +# define MACH64_BKGD_SRC_FRGD_CLR (1 << 0) +# define MACH64_BKGD_SRC_HOST (2 << 0) +# define MACH64_BKGD_SRC_BLIT (3 << 0) +# define MACH64_BKGD_SRC_PATTERN (4 << 0) +# define MACH64_BKGD_SRC_3D (5 << 0) +# define MACH64_FRGD_SRC_BKGD_CLR (0 << 8) +# define MACH64_FRGD_SRC_FRGD_CLR (1 << 8) +# define MACH64_FRGD_SRC_HOST (2 << 8) +# define MACH64_FRGD_SRC_BLIT (3 << 8) +# define MACH64_FRGD_SRC_PATTERN (4 << 8) +# define MACH64_FRGD_SRC_3D (5 << 8) +# define MACH64_MONO_SRC_ONE (0 << 16) +# define MACH64_MONO_SRC_PATTERN (1 << 16) +# define MACH64_MONO_SRC_HOST (2 << 16) +# define MACH64_MONO_SRC_BLIT (3 << 16) + +#define MACH64_DP_WRITE_MASK 0x06c8 + +#define MACH64_DST_CNTL 0x0530 +# define MACH64_DST_X_RIGHT_TO_LEFT (0 << 0) +# define MACH64_DST_X_LEFT_TO_RIGHT (1 << 0) +# define MACH64_DST_Y_BOTTOM_TO_TOP (0 << 1) +# define MACH64_DST_Y_TOP_TO_BOTTOM (1 << 1) +# define MACH64_DST_X_MAJOR (0 << 2) +# define MACH64_DST_Y_MAJOR (1 << 2) +# define MACH64_DST_X_TILE (1 << 3) +# define MACH64_DST_Y_TILE (1 << 4) +# define MACH64_DST_LAST_PEL (1 << 5) +# define MACH64_DST_POLYGON_ENABLE (1 << 6) +# define MACH64_DST_24_ROTATION_ENABLE (1 << 7) + +#define MACH64_DST_HEIGHT_WIDTH 0x0518 +#define MACH64_DST_OFF_PITCH 0x0500 +#define MACH64_DST_WIDTH_HEIGHT 0x06ec +#define MACH64_DST_X_Y 0x06e8 +#define MACH64_DST_Y_X 0x050c + +#define MACH64_FIFO_STAT 0x0710 +# define MACH64_FIFO_SLOT_MASK 0x0000ffff +# define MACH64_FIFO_ERR (1 << 31) + +#define MACH64_GEN_TEST_CNTL 0x04d0 +#define MACH64_GUI_CMDFIFO_DEBUG 0x0170 +#define MACH64_GUI_CMDFIFO_DATA 0x0174 +#define MACH64_GUI_CNTL 0x0178 +#define MACH64_GUI_STAT 0x0738 +# define MACH64_GUI_ACTIVE (1 << 0) +#define MACH64_GUI_TRAJ_CNTL 0x0730 + +#define MACH64_HOST_CNTL 0x0640 +#define MACH64_HOST_DATA0 0x0600 +#define MACH64_HW_DEBUG 0x047c + +#define MACH64_ONE_OVER_AREA 0x029c +#define MACH64_ONE_OVER_AREA_UC 0x0300 + +#define MACH64_PAT_REG0 0x0680 +#define MACH64_PAT_REG1 0x0684 + +#define MACH64_SC_LEFT_RIGHT 0x06a8 +#define MACH64_SC_TOP_BOTTOM 0x06b4 +#define MACH64_SCALE_3D_CNTL 0x05fc +# define MACH64_SCALE_PIX_EXPAND_ZERO_EXTEND (0 << 0) +# define MACH64_SCALE_PIX_EXPAND_DYNAMIC_RANGE (1 << 0) +# define MACH64_SCALE_DITHER_ERROR_DIFFUSE (0 << 1) +# define MACH64_SCALE_DITHER_2D_TABLE (1 << 1) +# define MACH64_DITHER_EN (1 << 2) +# define MACH64_DITHER_INIT_CURRENT (O << 3) +# define MACH64_DITHER_INIT_RESET (1 << 3) +# define MACH64_ROUND_EN (1 << 4) +# define MACH64_TEX_CACHE_DIS (1 << 5) +# define MACH64_SCALE_3D_FCN_MASK (3 << 6) +# define MACH64_SCALE_3D_FCN_NOP (0 << 6) +# define MACH64_SCALE_3D_FCN_SCALE (1 << 6) +# define MACH64_SCALE_3D_FCN_TEXTURE (2 << 6) +# define MACH64_SCALE_3D_FCN_SHADE (3 << 6) +# define MACH64_TEXTURE_DISABLE (1 << 6) +# define MACH64_EDGE_ANTI_ALIAS (1 << 8) +# define MACH64_TEX_CACHE_SPLIT (1 << 9) +# define MACH64_APPLE_YUV_MODE (1 << 10) +# define MACH64_ALPHA_FOG_EN_MASK (3 << 11) +# define MACH64_ALPHA_FOG_DIS (0 << 11) +# define MACH64_ALPHA_FOG_EN_ALPHA (1 << 11) +# define MACH64_ALPHA_FOG_EN_FOG (2 << 11) +# define MACH64_ALPHA_BLEND_SAT (1 << 13) +# define MACH64_RED_DITHER_MAX (1 << 14) +# define MACH64_SIGNED_DST_CLAMP (1 << 15) +# define MACH64_ALPHA_BLEND_SRC_MASK (7 << 16) +# define MACH64_ALPHA_BLEND_SRC_ZERO (0 << 16) +# define MACH64_ALPHA_BLEND_SRC_ONE (1 << 16) +# define MACH64_ALPHA_BLEND_SRC_DSTCOLOR (2 << 16) +# define MACH64_ALPHA_BLEND_SRC_INVDSTCOLOR (3 << 16) +# define MACH64_ALPHA_BLEND_SRC_SRCALPHA (4 << 16) +# define MACH64_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16) +# define MACH64_ALPHA_BLEND_SRC_DSTALPHA (6 << 16) +# define MACH64_ALPHA_BLEND_SRC_INVDSTALPHA (7 << 16) +# define MACH64_ALPHA_BLEND_DST_MASK (7 << 19) +# define MACH64_ALPHA_BLEND_DST_ZERO (0 << 19) +# define MACH64_ALPHA_BLEND_DST_ONE (1 << 19) +# define MACH64_ALPHA_BLEND_DST_SRCCOLOR (2 << 19) +# define MACH64_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 19) +# define MACH64_ALPHA_BLEND_DST_SRCALPHA (4 << 19) +# define MACH64_ALPHA_BLEND_DST_INVSRCALPHA (5 << 19) +# define MACH64_ALPHA_BLEND_DST_DSTALPHA (6 << 19) +# define MACH64_ALPHA_BLEND_DST_INVDSTALPHA (7 << 19) +# define MACH64_TEX_LIGHT_FCN_MASK (3 << 22) +# define MACH64_TEX_LIGHT_FCN_REPLACE (0 << 22) +# define MACH64_TEX_LIGHT_FCN_MODULATE (1 << 22) +# define MACH64_TEX_LIGHT_FCN_ALPHA_DECAL (2 << 22) +# define MACH64_MIP_MAP_DISABLE (1 << 24) +# define MACH64_BILINEAR_TEX_EN (1 << 25) +# define MACH64_TEX_BLEND_FCN_MASK (3 << 26) +# define MACH64_TEX_BLEND_FCN_NEAREST (0 << 26) +# define MACH64_TEX_BLEND_FCN_LINEAR (2 << 26) +# define MACH64_TEX_BLEND_FCN_TRILINEAR (3 << 26) +# define MACH64_TEX_AMASK_AEN (1 << 28) +# define MACH64_TEX_AMASK_BLEND_EDGE (1 << 29) +# define MACH64_TEX_MAP_AEN (1 << 30) +# define MACH64_SRC_3D_HOST_FIFO (1 << 31) +#define MACH64_SCRATCH_REG0 0x0480 +#define MACH64_SCRATCH_REG1 0x0484 +#define MACH64_SECONDARY_TEX_OFF 0x0778 +#define MACH64_SETUP_CNTL 0x0304 +# define MACH64_DONT_START_TRI (1 << 0) +# define MACH64_DONT_START_ANY (1 << 2) +# define MACH64_FLAT_SHADE_MASK (3 << 3) +# define MACH64_FLAT_SHADE_OFF (0 << 3) +# define MACH64_FLAT_SHADE_VERTEX_1 (1 << 3) +# define MACH64_FLAT_SHADE_VERTEX_2 (2 << 3) +# define MACH64_FLAT_SHADE_VERTEX_3 (3 << 3) +# define MACH64_SOLID_MODE_OFF (0 << 5) +# define MACH64_SOLID_MODE_ON (1 << 5) +# define MACH64_LOG_MAX_INC_ADJ (1 << 6) +# define MACH64_SET_UP_CONTINUE (1 << 31) +#define MACH64_SRC_CNTL 0x05b4 +#define MACH64_SRC_HEIGHT1 0x0594 +#define MACH64_SRC_HEIGHT2 0x05ac +#define MACH64_SRC_HEIGHT1_WIDTH1 0x0598 +#define MACH64_SRC_HEIGHT2_WIDTH2 0x05b0 +#define MACH64_SRC_OFF_PITCH 0x0580 +#define MACH64_SRC_WIDTH1 0x0590 +#define MACH64_SRC_Y_X 0x058c + +#define MACH64_TEX_0_OFF 0x05c0 +#define MACH64_TEX_CNTL 0x0774 +# define MACH64_LOD_BIAS_SHIFT 0 +# define MACH64_LOD_BIAS_MASK (0xf << 0) +# define MACH64_COMP_FACTOR_SHIFT 4 +# define MACH64_COMP_FACTOR_MASK (0xf << 4) +# define MACH64_TEXTURE_COMPOSITE (1 << 8) +# define MACH64_COMP_COMBINE_BLEND (0 << 9) +# define MACH64_COMP_COMBINE_MODULATE (1 << 9) +# define MACH64_COMP_BLEND_NEAREST (0 << 11) +# define MACH64_COMP_BLEND_BILINEAR (1 << 11) +# define MACH64_COMP_FILTER_NEAREST (0 << 12) +# define MACH64_COMP_FILTER_BILINEAR (1 << 12) +# define MACH64_COMP_ALPHA (1 << 13) +# define MACH64_TEXTURE_TILING (1 << 14) +# define MACH64_COMPOSITE_TEX_TILING (1 << 15) +# define MACH64_TEX_COLLISION_DISABLE (1 << 16) +# define MACH64_TEXTURE_CLAMP_S (1 << 17) +# define MACH64_TEXTURE_CLAMP_T (1 << 18) +# define MACH64_TEX_ST_MULT_W (0 << 19) +# define MACH64_TEX_ST_DIRECT (1 << 19) +# define MACH64_TEX_SRC_LOCAL (0 << 20) +# define MACH64_TEX_SRC_AGP (1 << 20) +# define MACH64_TEX_UNCOMPRESSED (0 << 21) +# define MACH64_TEX_VQ_COMPRESSED (1 << 21) +# define MACH64_COMP_TEX_UNCOMPRESSED (0 << 22) +# define MACH64_COMP_TEX_VQ_COMPRESSED (1 << 22) +# define MACH64_TEX_CACHE_FLUSH (1 << 23) +# define MACH64_SEC_TEX_CLAMP_S (1 << 24) +# define MACH64_SEC_TEX_CLAMP_T (1 << 25) +# define MACH64_TEX_WRAP_S (1 << 28) +# define MACH64_TEX_WRAP_T (1 << 29) +# define MACH64_TEX_CACHE_SIZE_4K (1 << 30) +# define MACH64_TEX_CACHE_SIZE_2K (1 << 30) +# define MACH64_SECONDARY_STW (1 << 31) +#define MACH64_TEX_PALETTE 0x077c +#define MACH64_TEX_PALETTE_INDEX 0x0740 +#define MACH64_TEX_SIZE_PITCH 0x0770 + +#define MACH64_VERTEX_1_ARGB 0x0254 +#define MACH64_VERTEX_1_S 0x0240 +#define MACH64_VERTEX_1_SECONDARY_S 0x0328 +#define MACH64_VERTEX_1_SECONDARY_T 0x032c +#define MACH64_VERTEX_1_SECONDARY_W 0x0330 +#define MACH64_VERTEX_1_SPEC_ARGB 0x024c +#define MACH64_VERTEX_1_T 0x0244 +#define MACH64_VERTEX_1_W 0x0248 +#define MACH64_VERTEX_1_X_Y 0x0258 +#define MACH64_VERTEX_1_Z 0x0250 +#define MACH64_VERTEX_2_ARGB 0x0274 +#define MACH64_VERTEX_2_S 0x0260 +#define MACH64_VERTEX_2_SECONDARY_S 0x0334 +#define MACH64_VERTEX_2_SECONDARY_T 0x0338 +#define MACH64_VERTEX_2_SECONDARY_W 0x033c +#define MACH64_VERTEX_2_SPEC_ARGB 0x026c +#define MACH64_VERTEX_2_T 0x0264 +#define MACH64_VERTEX_2_W 0x0268 +#define MACH64_VERTEX_2_X_Y 0x0278 +#define MACH64_VERTEX_2_Z 0x0270 +#define MACH64_VERTEX_3_ARGB 0x0294 +#define MACH64_VERTEX_3_S 0x0280 +#define MACH64_VERTEX_3_SECONDARY_S 0x02a0 +#define MACH64_VERTEX_3_SECONDARY_T 0x02a4 +#define MACH64_VERTEX_3_SECONDARY_W 0x02a8 +#define MACH64_VERTEX_3_SPEC_ARGB 0x028c +#define MACH64_VERTEX_3_T 0x0284 +#define MACH64_VERTEX_3_W 0x0288 +#define MACH64_VERTEX_3_X_Y 0x0298 +#define MACH64_VERTEX_3_Z 0x0290 + +#define MACH64_Z_CNTL 0x054c +# define MACH64_Z_EN (1 << 0) +# define MACH64_Z_SRC_2D (1 << 1) +# define MACH64_Z_TEST_MASK (7 << 4) +# define MACH64_Z_TEST_NEVER (0 << 4) +# define MACH64_Z_TEST_LESS (1 << 4) +# define MACH64_Z_TEST_LEQUAL (2 << 4) +# define MACH64_Z_TEST_EQUAL (3 << 4) +# define MACH64_Z_TEST_GEQUAL (4 << 4) +# define MACH64_Z_TEST_GREATER (5 << 4) +# define MACH64_Z_TEST_NOTEQUAL (6 << 4) +# define MACH64_Z_TEST_ALWAYS (7 << 4) +# define MACH64_Z_MASK_EN (1 << 8) +#define MACH64_Z_OFF_PITCH 0x0548 + + + +#define MACH64_DATATYPE_CI8 2 +#define MACH64_DATATYPE_ARGB1555 3 +#define MACH64_DATATYPE_RGB565 4 +#define MACH64_DATATYPE_ARGB8888 6 +#define MACH64_DATATYPE_RGB332 7 +#define MACH64_DATATYPE_Y8 8 +#define MACH64_DATATYPE_RGB8 9 +#define MACH64_DATATYPE_VYUY422 11 +#define MACH64_DATATYPE_YVYU422 12 +#define MACH64_DATATYPE_AYUV444 14 +#define MACH64_DATATYPE_ARGB4444 15 + +#define MACH64_LAST_FRAME_REG MACH64_PAT_REG0 +#define MACH64_LAST_DISPATCH_REG MACH64_PAT_REG1 + +#endif /* __MACH64_REG_H__ */ diff --git a/src/mach64_screen.c b/src/mach64_screen.c new file mode 100644 index 0000000..4e9e216 --- /dev/null +++ b/src/mach64_screen.c @@ -0,0 +1,557 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * Jos�Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "mach64_context.h" +#include "mach64_ioctl.h" +#include "mach64_tris.h" +#include "mach64_vb.h" +#include "mach64_span.h" + +#include "context.h" +#include "imports.h" +#include "framebuffer.h" +#include "renderbuffer.h" + +#include "utils.h" +#include "vblank.h" + +#include "GL/internal/dri_interface.h" + +/* Mach64 configuration + */ +#include "xmlpool.h" + +PUBLIC const char __driConfigOptions[] = +DRI_CONF_BEGIN + DRI_CONF_SECTION_PERFORMANCE + DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0) + DRI_CONF_SECTION_END + DRI_CONF_SECTION_DEBUG + DRI_CONF_NO_RAST(false) +#if ENABLE_PERF_BOXES + DRI_CONF_PERFORMANCE_BOXES(false) +#endif + DRI_CONF_SECTION_END +DRI_CONF_END; +#if ENABLE_PERF_BOXES +static const GLuint __driNConfigOptions = 3; +#else +static const GLuint __driNConfigOptions = 2; +#endif + +extern const struct dri_extension card_extensions[]; + +static __GLcontextModes * fill_in_modes( __GLcontextModes * modes, + unsigned pixel_bits, + unsigned depth_bits, + unsigned stencil_bits, + const GLenum * db_modes, + unsigned num_db_modes, + int visType ) +{ + static const u_int8_t bits[2][4] = { + { 5, 6, 5, 0 }, + { 8, 8, 8, 0 } + }; + + static const u_int32_t masks[2][4] = { + { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, + { 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000 } + }; + + unsigned i; + unsigned j; + const unsigned index = ((pixel_bits + 15) / 16) - 1; + + for ( i = 0 ; i < num_db_modes ; i++ ) { + for ( j = 0 ; j < 2 ; j++ ) { + + modes->redBits = bits[index][0]; + modes->greenBits = bits[index][1]; + modes->blueBits = bits[index][2]; + modes->alphaBits = bits[index][3]; + modes->redMask = masks[index][0]; + modes->greenMask = masks[index][1]; + modes->blueMask = masks[index][2]; + modes->alphaMask = masks[index][3]; + modes->rgbBits = modes->redBits + modes->greenBits + + modes->blueBits + modes->alphaBits; + + modes->accumRedBits = 16 * j; + modes->accumGreenBits = 16 * j; + modes->accumBlueBits = 16 * j; + modes->accumAlphaBits = 0; + modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG; + modes->drawableType = GLX_WINDOW_BIT | GLX_PIXMAP_BIT; + modes->stencilBits = stencil_bits; + modes->depthBits = depth_bits; + + modes->visualType = visType; + modes->renderType = GLX_RGBA_BIT; + modes->rgbMode = GL_TRUE; + + if ( db_modes[i] == GLX_NONE ) { + + modes->doubleBufferMode = GL_FALSE; + } + else { + modes->doubleBufferMode = GL_TRUE; + modes->swapMethod = db_modes[i]; + } + + modes = modes->next; + } + } + + return modes; +} + + +static __GLcontextModes * +mach64FillInModes( unsigned pixel_bits, unsigned depth_bits, + unsigned stencil_bits, GLboolean have_back_buffer ) +{ + __GLcontextModes * modes; + __GLcontextModes * m; + unsigned num_modes; + unsigned depth_buffer_factor; + unsigned back_buffer_factor; + unsigned i; + + /* Right now GLX_SWAP_COPY_OML isn't supported, but it would be easy + * enough to add support. Basically, if a context is created with an + * fbconfig where the swap method is GLX_SWAP_COPY_OML, pageflipping + * will never be used. + */ + static const GLenum back_buffer_modes[] = { + GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */ + }; + + int depth_buffer_modes[2][2]; + + + depth_buffer_modes[0][0] = depth_bits; + depth_buffer_modes[1][0] = depth_bits; + + /* Just like with the accumulation buffer, always provide some modes + * with a stencil buffer. It will be a sw fallback, but some apps won't + * care about that. + */ + depth_buffer_modes[0][1] = 0; + depth_buffer_modes[1][1] = (stencil_bits == 0) ? 8 : stencil_bits; + + depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1; + back_buffer_factor = (have_back_buffer) ? 2 : 1; + + num_modes = depth_buffer_factor * back_buffer_factor * 4; + + modes = (*dri_interface->createContextModes)( num_modes, sizeof( __GLcontextModes ) ); + m = modes; + for ( i = 0 ; i < depth_buffer_factor ; i++ ) { + m = fill_in_modes( m, pixel_bits, + depth_buffer_modes[i][0], depth_buffer_modes[i][1], + back_buffer_modes, back_buffer_factor, + GLX_TRUE_COLOR ); + } + + for ( i = 0 ; i < depth_buffer_factor ; i++ ) { + m = fill_in_modes( m, pixel_bits, + depth_buffer_modes[i][0], depth_buffer_modes[i][1], + back_buffer_modes, back_buffer_factor, + GLX_DIRECT_COLOR ); + } + + /* Mark the visual as slow if there are "fake" stencil bits. + */ + for ( m = modes ; m != NULL ; m = m->next ) { + if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ){ + m->visualRating = GLX_SLOW_CONFIG; + } + } + + return modes; +} + + +/* Create the device specific screen private data struct. + */ +static mach64ScreenRec * +mach64CreateScreen( __DRIscreenPrivate *sPriv ) +{ + mach64ScreenPtr mach64Screen; + ATIDRIPtr serverInfo = (ATIDRIPtr)sPriv->pDevPriv; + PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension = + (PFNGLXSCRENABLEEXTENSIONPROC) (*dri_interface->getProcAddress("glxEnableExtension")); + void * const psc = sPriv->psc->screenConfigs; + + if (sPriv->devPrivSize != sizeof(ATIDRIRec)) { + fprintf(stderr,"\nERROR! sizeof(ATIDRIRec) does not match passed size from device driver\n"); + return GL_FALSE; + } + + if ( MACH64_DEBUG & DEBUG_VERBOSE_DRI ) + fprintf( stderr, "%s\n", __FUNCTION__ ); + + /* Allocate the private area */ + mach64Screen = (mach64ScreenPtr) CALLOC( sizeof(*mach64Screen) ); + if ( !mach64Screen ) return NULL; + + /* parse information in __driConfigOptions */ + driParseOptionInfo (&mach64Screen->optionCache, + __driConfigOptions, __driNConfigOptions); + + mach64Screen->IsPCI = serverInfo->IsPCI; + + { + drm_mach64_getparam_t gp; + int ret; + + gp.param = MACH64_PARAM_IRQ_NR; + gp.value = (void *) &mach64Screen->irq; + + ret = drmCommandWriteRead( sPriv->fd, DRM_MACH64_GETPARAM, + &gp, sizeof(gp)); + if (ret) { + fprintf(stderr, "DRM_MACH64_GETPARAM (MACH64_PARAM_IRQ_NR): %d\n", ret); + FREE( mach64Screen ); + return NULL; + } + } + + mach64Screen->mmio.handle = serverInfo->regs; + mach64Screen->mmio.size = serverInfo->regsSize; + if ( drmMap( sPriv->fd, + mach64Screen->mmio.handle, + mach64Screen->mmio.size, + (drmAddressPtr)&mach64Screen->mmio.map ) != 0 ) { + FREE( mach64Screen ); + return NULL; + } + + mach64Screen->buffers = drmMapBufs( sPriv->fd ); + if ( !mach64Screen->buffers ) { + drmUnmap( (drmAddress)mach64Screen->mmio.map, + mach64Screen->mmio.size ); + FREE( mach64Screen ); + return NULL; + } + + if ( !mach64Screen->IsPCI ) { + mach64Screen->agpTextures.handle = serverInfo->agp; + mach64Screen->agpTextures.size = serverInfo->agpSize; + if ( drmMap( sPriv->fd, + mach64Screen->agpTextures.handle, + mach64Screen->agpTextures.size, + (drmAddressPtr)&mach64Screen->agpTextures.map ) ) { + drmUnmapBufs( mach64Screen->buffers ); + drmUnmap( (drmAddress)mach64Screen->mmio.map, mach64Screen->mmio.size ); + FREE( mach64Screen ); + return NULL; + } + } + + mach64Screen->AGPMode = serverInfo->AGPMode; + + mach64Screen->chipset = serverInfo->chipset; + mach64Screen->width = serverInfo->width; + mach64Screen->height = serverInfo->height; + mach64Screen->mem = serverInfo->mem; + mach64Screen->cpp = serverInfo->cpp; + + mach64Screen->frontOffset = serverInfo->frontOffset; + mach64Screen->frontPitch = serverInfo->frontPitch; + mach64Screen->backOffset = serverInfo->backOffset; + mach64Screen->backPitch = serverInfo->backPitch; + mach64Screen->depthOffset = serverInfo->depthOffset; + mach64Screen->depthPitch = serverInfo->depthPitch; + + mach64Screen->texOffset[MACH64_CARD_HEAP] = serverInfo->textureOffset; + mach64Screen->texSize[MACH64_CARD_HEAP] = serverInfo->textureSize; + mach64Screen->logTexGranularity[MACH64_CARD_HEAP] = + serverInfo->logTextureGranularity; + + if ( mach64Screen->IsPCI ) { + mach64Screen->numTexHeaps = MACH64_NR_TEX_HEAPS - 1; + mach64Screen->firstTexHeap = MACH64_CARD_HEAP; + mach64Screen->texOffset[MACH64_AGP_HEAP] = 0; + mach64Screen->texSize[MACH64_AGP_HEAP] = 0; + mach64Screen->logTexGranularity[MACH64_AGP_HEAP] = 0; + } else { + if (serverInfo->textureSize > 0) { + mach64Screen->numTexHeaps = MACH64_NR_TEX_HEAPS; + mach64Screen->firstTexHeap = MACH64_CARD_HEAP; + } else { + mach64Screen->numTexHeaps = MACH64_NR_TEX_HEAPS - 1; + mach64Screen->firstTexHeap = MACH64_AGP_HEAP; + } + mach64Screen->texOffset[MACH64_AGP_HEAP] = serverInfo->agpTextureOffset; + mach64Screen->texSize[MACH64_AGP_HEAP] = serverInfo->agpSize; + mach64Screen->logTexGranularity[MACH64_AGP_HEAP] = serverInfo->logAgpTextureGranularity; + } + + mach64Screen->driScreen = sPriv; + + if ( glx_enable_extension != NULL ) { + if ( mach64Screen->irq != 0 ) { + (*glx_enable_extension)( psc, "GLX_SGI_swap_control" ); + (*glx_enable_extension)( psc, "GLX_SGI_video_sync" ); + (*glx_enable_extension)( psc, "GLX_MESA_swap_control" ); + } + + (*glx_enable_extension)( psc, "GLX_MESA_swap_frame_usage" ); + } + + return mach64Screen; +} + +/* Destroy the device specific screen private data struct. + */ +static void +mach64DestroyScreen( __DRIscreenPrivate *driScreen ) +{ + mach64ScreenRec *mach64Screen = (mach64ScreenRec *) driScreen->private; + + if ( !mach64Screen ) + return; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_DRI ) + fprintf( stderr, "%s\n", __FUNCTION__ ); + + if ( !mach64Screen->IsPCI ) { + drmUnmap( (drmAddress)mach64Screen->agpTextures.map, + mach64Screen->agpTextures.size ); + } + + drmUnmapBufs( mach64Screen->buffers ); + drmUnmap( (drmAddress)mach64Screen->mmio.map, mach64Screen->mmio.size ); + + FREE( mach64Screen ); + driScreen->private = NULL; +} + + +/* Create and initialize the Mesa and driver specific pixmap buffer + * data. + */ +static GLboolean +mach64CreateBuffer( __DRIscreenPrivate *driScrnPriv, + __DRIdrawablePrivate *driDrawPriv, + const __GLcontextModes *mesaVis, + GLboolean isPixmap ) +{ + mach64ScreenPtr screen = (mach64ScreenPtr) driScrnPriv->private; + + if (isPixmap) { + return GL_FALSE; /* not implemented */ + } + else { + struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis); + + { + driRenderbuffer *frontRb + = driNewRenderbuffer(GL_RGBA, + NULL, + screen->cpp, + screen->frontOffset, screen->frontPitch, + driDrawPriv); + mach64SetSpanFunctions(frontRb, mesaVis); + _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base); + } + + if (mesaVis->doubleBufferMode) { + driRenderbuffer *backRb + = driNewRenderbuffer(GL_RGBA, + NULL, + screen->cpp, + screen->backOffset, screen->backPitch, + driDrawPriv); + mach64SetSpanFunctions(backRb, mesaVis); + _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base); + } + + if (mesaVis->depthBits == 16) { + driRenderbuffer *depthRb + = driNewRenderbuffer(GL_DEPTH_COMPONENT16, + NULL, screen->cpp, + screen->depthOffset, screen->depthPitch, + driDrawPriv); + mach64SetSpanFunctions(depthRb, mesaVis); + _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base); + } + else if (mesaVis->depthBits == 24) { + /* XXX I don't think 24-bit Z is supported - so this isn't used */ + driRenderbuffer *depthRb + = driNewRenderbuffer(GL_DEPTH_COMPONENT24, + NULL, + screen->cpp, + screen->depthOffset, screen->depthPitch, + driDrawPriv); + mach64SetSpanFunctions(depthRb, mesaVis); + _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base); + } + + _mesa_add_soft_renderbuffers(fb, + GL_FALSE, /* color */ + GL_FALSE, /* depth */ + mesaVis->stencilBits > 0, + mesaVis->accumRedBits > 0, + GL_FALSE, /* alpha */ + GL_FALSE /* aux */); + driDrawPriv->driverPrivate = (void *) fb; + + return (driDrawPriv->driverPrivate != NULL); + } +} + + +static void +mach64DestroyBuffer(__DRIdrawablePrivate *driDrawPriv) +{ + _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate))); +} + + +/* Copy the back color buffer to the front color buffer */ +static void +mach64SwapBuffers(__DRIdrawablePrivate *dPriv) +{ + if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { + mach64ContextPtr mmesa; + GLcontext *ctx; + mmesa = (mach64ContextPtr) dPriv->driContextPriv->driverPrivate; + ctx = mmesa->glCtx; + if (ctx->Visual.doubleBufferMode) { + _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */ + mach64CopyBuffer( dPriv ); + } + } + else { + /* XXX this shouldn't be an error but we can't handle it for now */ + _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__); + } +} + + +/* Initialize the driver specific screen private data. + */ +static GLboolean +mach64InitDriver( __DRIscreenPrivate *driScreen ) +{ + driScreen->private = (void *) mach64CreateScreen( driScreen ); + + if ( !driScreen->private ) { + mach64DestroyScreen( driScreen ); + return GL_FALSE; + } + + return GL_TRUE; +} + + +static struct __DriverAPIRec mach64API = { + .InitDriver = mach64InitDriver, + .DestroyScreen = mach64DestroyScreen, + .CreateContext = mach64CreateContext, + .DestroyContext = mach64DestroyContext, + .CreateBuffer = mach64CreateBuffer, + .DestroyBuffer = mach64DestroyBuffer, + .SwapBuffers = mach64SwapBuffers, + .MakeCurrent = mach64MakeCurrent, + .UnbindContext = mach64UnbindContext, + .GetSwapInfo = NULL, + .GetMSC = driGetMSC32, + .WaitForMSC = driWaitForMSC32, + .WaitForSBC = NULL, + .SwapBuffersMSC = NULL +}; + + +/** + * This is the bootstrap function for the driver. libGL supplies all of the + * requisite information about the system, and the driver initializes itself. + * This routine also fills in the linked list pointed to by \c driver_modes + * with the \c __GLcontextModes that the driver can support for windows or + * pbuffers. + * + * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on + * failure. + */ +PUBLIC +void * __driCreateNewScreen_20050727( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc, + const __GLcontextModes * modes, + const __DRIversion * ddx_version, + const __DRIversion * dri_version, + const __DRIversion * drm_version, + const __DRIframebuffer * frame_buffer, + drmAddress pSAREA, int fd, + int internal_api_version, + const __DRIinterfaceMethods * interface, + __GLcontextModes ** driver_modes ) + +{ + __DRIscreenPrivate *psp; + static const __DRIversion ddx_expected = { 6, 4, 0 }; + static const __DRIversion dri_expected = { 4, 0, 0 }; + static const __DRIversion drm_expected = { 2, 0, 0 }; + + dri_interface = interface; + + if ( ! driCheckDriDdxDrmVersions2( "Mach64", + dri_version, & dri_expected, + ddx_version, & ddx_expected, + drm_version, & drm_expected ) ) { + return NULL; + } + + psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL, + ddx_version, dri_version, drm_version, + frame_buffer, pSAREA, fd, + internal_api_version, &mach64API); + if ( psp != NULL ) { + ATIDRIPtr dri_priv = (ATIDRIPtr) psp->pDevPriv; + *driver_modes = mach64FillInModes( dri_priv->cpp * 8, + 16, + 0, + 1); + + /* Calling driInitExtensions here, with a NULL context pointer, does not actually + * enable the extensions. It just makes sure that all the dispatch offsets for all + * the extensions that *might* be enables are known. This is needed because the + * dispatch offsets need to be known when _mesa_context_create is called, but we can't + * enable the extensions until we have a context pointer. + * + * Hello chicken. Hello egg. How are you two today? + */ + driInitExtensions( NULL, card_extensions, GL_FALSE ); + } + + return (void *) psp; +} diff --git a/src/mach64_screen.h b/src/mach64_screen.h new file mode 100644 index 0000000..5305058 --- /dev/null +++ b/src/mach64_screen.h @@ -0,0 +1,78 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#ifndef __MACH64_SCREEN_H__ +#define __MACH64_SCREEN_H__ + +#include "xmlconfig.h" + +typedef struct { + drm_handle_t handle; /* Handle to the DRM region */ + drmSize size; /* Size of the DRM region */ + drmAddress *map; /* Mapping of the DRM region */ +} mach64RegionRec, *mach64RegionPtr; + +typedef struct { + int chipset; + int width; + int height; + int mem; + int cpp; + + unsigned int frontOffset; + unsigned int frontPitch; + unsigned int backOffset; + unsigned int backPitch; + + unsigned int depthOffset; + unsigned int depthPitch; + + int IsPCI; + int AGPMode; + unsigned int irq; /* IRQ number (0 means none) */ + + /* Shared Texture data */ + int firstTexHeap, numTexHeaps; + int texOffset[MACH64_NR_TEX_HEAPS]; + int texSize[MACH64_NR_TEX_HEAPS]; + int logTexGranularity[MACH64_NR_TEX_HEAPS]; + + mach64RegionRec mmio; + mach64RegionRec agpTextures; + + drmBufMapPtr buffers; + + __DRIscreenPrivate *driScreen; + + driOptionCache optionCache; +} mach64ScreenRec, *mach64ScreenPtr; + +#endif /* __MACH64_SCREEN_H__ */ diff --git a/src/mach64_span.c b/src/mach64_span.c new file mode 100644 index 0000000..3830a28 --- /dev/null +++ b/src/mach64_span.c @@ -0,0 +1,169 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * Jos�Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "mach64_context.h" +#include "mach64_ioctl.h" +#include "mach64_state.h" +#include "mach64_span.h" + +#include "swrast/swrast.h" + +#define DBG 0 + +#define LOCAL_VARS \ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); \ + __DRIscreenPrivate *sPriv = mmesa->driScreen; \ + __DRIdrawablePrivate *dPriv = mmesa->driDrawable; \ + driRenderbuffer *drb = (driRenderbuffer *) rb; \ + GLuint height = dPriv->h; \ + GLushort p; \ + (void) p; + +#define LOCAL_DEPTH_VARS \ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); \ + __DRIdrawablePrivate *dPriv = mmesa->driDrawable; \ + __DRIscreenPrivate *driScreen = mmesa->driScreen; \ + driRenderbuffer *drb = (driRenderbuffer *) rb; \ + GLuint height = dPriv->h; \ + char *buf = (char *)(driScreen->pFB + drb->offset + \ + (dPriv->x + dPriv->y * drb->pitch) * 2) + +#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS + +#define Y_FLIP( _y ) (height - _y - 1) + +#define HW_LOCK() + +/* FIXME could/should we use dPriv->numClipRects like the other drivers? */ +#define HW_CLIPLOOP() \ + do { \ + int _nc = mmesa->numClipRects; \ + \ + while ( _nc-- ) { \ + int minx = mmesa->pClipRects[_nc].x1 - mmesa->drawX; \ + int miny = mmesa->pClipRects[_nc].y1 - mmesa->drawY; \ + int maxx = mmesa->pClipRects[_nc].x2 - mmesa->drawX; \ + int maxy = mmesa->pClipRects[_nc].y2 - mmesa->drawY; + +#define HW_ENDCLIPLOOP() \ + } \ + } while (0) + +#define HW_UNLOCK() + + + +/* ================================================================ + * Color buffer + */ + +/* 16 bit, RGB565 color spanline and pixel functions + */ +#define SPANTMP_PIXEL_FMT GL_RGB +#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_SHORT_5_6_5 + +#define TAG(x) mach64##x##_RGB565 +#define TAG2(x,y) mach64##x##_RGB565##y +#define GET_PTR(X,Y) (sPriv->pFB + drb->offset \ + + ((dPriv->y + (Y)) * drb->pitch + (dPriv->x + (X))) * drb->cpp) +#include "spantmp2.h" + + +/* 32 bit, ARGB8888 color spanline and pixel functions + */ +/* FIXME the old code always read back alpha as 0xff, i.e. fully opaque. + Was there a reason to do so ? If so that'll won't work with that template... */ +#define SPANTMP_PIXEL_FMT GL_BGRA +#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV + +#define TAG(x) mach64##x##_ARGB8888 +#define TAG2(x,y) mach64##x##_ARGB8888##y +#define GET_PTR(X,Y) (sPriv->pFB + drb->offset \ + + ((dPriv->y + (Y)) * drb->pitch + (dPriv->x + (X))) * drb->cpp) +#include "spantmp2.h" + + +/* ================================================================ + * Depth buffer + */ + +/* 16 bit depthbuffer functions. + */ +#define WRITE_DEPTH( _x, _y, d ) \ + *(GLushort *)(buf + ((_x) + (_y) * drb->pitch) * 2) = d; + +#define READ_DEPTH( d, _x, _y ) \ + d = *(GLushort *)(buf + ((_x) + (_y) * drb->pitch) * 2); + +#define TAG(x) mach64##x##_z16 +#include "depthtmp.h" + + +static void mach64SpanRenderStart( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + LOCK_HARDWARE( mmesa ); + FINISH_DMA_LOCKED( mmesa ); +} + +static void mach64SpanRenderFinish( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + _swrast_flush( ctx ); + UNLOCK_HARDWARE( mmesa ); +} + +void mach64DDInitSpanFuncs( GLcontext *ctx ) +{ + struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx); + swdd->SpanRenderStart = mach64SpanRenderStart; + swdd->SpanRenderFinish = mach64SpanRenderFinish; +} + + +/** + * Plug in the Get/Put routines for the given driRenderbuffer. + */ +void +mach64SetSpanFunctions(driRenderbuffer *drb, const GLvisual *vis) +{ + if (drb->Base.InternalFormat == GL_RGBA) { + if (vis->redBits == 5 && vis->greenBits == 6 && vis->blueBits == 5) { + mach64InitPointers_RGB565(&drb->Base); + } + else { + mach64InitPointers_ARGB8888(&drb->Base); + } + } + else if (drb->Base.InternalFormat == GL_DEPTH_COMPONENT16) { + mach64InitDepthPointers_z16(&drb->Base); + } +} diff --git a/src/mach64_span.h b/src/mach64_span.h new file mode 100644 index 0000000..0f4c766 --- /dev/null +++ b/src/mach64_span.h @@ -0,0 +1,41 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * + */ + +#ifndef __MACH64_SPAN_H__ +#define __MACH64_SPAN_H__ + +#include "drirenderbuffer.h" + +extern void mach64DDInitSpanFuncs( GLcontext *ctx ); + +extern void +mach64SetSpanFunctions(driRenderbuffer *rb, const GLvisual *vis); + +#endif diff --git a/src/mach64_state.c b/src/mach64_state.c new file mode 100644 index 0000000..667a394 --- /dev/null +++ b/src/mach64_state.c @@ -0,0 +1,1189 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * Jos�Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "mach64_context.h" +#include "mach64_state.h" +#include "mach64_ioctl.h" +#include "mach64_tris.h" +#include "mach64_vb.h" +#include "mach64_tex.h" + +#include "context.h" +#include "enums.h" +#include "colormac.h" +#include "swrast/swrast.h" +#include "vbo/vbo.h" +#include "tnl/tnl.h" +#include "swrast_setup/swrast_setup.h" + +#include "tnl/t_pipeline.h" + + +/* ============================================================= + * Alpha blending + */ + +static void mach64UpdateAlphaMode( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint a = mmesa->setup.alpha_tst_cntl; + GLuint s = mmesa->setup.scale_3d_cntl; + GLuint m = mmesa->setup.dp_write_mask; + + if ( ctx->Color.AlphaEnabled ) { + GLubyte ref; + + CLAMPED_FLOAT_TO_UBYTE(ref, ctx->Color.AlphaRef); + + a &= ~(MACH64_ALPHA_TEST_MASK | MACH64_REF_ALPHA_MASK); + + switch ( ctx->Color.AlphaFunc ) { + case GL_NEVER: + a |= MACH64_ALPHA_TEST_NEVER; + break; + case GL_LESS: + a |= MACH64_ALPHA_TEST_LESS; + break; + case GL_LEQUAL: + a |= MACH64_ALPHA_TEST_LEQUAL; + break; + case GL_EQUAL: + a |= MACH64_ALPHA_TEST_EQUAL; + break; + case GL_GEQUAL: + a |= MACH64_ALPHA_TEST_GEQUAL; + break; + case GL_GREATER: + a |= MACH64_ALPHA_TEST_GREATER; + break; + case GL_NOTEQUAL: + a |= MACH64_ALPHA_TEST_NOTEQUAL; + break; + case GL_ALWAYS: + a |= MACH64_ALPHA_TEST_ALWAYS; + break; + } + + a |= (ref << MACH64_REF_ALPHA_SHIFT); + a |= MACH64_ALPHA_TEST_EN; + } else { + a &= ~MACH64_ALPHA_TEST_EN; + } + + FALLBACK( mmesa, MACH64_FALLBACK_BLEND_FUNC, GL_FALSE ); + + if ( ctx->Color.BlendEnabled ) { + s &= ~(MACH64_ALPHA_BLEND_SRC_MASK | + MACH64_ALPHA_BLEND_DST_MASK | + MACH64_ALPHA_BLEND_SAT); + + switch ( ctx->Color.BlendSrcRGB ) { + case GL_ZERO: + s |= MACH64_ALPHA_BLEND_SRC_ZERO; + break; + case GL_ONE: + s |= MACH64_ALPHA_BLEND_SRC_ONE; + break; + case GL_DST_COLOR: + s |= MACH64_ALPHA_BLEND_SRC_DSTCOLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + s |= MACH64_ALPHA_BLEND_SRC_INVDSTCOLOR; + break; + case GL_SRC_ALPHA: + s |= MACH64_ALPHA_BLEND_SRC_SRCALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + s |= MACH64_ALPHA_BLEND_SRC_INVSRCALPHA; + break; + case GL_DST_ALPHA: + s |= MACH64_ALPHA_BLEND_SRC_DSTALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + s |= MACH64_ALPHA_BLEND_SRC_INVDSTALPHA; + break; + case GL_SRC_ALPHA_SATURATE: + s |= (MACH64_ALPHA_BLEND_SRC_SRCALPHA | + MACH64_ALPHA_BLEND_SAT); + break; + default: + FALLBACK( mmesa, MACH64_FALLBACK_BLEND_FUNC, GL_TRUE ); + } + + switch ( ctx->Color.BlendDstRGB ) { + case GL_ZERO: + s |= MACH64_ALPHA_BLEND_DST_ZERO; + break; + case GL_ONE: + s |= MACH64_ALPHA_BLEND_DST_ONE; + break; + case GL_SRC_COLOR: + s |= MACH64_ALPHA_BLEND_DST_SRCCOLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + s |= MACH64_ALPHA_BLEND_DST_INVSRCCOLOR; + break; + case GL_SRC_ALPHA: + s |= MACH64_ALPHA_BLEND_DST_SRCALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + s |= MACH64_ALPHA_BLEND_DST_INVSRCALPHA; + break; + case GL_DST_ALPHA: + s |= MACH64_ALPHA_BLEND_DST_DSTALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + s |= MACH64_ALPHA_BLEND_DST_INVDSTALPHA; + break; + default: + FALLBACK( mmesa, MACH64_FALLBACK_BLEND_FUNC, GL_TRUE ); + } + + m = 0xffffffff; /* Can't color mask and blend at the same time */ + s &= ~MACH64_ALPHA_FOG_EN_FOG; /* Can't fog and blend at the same time */ + s |= MACH64_ALPHA_FOG_EN_ALPHA; + } else { + s &= ~MACH64_ALPHA_FOG_EN_ALPHA; + } + + if ( mmesa->setup.alpha_tst_cntl != a ) { + mmesa->setup.alpha_tst_cntl = a; + mmesa->dirty |= MACH64_UPLOAD_Z_ALPHA_CNTL; + } + if ( mmesa->setup.scale_3d_cntl != s ) { + mmesa->setup.scale_3d_cntl = s; + mmesa->dirty |= MACH64_UPLOAD_SCALE_3D_CNTL; + } + if ( mmesa->setup.dp_write_mask != m ) { + mmesa->setup.dp_write_mask = m; + mmesa->dirty |= MACH64_UPLOAD_DP_WRITE_MASK; + } +} + +static void mach64DDAlphaFunc( GLcontext *ctx, GLenum func, GLfloat ref ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_ALPHA; +} + +static void mach64DDBlendEquationSeparate( GLcontext *ctx, + GLenum modeRGB, GLenum modeA ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + assert( modeRGB == modeA ); + FLUSH_BATCH( mmesa ); + + /* BlendEquation affects ColorLogicOpEnabled + */ + FALLBACK( MACH64_CONTEXT(ctx), MACH64_FALLBACK_LOGICOP, + (ctx->Color.ColorLogicOpEnabled && + ctx->Color.LogicOp != GL_COPY)); + + /* Can only do blend addition, not min, max, subtract, etc. */ + FALLBACK( MACH64_CONTEXT(ctx), MACH64_FALLBACK_BLEND_EQ, + modeRGB != GL_FUNC_ADD); + + mmesa->new_state |= MACH64_NEW_ALPHA; +} + +static void mach64DDBlendFuncSeparate( GLcontext *ctx, + GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_ALPHA; +} + + +/* ============================================================= + * Depth testing + */ + +static void mach64UpdateZMode( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint z = mmesa->setup.z_cntl; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_MSG ) { + fprintf( stderr, "%s:\n", __FUNCTION__ ); + } + + if ( ctx->Depth.Test ) { + z &= ~MACH64_Z_TEST_MASK; + + switch ( ctx->Depth.Func ) { + case GL_NEVER: + z |= MACH64_Z_TEST_NEVER; + break; + case GL_ALWAYS: + z |= MACH64_Z_TEST_ALWAYS; + break; + case GL_LESS: + z |= MACH64_Z_TEST_LESS; + break; + case GL_LEQUAL: + z |= MACH64_Z_TEST_LEQUAL; + break; + case GL_EQUAL: + z |= MACH64_Z_TEST_EQUAL; + break; + case GL_GEQUAL: + z |= MACH64_Z_TEST_GEQUAL; + break; + case GL_GREATER: + z |= MACH64_Z_TEST_GREATER; + break; + case GL_NOTEQUAL: + z |= MACH64_Z_TEST_NOTEQUAL; + break; + } + + z |= MACH64_Z_EN; + } else { + z &= ~MACH64_Z_EN; + } + + if ( ctx->Depth.Mask ) { + z |= MACH64_Z_MASK_EN; + } else { + z &= ~MACH64_Z_MASK_EN; + } + + if ( mmesa->setup.z_cntl != z ) { + mmesa->setup.z_cntl = z; + mmesa->dirty |= MACH64_UPLOAD_Z_ALPHA_CNTL; + } +} + +static void mach64DDDepthFunc( GLcontext *ctx, GLenum func ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_DEPTH; +} + +static void mach64DDDepthMask( GLcontext *ctx, GLboolean flag ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_DEPTH; +} + +static void mach64DDClearDepth( GLcontext *ctx, GLclampd d ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + /* Always have a 16-bit depth buffer. + */ + mmesa->ClearDepth = d * 0xffff; +} + + +/* ============================================================= + * Fog + */ + +static void mach64UpdateFogAttrib( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + CARD32 s = mmesa->setup.scale_3d_cntl; + GLubyte c[4]; + CARD32 col; + + /* Can't fog if blending is on */ + if ( ctx->Color.BlendEnabled ) + return; + + if ( ctx->Fog.Enabled ) { + s |= MACH64_ALPHA_FOG_EN_FOG; + s &= ~(MACH64_ALPHA_BLEND_SRC_MASK | + MACH64_ALPHA_BLEND_DST_MASK | + MACH64_ALPHA_BLEND_SAT); + /* From Utah-glx: "fog color is now dest and fog factor is alpha, so + * use GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA" + */ + s |= (MACH64_ALPHA_BLEND_SRC_SRCALPHA | + MACH64_ALPHA_BLEND_DST_INVSRCALPHA); + /* From Utah-glx: "can't use texture alpha when fogging" */ + s &= ~MACH64_TEX_MAP_AEN; + } else { + s &= ~(MACH64_ALPHA_BLEND_SRC_MASK | + MACH64_ALPHA_BLEND_DST_MASK | + MACH64_ALPHA_BLEND_SAT); + s |= (MACH64_ALPHA_BLEND_SRC_ONE | + MACH64_ALPHA_BLEND_DST_ZERO); + s &= ~MACH64_ALPHA_FOG_EN_FOG; + } + + c[0] = FLOAT_TO_UBYTE( ctx->Fog.Color[0] ); + c[1] = FLOAT_TO_UBYTE( ctx->Fog.Color[1] ); + c[2] = FLOAT_TO_UBYTE( ctx->Fog.Color[2] ); + c[3] = FLOAT_TO_UBYTE( ctx->Fog.Color[3] ); + + col = mach64PackColor( 4, c[0], c[1], c[2], c[3] ); + + if ( mmesa->setup.dp_fog_clr != col ) { + mmesa->setup.dp_fog_clr = col; + mmesa->dirty |= MACH64_UPLOAD_DP_FOG_CLR; + } + if ( mmesa->setup.scale_3d_cntl != s ) { + mmesa->setup.scale_3d_cntl = s; + mmesa->dirty |= MACH64_UPLOAD_SCALE_3D_CNTL; + } + +} + +static void mach64DDFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_FOG; +} + + +/* ============================================================= + * Clipping + */ + +static void mach64UpdateClipping( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + mach64ScreenPtr mach64Screen = mmesa->mach64Screen; + + if ( mmesa->driDrawable ) { + __DRIdrawablePrivate *drawable = mmesa->driDrawable; + int x1 = 0; + int y1 = 0; + int x2 = drawable->w - 1; + int y2 = drawable->h - 1; + + if ( ctx->Scissor.Enabled ) { + if ( ctx->Scissor.X > x1 ) { + x1 = ctx->Scissor.X; + } + if ( drawable->h - ctx->Scissor.Y - ctx->Scissor.Height > y1 ) { + y1 = drawable->h - ctx->Scissor.Y - ctx->Scissor.Height; + } + if ( ctx->Scissor.X + ctx->Scissor.Width - 1 < x2 ) { + x2 = ctx->Scissor.X + ctx->Scissor.Width - 1; + } + if ( drawable->h - ctx->Scissor.Y - 1 < y2 ) { + y2 = drawable->h - ctx->Scissor.Y - 1; + } + } + + x1 += drawable->x; + y1 += drawable->y; + x2 += drawable->x; + y2 += drawable->y; + + /* clamp to screen borders */ + if (x1 < 0) x1 = 0; + if (y1 < 0) y1 = 0; + if (x2 < 0) x2 = 0; + if (y2 < 0) y2 = 0; + if (x2 > mach64Screen->width-1) x2 = mach64Screen->width-1; + if (y2 > mach64Screen->height-1) y2 = mach64Screen->height-1; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_MSG ) { + fprintf( stderr, "%s: drawable %3d %3d %3d %3d\n", + __FUNCTION__, + drawable->x, + drawable->y, + drawable->w, + drawable->h ); + fprintf( stderr, "%s: scissor %3d %3d %3d %3d\n", + __FUNCTION__, + ctx->Scissor.X, + ctx->Scissor.Y, + ctx->Scissor.Width, + ctx->Scissor.Height ); + fprintf( stderr, "%s: final %3d %3d %3d %3d\n", + __FUNCTION__, x1, y1, x2, y2 ); + fprintf( stderr, "\n" ); + } + + mmesa->setup.sc_top_bottom = ((y1 << 0) | + (y2 << 16)); + + mmesa->setup.sc_left_right = ((x1 << 0) | + (x2 << 16)); + + /* UPLOAD_MISC reduces the dirty state, we just need to + * emit the scissor to the SAREA. We need to dirty cliprects + * since the scissor and cliprects are intersected to update the + * single hardware scissor + */ + mmesa->dirty |= MACH64_UPLOAD_MISC | MACH64_UPLOAD_CLIPRECTS; + } +} + +static void mach64DDScissor( GLcontext *ctx, + GLint x, GLint y, GLsizei w, GLsizei h ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_CLIP; +} + + +/* ============================================================= + * Culling + */ + +static void mach64UpdateCull( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLfloat backface_sign = 1; + + if ( ctx->Polygon.CullFlag /*&& ctx->PB->primitive == GL_POLYGON*/ ) { + backface_sign = 1; + switch ( ctx->Polygon.CullFaceMode ) { + case GL_BACK: + if ( ctx->Polygon.FrontFace == GL_CCW ) + backface_sign = -1; + break; + case GL_FRONT: + if ( ctx->Polygon.FrontFace != GL_CCW ) + backface_sign = -1; + break; + default: + case GL_FRONT_AND_BACK: + backface_sign = 0; + break; + } + } else { + backface_sign = 0; + } + + mmesa->backface_sign = backface_sign; + +} + +static void mach64DDCullFace( GLcontext *ctx, GLenum mode ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_CULL; +} + +static void mach64DDFrontFace( GLcontext *ctx, GLenum mode ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_CULL; +} + + +/* ============================================================= + * Masks + */ + +static void mach64UpdateMasks( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint mask = 0xffffffff; + + /* mach64 can't color mask with alpha blending enabled */ + if ( !ctx->Color.BlendEnabled ) { + mask = mach64PackColor( mmesa->mach64Screen->cpp, + ctx->Color.ColorMask[RCOMP], + ctx->Color.ColorMask[GCOMP], + ctx->Color.ColorMask[BCOMP], + ctx->Color.ColorMask[ACOMP] ); + } + + if ( mmesa->setup.dp_write_mask != mask ) { + mmesa->setup.dp_write_mask = mask; + mmesa->dirty |= MACH64_UPLOAD_DP_WRITE_MASK; + } +} + +static void mach64DDColorMask( GLcontext *ctx, + GLboolean r, GLboolean g, + GLboolean b, GLboolean a ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_MASKS; +} + + +/* ============================================================= + * 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 mach64UpdateSpecularLighting( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint a = mmesa->setup.alpha_tst_cntl; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_MSG ) { + fprintf( stderr, "%s:\n", __FUNCTION__ ); + } + + if ( ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR && + ctx->Light.Enabled ) { + a |= MACH64_SPECULAR_LIGHT_EN; + } else { + a &= ~MACH64_SPECULAR_LIGHT_EN; + } + + if ( mmesa->setup.alpha_tst_cntl != a ) { + mmesa->setup.alpha_tst_cntl = a; + mmesa->dirty |= MACH64_UPLOAD_Z_ALPHA_CNTL; + mmesa->new_state |= MACH64_NEW_CONTEXT; + } +} + +static void mach64DDLightModelfv( GLcontext *ctx, GLenum pname, + const GLfloat *param ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + if ( pname == GL_LIGHT_MODEL_COLOR_CONTROL ) { + FLUSH_BATCH( mmesa ); + mach64UpdateSpecularLighting(ctx); + } +} + +static void mach64DDShadeModel( GLcontext *ctx, GLenum mode ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint s = mmesa->setup.setup_cntl; + + s &= ~MACH64_FLAT_SHADE_MASK; + + switch ( mode ) { + case GL_FLAT: + s |= MACH64_FLAT_SHADE_VERTEX_3; + break; + case GL_SMOOTH: + s |= MACH64_FLAT_SHADE_OFF; + break; + default: + return; + } + + if ( mmesa->setup.setup_cntl != s ) { + FLUSH_BATCH( mmesa ); + mmesa->setup.setup_cntl = s; + + mmesa->dirty |= MACH64_UPLOAD_SETUP_CNTL; + } +} + + +/* ============================================================= + * Viewport + */ + + +void mach64CalcViewport( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + const GLfloat *v = ctx->Viewport._WindowMap.m; + GLfloat *m = mmesa->hw_viewport; + + /* See also mach64_translate_vertex. + */ + m[MAT_SX] = v[MAT_SX]; + m[MAT_TX] = v[MAT_TX] + (GLfloat)mmesa->drawX + SUBPIXEL_X; + m[MAT_SY] = - v[MAT_SY]; + m[MAT_TY] = - v[MAT_TY] + mmesa->driDrawable->h + (GLfloat)mmesa->drawY + SUBPIXEL_Y; + m[MAT_SZ] = v[MAT_SZ] * mmesa->depth_scale; + m[MAT_TZ] = v[MAT_TZ] * mmesa->depth_scale; + + mmesa->SetupNewInputs = ~0; +} + +static void mach64Viewport( GLcontext *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height ) +{ + mach64CalcViewport( ctx ); +} + +static void mach64DepthRange( GLcontext *ctx, + GLclampd nearval, GLclampd farval ) +{ + mach64CalcViewport( ctx ); +} + + +/* ============================================================= + * Miscellaneous + */ + +static void mach64DDClearColor( GLcontext *ctx, + const GLfloat color[4] ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLubyte c[4]; + + CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]); + CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]); + CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]); + CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]); + + mmesa->ClearColor = mach64PackColor( mmesa->mach64Screen->cpp, + c[0], c[1], c[2], c[3] ); +} + +static void mach64DDLogicOpCode( GLcontext *ctx, GLenum opcode ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + if ( ctx->Color.ColorLogicOpEnabled ) { + FLUSH_BATCH( mmesa ); + + FALLBACK( mmesa, MACH64_FALLBACK_LOGICOP, opcode != GL_COPY); + } +} + +void mach64SetCliprects( GLcontext *ctx, GLenum mode ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = mmesa->driDrawable; + + switch ( mode ) { + case GL_FRONT_LEFT: + mmesa->numClipRects = dPriv->numClipRects; + mmesa->pClipRects = dPriv->pClipRects; + mmesa->drawX = dPriv->x; + mmesa->drawY = dPriv->y; + break; + case GL_BACK_LEFT: + if ( dPriv->numBackClipRects == 0 ) { + mmesa->numClipRects = dPriv->numClipRects; + mmesa->pClipRects = dPriv->pClipRects; + mmesa->drawX = dPriv->x; + mmesa->drawY = dPriv->y; + } else { + mmesa->numClipRects = dPriv->numBackClipRects; + mmesa->pClipRects = dPriv->pBackClipRects; + mmesa->drawX = dPriv->backX; + mmesa->drawY = dPriv->backY; + } + break; + default: + return; + } + + mach64UpdateClipping( ctx ); + + mmesa->dirty |= MACH64_UPLOAD_CLIPRECTS; +} + +static void mach64DDDrawBuffer( GLcontext *ctx, GLenum mode ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + + /* + * _DrawDestMask is easier to cope with than <mode>. + */ + switch ( ctx->DrawBuffer->_ColorDrawBufferMask[0] ) { + case BUFFER_BIT_FRONT_LEFT: + FALLBACK( mmesa, MACH64_FALLBACK_DRAW_BUFFER, GL_FALSE ); + mach64SetCliprects( ctx, GL_FRONT_LEFT ); + if (MACH64_DEBUG & DEBUG_VERBOSE_MSG) + fprintf(stderr,"%s: BUFFER_BIT_FRONT_LEFT\n", __FUNCTION__); + break; + case BUFFER_BIT_BACK_LEFT: + FALLBACK( mmesa, MACH64_FALLBACK_DRAW_BUFFER, GL_FALSE ); + mach64SetCliprects( ctx, GL_BACK_LEFT ); + if (MACH64_DEBUG & DEBUG_VERBOSE_MSG) + fprintf(stderr,"%s: BUFFER_BIT_BACK_LEFT\n", __FUNCTION__); + break; + default: + /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */ + FALLBACK( mmesa, MACH64_FALLBACK_DRAW_BUFFER, GL_TRUE ); + if (MACH64_DEBUG & DEBUG_VERBOSE_MSG) + fprintf(stderr,"%s: fallback (mode=%d)\n", __FUNCTION__, mode); + break; + } + + mmesa->setup.dst_off_pitch = (((mmesa->drawPitch/8) << 22) | + (mmesa->drawOffset >> 3)); + + mmesa->dirty |= MACH64_UPLOAD_DST_OFF_PITCH; +} + +static void mach64DDReadBuffer( GLcontext *ctx, GLenum mode ) +{ + /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */ +} + +/* ============================================================= + * State enable/disable + */ + +static void mach64DDEnable( GLcontext *ctx, GLenum cap, GLboolean state ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s = %s )\n", + __FUNCTION__, _mesa_lookup_enum_by_nr( cap ), + state ? "GL_TRUE" : "GL_FALSE" ); + } + + switch ( cap ) { + case GL_ALPHA_TEST: + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_ALPHA; + break; + + case GL_BLEND: + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_ALPHA; + + /* enable(GL_BLEND) affects ColorLogicOpEnabled. + */ + FALLBACK( mmesa, MACH64_FALLBACK_LOGICOP, + (ctx->Color.ColorLogicOpEnabled && + ctx->Color.LogicOp != GL_COPY)); + break; + + case GL_CULL_FACE: + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_CULL; + break; + + case GL_DEPTH_TEST: + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_DEPTH; + break; + + case GL_DITHER: + do { + GLuint s = mmesa->setup.scale_3d_cntl; + FLUSH_BATCH( mmesa ); + + if ( ctx->Color.DitherFlag ) { + /* Dithering causes problems w/ 24bpp depth */ + if ( mmesa->mach64Screen->cpp == 4 ) + s |= MACH64_ROUND_EN; + else + s |= MACH64_DITHER_EN; + } else { + s &= ~MACH64_DITHER_EN; + s &= ~MACH64_ROUND_EN; + } + + if ( mmesa->setup.scale_3d_cntl != s ) { + mmesa->setup.scale_3d_cntl = s; + mmesa->dirty |= ( MACH64_UPLOAD_SCALE_3D_CNTL ); + } + } while (0); + break; + + case GL_FOG: + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_FOG; + break; + + case GL_INDEX_LOGIC_OP: + case GL_COLOR_LOGIC_OP: + FLUSH_BATCH( mmesa ); + FALLBACK( mmesa, MACH64_FALLBACK_LOGICOP, + state && ctx->Color.LogicOp != GL_COPY ); + break; + + case GL_LIGHTING: + mach64UpdateSpecularLighting(ctx); + break; + + case GL_SCISSOR_TEST: + FLUSH_BATCH( mmesa ); + mmesa->scissor = state; + mmesa->new_state |= MACH64_NEW_CLIP; + break; + + case GL_STENCIL_TEST: + FLUSH_BATCH( mmesa ); + FALLBACK( mmesa, MACH64_FALLBACK_STENCIL, state ); + break; + + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_TEXTURE; + break; + + default: + return; + } +} + +/* ============================================================= + * Render mode + */ + +static void mach64DDRenderMode( GLcontext *ctx, GLenum mode ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + FALLBACK( mmesa, MACH64_FALLBACK_RENDER_MODE, (mode != GL_RENDER) ); +} + +/* ============================================================= + * State initialization, management + */ + +static void mach64DDPrintDirty( const char *msg, GLuint state ) +{ + fprintf( stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s%s%s%s%s\n", + msg, + state, + (state & MACH64_UPLOAD_DST_OFF_PITCH) ? "dst_off_pitch, " : "", + (state & MACH64_UPLOAD_Z_ALPHA_CNTL) ? "z_alpha_cntl, " : "", + (state & MACH64_UPLOAD_SCALE_3D_CNTL) ? "scale_3d_cntl, " : "", + (state & MACH64_UPLOAD_DP_FOG_CLR) ? "dp_fog_clr, " : "", + (state & MACH64_UPLOAD_DP_WRITE_MASK) ? "dp_write_mask, " : "", + (state & MACH64_UPLOAD_DP_PIX_WIDTH) ? "dp_pix_width, " : "", + (state & MACH64_UPLOAD_SETUP_CNTL) ? "setup_cntl, " : "", + (state & MACH64_UPLOAD_MISC) ? "misc, " : "", + (state & MACH64_UPLOAD_TEXTURE) ? "texture, " : "", + (state & MACH64_UPLOAD_TEX0IMAGE) ? "tex0 image, " : "", + (state & MACH64_UPLOAD_TEX1IMAGE) ? "tex1 image, " : "", + (state & MACH64_UPLOAD_CLIPRECTS) ? "cliprects, " : "" ); +} + +/* + * 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 mach64EmitHwStateLocked( mach64ContextPtr mmesa ) +{ + drm_mach64_sarea_t *sarea = mmesa->sarea; + drm_mach64_context_regs_t *regs = &(mmesa->setup); + mach64TexObjPtr t0 = mmesa->CurrentTexObj[0]; + mach64TexObjPtr t1 = mmesa->CurrentTexObj[1]; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_MSG ) { + mach64DDPrintDirty( __FUNCTION__, mmesa->dirty ); + } + + if ( t0 && t1 && mmesa->mach64Screen->numTexHeaps > 1 ) { + if (t0->heap != t1->heap || + (mmesa->dirty & MACH64_UPLOAD_TEX0IMAGE) || + (mmesa->dirty & MACH64_UPLOAD_TEX1IMAGE)) + mach64UploadMultiTexImages( mmesa, t0, t1 ); + } else { + if ( mmesa->dirty & MACH64_UPLOAD_TEX0IMAGE ) { + if ( t0 ) mach64UploadTexImages( mmesa, t0 ); + } + if ( mmesa->dirty & MACH64_UPLOAD_TEX1IMAGE ) { + if ( t1 ) mach64UploadTexImages( mmesa, t1 ); + } + } + + if ( mmesa->dirty & (MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC) ) { + memcpy( &sarea->context_state, regs, + MACH64_NR_CONTEXT_REGS * sizeof(GLuint) ); + } + + if ( mmesa->dirty & MACH64_UPLOAD_TEXTURE ) { + mach64EmitTexStateLocked( mmesa, t0, t1 ); + } + + sarea->vertsize = mmesa->vertex_size; + + /* Turn off the texture cache flushing. + */ + mmesa->setup.tex_cntl &= ~MACH64_TEX_CACHE_FLUSH; + + sarea->dirty |= mmesa->dirty; + + mmesa->dirty &= MACH64_UPLOAD_CLIPRECTS; +} + +static void mach64DDPrintState( const char *msg, GLuint flags ) +{ + fprintf( stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n", + msg, + flags, + (flags & MACH64_NEW_CONTEXT) ? "context, " : "", + (flags & MACH64_NEW_ALPHA) ? "alpha, " : "", + (flags & MACH64_NEW_DEPTH) ? "depth, " : "", + (flags & MACH64_NEW_FOG) ? "fog, " : "", + (flags & MACH64_NEW_CLIP) ? "clip, " : "", + (flags & MACH64_NEW_TEXTURE) ? "texture, " : "", + (flags & MACH64_NEW_CULL) ? "cull, " : "", + (flags & MACH64_NEW_MASKS) ? "masks, " : "", + (flags & MACH64_NEW_WINDOW) ? "window, " : "" ); +} + +/* Update the hardware state */ +void mach64DDUpdateHWState( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + int new_state = mmesa->new_state; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_MSG ) { + fprintf( stderr, "%s:\n", __FUNCTION__ ); + } + + if ( new_state ) + { + FLUSH_BATCH( mmesa ); + + mmesa->new_state = 0; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_MSG ) + mach64DDPrintState( __FUNCTION__, new_state ); + + /* Update the various parts of the context's state. + */ + if ( new_state & MACH64_NEW_ALPHA ) + mach64UpdateAlphaMode( ctx ); + + if ( new_state & MACH64_NEW_DEPTH ) + mach64UpdateZMode( ctx ); + + if ( new_state & MACH64_NEW_FOG ) + mach64UpdateFogAttrib( ctx ); + + if ( new_state & MACH64_NEW_CLIP ) + mach64UpdateClipping( ctx ); + + if ( new_state & MACH64_NEW_WINDOW ) + mach64CalcViewport( ctx ); + + if ( new_state & MACH64_NEW_CULL ) + mach64UpdateCull( ctx ); + + if ( new_state & MACH64_NEW_MASKS ) + mach64UpdateMasks( ctx ); + + if ( new_state & MACH64_NEW_TEXTURE ) + mach64UpdateTextureState( ctx ); + } +} + + +static void mach64DDInvalidateState( GLcontext *ctx, GLuint new_state ) +{ + _swrast_InvalidateState( ctx, new_state ); + _swsetup_InvalidateState( ctx, new_state ); + _vbo_InvalidateState( ctx, new_state ); + _tnl_InvalidateState( ctx, new_state ); + MACH64_CONTEXT(ctx)->NewGLState |= new_state; +} + + +/* Initialize the context's hardware state */ +void mach64DDInitState( mach64ContextPtr mmesa ) +{ + GLuint format; + + switch ( mmesa->mach64Screen->cpp ) { + case 2: + format = MACH64_DATATYPE_RGB565; + break; + case 4: + format = MACH64_DATATYPE_ARGB8888; + break; + default: + fprintf( stderr, "Error: Unsupported pixel depth... exiting\n" ); + exit( -1 ); + } + + /* Always have a 16-bit depth buffer + * but Z coordinates are specified in 16.1 format to the setup engine. + */ + mmesa->depth_scale = 2.0; + + mmesa->ClearColor = 0x00000000; + mmesa->ClearDepth = 0x0000ffff; + + mmesa->Fallback = 0; + + if ( mmesa->glCtx->Visual.doubleBufferMode ) { + mmesa->drawOffset = mmesa->readOffset = mmesa->mach64Screen->backOffset; + mmesa->drawPitch = mmesa->readPitch = mmesa->mach64Screen->backPitch; + } else { + mmesa->drawOffset = mmesa->readOffset = mmesa->mach64Screen->frontOffset; + mmesa->drawPitch = mmesa->readPitch = mmesa->mach64Screen->frontPitch; + } + + /* Harware state: + */ + mmesa->setup.dst_off_pitch = (((mmesa->drawPitch/8) << 22) | + (mmesa->drawOffset >> 3)); + + mmesa->setup.z_off_pitch = (((mmesa->mach64Screen->depthPitch/8) << 22) | + (mmesa->mach64Screen->depthOffset >> 3)); + + mmesa->setup.z_cntl = (MACH64_Z_TEST_LESS | + MACH64_Z_MASK_EN); + + mmesa->setup.alpha_tst_cntl = (MACH64_ALPHA_TEST_ALWAYS | + MACH64_ALPHA_DST_SRCALPHA | + MACH64_ALPHA_TST_SRC_TEXEL | + (0 << MACH64_REF_ALPHA_SHIFT)); + + mmesa->setup.scale_3d_cntl = (MACH64_SCALE_PIX_EXPAND_DYNAMIC_RANGE | + /* MACH64_SCALE_DITHER_ERROR_DIFFUSE | */ + MACH64_SCALE_DITHER_2D_TABLE | + /* MACH64_DITHER_INIT_CURRENT | */ + MACH64_DITHER_INIT_RESET | + MACH64_SCALE_3D_FCN_SHADE | + MACH64_ALPHA_FOG_DIS | + MACH64_ALPHA_BLEND_SRC_ONE | + MACH64_ALPHA_BLEND_DST_ZERO | + MACH64_TEX_LIGHT_FCN_MODULATE | + MACH64_MIP_MAP_DISABLE | + MACH64_BILINEAR_TEX_EN | + MACH64_TEX_BLEND_FCN_LINEAR); + + /* GL spec says dithering initially enabled, but dithering causes + * problems w/ 24bpp depth + */ + if ( mmesa->mach64Screen->cpp == 4 ) + mmesa->setup.scale_3d_cntl |= MACH64_ROUND_EN; + else + mmesa->setup.scale_3d_cntl |= MACH64_DITHER_EN; + + mmesa->setup.sc_left_right = 0x1fff0000; + mmesa->setup.sc_top_bottom = 0x3fff0000; + + mmesa->setup.dp_fog_clr = 0x00ffffff; + mmesa->setup.dp_write_mask = 0xffffffff; + + mmesa->setup.dp_pix_width = ((format << 0) | + (format << 4) | + (format << 8) | + (format << 16) | + (format << 28)); + + mmesa->setup.dp_mix = (MACH64_BKGD_MIX_S | + MACH64_FRGD_MIX_S); + mmesa->setup.dp_src = (MACH64_BKGD_SRC_3D | + MACH64_FRGD_SRC_3D | + MACH64_MONO_SRC_ONE); + + mmesa->setup.clr_cmp_cntl = 0x00000000; + mmesa->setup.gui_traj_cntl = (MACH64_DST_X_LEFT_TO_RIGHT | + MACH64_DST_Y_TOP_TO_BOTTOM); + + mmesa->setup.setup_cntl = (MACH64_FLAT_SHADE_OFF | + MACH64_SOLID_MODE_OFF | + MACH64_LOG_MAX_INC_ADJ); + mmesa->setup.setup_cntl = 0; + + mmesa->setup.tex_size_pitch = 0x00000000; + + mmesa->setup.tex_cntl = ((0 << MACH64_LOD_BIAS_SHIFT) | + (0 << MACH64_COMP_FACTOR_SHIFT) | + MACH64_COMP_COMBINE_MODULATE | + MACH64_COMP_BLEND_NEAREST | + MACH64_COMP_FILTER_NEAREST | + /* MACH64_TEXTURE_TILING | */ +#ifdef MACH64_PREMULT_TEXCOORDS + MACH64_TEX_ST_DIRECT | +#endif + MACH64_TEX_SRC_LOCAL | + MACH64_TEX_UNCOMPRESSED | + MACH64_TEX_CACHE_FLUSH | + MACH64_TEX_CACHE_SIZE_4K); + + mmesa->setup.secondary_tex_off = 0x00000000; + mmesa->setup.tex_offset = 0x00000000; + + mmesa->new_state = MACH64_NEW_ALL; +} + +/* Initialize the driver's state functions. + */ +void mach64DDInitStateFuncs( GLcontext *ctx ) +{ + ctx->Driver.UpdateState = mach64DDInvalidateState; + + ctx->Driver.ClearIndex = NULL; + ctx->Driver.ClearColor = mach64DDClearColor; + ctx->Driver.DrawBuffer = mach64DDDrawBuffer; + ctx->Driver.ReadBuffer = mach64DDReadBuffer; + + ctx->Driver.IndexMask = NULL; + ctx->Driver.ColorMask = mach64DDColorMask; + ctx->Driver.AlphaFunc = mach64DDAlphaFunc; + ctx->Driver.BlendEquationSeparate = mach64DDBlendEquationSeparate; + ctx->Driver.BlendFuncSeparate = mach64DDBlendFuncSeparate; + ctx->Driver.ClearDepth = mach64DDClearDepth; + ctx->Driver.CullFace = mach64DDCullFace; + ctx->Driver.FrontFace = mach64DDFrontFace; + ctx->Driver.DepthFunc = mach64DDDepthFunc; + ctx->Driver.DepthMask = mach64DDDepthMask; + ctx->Driver.Enable = mach64DDEnable; + ctx->Driver.Fogfv = mach64DDFogfv; + ctx->Driver.Hint = NULL; + ctx->Driver.Lightfv = NULL; + ctx->Driver.LightModelfv = mach64DDLightModelfv; + ctx->Driver.LogicOpcode = mach64DDLogicOpCode; + ctx->Driver.PolygonMode = NULL; + ctx->Driver.PolygonStipple = NULL; + ctx->Driver.RenderMode = mach64DDRenderMode; + ctx->Driver.Scissor = mach64DDScissor; + ctx->Driver.ShadeModel = mach64DDShadeModel; + + ctx->Driver.DepthRange = mach64DepthRange; + ctx->Driver.Viewport = mach64Viewport; +} diff --git a/src/mach64_state.h b/src/mach64_state.h new file mode 100644 index 0000000..95bcab3 --- /dev/null +++ b/src/mach64_state.h @@ -0,0 +1,47 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_STATE_H__ +#define __MACH64_STATE_H__ + +#include "mach64_context.h" + +extern void mach64DDInitState( mach64ContextPtr mmesa ); +extern void mach64DDInitStateFuncs( GLcontext *ctx ); + +extern void mach64SetCliprects( GLcontext *ctx, GLenum mode ); +extern void mach64CalcViewport( GLcontext *ctx ); + +extern void mach64DDUpdateState( GLcontext *ctx ); +extern void mach64DDUpdateHWState( GLcontext *ctx ); + +extern void mach64EmitHwStateLocked( mach64ContextPtr mmesa ); + +#endif diff --git a/src/mach64_tex.c b/src/mach64_tex.c new file mode 100644 index 0000000..5288d32 --- /dev/null +++ b/src/mach64_tex.c @@ -0,0 +1,567 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "mach64_context.h" +#include "mach64_ioctl.h" +#include "mach64_state.h" +#include "mach64_vb.h" +#include "mach64_tris.h" +#include "mach64_tex.h" + +#include "context.h" +#include "macros.h" +#include "simple_list.h" +#include "enums.h" +#include "texstore.h" +#include "texformat.h" +#include "teximage.h" +#include "texobj.h" +#include "imports.h" + + +static void mach64SetTexWrap( mach64TexObjPtr t, + GLenum swrap, GLenum twrap ) +{ + switch ( swrap ) { + case GL_CLAMP: + case GL_CLAMP_TO_EDGE: + case GL_CLAMP_TO_BORDER: + t->ClampS = GL_TRUE; + break; + case GL_REPEAT: + t->ClampS = GL_FALSE; + break; + } + + switch ( twrap ) { + case GL_CLAMP: + case GL_CLAMP_TO_EDGE: + case GL_CLAMP_TO_BORDER: + t->ClampT = GL_TRUE; + break; + case GL_REPEAT: + t->ClampT = GL_FALSE; + break; + } +} + +static void mach64SetTexFilter( mach64TexObjPtr t, + GLenum minf, GLenum magf ) +{ + switch ( minf ) { + case GL_NEAREST: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + t->BilinearMin = GL_FALSE; + break; + case GL_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + t->BilinearMin = GL_TRUE; + break; + } + + switch ( magf ) { + case GL_NEAREST: + t->BilinearMag = GL_FALSE; + break; + case GL_LINEAR: + t->BilinearMag = GL_TRUE; + break; + } +} + +static void mach64SetTexBorderColor( mach64TexObjPtr t, GLubyte c[4] ) +{ +#if 0 + GLuint border = mach64PackColor( 4, c[0], c[1], c[2], c[3] ); +#endif +} + + +static mach64TexObjPtr +mach64AllocTexObj( struct gl_texture_object *texObj ) +{ + mach64TexObjPtr t; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) + fprintf( stderr, "%s( %p )\n", __FUNCTION__, texObj ); + + t = (mach64TexObjPtr) CALLOC_STRUCT( mach64_texture_object ); + texObj->DriverData = t; + if ( !t ) + return NULL; + + /* Initialize non-image-dependent parts of the state: + */ + t->base.tObj = texObj; + t->base.dirty_images[0] = (1 << 0); + + t->bufAddr = 0; + + make_empty_list( (driTextureObject *) t ); + + mach64SetTexWrap( t, texObj->WrapS, texObj->WrapT ); + mach64SetTexFilter( t, texObj->MinFilter, texObj->MagFilter ); + mach64SetTexBorderColor( t, texObj->_BorderChan ); + + return t; +} + + +/* Called by the _mesa_store_teximage[123]d() functions. */ +static const struct gl_texture_format * +mach64ChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + (void) format; + (void) type; + + switch ( internalFormat ) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + case 2: + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + case 4: + case GL_RGBA: + case GL_RGBA2: + if (mmesa->mach64Screen->cpp == 4) + return &_mesa_texformat_argb8888; + else + return &_mesa_texformat_argb4444; + + case GL_RGB5_A1: + if (mmesa->mach64Screen->cpp == 4) + return &_mesa_texformat_argb8888; + else + return &_mesa_texformat_argb1555; + + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + case GL_RGBA4: + if (mmesa->mach64Screen->cpp == 4) + return &_mesa_texformat_argb8888; + else + return &_mesa_texformat_argb4444; + + case 3: + case GL_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + if (mmesa->mach64Screen->cpp == 4) + return &_mesa_texformat_argb8888; + else + return &_mesa_texformat_rgb565; + + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + if (mmesa->mach64Screen->cpp == 4) + return &_mesa_texformat_argb8888; /* inefficient but accurate */ + else + return &_mesa_texformat_argb1555; + + case GL_INTENSITY4: + case GL_INTENSITY: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + if (mmesa->mach64Screen->cpp == 4) + return &_mesa_texformat_argb8888; /* inefficient but accurate */ + else + return &_mesa_texformat_argb4444; + + case GL_COLOR_INDEX: + case GL_COLOR_INDEX1_EXT: + case GL_COLOR_INDEX2_EXT: + case GL_COLOR_INDEX4_EXT: + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX12_EXT: + case GL_COLOR_INDEX16_EXT: + return &_mesa_texformat_ci8; + + case GL_YCBCR_MESA: + if (type == GL_UNSIGNED_SHORT_8_8_APPLE || + type == GL_UNSIGNED_BYTE) + return &_mesa_texformat_ycbcr; + else + return &_mesa_texformat_ycbcr_rev; + + default: + _mesa_problem( ctx, "unexpected format in %s", __FUNCTION__ ); + return NULL; + } +} + +static void mach64TexImage1D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) mach64AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); + return; + } + } + + /* Note, this will call mach64ChooseTextureFormat */ + _mesa_store_teximage1d( ctx, target, level, internalFormat, + width, border, format, type, + pixels, packing, texObj, texImage ); + + mmesa->new_state |= MACH64_NEW_TEXTURE; +} + +static void mach64TexSubImage1D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) mach64AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D"); + return; + } + } + + _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, + format, type, pixels, packing, texObj, + texImage); + + mmesa->new_state |= MACH64_NEW_TEXTURE; +} + +static void mach64TexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) mach64AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + return; + } + } + + /* Note, this will call mach64ChooseTextureFormat */ + _mesa_store_teximage2d( ctx, target, level, internalFormat, + width, height, border, format, type, pixels, + &ctx->Unpack, texObj, texImage ); + + mmesa->new_state |= MACH64_NEW_TEXTURE; +} + +static void mach64TexSubImage2D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) mach64AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D"); + return; + } + } + + _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, type, pixels, packing, texObj, + texImage); + + mmesa->new_state |= MACH64_NEW_TEXTURE; +} + +/* ================================================================ + * Device Driver API texture functions + */ + +static void mach64DDTexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); +#if 0 + struct gl_texture_unit *texUnit; + GLubyte c[4]; +#endif + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s )\n", + __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); + } + + switch ( pname ) { + case GL_TEXTURE_ENV_MODE: + FLUSH_BATCH( mmesa ); + mmesa->new_state |= MACH64_NEW_TEXTURE | MACH64_NEW_ALPHA; + break; + +#if 0 + case GL_TEXTURE_ENV_COLOR: + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + CLAMPED_FLOAT_TO_UBYTE( c[0], texUnit->EnvColor[0] ); + CLAMPED_FLOAT_TO_UBYTE( c[1], texUnit->EnvColor[1] ); + CLAMPED_FLOAT_TO_UBYTE( c[2], texUnit->EnvColor[2] ); + CLAMPED_FLOAT_TO_UBYTE( c[3], texUnit->EnvColor[3] ); + mmesa->env_color = mach64PackColor( 32, c[0], c[1], c[2], c[3] ); + if ( mmesa->setup.constant_color_c != mmesa->env_color ) { + FLUSH_BATCH( mmesa ); + mmesa->setup.constant_color_c = mmesa->env_color; + + mmesa->new_state |= MACH64_NEW_TEXTURE; + + /* More complex multitexture/multipass fallbacks for GL_BLEND + * can be done later, but this allows a single pass GL_BLEND + * in some cases (ie. Performer town demo). + */ + mmesa->blend_flags &= ~MACH64_BLEND_ENV_COLOR; + if ( mmesa->env_color != 0x00000000 && + mmesa->env_color != 0xff000000 && + mmesa->env_color != 0x00ffffff && + mmesa->env_color != 0xffffffff )) { + mmesa->blend_flags |= MACH64_BLEND_ENV_COLOR; + } + } + break; +#endif + + default: + return; + } +} + +static void mach64DDTexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, + GLenum pname, const GLfloat *params ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + mach64TexObjPtr t = (mach64TexObjPtr)tObj->DriverData; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s )\n", + __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); + } + + if ( ( target != GL_TEXTURE_2D ) && + ( target != GL_TEXTURE_1D ) ) { + return; + } + + if (!t) { + t = mach64AllocTexObj(tObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexParameter"); + return; + } + } + + switch ( pname ) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + if ( t->base.bound ) FLUSH_BATCH( mmesa ); + mach64SetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + if ( t->base.bound ) FLUSH_BATCH( mmesa ); + mach64SetTexWrap( t, tObj->WrapS, tObj->WrapT ); + break; + + case GL_TEXTURE_BORDER_COLOR: + if ( t->base.bound ) FLUSH_BATCH( mmesa ); + mach64SetTexBorderColor( t, tObj->_BorderChan ); + break; + + case GL_TEXTURE_BASE_LEVEL: + /* From Radeon/Rage128: + * This isn't the most efficient solution but there doesn't appear to + * be a nice alternative. Since there's no LOD clamping, + * we just have to rely on loading the right subset of mipmap levels + * to simulate a clamped LOD. + * + * For mach64 we're only concerned with the base level + * since that's the only texture we upload. + */ + if ( t->base.bound ) FLUSH_BATCH( mmesa ); + driSwapOutTextureObject( (driTextureObject *) t ); + break; + + default: + return; + } + + mmesa->new_state |= MACH64_NEW_TEXTURE; +} + +static void mach64DDBindTexture( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLint unit = ctx->Texture.CurrentUnit; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p ) unit=%d\n", + __FUNCTION__, tObj, unit ); + } + + FLUSH_BATCH( mmesa ); + + if ( mmesa->CurrentTexObj[unit] ) { + mmesa->CurrentTexObj[unit]->base.bound &= ~(1 << unit); + mmesa->CurrentTexObj[unit] = NULL; + } + + mmesa->new_state |= MACH64_NEW_TEXTURE; +} + +static void mach64DDDeleteTexture( GLcontext *ctx, + struct gl_texture_object *tObj ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + driTextureObject * t = (driTextureObject *) tObj->DriverData; + + if ( t ) { + if ( t->bound && mmesa ) { + FLUSH_BATCH( mmesa ); + + mmesa->new_state |= MACH64_NEW_TEXTURE; + } + + driDestroyTextureObject( t ); + + /* Free mipmap images and the texture object itself */ + _mesa_delete_texture_object(ctx, tObj); + } +} + +/** + * Allocate a new texture object. + * Called via ctx->Driver.NewTextureObject. + * Note: we could use containment here to 'derive' the driver-specific + * texture object from the core mesa gl_texture_object. Not done at this time. + */ +static struct gl_texture_object * +mach64NewTextureObject( GLcontext *ctx, GLuint name, GLenum target ) +{ + struct gl_texture_object *obj; + obj = _mesa_new_texture_object(ctx, name, target); + mach64AllocTexObj( obj ); + return obj; +} + +void mach64InitTextureFuncs( struct dd_function_table *functions ) +{ + functions->TexEnv = mach64DDTexEnv; + functions->ChooseTextureFormat = mach64ChooseTextureFormat; + functions->TexImage1D = mach64TexImage1D; + functions->TexSubImage1D = mach64TexSubImage1D; + functions->TexImage2D = mach64TexImage2D; + functions->TexSubImage2D = mach64TexSubImage2D; + functions->TexParameter = mach64DDTexParameter; + functions->BindTexture = mach64DDBindTexture; + functions->NewTextureObject = mach64NewTextureObject; + functions->DeleteTexture = mach64DDDeleteTexture; + functions->IsTextureResident = driIsTextureResident; + + functions->UpdateTexturePalette = NULL; + functions->ActiveTexture = NULL; + functions->PrioritizeTexture = NULL; + + driInitTextureFormats(); +} diff --git a/src/mach64_tex.h b/src/mach64_tex.h new file mode 100644 index 0000000..f6cf1cf --- /dev/null +++ b/src/mach64_tex.h @@ -0,0 +1,89 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#ifndef __MACH64_TEX_H__ +#define __MACH64_TEX_H__ + +extern void mach64UpdateTextureState( GLcontext *ctx ); + +extern void mach64UploadTexImages( mach64ContextPtr mach64ctx, + mach64TexObjPtr t ); + +extern void mach64UploadMultiTexImages( mach64ContextPtr mach64ctx, + mach64TexObjPtr t0, mach64TexObjPtr t1 ); + +extern void mach64DestroyTexObj( mach64ContextPtr mach64ctx, + mach64TexObjPtr t ); + +extern void mach64EmitTexStateLocked( mach64ContextPtr mmesa, + mach64TexObjPtr t0, + mach64TexObjPtr t1 ); + +extern void mach64InitTextureFuncs( struct dd_function_table *functions ); + +/* ================================================================ + * Color conversion macros: + */ + +#define MACH64PACKCOLOR332(r, g, b) \ + (((r) & 0xe0) | (((g) & 0xe0) >> 3) | (((b) & 0xc0) >> 6)) + +#define MACH64PACKCOLOR1555(r, g, b, a) \ + ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \ + ((a) ? 0x8000 : 0)) + +#define MACH64PACKCOLOR565(r, g, b) \ + ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3)) + +#define MACH64PACKCOLOR888(r, g, b) \ + (((r) << 16) | ((g) << 8) | (b)) + +#define MACH64PACKCOLOR8888(r, g, b, a) \ + (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) + +#define MACH64PACKCOLOR4444(r, g, b, a) \ + ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4)) + +static __inline__ GLuint mach64PackColor( GLuint cpp, + GLubyte r, GLubyte g, + GLubyte b, GLubyte a ) +{ + switch ( cpp ) { + case 2: + return MACH64PACKCOLOR565( r, g, b ); + case 4: + return MACH64PACKCOLOR8888( r, g, b, a ); + default: + return 0; + } +} + +#endif diff --git a/src/mach64_texmem.c b/src/mach64_texmem.c new file mode 100644 index 0000000..3b7b93b --- /dev/null +++ b/src/mach64_texmem.c @@ -0,0 +1,506 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, Inc., + * Cedar Park, Texas. + * 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, PRECISION INSIGHT 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> + * Leif Delgass <ldelgass@retinalburn.net> + * Jose Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "mach64_context.h" +#include "mach64_state.h" +#include "mach64_ioctl.h" +#include "mach64_vb.h" +#include "mach64_tris.h" +#include "mach64_tex.h" + +#include "context.h" +#include "macros.h" +#include "simple_list.h" +#include "texformat.h" +#include "imports.h" + + +/* Destroy hardware state associated with texture `t'. + */ +void mach64DestroyTexObj( mach64ContextPtr mmesa, mach64TexObjPtr t ) +{ + unsigned i; + + /* See if it was the driver's current object. + */ + if ( mmesa != NULL ) + { + for ( i = 0 ; i < mmesa->glCtx->Const.MaxTextureUnits ; i++ ) + { + if ( t == mmesa->CurrentTexObj[ i ] ) { + assert( t->base.bound & (1 << i) ); + mmesa->CurrentTexObj[ i ] = NULL; + } + } + } +} + +/* Upload the texture image associated with texture `t' at level `level' + * at the address relative to `start'. + */ +static void mach64UploadAGPSubImage( mach64ContextPtr mmesa, + mach64TexObjPtr t, int level, + int x, int y, int width, int height ) +{ + mach64ScreenRec *mach64Screen = mmesa->mach64Screen; + struct gl_texture_image *image; + int texelsPerDword = 0; + int dwords; + + /* Ensure we have a valid texture to upload */ + if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) ) + return; + + image = t->base.tObj->Image[0][level]; + if ( !image ) + return; + + switch ( image->TexFormat->TexelBytes ) { + case 1: texelsPerDword = 4; break; + case 2: texelsPerDword = 2; break; + case 4: texelsPerDword = 1; break; + } + +#if 1 + /* FIXME: The subimage index calcs are wrong... */ + x = 0; + y = 0; + width = image->Width; + height = image->Height; +#endif + + dwords = width * height / texelsPerDword; + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + mmesa->c_agpTextureBytes += (dwords << 2); +#endif + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n", + width, height, image->Width, image->Height, x, y ); + fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n", + (GLuint)t->bufAddr, (GLint)width, dwords ); + } + + assert(image->Data); + + { + CARD32 *dst = (CARD32 *)((char *)mach64Screen->agpTextures.map + t->base.memBlock->ofs); + const GLubyte *src = (const GLubyte *) image->Data + + (y * image->Width + x) * image->TexFormat->TexelBytes; + const GLuint bytes = width * height * image->TexFormat->TexelBytes; + memcpy(dst, src, bytes); + } + +} + +/* Upload the texture image associated with texture `t' at level `level' + * at the address relative to `start'. + */ +static void mach64UploadLocalSubImage( mach64ContextPtr mmesa, + mach64TexObjPtr t, int level, + int x, int y, int width, int height ) +{ + struct gl_texture_image *image; + int texelsPerDword = 0; + int imageWidth, imageHeight; + int remaining, rows; + int format, dwords; + const int maxdwords = (MACH64_BUFFER_MAX_DWORDS - (MACH64_HOSTDATA_BLIT_OFFSET / 4)); + CARD32 pitch, offset; + int i; + + /* Ensure we have a valid texture to upload */ + if ( ( level < 0 ) || ( level > mmesa->glCtx->Const.MaxTextureLevels ) ) + return; + + image = t->base.tObj->Image[0][level]; + if ( !image ) + return; + + switch ( image->TexFormat->TexelBytes ) { + case 1: texelsPerDword = 4; break; + case 2: texelsPerDword = 2; break; + case 4: texelsPerDword = 1; break; + } + +#if 1 + /* FIXME: The subimage index calcs are wrong... */ + x = 0; + y = 0; + width = image->Width; + height = image->Height; +#endif + + imageWidth = image->Width; + imageHeight = image->Height; + + format = t->textureFormat; + + /* The texel upload routines have a minimum width, so force the size + * if needed. + */ + if ( imageWidth < texelsPerDword ) { + int factor; + + factor = texelsPerDword / imageWidth; + imageWidth = texelsPerDword; + imageHeight /= factor; + if ( imageHeight == 0 ) { + /* In this case, the texel converter will actually walk a + * texel or two off the end of the image, but normal malloc + * alignment should prevent it from ever causing a fault. + */ + imageHeight = 1; + } + } + + /* We can't upload to a pitch less than 64 texels so we will need to + * linearly upload all modified rows for textures smaller than this. + * This makes the x/y/width/height different for the blitter and the + * texture walker. + */ + if ( imageWidth >= 64 ) { + /* The texture walker and the blitter look identical */ + pitch = imageWidth >> 3; + } else { + int factor; + int y2; + int start, end; + + start = (y * imageWidth) & ~63; + end = (y + height) * imageWidth; + + if ( end - start < 64 ) { + /* Handle the case where the total number of texels + * uploaded is < 64. + */ + x = 0; + y = start / 64; + width = end - start; + height = 1; + } else { + /* Upload some number of full 64 texel blit rows */ + factor = 64 / imageWidth; + + y2 = y + height - 1; + y /= factor; + y2 /= factor; + + x = 0; + width = 64; + height = y2 - y + 1; + } + + /* Fixed pitch of 64 */ + pitch = 8; + } + + dwords = width * height / texelsPerDword; + offset = t->bufAddr; + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + mmesa->c_textureBytes += (dwords << 2); +#endif + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "mach64UploadSubImage: %d,%d of %d,%d at %d,%d\n", + width, height, image->Width, image->Height, x, y ); + fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d\n", + (GLuint)offset, (GLint)width, dwords ); + } + + /* Subdivide the texture if required (account for the registers added by the drm) */ + if ( dwords <= maxdwords ) { + rows = height; + } else { + rows = (maxdwords * texelsPerDword) / (2 * width); + } + + for ( i = 0, remaining = height ; + remaining > 0 ; + remaining -= rows, y += rows, i++ ) + { + height = MIN2(remaining, rows); + + assert(image->Data); + + { + const GLubyte *src = (const GLubyte *) image->Data + + (y * image->Width + x) * image->TexFormat->TexelBytes; + + mach64FireBlitLocked( mmesa, (void *)src, offset, pitch, format, + x, y, width, height ); + } + + } + + mmesa->new_state |= MACH64_NEW_CONTEXT; + mmesa->dirty |= MACH64_UPLOAD_CONTEXT | MACH64_UPLOAD_MISC; +} + + +/* 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. + */ +void mach64UploadTexImages( mach64ContextPtr mmesa, mach64TexObjPtr t ) +{ + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %p )\n", + __FUNCTION__, mmesa->glCtx, t ); + } + + assert(t); + assert(t->base.tObj); + + if ( !t->base.memBlock ) { + int heap; + + /* NULL heaps are skipped */ + heap = driAllocateTexture( mmesa->texture_heaps, MACH64_NR_TEX_HEAPS, + (driTextureObject *) t ); + + if ( heap == -1 ) { + fprintf( stderr, "%s: upload texture failure, sz=%d\n", __FUNCTION__, + t->base.totalSize ); + exit(-1); + return; + } + + t->heap = heap; + + /* Set the base offset of the texture image */ + t->bufAddr = mmesa->mach64Screen->texOffset[heap] + t->base.memBlock->ofs; + + /* Force loading the new state into the hardware */ + mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL | + MACH64_UPLOAD_TEXTURE); + } + + /* Let the world know we've used this memory recently */ + driUpdateTextureLRU( (driTextureObject *) t ); + + /* Upload any images that are new */ + if ( t->base.dirty_images[0] ) { + const GLint j = t->base.tObj->BaseLevel; + if (t->heap == MACH64_AGP_HEAP) { + /* Need to make sure any vertex buffers in the queue complete */ + mach64WaitForIdleLocked( mmesa ); + mach64UploadAGPSubImage( mmesa, t, j, 0, 0, + t->base.tObj->Image[0][j]->Width, + t->base.tObj->Image[0][j]->Height ); + } else { + mach64UploadLocalSubImage( mmesa, t, j, 0, 0, + t->base.tObj->Image[0][j]->Width, + t->base.tObj->Image[0][j]->Height ); + } + + mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; + t->base.dirty_images[0] = 0; + } + + mmesa->dirty |= MACH64_UPLOAD_TEXTURE; +} + + +/* Allocate memory from the same texture heap `heap' for both textures + * `u0' and `u1'. + */ +static int mach64AllocateMultiTex( mach64ContextPtr mmesa, + mach64TexObjPtr u0, + mach64TexObjPtr u1, + int heap, GLboolean alloc_u0 ) +{ + /* Both objects should be bound */ + assert( u0->base.bound && u1->base.bound ); + + if ( alloc_u0 ) { + /* Evict u0 from its current heap */ + if ( u0->base.memBlock ) { + assert( u0->heap != heap ); + driSwapOutTextureObject( (driTextureObject *) u0 ); + } + + /* Try to allocate u0 in the chosen heap */ + u0->heap = driAllocateTexture( &mmesa->texture_heaps[heap], 1, + (driTextureObject *) u0 ); + + if ( u0->heap == -1 ) { + return -1; + } + } + + /* Evict u1 from its current heap */ + if ( u1->base.memBlock ) { + assert( u1->heap != heap ); + driSwapOutTextureObject( (driTextureObject *) u1 ); + } + + /* Try to allocate u1 in the same heap as u0 */ + u1->heap = driAllocateTexture( &mmesa->texture_heaps[heap], 1, + (driTextureObject *) u1 ); + + if ( u1->heap == -1 ) { + return -1; + } + + /* Bound objects are not evicted */ + assert( u0->base.memBlock && u1->base.memBlock ); + assert( u0->heap == u1->heap ); + + return heap; +} + +/* The mach64 needs to have both primary and secondary textures in either + * local or AGP memory, so we need a "buddy system" to make sure that allocation + * succeeds or fails for both textures. + */ +void mach64UploadMultiTexImages( mach64ContextPtr mmesa, + mach64TexObjPtr t0, + mach64TexObjPtr t1 ) +{ + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %p %p )\n", + __FUNCTION__, mmesa->glCtx, t0, t1 ); + } + + assert(t0 && t1); + assert(t0->base.tObj && t1->base.tObj); + + if ( !t0->base.memBlock || !t1->base.memBlock || t0->heap != t1->heap ) { + mach64TexObjPtr u0 = NULL; + mach64TexObjPtr u1 = NULL; + unsigned totalSize = t0->base.totalSize + t1->base.totalSize; + + int heap, ret; + + /* Check if one of the textures is already swapped in a heap and the + * other texture fits in that heap. + */ + if ( t0->base.memBlock && totalSize <= t0->base.heap->size ) { + u0 = t0; + u1 = t1; + } else if ( t1->base.memBlock && totalSize <= t1->base.heap->size ) { + u0 = t1; + u1 = t0; + } + + if ( u0 ) { + heap = u0->heap; + + ret = mach64AllocateMultiTex( mmesa, u0, u1, heap, GL_FALSE ); + } else { + /* Both textures are swapped out or collocation is impossible */ + u0 = t0; + u1 = t1; + + /* Choose the heap appropriately */ + heap = MACH64_CARD_HEAP; + + if ( totalSize > mmesa->texture_heaps[heap]->size ) { + heap = MACH64_AGP_HEAP; + } + + ret = mach64AllocateMultiTex( mmesa, u0, u1, heap, GL_TRUE ); + } + + if ( ret == -1 && heap == MACH64_CARD_HEAP ) { + /* Try AGP if local memory failed */ + heap = MACH64_AGP_HEAP; + + ret = mach64AllocateMultiTex( mmesa, u0, u1, heap, GL_TRUE ); + } + + if ( ret == -1 ) { + /* FIXME: + * Swap out all textures from the AGP heap and re-run allocation, this + * should succeed in all cases. + */ + fprintf( stderr, "%s: upload multi-texture failure, sz0=%d sz1=%d\n", + __FUNCTION__, t0->base.totalSize, t1->base.totalSize ); + exit(-1); + } + + /* Set the base offset of the texture image */ + t0->bufAddr = mmesa->mach64Screen->texOffset[heap] + t0->base.memBlock->ofs; + t1->bufAddr = mmesa->mach64Screen->texOffset[heap] + t1->base.memBlock->ofs; + + /* Force loading the new state into the hardware */ + mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL | + MACH64_UPLOAD_TEXTURE); + } + + /* Let the world know we've used this memory recently */ + driUpdateTextureLRU( (driTextureObject *) t0 ); + driUpdateTextureLRU( (driTextureObject *) t1 ); + + /* Upload any images that are new */ + if ( t0->base.dirty_images[0] ) { + const GLint j0 = t0->base.tObj->BaseLevel; + if (t0->heap == MACH64_AGP_HEAP) { + /* Need to make sure any vertex buffers in the queue complete */ + mach64WaitForIdleLocked( mmesa ); + mach64UploadAGPSubImage( mmesa, t0, j0, 0, 0, + t0->base.tObj->Image[0][j0]->Width, + t0->base.tObj->Image[0][j0]->Height ); + } else { + mach64UploadLocalSubImage( mmesa, t0, j0, 0, 0, + t0->base.tObj->Image[0][j0]->Width, + t0->base.tObj->Image[0][j0]->Height ); + } + mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; + t0->base.dirty_images[0] = 0; + } + if ( t1->base.dirty_images[0] ) { + const GLint j1 = t1->base.tObj->BaseLevel; + if (t1->heap == MACH64_AGP_HEAP) { + /* Need to make sure any vertex buffers in the queue complete */ + mach64WaitForIdleLocked( mmesa ); + mach64UploadAGPSubImage( mmesa, t1, j1, 0, 0, + t1->base.tObj->Image[0][j1]->Width, + t1->base.tObj->Image[0][j1]->Height ); + } else { + mach64UploadLocalSubImage( mmesa, t1, j1, 0, 0, + t1->base.tObj->Image[0][j1]->Width, + t1->base.tObj->Image[0][j1]->Height ); + } + + mmesa->setup.tex_cntl |= MACH64_TEX_CACHE_FLUSH; + t1->base.dirty_images[0] = 0; + } + + mmesa->dirty |= MACH64_UPLOAD_TEXTURE; +} diff --git a/src/mach64_texstate.c b/src/mach64_texstate.c new file mode 100644 index 0000000..3ace370 --- /dev/null +++ b/src/mach64_texstate.c @@ -0,0 +1,525 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "macros.h" +#include "texformat.h" + +#include "mach64_context.h" +#include "mach64_ioctl.h" +#include "mach64_state.h" +#include "mach64_vb.h" +#include "mach64_tris.h" +#include "mach64_tex.h" + +static void mach64SetTexImages( mach64ContextPtr mmesa, + const struct gl_texture_object *tObj ) +{ + mach64TexObjPtr t = (mach64TexObjPtr) tObj->DriverData; + struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; + int totalSize; + + assert(t); + assert(baseImage); + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) + fprintf( stderr, "%s( %p )\n", __FUNCTION__, tObj ); + + switch (baseImage->TexFormat->MesaFormat) { + case MESA_FORMAT_ARGB8888: + t->textureFormat = MACH64_DATATYPE_ARGB8888; + break; + case MESA_FORMAT_ARGB4444: + t->textureFormat = MACH64_DATATYPE_ARGB4444; + break; + case MESA_FORMAT_RGB565: + t->textureFormat = MACH64_DATATYPE_RGB565; + break; + case MESA_FORMAT_ARGB1555: + t->textureFormat = MACH64_DATATYPE_ARGB1555; + break; + case MESA_FORMAT_RGB332: + t->textureFormat = MACH64_DATATYPE_RGB332; + break; + case MESA_FORMAT_RGB888: + t->textureFormat = MACH64_DATATYPE_RGB8; + break; + case MESA_FORMAT_CI8: + t->textureFormat = MACH64_DATATYPE_CI8; + break; + case MESA_FORMAT_YCBCR: + t->textureFormat = MACH64_DATATYPE_YVYU422; + break; + case MESA_FORMAT_YCBCR_REV: + t->textureFormat = MACH64_DATATYPE_VYUY422; + break; + default: + _mesa_problem(mmesa->glCtx, "Bad texture format in %s", __FUNCTION__); + }; + + totalSize = ( baseImage->Height * + baseImage->Width * + baseImage->TexFormat->TexelBytes ); + + totalSize = (totalSize + 31) & ~31; + + t->base.totalSize = totalSize; + t->base.firstLevel = tObj->BaseLevel; + t->base.lastLevel = tObj->BaseLevel; + + /* Set the texture format */ + if ( ( baseImage->_BaseFormat == GL_RGBA ) || + ( baseImage->_BaseFormat == GL_ALPHA ) || + ( baseImage->_BaseFormat == GL_LUMINANCE_ALPHA ) ) { + t->hasAlpha = 1; + } else { + t->hasAlpha = 0; + } + + t->widthLog2 = baseImage->WidthLog2; + t->heightLog2 = baseImage->HeightLog2; + t->maxLog2 = baseImage->MaxLog2; +} + +static void mach64UpdateTextureEnv( GLcontext *ctx, int unit ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLint source = mmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + const struct gl_texture_object *tObj = texUnit->_Current; + const GLenum format = tObj->Image[0][tObj->BaseLevel]->_BaseFormat; + GLuint s = mmesa->setup.scale_3d_cntl; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %d )\n", + __FUNCTION__, ctx, unit ); + } + +/* REPLACE MODULATE DECAL GL_BLEND + * + * ALPHA C = Cf C = Cf undef C = Cf + * A = At A = AfAt A = AfAt + * + * LUMINANCE C = Ct C = CfCt undef C = Cf(1-Ct)+CcCt + * A = Af A = Af A = Af + * + * LUMINANCE_ALPHA C = Ct C = CfCt undef C = Cf(1-Ct)+CcCt + * A = At A = AfAt A = AfAt + * + * INTENSITY C = Ct C = CfCt undef C = Cf(1-Ct)+CcCt + * A = At A = AfAt A = Af(1-At)+AcAt + * + * RGB C = Ct C = CfCt C = Ct C = Cf(1-Ct)+CcCt + * A = Af A = Af A = Af A = Af + * + * RGBA C = Ct C = CfCt C = Cf(1-At)+CtAt C = Cf(1-Ct)+CcCt + * A = At A = AfAt A = Af A = AfAt + */ + + + if ( unit == 0 ) { + s &= ~MACH64_TEX_LIGHT_FCN_MASK; + + /* Set the texture environment state + * Need to verify these are working correctly, but the + * texenv Mesa demo seems to work. + */ + switch ( texUnit->EnvMode ) { + case GL_REPLACE: + switch ( format ) { + case GL_ALPHA: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + /* Not compliant - can't get At */ + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + default: + s |= MACH64_TEX_LIGHT_FCN_REPLACE; + } + break; + case GL_MODULATE: + switch ( format ) { + case GL_ALPHA: + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + case GL_RGB: + case GL_LUMINANCE: + /* These should be compliant */ + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + case GL_RGBA: + /* Should fallback when blending enabled for complete compliance */ + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + default: + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + } + break; + case GL_DECAL: + switch ( format ) { + case GL_RGBA: + s |= MACH64_TEX_LIGHT_FCN_ALPHA_DECAL; + break; + case GL_RGB: + s |= MACH64_TEX_LIGHT_FCN_REPLACE; + break; + case GL_ALPHA: + case GL_LUMINANCE_ALPHA: + /* undefined - disable texturing, pass fragment unmodified */ + /* Also, pass fragment alpha instead of texture alpha */ + s &= ~MACH64_TEX_MAP_AEN; + s |= MACH64_TEXTURE_DISABLE; + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + case GL_LUMINANCE: + case GL_INTENSITY: + /* undefined - disable texturing, pass fragment unmodified */ + s |= MACH64_TEXTURE_DISABLE; + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + default: + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + } + break; + case GL_BLEND: + /* GL_BLEND not supported by RagePRO, use software */ + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + case GL_ADD: + case GL_COMBINE: + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + break; + default: + s |= MACH64_TEX_LIGHT_FCN_MODULATE; + } + + if ( mmesa->setup.scale_3d_cntl != s ) { + mmesa->setup.scale_3d_cntl = s; + mmesa->dirty |= MACH64_UPLOAD_SCALE_3D_CNTL; + } + + } else { + /* blend = 0, modulate = 1 - initialize to blend */ + mmesa->setup.tex_cntl &= ~MACH64_COMP_COMBINE_MODULATE; + /* Set the texture composite function for multitexturing*/ + switch ( texUnit->EnvMode ) { + case GL_BLEND: + /* GL_BLEND not supported by RagePRO, use software */ + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; + break; + case GL_MODULATE: + /* Should fallback when blending enabled for complete compliance */ + mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; + break; + case GL_REPLACE: + switch ( format ) { + case GL_ALPHA: + mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; + break; + default: /* not supported by RagePRO */ + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; + } + break; + case GL_DECAL: + switch ( format ) { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + /* undefined, disable compositing and pass fragment unmodified */ + mmesa->setup.tex_cntl &= ~MACH64_TEXTURE_COMPOSITE; + break; + default: /* not supported by RagePRO */ + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; + } + break; + case GL_ADD: + case GL_COMBINE: + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; + break; + default: + mmesa->setup.tex_cntl |= MACH64_COMP_COMBINE_MODULATE; + } + } +} + + +static void mach64UpdateTextureUnit( GLcontext *ctx, int unit ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + int source = mmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + const struct gl_texture_object *tObj = ctx->Texture.Unit[source]._Current; + mach64TexObjPtr t = tObj->DriverData; + GLuint d = mmesa->setup.dp_pix_width; + GLuint s = mmesa->setup.scale_3d_cntl; + + assert(unit == 0 || unit == 1); /* only two tex units */ + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %d ) enabled=0x%x 0x%x\n", + __FUNCTION__, ctx, unit, ctx->Texture.Unit[0]._ReallyEnabled, + ctx->Texture.Unit[1]._ReallyEnabled); + } + + if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) { + + assert(t); /* should have driver tex data by now */ + + /* Fallback if there's a texture border */ + if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) { + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + return; + } + + /* Upload teximages */ + if (t->base.dirty_images[0]) { + mach64SetTexImages( mmesa, tObj ); + mmesa->dirty |= (MACH64_UPLOAD_TEX0IMAGE << unit); + } + + /* Bind to the given texture unit */ + mmesa->CurrentTexObj[unit] = t; + t->base.bound |= (1 << unit); + + if ( t->base.memBlock ) + driUpdateTextureLRU( (driTextureObject *) t ); /* XXX: should be locked! */ + + /* register setup */ + if ( unit == 0 ) { + d &= ~MACH64_SCALE_PIX_WIDTH_MASK; + d |= (t->textureFormat << 28); + + s &= ~(MACH64_TEXTURE_DISABLE | + MACH64_TEX_CACHE_SPLIT | + MACH64_TEX_BLEND_FCN_MASK | + MACH64_TEX_MAP_AEN); + + if ( mmesa->multitex ) { + s |= MACH64_TEX_BLEND_FCN_TRILINEAR | MACH64_TEX_CACHE_SPLIT; + } else if ( t->BilinearMin ) { + s |= MACH64_TEX_BLEND_FCN_LINEAR; + } else { + s |= MACH64_TEX_BLEND_FCN_NEAREST; + } + if ( t->BilinearMag ) { + s |= MACH64_BILINEAR_TEX_EN; + } else { + s &= ~MACH64_BILINEAR_TEX_EN; + } + + if ( t->hasAlpha ) { + s |= MACH64_TEX_MAP_AEN; + } + + mmesa->setup.tex_cntl &= ~(MACH64_TEXTURE_CLAMP_S | + MACH64_TEXTURE_CLAMP_T | + MACH64_SECONDARY_STW); + + if ( t->ClampS ) { + mmesa->setup.tex_cntl |= MACH64_TEXTURE_CLAMP_S; + } + if ( t->ClampT ) { + mmesa->setup.tex_cntl |= MACH64_TEXTURE_CLAMP_T; + } + + mmesa->setup.tex_size_pitch |= ((t->widthLog2 << 0) | + (t->maxLog2 << 4) | + (t->heightLog2 << 8)); + } else { + + /* Enable texture mapping mode */ + s &= ~MACH64_TEXTURE_DISABLE; + + d &= ~MACH64_COMPOSITE_PIX_WIDTH_MASK; + d |= (t->textureFormat << 4); + + mmesa->setup.tex_cntl &= ~(MACH64_COMP_ALPHA | + MACH64_SEC_TEX_CLAMP_S | + MACH64_SEC_TEX_CLAMP_T); + mmesa->setup.tex_cntl |= (MACH64_TEXTURE_COMPOSITE | + MACH64_SECONDARY_STW); + + if ( t->BilinearMin ) { + mmesa->setup.tex_cntl |= MACH64_COMP_BLEND_BILINEAR; + } else { + mmesa->setup.tex_cntl &= ~MACH64_COMP_BLEND_BILINEAR; + } + if ( t->BilinearMag ) { + mmesa->setup.tex_cntl |= MACH64_COMP_FILTER_BILINEAR; + } else { + mmesa->setup.tex_cntl &= ~MACH64_COMP_FILTER_BILINEAR; + } + + if ( t->hasAlpha ) { + mmesa->setup.tex_cntl |= MACH64_COMP_ALPHA; + } + if ( t->ClampS ) { + mmesa->setup.tex_cntl |= MACH64_SEC_TEX_CLAMP_S; + } + if ( t->ClampT ) { + mmesa->setup.tex_cntl |= MACH64_SEC_TEX_CLAMP_T; + } + + mmesa->setup.tex_size_pitch |= ((t->widthLog2 << 16) | + (t->maxLog2 << 20) | + (t->heightLog2 << 24)); + } + + if ( mmesa->setup.scale_3d_cntl != s ) { + mmesa->setup.scale_3d_cntl = s; + mmesa->dirty |= MACH64_UPLOAD_SCALE_3D_CNTL; + } + + if ( mmesa->setup.dp_pix_width != d ) { + mmesa->setup.dp_pix_width = d; + mmesa->dirty |= MACH64_UPLOAD_DP_PIX_WIDTH; + } + } + else if (texUnit->_ReallyEnabled) { + /* 3D or cube map texture enabled - fallback */ + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_TRUE ); + } + else { + /* texture unit disabled */ + } +} + + +/* Update the hardware texture state */ +void mach64UpdateTextureState( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + if ( MACH64_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p ) en=0x%x 0x%x\n", + __FUNCTION__, ctx, ctx->Texture.Unit[0]._ReallyEnabled, + ctx->Texture.Unit[1]._ReallyEnabled); + } + + /* Clear any texturing fallbacks */ + FALLBACK( mmesa, MACH64_FALLBACK_TEXTURE, GL_FALSE ); + + /* Unbind any currently bound textures */ + if ( mmesa->CurrentTexObj[0] ) mmesa->CurrentTexObj[0]->base.bound = 0; + if ( mmesa->CurrentTexObj[1] ) mmesa->CurrentTexObj[1]->base.bound = 0; + mmesa->CurrentTexObj[0] = NULL; + mmesa->CurrentTexObj[1] = NULL; + + /* Disable all texturing until it is known to be good */ + mmesa->setup.scale_3d_cntl |= MACH64_TEXTURE_DISABLE; + mmesa->setup.scale_3d_cntl &= ~MACH64_TEX_MAP_AEN; + mmesa->setup.tex_cntl &= ~MACH64_TEXTURE_COMPOSITE; + + mmesa->setup.tex_size_pitch = 0x00000000; + + mmesa->tmu_source[0] = 0; + mmesa->tmu_source[1] = 1; + mmesa->multitex = 0; + + if (ctx->Texture._EnabledUnits & 0x2) { + /* unit 1 enabled */ + if (ctx->Texture._EnabledUnits & 0x1) { + /* units 0 and 1 enabled */ + mmesa->multitex = 1; + mach64UpdateTextureUnit( ctx, 0 ); + mach64UpdateTextureEnv( ctx, 0 ); + mach64UpdateTextureUnit( ctx, 1 ); + mach64UpdateTextureEnv( ctx, 1 ); + } else { + mmesa->tmu_source[0] = 1; + mmesa->tmu_source[1] = 0; + mach64UpdateTextureUnit( ctx, 0 ); + mach64UpdateTextureEnv( ctx, 0 ); + } + } else if (ctx->Texture._EnabledUnits & 0x1) { + /* only unit 0 enabled */ + mach64UpdateTextureUnit( ctx, 0 ); + mach64UpdateTextureEnv( ctx, 0 ); + } + + mmesa->dirty |= (MACH64_UPLOAD_SCALE_3D_CNTL | + MACH64_UPLOAD_TEXTURE); +} + + +/* Due to the way we must program texture state into the Rage Pro, + * we must leave these calculations to the absolute last minute. + */ +void mach64EmitTexStateLocked( mach64ContextPtr mmesa, + mach64TexObjPtr t0, + mach64TexObjPtr t1 ) +{ + drm_mach64_sarea_t *sarea = mmesa->sarea; + drm_mach64_context_regs_t *regs = &(mmesa->setup); + + /* for multitex, both textures must be local or AGP */ + if ( t0 && t1 ) + assert(t0->heap == t1->heap); + + if ( t0 ) { + if (t0->heap == MACH64_CARD_HEAP) { +#if ENABLE_PERF_BOXES + mmesa->c_texsrc_card++; +#endif + mmesa->setup.tex_cntl &= ~MACH64_TEX_SRC_AGP; + } else { +#if ENABLE_PERF_BOXES + mmesa->c_texsrc_agp++; +#endif + mmesa->setup.tex_cntl |= MACH64_TEX_SRC_AGP; + } + mmesa->setup.tex_offset = t0->bufAddr; + } + + if ( t1 ) { + mmesa->setup.secondary_tex_off = t1->bufAddr; + } + + memcpy( &sarea->context_state.tex_size_pitch, ®s->tex_size_pitch, + MACH64_NR_TEXTURE_REGS * sizeof(GLuint) ); +} + diff --git a/src/mach64_tris.c b/src/mach64_tris.c new file mode 100644 index 0000000..08cc184 --- /dev/null +++ b/src/mach64_tris.c @@ -0,0 +1,1924 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "glheader.h" +#include "mtypes.h" +#include "colormac.h" +#include "macros.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_pipeline.h" + +#include "mach64_tris.h" +#include "mach64_state.h" +#include "mach64_context.h" +#include "mach64_vb.h" +#include "mach64_ioctl.h" + +static const GLuint hw_prim[GL_POLYGON+1] = { + MACH64_PRIM_POINTS, + MACH64_PRIM_LINES, + MACH64_PRIM_LINE_LOOP, + MACH64_PRIM_LINE_STRIP, + MACH64_PRIM_TRIANGLES, + MACH64_PRIM_TRIANGLE_STRIP, + MACH64_PRIM_TRIANGLE_FAN, + MACH64_PRIM_QUADS, + MACH64_PRIM_QUAD_STRIP, + MACH64_PRIM_POLYGON, +}; + +static void mach64RasterPrimitive( GLcontext *ctx, GLuint hwprim ); +static void mach64RenderPrimitive( GLcontext *ctx, GLenum prim ); + + +/* FIXME: Remove this when native template is finished. */ +#define MACH64_PRINT_BUFFER 0 + +/*********************************************************************** + * Emit primitives as inline vertices * + ***********************************************************************/ + +#if defined(USE_X86_ASM) +#define DO_COPY_VERTEX( vb, vertsize, v, n, m ) \ +do { \ + register const CARD32 *__p __asm__( "esi" ) = (CARD32 *)v + 10 - vertsize; \ + register int __s __asm__( "ecx" ) = vertsize; \ + if ( vertsize > 7 ) { \ + *vb++ = (2 << 16) | ADRINDEX( MACH64_VERTEX_##n##_SECONDARY_S ); \ + __asm__ __volatile__( "movsl ; movsl ; movsl" \ + : "=D" (vb), "=S" (__p) \ + : "0" (vb), "1" (__p) ); \ + __s -= 3; \ + } \ + *vb++ = ((__s - 1 + m) << 16) | \ + (ADRINDEX( MACH64_VERTEX_##n##_X_Y ) - (__s - 1) ); \ + __asm__ __volatile__( "rep ; movsl" \ + : "=%c" (__s), "=D" (vb), "=S" (__p) \ + : "0" (__s), "1" (vb), "2" (__p) ); \ +} while (0) +#else +#define DO_COPY_VERTEX( vb, vertsize, v, n, m ) \ +do { \ + CARD32 *__p = (CARD32 *)v + 10 - vertsize; \ + int __s = vertsize; \ + if ( vertsize > 7 ) { \ + LE32_OUT( vb++, (2 << 16) | \ + ADRINDEX( MACH64_VERTEX_##n##_SECONDARY_S ) ); \ + *vb++ = *__p++; \ + *vb++ = *__p++; \ + *vb++ = *__p++; \ + __s -= 3; \ + } \ + LE32_OUT( vb++, ((__s - 1 + m) << 16) | \ + (ADRINDEX( MACH64_VERTEX_##n##_X_Y ) - (__s - 1)) ); \ + while ( __s-- ) { \ + *vb++ = *__p++; \ + } \ +} while (0) +#endif + +#define COPY_VERTEX( vb, vertsize, v, n ) DO_COPY_VERTEX( vb, vertsize, v, n, 0 ) +#define COPY_VERTEX_OOA( vb, vertsize, v, n ) DO_COPY_VERTEX( vb, vertsize, v, n, 1 ) + + +static __inline void mach64_draw_quad( mach64ContextPtr mmesa, + mach64VertexPtr v0, + mach64VertexPtr v1, + mach64VertexPtr v2, + mach64VertexPtr v3 ) +{ +#if MACH64_NATIVE_VTXFMT + GLcontext *ctx = mmesa->glCtx; + const GLuint vertsize = mmesa->vertex_size; + GLint a; + GLfloat ooa; + GLuint xy; + const GLuint xyoffset = 9; + GLint xx[3], yy[3]; /* 2 fractional bits for hardware */ + unsigned vbsiz = (vertsize + (vertsize > 7 ? 2 : 1)) * 4 + 2; + CARD32 *vb, *vbchk; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1:\n"); + mach64_print_vertex( ctx, v0 ); + fprintf(stderr,"Vertex 2:\n"); + mach64_print_vertex( ctx, v1 ); + fprintf(stderr,"Vertex 3:\n"); + mach64_print_vertex( ctx, v2 ); + fprintf(stderr,"Vertex 4:\n"); + mach64_print_vertex( ctx, v3 ); + } + + xy = LE32_IN( &v0->ui[xyoffset] ); + xx[0] = (GLshort)( xy >> 16 ); + yy[0] = (GLshort)( xy & 0xffff ); + + xy = LE32_IN( &v1->ui[xyoffset] ); + xx[1] = (GLshort)( xy >> 16 ); + yy[1] = (GLshort)( xy & 0xffff ); + + xy = LE32_IN( &v3->ui[xyoffset] ); + xx[2] = (GLshort)( xy >> 16 ); + yy[2] = (GLshort)( xy & 0xffff ); + + a = (xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2]); + + if ( (mmesa->backface_sign && + ((a < 0 && !signbit( mmesa->backface_sign )) || + (a > 0 && signbit( mmesa->backface_sign )))) ) { + /* cull quad */ + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) + fprintf(stderr,"Quad culled\n"); + return; + } + + ooa = 16.0 / a; + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * sizeof(CARD32) ); + vbchk = vb + vbsiz; + + COPY_VERTEX( vb, vertsize, v0, 1 ); + COPY_VERTEX( vb, vertsize, v1, 2 ); + COPY_VERTEX_OOA( vb, vertsize, v3, 3 ); + LE32_OUT( vb++, *(CARD32 *)&ooa ); + + xy = LE32_IN( &v2->ui[xyoffset] ); + xx[0] = (GLshort)( xy >> 16 ); + yy[0] = (GLshort)( xy & 0xffff ); + + a = (xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2]); + + ooa = 16.0 / a; + + COPY_VERTEX_OOA( vb, vertsize, v2, 1 ); + LE32_OUT( vb++, *(CARD32 *)&ooa ); + + assert( vb == vbchk ); + +#if MACH64_PRINT_BUFFER + { + int i; + fprintf(stderr, "quad:\n"); + for (i = 0; i < vbsiz; i++) + fprintf(stderr, " %08lx\n", *(vb - vbsiz + i)); + fprintf(stderr, "\n"); + } +#endif +#else + GLuint vertsize = mmesa->vertex_size; + GLint coloridx; + GLfloat ooa; + GLint xx[3], yy[3]; /* 2 fractional bits for hardware */ + unsigned vbsiz = + (( + 1 + + (vertsize > 6 ? 2 : 0) + + (vertsize > 4 ? 2 : 0) + + 3 + + (mmesa->multitex ? 4 : 0) + ) * 4 + 4); + CARD32 *vb; + unsigned vbidx = 0; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1: x: %.2f, y: %.2f, z: %.2f, w: %f\n\ts0: %f, t0: %f\n\ts1: %f, t1: %f\n", + v0->v.x, v0->v.y, v0->v.z, v0->v.w, v0->v.u0, v0->v.v0, v0->v.u1, v0->v.v1); + fprintf(stderr,"Vertex 2: x: %.2f, y: %.2f, z: %.2f, w: %f\n\ts0: %f, t0: %f\n\ts1: %f, t1: %f\n", + v1->v.x, v1->v.y, v1->v.z, v1->v.w, v1->v.u0, v1->v.v0, v1->v.u1, v1->v.v1); + fprintf(stderr,"Vertex 3: x: %.2f, y: %.2f, z: %.2f, w: %f\n\ts0: %f, t0: %f\n\ts1: %f, t1: %f\n", + v2->v.x, v2->v.y, v2->v.z, v2->v.w, v2->v.u0, v2->v.v0, v2->v.u1, v2->v.v1); + fprintf(stderr,"Vertex 4: x: %.2f, y: %.2f, z: %.2f, w: %f\n\ts0: %f, t0: %f\n\ts1: %f, t1: %f\n", + v3->v.x, v3->v.y, v3->v.z, v3->v.w, v3->v.u0, v3->v.v0, v3->v.u1, v3->v.v1); + } + +#if MACH64_CLIENT_STATE_EMITS + /* Enable for interleaved client-side state emits */ + LOCK_HARDWARE( mmesa ); + if ( mmesa->dirty ) { + mach64EmitHwStateLocked( mmesa ); + } + if ( mmesa->sarea->dirty ) { + mach64UploadHwStateLocked( mmesa ); + } + UNLOCK_HARDWARE( mmesa ); +#endif + + xx[0] = (GLint)(v0->v.x * 4); + yy[0] = (GLint)(v0->v.y * 4); + + xx[1] = (GLint)(v1->v.x * 4); + yy[1] = (GLint)(v1->v.y * 4); + + xx[2] = (GLint)(v3->v.x * 4); + yy[2] = (GLint)(v3->v.y * 4); + + ooa = 0.25 * 0.25 * ((xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2])); + + if ( ooa * mmesa->backface_sign < 0 ) { + /* cull quad */ + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) + fprintf(stderr,"Quad culled\n"); + return; + } + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * 4 ); + + ooa = 1.0 / ooa; + + coloridx = (vertsize > 4) ? 4: 3; + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_1_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_1_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_1_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_1_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_1_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_1_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_1_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_1_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[0] << 16) | (yy[0] & 0xffff) ); /* MACH64_VERTEX_1_X_Y */ + + if (mmesa->multitex) { + /* setup for 3 sequential reg writes */ + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_SECONDARY_S) ); + LE32_OUT( &vb[vbidx++], v0->ui[8] ); /* MACH64_VERTEX_1_SECONDARY_S */ + LE32_OUT( &vb[vbidx++], v0->ui[9] ); /* MACH64_VERTEX_1_SECONDARY_T */ + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_1_SECONDARY_W */ + } + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_2_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_2_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_2_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v1->ui[6] ); /* MACH64_VERTEX_2_S */ + LE32_OUT( &vb[vbidx++], v1->ui[7] ); /* MACH64_VERTEX_2_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v1->ui[3] ); /* MACH64_VERTEX_2_W */ + LE32_OUT( &vb[vbidx++], v1->ui[5] ); /* MACH64_VERTEX_2_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v1->v.z) << 15) ); /* MACH64_VERTEX_2_Z */ + vb[vbidx++] = v1->ui[coloridx]; /* MACH64_VERTEX_2_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[1] << 16) | (yy[1] & 0xffff) ); /* MACH64_VERTEX_2_X_Y */ + + if (mmesa->multitex) { + /* setup for 3 sequential reg writes */ + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_2_SECONDARY_S) ); + LE32_OUT( &vb[vbidx++], v1->ui[8] ); /* MACH64_VERTEX_2_SECONDARY_S */ + LE32_OUT( &vb[vbidx++], v1->ui[9] ); /* MACH64_VERTEX_2_SECONDARY_T */ + LE32_OUT( &vb[vbidx++], v1->ui[3] ); /* MACH64_VERTEX_2_SECONDARY_W */ + } + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_3_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_3_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_3_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v3->ui[6] ); /* MACH64_VERTEX_3_S */ + LE32_OUT( &vb[vbidx++], v3->ui[7] ); /* MACH64_VERTEX_3_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v3->ui[3] ); /* MACH64_VERTEX_3_W */ + LE32_OUT( &vb[vbidx++], v3->ui[5] ); /* MACH64_VERTEX_3_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v3->v.z) << 15) ); /* MACH64_VERTEX_3_Z */ + vb[vbidx++] = v3->ui[coloridx]; /* MACH64_VERTEX_3_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[2] << 16) | (yy[2] & 0xffff) ); /* MACH64_VERTEX_3_X_Y */ + + if (mmesa->multitex) { + /* setup for 3 sequential reg writes */ + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_3_SECONDARY_S) ); + LE32_OUT( &vb[vbidx++], v3->ui[8] ); /* MACH64_VERTEX_3_SECONDARY_S */ + LE32_OUT( &vb[vbidx++], v3->ui[9] ); /* MACH64_VERTEX_3_SECONDARY_T */ + LE32_OUT( &vb[vbidx++], v3->ui[3] ); /* MACH64_VERTEX_3_SECONDARY_W */ + } + + LE32_OUT( &vb[vbidx++], ADRINDEX(MACH64_ONE_OVER_AREA_UC) ); + LE32_OUT( &vb[vbidx++], *(GLuint *)&ooa ); + + xx[0] = (GLint)(v2->v.x * 4); + yy[0] = (GLint)(v2->v.y * 4); + + ooa = 0.25 * 0.25 * ((xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2])); + ooa = 1.0 / ooa; + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_1_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_1_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v2->ui[6] ); /* MACH64_VERTEX_1_S */ + LE32_OUT( &vb[vbidx++], v2->ui[7] ); /* MACH64_VERTEX_1_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v2->ui[3] ); /* MACH64_VERTEX_1_W */ + LE32_OUT( &vb[vbidx++], v2->ui[5] ); /* MACH64_VERTEX_1_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v2->v.z) << 15) ); /* MACH64_VERTEX_1_Z */ + vb[vbidx++] = v2->ui[coloridx]; /* MACH64_VERTEX_1_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[0] << 16) | (yy[0] & 0xffff) ); /* MACH64_VERTEX_1_X_Y */ + + if (mmesa->multitex) { + /* setup for 3 sequential reg writes */ + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_SECONDARY_S) ); + LE32_OUT( &vb[vbidx++], v2->ui[8] ); /* MACH64_VERTEX_1_SECONDARY_S */ + LE32_OUT( &vb[vbidx++], v2->ui[9] ); /* MACH64_VERTEX_1_SECONDARY_T */ + LE32_OUT( &vb[vbidx++], v2->ui[3] ); /* MACH64_VERTEX_1_SECONDARY_W */ + } + + LE32_OUT( &vb[vbidx++], ADRINDEX(MACH64_ONE_OVER_AREA_UC) ); + LE32_OUT( &vb[vbidx++], *(GLuint *)&ooa ); + + assert(vbsiz == vbidx); + +#if MACH64_PRINT_BUFFER + { + int i; + fprintf(stderr, "quad:\n"); + for (i = 0; i < vbsiz; i++) + fprintf(stderr, " %08lx\n", *(vb + i)); + fprintf(stderr, "\n"); + } +#endif +#endif +} + +static __inline void mach64_draw_triangle( mach64ContextPtr mmesa, + mach64VertexPtr v0, + mach64VertexPtr v1, + mach64VertexPtr v2 ) +{ +#if MACH64_NATIVE_VTXFMT + GLcontext *ctx = mmesa->glCtx; + GLuint vertsize = mmesa->vertex_size; + GLint a; + GLfloat ooa; + GLuint xy; + const GLuint xyoffset = 9; + GLint xx[3], yy[3]; /* 2 fractional bits for hardware */ + unsigned vbsiz = (vertsize + (vertsize > 7 ? 2 : 1)) * 3 + 1; + CARD32 *vb, *vbchk; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1:\n"); + mach64_print_vertex( ctx, v0 ); + fprintf(stderr,"Vertex 2:\n"); + mach64_print_vertex( ctx, v1 ); + fprintf(stderr,"Vertex 3:\n"); + mach64_print_vertex( ctx, v2 ); + } + + xy = LE32_IN( &v0->ui[xyoffset] ); + xx[0] = (GLshort)( xy >> 16 ); + yy[0] = (GLshort)( xy & 0xffff ); + + xy = LE32_IN( &v1->ui[xyoffset] ); + xx[1] = (GLshort)( xy >> 16 ); + yy[1] = (GLshort)( xy & 0xffff ); + + xy = LE32_IN( &v2->ui[xyoffset] ); + xx[2] = (GLshort)( xy >> 16 ); + yy[2] = (GLshort)( xy & 0xffff ); + + a = (xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2]); + + if ( mmesa->backface_sign && + ((a < 0 && !signbit( mmesa->backface_sign )) || + (a > 0 && signbit( mmesa->backface_sign ))) ) { + /* cull triangle */ + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) + fprintf(stderr,"Triangle culled\n"); + return; + } + + ooa = 16.0 / a; + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * sizeof(CARD32) ); + vbchk = vb + vbsiz; + + COPY_VERTEX( vb, vertsize, v0, 1 ); + COPY_VERTEX( vb, vertsize, v1, 2 ); + COPY_VERTEX_OOA( vb, vertsize, v2, 3 ); + LE32_OUT( vb++, *(CARD32 *)&ooa ); + + assert( vb == vbchk ); + +#if MACH64_PRINT_BUFFER + { + int i; + fprintf(stderr, "tri:\n"); + for (i = 0; i < vbsiz; i++) + fprintf(stderr, " %08lx\n", *(vb - vbsiz + i)); + fprintf(stderr, "\n"); + } +#endif +#else + GLuint vertsize = mmesa->vertex_size; + GLint coloridx; + GLfloat ooa; + GLint xx[3], yy[3]; /* 2 fractional bits for hardware */ + unsigned vbsiz = + (( + 1 + + (vertsize > 6 ? 2 : 0) + + (vertsize > 4 ? 2 : 0) + + 3 + + (mmesa->multitex ? 4 : 0) + ) * 3 + 2); + CARD32 *vb; + unsigned vbidx = 0; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1: x: %.2f, y: %.2f, z: %.2f, w: %f\n\ts0: %f, t0: %f\n\ts1: %f, t1: %f\n", + v0->v.x, v0->v.y, v0->v.z, v0->v.w, v0->v.u0, v0->v.v0, v0->v.u1, v0->v.v1); + fprintf(stderr,"Vertex 2: x: %.2f, y: %.2f, z: %.2f, w: %f\n\ts0: %f, t0: %f\n\ts1: %f, t1: %f\n", + v1->v.x, v1->v.y, v1->v.z, v1->v.w, v1->v.u0, v1->v.v0, v1->v.u1, v1->v.v1); + fprintf(stderr,"Vertex 3: x: %.2f, y: %.2f, z: %.2f, w: %f\n\ts0: %f, t0: %f\n\ts1: %f, t1: %f\n", + v2->v.x, v2->v.y, v2->v.z, v2->v.w, v2->v.u0, v2->v.v0, v2->v.u1, v2->v.v1); + } + +#if MACH64_CLIENT_STATE_EMITS + /* Enable for interleaved client-side state emits */ + LOCK_HARDWARE( mmesa ); + if ( mmesa->dirty ) { + mach64EmitHwStateLocked( mmesa ); + } + if ( mmesa->sarea->dirty ) { + mach64UploadHwStateLocked( mmesa ); + } + UNLOCK_HARDWARE( mmesa ); +#endif + + xx[0] = (GLint)(v0->v.x * 4); + yy[0] = (GLint)(v0->v.y * 4); + + xx[1] = (GLint)(v1->v.x * 4); + yy[1] = (GLint)(v1->v.y * 4); + + xx[2] = (GLint)(v2->v.x * 4); + yy[2] = (GLint)(v2->v.y * 4); + + ooa = 0.25 * 0.25 * ((xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2])); + + if ( ooa * mmesa->backface_sign < 0 ) { + /* cull triangle */ + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) + fprintf(stderr,"Triangle culled\n"); + return; + } + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * 4 ); + + ooa = 1.0 / ooa; + + coloridx = (vertsize > 4) ? 4: 3; + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_1_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_1_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_1_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_1_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_1_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_1_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_1_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_1_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[0] << 16) | (yy[0] & 0xffff) ); /* MACH64_VERTEX_1_X_Y */ + + if (mmesa->multitex) { + /* setup for 3 sequential reg writes */ + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_SECONDARY_S) ); + LE32_OUT( &vb[vbidx++], v0->ui[8] ); /* MACH64_VERTEX_1_SECONDARY_S */ + LE32_OUT( &vb[vbidx++], v0->ui[9] ); /* MACH64_VERTEX_1_SECONDARY_T */ + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_1_SECONDARY_W */ + } + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_2_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_2_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_2_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v1->ui[6] ); /* MACH64_VERTEX_2_S */ + LE32_OUT( &vb[vbidx++], v1->ui[7] ); /* MACH64_VERTEX_2_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v1->ui[3] ); /* MACH64_VERTEX_2_W */ + LE32_OUT( &vb[vbidx++], v1->ui[5] ); /* MACH64_VERTEX_2_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v1->v.z) << 15) ); /* MACH64_VERTEX_2_Z */ + vb[vbidx++] = v1->ui[coloridx]; /* MACH64_VERTEX_2_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[1] << 16) | (yy[1] & 0xffff) ); /* MACH64_VERTEX_2_X_Y */ + + if (mmesa->multitex) { + /* setup for 3 sequential reg writes */ + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_2_SECONDARY_S) ); + LE32_OUT( &vb[vbidx++], v1->ui[8] ); /* MACH64_VERTEX_2_SECONDARY_S */ + LE32_OUT( &vb[vbidx++], v1->ui[9] ); /* MACH64_VERTEX_2_SECONDARY_T */ + LE32_OUT( &vb[vbidx++], v1->ui[3] ); /* MACH64_VERTEX_2_SECONDARY_W */ + } + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_3_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_3_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_3_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v2->ui[6] ); /* MACH64_VERTEX_3_S */ + LE32_OUT( &vb[vbidx++], v2->ui[7] ); /* MACH64_VERTEX_3_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v2->ui[3] ); /* MACH64_VERTEX_3_W */ + LE32_OUT( &vb[vbidx++], v2->ui[5] ); /* MACH64_VERTEX_3_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v2->v.z) << 15) ); /* MACH64_VERTEX_3_Z */ + vb[vbidx++] = v2->ui[coloridx]; /* MACH64_VERTEX_3_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[2] << 16) | (yy[2] & 0xffff) ); /* MACH64_VERTEX_3_X_Y */ + + if (mmesa->multitex) { + /* setup for 3 sequential reg writes */ + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_3_SECONDARY_S) ); + LE32_OUT( &vb[vbidx++], v2->ui[8] ); /* MACH64_VERTEX_3_SECONDARY_S */ + LE32_OUT( &vb[vbidx++], v2->ui[9] ); /* MACH64_VERTEX_3_SECONDARY_T */ + LE32_OUT( &vb[vbidx++], v2->ui[3] ); /* MACH64_VERTEX_3_SECONDARY_W */ + } + + LE32_OUT( &vb[vbidx++], ADRINDEX(MACH64_ONE_OVER_AREA_UC) ); + LE32_OUT( &vb[vbidx++], *(GLuint *)&ooa ); + + assert(vbsiz == vbidx); + +#if MACH64_PRINT_BUFFER + { + int i; + fprintf(stderr, "tri:\n"); + for (i = 0; i < vbsiz; ++i) + fprintf(stderr, " %08lx\n", *(vb + i)); + fprintf(stderr, "\n"); + } +#endif +#endif +} + +static __inline void mach64_draw_line( mach64ContextPtr mmesa, + mach64VertexPtr v0, + mach64VertexPtr v1 ) +{ +#if MACH64_NATIVE_VTXFMT + GLcontext *ctx = mmesa->glCtx; + const GLuint vertsize = mmesa->vertex_size; + GLint width = (GLint)(mmesa->glCtx->Line._Width * 2.0); /* 2 fractional bits for hardware */ + GLfloat ooa; + GLuint *pxy0, *pxy1; + GLuint xy0old, xy0, xy1old, xy1; + const GLuint xyoffset = 9; + GLint x0, y0, x1, y1; + GLint dx, dy, ix, iy; + unsigned vbsiz = (vertsize + (vertsize > 7 ? 2 : 1)) * 4 + 2; + CARD32 *vb, *vbchk; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1:\n"); + mach64_print_vertex( ctx, v0 ); + fprintf(stderr,"Vertex 2:\n"); + mach64_print_vertex( ctx, v1 ); + } + + if( !width ) + width = 1; /* round to the nearest supported width */ + + pxy0 = &v0->ui[xyoffset]; + xy0old = *pxy0; + xy0 = LE32_IN( &xy0old ); + x0 = (GLshort)( xy0 >> 16 ); + y0 = (GLshort)( xy0 & 0xffff ); + + pxy1 = &v1->ui[xyoffset]; + xy1old = *pxy1; + xy1 = LE32_IN( &xy1old ); + x1 = (GLshort)( xy1 >> 16 ); + y1 = (GLshort)( xy1 & 0xffff ); + + if ( (dx = x1 - x0) < 0 ) { + dx = -dx; + } + if ( (dy = y1 - y0) < 0 ) { + dy = -dy; + } + + /* adjust vertices depending on line direction */ + if ( dx > dy ) { + ix = 0; + iy = width; + ooa = 8.0 / ((x1 - x0) * width); + } else { + ix = width; + iy = 0; + ooa = 8.0 / ((y0 - y1) * width); + } + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * sizeof(CARD32) ); + vbchk = vb + vbsiz; + + LE32_OUT( pxy0, (( x0 - ix ) << 16) | (( y0 - iy ) & 0xffff) ); + COPY_VERTEX( vb, vertsize, v0, 1 ); + LE32_OUT( pxy1, (( x1 - ix ) << 16) | (( y1 - iy ) & 0xffff) ); + COPY_VERTEX( vb, vertsize, v1, 2 ); + LE32_OUT( pxy0, (( x0 + ix ) << 16) | (( y0 + iy ) & 0xffff) ); + COPY_VERTEX_OOA( vb, vertsize, v0, 3 ); + LE32_OUT( vb++, *(CARD32 *)&ooa ); + + ooa = -ooa; + + LE32_OUT( pxy1, (( x1 + ix ) << 16) | (( y1 + iy ) & 0xffff) ); + COPY_VERTEX_OOA( vb, vertsize, v1, 1 ); + LE32_OUT( vb++, *(CARD32 *)&ooa ); + + *pxy0 = xy0old; + *pxy1 = xy1old; +#else /* !MACH64_NATIVE_VTXFMT */ + GLuint vertsize = mmesa->vertex_size; + GLint coloridx; + float width = 1.0; /* Only support 1 pix lines now */ + GLfloat ooa; + GLint xx[3], yy[3]; /* 2 fractional bits for hardware */ + unsigned vbsiz = + (( + 1 + + (vertsize > 6 ? 2 : 0) + + (vertsize > 4 ? 2 : 0) + + 3 + + (mmesa->multitex ? 4 : 0) + ) * 4 + 4); + CARD32 *vb; + unsigned vbidx = 0; + + GLfloat hw, dx, dy, ix, iy; + GLfloat x0 = v0->v.x; + GLfloat y0 = v0->v.y; + GLfloat x1 = v1->v.x; + GLfloat y1 = v1->v.y; + +#if MACH64_CLIENT_STATE_EMITS + /* Enable for interleaved client-side state emits */ + LOCK_HARDWARE( mmesa ); + if ( mmesa->dirty ) { + mach64EmitHwStateLocked( mmesa ); + } + if ( mmesa->sarea->dirty ) { + mach64UploadHwStateLocked( mmesa ); + } + UNLOCK_HARDWARE( mmesa ); +#endif + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1: x: %.2f, y: %.2f, z: %.2f, w: %f\n", + v0->v.x, v0->v.y, v0->v.z, v0->v.w); + fprintf(stderr,"Vertex 2: x: %.2f, y: %.2f, z: %.2f, w: %f\n", + v1->v.x, v1->v.y, v1->v.z, v1->v.w); + } + + hw = 0.5F * width; + if (hw > 0.1F && hw < 0.5F) { + hw = 0.5F; + } + + /* adjust vertices depending on line direction */ + dx = v0->v.x - v1->v.x; + dy = v0->v.y - v1->v.y; + if (dx * dx > dy * dy) { + /* X-major line */ + ix = 0.0F; + iy = hw; + if (x1 < x0) { + x0 += 0.5F; + x1 += 0.5F; + } + y0 -= 0.5F; + y1 -= 0.5F; + } + else { + /* Y-major line */ + ix = hw; + iy = 0.0F; + if (y1 > y0) { + y0 -= 0.5F; + y1 -= 0.5F; + } + x0 += 0.5F; + x1 += 0.5F; + } + + xx[0] = (GLint)((x0 - ix) * 4); + yy[0] = (GLint)((y0 - iy) * 4); + + xx[1] = (GLint)((x1 - ix) * 4); + yy[1] = (GLint)((y1 - iy) * 4); + + xx[2] = (GLint)((x0 + ix) * 4); + yy[2] = (GLint)((y0 + iy) * 4); + + ooa = 0.25 * 0.25 * ((xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2])); + + if ( ooa * mmesa->backface_sign < 0 ) { + /* cull line */ + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) + fprintf(stderr,"Line culled\n"); + return; + } + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * 4 ); + + ooa = 1.0 / ooa; + + coloridx = (vertsize > 4) ? 4: 3; + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_1_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_1_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_1_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_1_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_1_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_1_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_1_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_1_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[0] << 16) | (yy[0] & 0xffff) ); /* MACH64_VERTEX_1_X_Y */ + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_2_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_2_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_2_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v1->ui[6] ); /* MACH64_VERTEX_2_S */ + LE32_OUT( &vb[vbidx++], v1->ui[7] ); /* MACH64_VERTEX_2_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v1->ui[3] ); /* MACH64_VERTEX_2_W */ + LE32_OUT( &vb[vbidx++], v1->ui[5] ); /* MACH64_VERTEX_2_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v1->v.z) << 15) ); /* MACH64_VERTEX_2_Z */ + vb[vbidx++] = v1->ui[coloridx]; /* MACH64_VERTEX_2_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[1] << 16) | (yy[1] & 0xffff) ); /* MACH64_VERTEX_2_X_Y */ + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_3_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_3_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_3_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_3_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_3_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_3_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_3_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_3_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_3_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[2] << 16) | (yy[2] & 0xffff) ); /* MACH64_VERTEX_3_X_Y */ + + LE32_OUT( &vb[vbidx++], ADRINDEX(MACH64_ONE_OVER_AREA_UC) ); + LE32_OUT( &vb[vbidx++], *(GLuint *)&ooa ); + + xx[0] = (GLint)((x1 + ix) * 4); + yy[0] = (GLint)((y1 + iy) * 4); + + ooa = 0.25 * 0.25 * ((xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2])); + ooa = 1.0 / ooa; + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_1_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_1_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v1->ui[6] ); /* MACH64_VERTEX_1_S */ + LE32_OUT( &vb[vbidx++], v1->ui[7] ); /* MACH64_VERTEX_1_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v1->ui[3] ); /* MACH64_VERTEX_1_W */ + LE32_OUT( &vb[vbidx++], v1->ui[5] ); /* MACH64_VERTEX_1_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v1->v.z) << 15) ); /* MACH64_VERTEX_1_Z */ + vb[vbidx++] = v1->ui[coloridx]; /* MACH64_VERTEX_1_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[0] << 16) | (yy[0] & 0xffff) ); /* MACH64_VERTEX_1_X_Y */ + + LE32_OUT( &vb[vbidx++], ADRINDEX(MACH64_ONE_OVER_AREA_UC) ); + LE32_OUT( &vb[vbidx++], *(GLuint *)&ooa ); + + assert(vbsiz == vbidx); +#endif +} + +static __inline void mach64_draw_point( mach64ContextPtr mmesa, + mach64VertexPtr v0 ) +{ +#if MACH64_NATIVE_VTXFMT + GLcontext *ctx = mmesa->glCtx; + const GLuint vertsize = mmesa->vertex_size; + GLint sz = (GLint)(mmesa->glCtx->Point._Size * 2.0); /* 2 fractional bits for hardware */ + GLfloat ooa; + GLuint *pxy; + GLuint xyold, xy; + const GLuint xyoffset = 9; + GLint x, y; + unsigned vbsiz = (vertsize + (vertsize > 7 ? 2 : 1)) * 4 + 2; + CARD32 *vb, *vbchk; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1:\n"); + mach64_print_vertex( ctx, v0 ); + } + + if( !sz ) + sz = 1; /* round to the nearest supported size */ + + pxy = &v0->ui[xyoffset]; + xyold = *pxy; + xy = LE32_IN( &xyold ); + x = (GLshort)( xy >> 16 ); + y = (GLshort)( xy & 0xffff ); + + ooa = 4.0 / (sz * sz); + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * sizeof(CARD32) ); + vbchk = vb + vbsiz; + + LE32_OUT( pxy, (( x - sz ) << 16) | (( y - sz ) & 0xffff) ); + COPY_VERTEX( vb, vertsize, v0, 1 ); + LE32_OUT( pxy, (( x + sz ) << 16) | (( y - sz ) & 0xffff) ); + COPY_VERTEX( vb, vertsize, v0, 2 ); + LE32_OUT( pxy, (( x - sz ) << 16) | (( y + sz ) & 0xffff) ); + COPY_VERTEX_OOA( vb, vertsize, v0, 3 ); + LE32_OUT( vb++, *(CARD32 *)&ooa ); + + ooa = -ooa; + + LE32_OUT( pxy, (( x + sz ) << 16) | (( y + sz ) & 0xffff) ); + COPY_VERTEX_OOA( vb, vertsize, v0, 1 ); + LE32_OUT( vb++, *(CARD32 *)&ooa ); + + *pxy = xyold; +#else /* !MACH64_NATIVE_VTXFMT */ + GLuint vertsize = mmesa->vertex_size; + GLint coloridx; + float sz = 1.0; /* Only support 1 pix points now */ + GLfloat ooa; + GLint xx[3], yy[3]; /* 2 fractional bits for hardware */ + unsigned vbsiz = + (( + 1 + + (vertsize > 6 ? 2 : 0) + + (vertsize > 4 ? 2 : 0) + + 3 + + (mmesa->multitex ? 4 : 0) + ) * 4 + 4); + CARD32 *vb; + unsigned vbidx = 0; + + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) { + fprintf(stderr, "%s:\n", __FUNCTION__); + fprintf(stderr,"Vertex 1: x: %.2f, y: %.2f, z: %.2f, w: %f\n", + v0->v.x, v0->v.y, v0->v.z, v0->v.w); + } + +#if MACH64_CLIENT_STATE_EMITS + /* Enable for interleaved client-side state emits */ + LOCK_HARDWARE( mmesa ); + if ( mmesa->dirty ) { + mach64EmitHwStateLocked( mmesa ); + } + if ( mmesa->sarea->dirty ) { + mach64UploadHwStateLocked( mmesa ); + } + UNLOCK_HARDWARE( mmesa ); +#endif + + xx[0] = (GLint)((v0->v.x - sz) * 4); + yy[0] = (GLint)((v0->v.y - sz) * 4); + + xx[1] = (GLint)((v0->v.x + sz) * 4); + yy[1] = (GLint)((v0->v.y - sz) * 4); + + xx[2] = (GLint)((v0->v.x - sz) * 4); + yy[2] = (GLint)((v0->v.y + sz) * 4); + + ooa = 0.25 * 0.25 * ((xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2])); + + if ( ooa * mmesa->backface_sign < 0 ) { + /* cull quad */ + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) + fprintf(stderr,"Point culled\n"); + return; + } + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * 4 ); + + ooa = 1.0 / ooa; + + coloridx = (vertsize > 4) ? 4: 3; + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_1_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_1_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_1_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_1_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_1_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_1_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_1_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_1_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[0] << 16) | (yy[0] & 0xffff) ); /* MACH64_VERTEX_1_X_Y */ + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_2_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_2_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_2_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_2_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_2_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_2_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_2_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_2_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_2_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[1] << 16) | (yy[1] & 0xffff) ); /* MACH64_VERTEX_2_X_Y */ + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_3_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_3_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_3_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_3_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_3_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_3_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_3_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_3_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_3_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[2] << 16) | (yy[2] & 0xffff) ); /* MACH64_VERTEX_3_X_Y */ + + LE32_OUT( &vb[vbidx++], ADRINDEX(MACH64_ONE_OVER_AREA_UC) ); + LE32_OUT( &vb[vbidx++], *(GLuint *)&ooa ); + + xx[0] = (GLint)((v0->v.x + sz) * 4); + yy[0] = (GLint)((v0->v.y + sz) * 4); + + ooa = 0.25 * 0.25 * ((xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2])); + ooa = 1.0 / ooa; + + /* setup for 3,5, or 7 sequential reg writes based on vertex format */ + switch (vertsize) { + case 6: + LE32_OUT( &vb[vbidx++], (4 << 16) | ADRINDEX(MACH64_VERTEX_1_W) ); + break; + case 4: + LE32_OUT( &vb[vbidx++], (2 << 16) | ADRINDEX(MACH64_VERTEX_1_Z) ); + break; + default: /* vertsize >= 8 */ + LE32_OUT( &vb[vbidx++], (6 << 16) | ADRINDEX(MACH64_VERTEX_1_S) ); + break; + } + if (vertsize > 6) { + LE32_OUT( &vb[vbidx++], v0->ui[6] ); /* MACH64_VERTEX_1_S */ + LE32_OUT( &vb[vbidx++], v0->ui[7] ); /* MACH64_VERTEX_1_T */ + } + if (vertsize > 4) { + LE32_OUT( &vb[vbidx++], v0->ui[3] ); /* MACH64_VERTEX_1_W */ + LE32_OUT( &vb[vbidx++], v0->ui[5] ); /* MACH64_VERTEX_1_SPEC_ARGB */ + } + LE32_OUT( &vb[vbidx++], ((GLint)(v0->v.z) << 15) ); /* MACH64_VERTEX_1_Z */ + vb[vbidx++] = v0->ui[coloridx]; /* MACH64_VERTEX_1_ARGB */ + LE32_OUT( &vb[vbidx++], (xx[0] << 16) | (yy[0] & 0xffff) ); /* MACH64_VERTEX_1_X_Y */ + + LE32_OUT( &vb[vbidx++], ADRINDEX(MACH64_ONE_OVER_AREA_UC) ); + LE32_OUT( &vb[vbidx++], *(GLuint *)&ooa ); + + assert(vbsiz == vbidx); +#endif +} + +/*********************************************************************** + * Macros for t_dd_tritmp.h to draw basic primitives * + ***********************************************************************/ + +#define TRI( a, b, c ) \ +do { \ + if (DO_FALLBACK) \ + mmesa->draw_tri( mmesa, a, b, c ); \ + else \ + mach64_draw_triangle( mmesa, a, b, c ); \ +} while (0) + +#define QUAD( a, b, c, d ) \ +do { \ + if (DO_FALLBACK) { \ + mmesa->draw_tri( mmesa, a, b, d ); \ + mmesa->draw_tri( mmesa, b, c, d ); \ + } else \ + mach64_draw_quad( mmesa, a, b, c, d ); \ +} while (0) + +#define LINE( v0, v1 ) \ +do { \ + if (DO_FALLBACK) \ + mmesa->draw_line( mmesa, v0, v1 ); \ + else \ + mach64_draw_line( mmesa, v0, v1 ); \ +} while (0) + +#define POINT( v0 ) \ +do { \ + if (DO_FALLBACK) \ + mmesa->draw_point( mmesa, v0 ); \ + else \ + mach64_draw_point( mmesa, v0 ); \ +} while (0) + + +/*********************************************************************** + * Build render functions from dd templates * + ***********************************************************************/ + +#define MACH64_OFFSET_BIT 0x01 +#define MACH64_TWOSIDE_BIT 0x02 +#define MACH64_UNFILLED_BIT 0x04 +#define MACH64_FALLBACK_BIT 0x08 +#define MACH64_MAX_TRIFUNC 0x10 + +static struct { + tnl_points_func points; + tnl_line_func line; + tnl_triangle_func triangle; + tnl_quad_func quad; +} rast_tab[MACH64_MAX_TRIFUNC]; + + +#define DO_FALLBACK (IND & MACH64_FALLBACK_BIT) +#define DO_OFFSET (IND & MACH64_OFFSET_BIT) +#define DO_UNFILLED (IND & MACH64_UNFILLED_BIT) +#define DO_TWOSIDE (IND & MACH64_TWOSIDE_BIT) +#define DO_FLAT 0 +#define DO_TRI 1 +#define DO_QUAD 1 +#define DO_LINE 1 +#define DO_POINTS 1 +#define DO_FULL_QUAD 1 + +#define HAVE_RGBA 1 +#define HAVE_SPEC 1 +#define HAVE_BACK_COLORS 0 +#define HAVE_HW_FLATSHADE 1 +#define VERTEX mach64Vertex +#define TAB rast_tab + +#if MACH64_NATIVE_VTXFMT + +/* #define DEPTH_SCALE 65536.0 */ +#define DEPTH_SCALE 1 +#define UNFILLED_TRI unfilled_tri +#define UNFILLED_QUAD unfilled_quad +#define VERT_X(_v) ((GLfloat)(GLshort)(LE32_IN( &(_v)->ui[xyoffset] ) & 0xffff) / 4.0) +#define VERT_Y(_v) ((GLfloat)(GLshort)(LE32_IN( &(_v)->ui[xyoffset] ) >> 16) / 4.0) +#define VERT_Z(_v) ((GLfloat) LE32_IN( &(_v)->ui[zoffset] )) +#define INSANE_VERTICES +#define VERT_SET_Z(_v,val) LE32_OUT( &(_v)->ui[zoffset], (GLuint)(val) ) +#define VERT_Z_ADD(_v,val) LE32_OUT( &(_v)->ui[zoffset], LE32_IN( &(_v)->ui[zoffset] ) + (GLuint)(val) ) +#define AREA_IS_CCW( a ) ((a) < 0) +#define GET_VERTEX(e) (mmesa->verts + ((e) * mmesa->vertex_size * sizeof(int))) + +#define MACH64_COLOR( dst, src ) \ +do { \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[0], src[2]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[1], src[1]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[2], src[0]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[3], src[3]); \ +} while (0) + +#define MACH64_SPEC( dst, src ) \ +do { \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[0], src[2]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[1], src[1]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[2], src[0]); \ +} while (0) + +#define VERT_SET_RGBA( v, c ) MACH64_COLOR( v->ub4[coloroffset], c ) +#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset] +#define VERT_SAVE_RGBA( idx ) color[idx] = v[idx]->ui[coloroffset] +#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = color[idx] + +#define VERT_SET_SPEC( v, c ) if (havespec) MACH64_SPEC( v->ub4[specoffset], c ) +#define VERT_COPY_SPEC( v0, v1 ) if (havespec) COPY_3V( v0->ub4[specoffset], v1->ub4[specoffset] ) +#define VERT_SAVE_SPEC( idx ) if (havespec) spec[idx] = v[idx]->ui[specoffset] +#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[specoffset] = spec[idx] + +#define LOCAL_VARS(n) \ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); \ + GLuint color[n], spec[n]; \ + GLuint vertex_size = mmesa->vertex_size; \ + const GLuint xyoffset = 9; \ + const GLuint coloroffset = 8; \ + const GLuint zoffset = 7; \ + const GLuint specoffset = 6; \ + GLboolean havespec = vertex_size >= 4 ? 1 : 0; \ + (void) color; (void) spec; (void) vertex_size; \ + (void) xyoffset; (void) coloroffset; (void) zoffset; \ + (void) specoffset; (void) havespec; + +#else + +#define DEPTH_SCALE 1.0 +#define UNFILLED_TRI unfilled_tri +#define UNFILLED_QUAD unfilled_quad +#define VERT_X(_v) _v->v.x +#define VERT_Y(_v) _v->v.y +#define VERT_Z(_v) _v->v.z +#define AREA_IS_CCW( a ) (a > 0) +#define GET_VERTEX(e) (mmesa->verts + ((e) * mmesa->vertex_size * sizeof(int))) + +#define MACH64_COLOR( dst, src ) \ +do { \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[0], src[2]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[1], src[1]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[2], src[0]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[3], src[3]); \ +} while (0) + +#define MACH64_SPEC( dst, src ) \ +do { \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[0], src[2]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[1], src[1]); \ + UNCLAMPED_FLOAT_TO_UBYTE(dst[2], src[0]); \ +} while (0) + +#define VERT_SET_RGBA( v, c ) MACH64_COLOR( v->ub4[coloroffset], c ) +#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset] +#define VERT_SAVE_RGBA( idx ) color[idx] = v[idx]->ui[coloroffset] +#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = color[idx] + +#define VERT_SET_SPEC( v, c ) if (havespec) MACH64_SPEC( v->ub4[5], c ) +#define VERT_COPY_SPEC( v0, v1 ) if (havespec) COPY_3V(v0->ub4[5], v1->ub4[5]) +#define VERT_SAVE_SPEC( idx ) if (havespec) spec[idx] = v[idx]->ui[5] +#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[5] = spec[idx] + +#define LOCAL_VARS(n) \ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); \ + GLuint color[n], spec[n]; \ + GLuint coloroffset = (mmesa->vertex_size == 4 ? 3 : 4); \ + GLboolean havespec = (mmesa->vertex_size == 4 ? 0 : 1); \ + (void) color; (void) spec; (void) coloroffset; (void) havespec; + +#endif + +/*********************************************************************** + * Helpers for rendering unfilled primitives * + ***********************************************************************/ + +#define RASTERIZE(x) if (mmesa->hw_primitive != hw_prim[x]) \ + mach64RasterPrimitive( ctx, hw_prim[x] ) +#define RENDER_PRIMITIVE mmesa->render_primitive +#define IND MACH64_FALLBACK_BIT +#define TAG(x) x +#include "tnl_dd/t_dd_unfilled.h" +#undef IND + + +/*********************************************************************** + * Generate GL render functions * + ***********************************************************************/ + + +#define IND (0) +#define TAG(x) x +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_OFFSET_BIT) +#define TAG(x) x##_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT) +#define TAG(x) x##_twoside +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT|MACH64_OFFSET_BIT) +#define TAG(x) x##_twoside_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_UNFILLED_BIT) +#define TAG(x) x##_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_OFFSET_BIT|MACH64_UNFILLED_BIT) +#define TAG(x) x##_offset_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT|MACH64_UNFILLED_BIT) +#define TAG(x) x##_twoside_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT|MACH64_OFFSET_BIT|MACH64_UNFILLED_BIT) +#define TAG(x) x##_twoside_offset_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_FALLBACK_BIT) +#define TAG(x) x##_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_OFFSET_BIT|MACH64_FALLBACK_BIT) +#define TAG(x) x##_offset_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT|MACH64_FALLBACK_BIT) +#define TAG(x) x##_twoside_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT|MACH64_OFFSET_BIT|MACH64_FALLBACK_BIT) +#define TAG(x) x##_twoside_offset_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_UNFILLED_BIT|MACH64_FALLBACK_BIT) +#define TAG(x) x##_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_OFFSET_BIT|MACH64_UNFILLED_BIT|MACH64_FALLBACK_BIT) +#define TAG(x) x##_offset_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT|MACH64_UNFILLED_BIT|MACH64_FALLBACK_BIT) +#define TAG(x) x##_twoside_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (MACH64_TWOSIDE_BIT|MACH64_OFFSET_BIT|MACH64_UNFILLED_BIT| \ + MACH64_FALLBACK_BIT) +#define TAG(x) x##_twoside_offset_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + + +static void init_rast_tab( void ) +{ + init(); + init_offset(); + init_twoside(); + init_twoside_offset(); + init_unfilled(); + init_offset_unfilled(); + init_twoside_unfilled(); + init_twoside_offset_unfilled(); + init_fallback(); + init_offset_fallback(); + init_twoside_fallback(); + init_twoside_offset_fallback(); + init_unfilled_fallback(); + init_offset_unfilled_fallback(); + init_twoside_unfilled_fallback(); + init_twoside_offset_unfilled_fallback(); +} + + +/*********************************************************************** + * Rasterization fallback helpers * + ***********************************************************************/ + + +/* This code is hit only when a mix of accelerated and unaccelerated + * primitives are being drawn, and only for the unaccelerated + * primitives. + */ +static void +mach64_fallback_tri( mach64ContextPtr mmesa, + mach64Vertex *v0, + mach64Vertex *v1, + mach64Vertex *v2 ) +{ + GLcontext *ctx = mmesa->glCtx; + SWvertex v[3]; + mach64_translate_vertex( ctx, v0, &v[0] ); + mach64_translate_vertex( ctx, v1, &v[1] ); + mach64_translate_vertex( ctx, v2, &v[2] ); + _swrast_Triangle( ctx, &v[0], &v[1], &v[2] ); +} + + +static void +mach64_fallback_line( mach64ContextPtr mmesa, + mach64Vertex *v0, + mach64Vertex *v1 ) +{ + GLcontext *ctx = mmesa->glCtx; + SWvertex v[2]; + mach64_translate_vertex( ctx, v0, &v[0] ); + mach64_translate_vertex( ctx, v1, &v[1] ); + _swrast_Line( ctx, &v[0], &v[1] ); +} + + +static void +mach64_fallback_point( mach64ContextPtr mmesa, + mach64Vertex *v0 ) +{ + GLcontext *ctx = mmesa->glCtx; + SWvertex v[1]; + mach64_translate_vertex( ctx, v0, &v[0] ); + _swrast_Point( ctx, &v[0] ); +} + + + +/**********************************************************************/ +/* Render unclipped begin/end objects */ +/**********************************************************************/ + +#define VERT(x) (mach64Vertex *)(mach64verts + ((x) * vertsize * sizeof(int))) +#define RENDER_POINTS( start, count ) \ + for ( ; start < count ; start++) \ + mach64_draw_point( mmesa, VERT(start) ) +#define RENDER_LINE( v0, v1 ) \ + mach64_draw_line( mmesa, VERT(v0), VERT(v1) ) +#define RENDER_TRI( v0, v1, v2 ) \ + mach64_draw_triangle( mmesa, VERT(v0), VERT(v1), VERT(v2) ) +#define RENDER_QUAD( v0, v1, v2, v3 ) \ + mach64_draw_quad( mmesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) ) +#define INIT(x) do { \ + if (0) fprintf(stderr, "%s\n", __FUNCTION__); \ + mach64RenderPrimitive( ctx, x ); \ +} while (0) +#undef LOCAL_VARS +#define LOCAL_VARS \ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); \ + const GLuint vertsize = mmesa->vertex_size; \ + const char *mach64verts = (char *)mmesa->verts; \ + const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \ + (void) elt; +#define RESET_STIPPLE +#define RESET_OCCLUSION +#define PRESERVE_VB_DEFS +#define ELT(x) (x) +#define TAG(x) mach64_##x##_verts +#include "tnl/t_vb_rendertmp.h" +#undef ELT +#undef TAG +#define TAG(x) mach64_##x##_elts +#define ELT(x) elt[x] +#include "tnl/t_vb_rendertmp.h" + + +/**********************************************************************/ +/* Render clipped primitives */ +/**********************************************************************/ + +static void mach64RenderClippedPoly( GLcontext *ctx, const GLuint *elts, + GLuint n ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLuint prim = mmesa->render_primitive; + + /* Render the new vertices as an unclipped polygon. + */ + { + GLuint *tmp = VB->Elts; + VB->Elts = (GLuint *)elts; + tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, PRIM_BEGIN|PRIM_END ); + VB->Elts = tmp; + } + + /* Restore the render primitive + */ + if (prim != GL_POLYGON) + tnl->Driver.Render.PrimitiveNotify( ctx, prim ); + +} + +static void mach64RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + tnl->Driver.Render.Line( ctx, ii, jj ); +} + +#if MACH64_NATIVE_VTXFMT +static void mach64FastRenderClippedPoly( GLcontext *ctx, const GLuint *elts, + GLuint n ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); + const GLuint vertsize = mmesa->vertex_size; + GLint a; + union { + GLfloat f; + CARD32 u; + } ooa; + GLuint xy; + const GLuint xyoffset = 9; + GLint xx[3], yy[3]; /* 2 fractional bits for hardware */ + unsigned vbsiz = (vertsize + (vertsize > 7 ? 2 : 1)) * n + (n-2); + CARD32 *vb, *vbchk; + GLubyte *mach64verts = (GLubyte *)mmesa->verts; + mach64VertexPtr v0, v1, v2; + int i; + + v0 = (mach64VertexPtr)VERT(elts[1]); + v1 = (mach64VertexPtr)VERT(elts[2]); + v2 = (mach64VertexPtr)VERT(elts[0]); + + xy = LE32_IN( &v0->ui[xyoffset] ); + xx[0] = (GLshort)( xy >> 16 ); + yy[0] = (GLshort)( xy & 0xffff ); + + xy = LE32_IN( &v1->ui[xyoffset] ); + xx[1] = (GLshort)( xy >> 16 ); + yy[1] = (GLshort)( xy & 0xffff ); + + xy = LE32_IN( &v2->ui[xyoffset] ); + xx[2] = (GLshort)( xy >> 16 ); + yy[2] = (GLshort)( xy & 0xffff ); + + a = (xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2]); + + if ( (mmesa->backface_sign && + ((a < 0 && !signbit( mmesa->backface_sign )) || + (a > 0 && signbit( mmesa->backface_sign )))) ) { + /* cull polygon */ + if ( MACH64_DEBUG & DEBUG_VERBOSE_PRIMS ) + fprintf(stderr,"Polygon culled\n"); + return; + } + + ooa.f = 16.0 / a; + + vb = (CARD32 *)mach64AllocDmaLow( mmesa, vbsiz * sizeof(CARD32) ); + vbchk = vb + vbsiz; + + COPY_VERTEX( vb, vertsize, v0, 1 ); + COPY_VERTEX( vb, vertsize, v1, 2 ); + COPY_VERTEX_OOA( vb, vertsize, v2, 3 ); + LE32_OUT( vb++, ooa.u ); + + i = 3; + while (1) { + if (i >= n) + break; + v0 = (mach64VertexPtr)VERT(elts[i]); + i++; + + xy = LE32_IN( &v0->ui[xyoffset] ); + xx[0] = (GLshort)( xy >> 16 ); + yy[0] = (GLshort)( xy & 0xffff ); + + a = (xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2]); + ooa.f = 16.0 / a; + + COPY_VERTEX_OOA( vb, vertsize, v0, 1 ); + LE32_OUT( vb++, ooa.u ); + + if (i >= n) + break; + v1 = (mach64VertexPtr)VERT(elts[i]); + i++; + + xy = LE32_IN( &v1->ui[xyoffset] ); + xx[1] = (GLshort)( xy >> 16 ); + yy[1] = (GLshort)( xy & 0xffff ); + + a = (xx[0] - xx[2]) * (yy[1] - yy[2]) - + (yy[0] - yy[2]) * (xx[1] - xx[2]); + ooa.f = 16.0 / a; + + COPY_VERTEX_OOA( vb, vertsize, v1, 2 ); + LE32_OUT( vb++, ooa.u ); + } + + assert( vb == vbchk ); +} +#else +static void mach64FastRenderClippedPoly( GLcontext *ctx, const GLuint *elts, + GLuint n ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); + const GLuint vertsize = mmesa->vertex_size; + GLubyte *mach64verts = (GLubyte *)mmesa->verts; + const GLuint *start = (const GLuint *)VERT(elts[0]); + int i; + + for (i = 2 ; i < n ; i++) { + mach64_draw_triangle( mmesa, + VERT(elts[i-1]), + VERT(elts[i]), + (mach64VertexPtr) start + ); + } +} +#endif /* MACH64_NATIVE_VTXFMT */ + +/**********************************************************************/ +/* Choose render functions */ +/**********************************************************************/ + +#define _MACH64_NEW_RENDER_STATE (_DD_NEW_POINT_SMOOTH | \ + _DD_NEW_LINE_SMOOTH | \ + _DD_NEW_LINE_STIPPLE | \ + _DD_NEW_TRI_SMOOTH | \ + _DD_NEW_TRI_STIPPLE | \ + _NEW_POLYGONSTIPPLE | \ + _DD_NEW_TRI_UNFILLED | \ + _DD_NEW_TRI_LIGHT_TWOSIDE | \ + _DD_NEW_TRI_OFFSET) \ + +#define POINT_FALLBACK (DD_POINT_SMOOTH) +#define LINE_FALLBACK (DD_LINE_SMOOTH|DD_LINE_STIPPLE) +#define TRI_FALLBACK (DD_TRI_SMOOTH|DD_TRI_STIPPLE) +#define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK) +#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED) + + +static void mach64ChooseRenderState(GLcontext *ctx) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint flags = ctx->_TriangleCaps; + GLuint index = 0; + + if (flags & (ANY_RASTER_FLAGS|ANY_FALLBACK_FLAGS)) { + mmesa->draw_point = mach64_draw_point; + mmesa->draw_line = mach64_draw_line; + mmesa->draw_tri = mach64_draw_triangle; + + if (flags & ANY_RASTER_FLAGS) { + if (flags & DD_TRI_LIGHT_TWOSIDE) index |= MACH64_TWOSIDE_BIT; + if (flags & DD_TRI_OFFSET) index |= MACH64_OFFSET_BIT; + if (flags & DD_TRI_UNFILLED) index |= MACH64_UNFILLED_BIT; + } + + /* Hook in fallbacks for specific primitives. + */ + if (flags & (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)) { + if (flags & POINT_FALLBACK) mmesa->draw_point = mach64_fallback_point; + if (flags & LINE_FALLBACK) mmesa->draw_line = mach64_fallback_line; + if (flags & TRI_FALLBACK) mmesa->draw_tri = mach64_fallback_tri; + index |= MACH64_FALLBACK_BIT; + } + } + + if (index != mmesa->RenderIndex) { + TNLcontext *tnl = TNL_CONTEXT(ctx); + tnl->Driver.Render.Points = rast_tab[index].points; + tnl->Driver.Render.Line = rast_tab[index].line; + tnl->Driver.Render.Triangle = rast_tab[index].triangle; + tnl->Driver.Render.Quad = rast_tab[index].quad; + + if (index == 0) { + tnl->Driver.Render.PrimTabVerts = mach64_render_tab_verts; + tnl->Driver.Render.PrimTabElts = mach64_render_tab_elts; + tnl->Driver.Render.ClippedLine = rast_tab[index].line; + tnl->Driver.Render.ClippedPolygon = mach64FastRenderClippedPoly; + } else { + tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; + tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; + tnl->Driver.Render.ClippedLine = mach64RenderClippedLine; + tnl->Driver.Render.ClippedPolygon = mach64RenderClippedPoly; + } + + mmesa->RenderIndex = index; + } +} + +/**********************************************************************/ +/* Validate state at pipeline start */ +/**********************************************************************/ + +static void mach64RunPipeline( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + if (mmesa->new_state) + mach64DDUpdateHWState( ctx ); + + if (!mmesa->Fallback && mmesa->NewGLState) { + if (mmesa->NewGLState & _MACH64_NEW_VERTEX_STATE) + mach64ChooseVertexState( ctx ); + + if (mmesa->NewGLState & _MACH64_NEW_RENDER_STATE) + mach64ChooseRenderState( ctx ); + + mmesa->NewGLState = 0; + } + + _tnl_run_pipeline( ctx ); +} + +/**********************************************************************/ +/* High level hooks for t_vb_render.c */ +/**********************************************************************/ + +/* 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. + */ + +static void mach64RasterPrimitive( GLcontext *ctx, GLuint hwprim ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + + mmesa->new_state |= MACH64_NEW_CONTEXT; + mmesa->dirty |= MACH64_UPLOAD_CONTEXT; + + if (mmesa->hw_primitive != hwprim) { + FLUSH_BATCH( mmesa ); + mmesa->hw_primitive = hwprim; + } +} + +static void mach64RenderPrimitive( GLcontext *ctx, GLenum prim ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint hw = hw_prim[prim]; + + mmesa->render_primitive = prim; + + if (prim >= GL_TRIANGLES && (ctx->_TriangleCaps & DD_TRI_UNFILLED)) + return; + + mach64RasterPrimitive( ctx, hw ); +} + + +static void mach64RenderStart( GLcontext *ctx ) +{ + /* Check for projective texturing. Make sure all texcoord + * pointers point to something. (fix in mesa?) + */ + mach64CheckTexSizes( ctx ); +} + +static void mach64RenderFinish( GLcontext *ctx ) +{ + if (MACH64_CONTEXT(ctx)->RenderIndex & MACH64_FALLBACK_BIT) + _swrast_flush( ctx ); +} + + +/**********************************************************************/ +/* Transition to/from hardware rasterization. */ +/**********************************************************************/ + +static const char * const fallbackStrings[] = { + "Texture mode", + "glDrawBuffer(GL_FRONT_AND_BACK)", + "glReadBuffer", + "glEnable(GL_STENCIL) without hw stencil buffer", + "glRenderMode(selection or feedback)", + "glLogicOp (mode != GL_COPY)", + "GL_SEPARATE_SPECULAR_COLOR", + "glBlendEquation (mode != ADD)", + "glBlendFunc", + "Rasterization disable", +}; + + +static const char *getFallbackString(GLuint bit) +{ + int i = 0; + while (bit > 1) { + i++; + bit >>= 1; + } + return fallbackStrings[i]; +} + +void mach64Fallback( GLcontext *ctx, GLuint bit, GLboolean mode ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint oldfallback = mmesa->Fallback; + + if (mode) { + mmesa->Fallback |= bit; + if (oldfallback == 0) { + FLUSH_BATCH( mmesa ); + _swsetup_Wakeup( ctx ); + mmesa->RenderIndex = ~0; + if (MACH64_DEBUG & DEBUG_VERBOSE_FALLBACK) { + fprintf(stderr, "Mach64 begin rasterization fallback: 0x%x %s\n", + bit, getFallbackString(bit)); + } + } + } + else { + mmesa->Fallback &= ~bit; + if (oldfallback == bit) { + _swrast_flush( ctx ); + tnl->Driver.Render.Start = mach64RenderStart; + tnl->Driver.Render.PrimitiveNotify = mach64RenderPrimitive; + tnl->Driver.Render.Finish = mach64RenderFinish; + tnl->Driver.Render.BuildVertices = mach64BuildVertices; + mmesa->NewGLState |= (_MACH64_NEW_RENDER_STATE| + _MACH64_NEW_VERTEX_STATE); + if (MACH64_DEBUG & DEBUG_VERBOSE_FALLBACK) { + fprintf(stderr, "Mach64 end rasterization fallback: 0x%x %s\n", + bit, getFallbackString(bit)); + } + } + } +} + +/**********************************************************************/ +/* Initialization. */ +/**********************************************************************/ + +void mach64InitTriFuncs( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + static int firsttime = 1; + + if (firsttime) { + init_rast_tab(); + firsttime = 0; + } + + tnl->Driver.RunPipeline = mach64RunPipeline; + tnl->Driver.Render.Start = mach64RenderStart; + tnl->Driver.Render.Finish = mach64RenderFinish; + tnl->Driver.Render.PrimitiveNotify = mach64RenderPrimitive; + tnl->Driver.Render.ResetLineStipple = _swrast_ResetLineStipple; + tnl->Driver.Render.BuildVertices = mach64BuildVertices; +} diff --git a/src/mach64_tris.h b/src/mach64_tris.h new file mode 100644 index 0000000..2087032 --- /dev/null +++ b/src/mach64_tris.h @@ -0,0 +1,43 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#ifndef __MACH64_TRIS_H__ +#define __MACH64_TRIS_H__ + +#include "mtypes.h" + +extern void mach64InitTriFuncs( GLcontext *ctx ); + + +extern void mach64Fallback( GLcontext *ctx, GLuint bit, GLboolean mode ); +#define FALLBACK( mmesa, bit, mode ) mach64Fallback( mmesa->glCtx, bit, mode ) + + +#endif /* __MACH64_TRIS_H__ */ diff --git a/src/mach64_vb.c b/src/mach64_vb.c new file mode 100644 index 0000000..83a5f73 --- /dev/null +++ b/src/mach64_vb.c @@ -0,0 +1,642 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#include "glheader.h" +#include "mtypes.h" +#include "imports.h" +#include "macros.h" +#include "colormac.h" + +#include "swrast_setup/swrast_setup.h" +#include "tnl/t_context.h" + +#include "mach64_context.h" +#include "mach64_vb.h" +#include "mach64_ioctl.h" +#include "mach64_tris.h" +#include "mach64_state.h" + + +#define MACH64_TEX1_BIT 0x1 +#define MACH64_TEX0_BIT 0x2 +#define MACH64_RGBA_BIT 0x4 +#define MACH64_SPEC_BIT 0x8 +#define MACH64_FOG_BIT 0x10 +#define MACH64_XYZW_BIT 0x20 +#define MACH64_PTEX_BIT 0x40 +#define MACH64_MAX_SETUP 0x80 + +static struct { + void (*emit)( GLcontext *, GLuint, GLuint, void *, GLuint ); + tnl_interp_func interp; + tnl_copy_pv_func copy_pv; + GLboolean (*check_tex_sizes)( GLcontext *ctx ); + GLuint vertex_size; + GLuint vertex_format; +} setup_tab[MACH64_MAX_SETUP]; + +#define TINY_VERTEX_FORMAT 1 +#define NOTEX_VERTEX_FORMAT 2 +#define TEX0_VERTEX_FORMAT 3 +#define TEX1_VERTEX_FORMAT 4 +#define PROJ_TEX1_VERTEX_FORMAT 0 +#define TEX2_VERTEX_FORMAT 0 +#define TEX3_VERTEX_FORMAT 0 +#define PROJ_TEX3_VERTEX_FORMAT 0 + +#define DO_XYZW (IND & MACH64_XYZW_BIT) +#define DO_RGBA (IND & MACH64_RGBA_BIT) +#define DO_SPEC (IND & MACH64_SPEC_BIT) +#define DO_FOG (IND & MACH64_FOG_BIT) +#define DO_TEX0 (IND & MACH64_TEX0_BIT) +#define DO_TEX1 (IND & MACH64_TEX1_BIT) +#define DO_TEX2 0 +#define DO_TEX3 0 +#define DO_PTEX (IND & MACH64_PTEX_BIT) + +#define VERTEX mach64Vertex +#define LOCALVARS mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); +#define GET_VIEWPORT_MAT() mmesa->hw_viewport +#define GET_TEXSOURCE(n) mmesa->tmu_source[n] +#define GET_VERTEX_FORMAT() mmesa->vertex_format +#define GET_VERTEX_STORE() mmesa->verts +#define GET_VERTEX_SIZE() mmesa->vertex_size * sizeof(GLuint) + +#define HAVE_HW_VIEWPORT 0 +#define HAVE_HW_DIVIDE 0 +#define HAVE_RGBA_COLOR 0 +#define HAVE_TINY_VERTICES 1 +#define HAVE_NOTEX_VERTICES 1 +#define HAVE_TEX0_VERTICES 1 +#define HAVE_TEX1_VERTICES 1 +#define HAVE_TEX2_VERTICES 0 +#define HAVE_TEX3_VERTICES 0 +#define HAVE_PTEX_VERTICES 0 + +#define UNVIEWPORT_VARS \ + const GLfloat dx = - (GLfloat)mmesa->drawX - SUBPIXEL_X; \ + const GLfloat dy = (mmesa->driDrawable->h + \ + (GLfloat)mmesa->drawY + SUBPIXEL_Y); \ + const GLfloat sz = 1.0 / mmesa->depth_scale + +#if MACH64_NATIVE_VTXFMT + +#define UNVIEWPORT_X(x) ((GLfloat)(x) / 4.0) + dx +#define UNVIEWPORT_Y(y) - ((GLfloat)(y) / 4.0) + dy +#define UNVIEWPORT_Z(z) (GLfloat)((z) >> 15) * sz + +#else + +#define UNVIEWPORT_X(x) x + dx; +#define UNVIEWPORT_Y(y) - y + dy; +#define UNVIEWPORT_Z(z) z * sz; + +#endif + +#define PTEX_FALLBACK() FALLBACK(MACH64_CONTEXT(ctx), MACH64_FALLBACK_TEXTURE, 1) + +#define IMPORT_FLOAT_COLORS mach64_import_float_colors +#define IMPORT_FLOAT_SPEC_COLORS mach64_import_float_spec_colors + +#define INTERP_VERTEX setup_tab[mmesa->SetupIndex].interp +#define COPY_PV_VERTEX setup_tab[mmesa->SetupIndex].copy_pv + +/*********************************************************************** + * Generate pv-copying and translation functions * + ***********************************************************************/ + +#if MACH64_NATIVE_VTXFMT + +#define TAG(x) mach64_##x +#include "mach64_native_vb.c" + +#else + +#define TAG(x) mach64_##x +#include "tnl_dd/t_dd_vb.c" + +#endif + +/*********************************************************************** + * Generate vertex emit and interp functions * + ***********************************************************************/ + + +#if MACH64_NATIVE_VTXFMT + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT) +#define TAG(x) x##_wg +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_wgs +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_wgt0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_wgt0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_TEX0_BIT|MACH64_PTEX_BIT) +#define TAG(x) x##_wgpt0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_wgst0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|\ + MACH64_TEX1_BIT) +#define TAG(x) x##_wgst0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|\ + MACH64_PTEX_BIT) +#define TAG(x) x##_wgspt0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT) +#define TAG(x) x##_wgf +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_wgfs +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_wgft0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT|\ + MACH64_TEX1_BIT) +#define TAG(x) x##_wgft0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT|\ + MACH64_PTEX_BIT) +#define TAG(x) x##_wgfpt0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|\ + MACH64_TEX0_BIT) +#define TAG(x) x##_wgfst0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|\ + MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_wgfst0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|\ + MACH64_TEX0_BIT|MACH64_PTEX_BIT) +#define TAG(x) x##_wgfspt0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_TEX0_BIT) +#define TAG(x) x##_t0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_t0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_FOG_BIT) +#define TAG(x) x##_f +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_FOG_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_ft0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_FOG_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_ft0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT) +#define TAG(x) x##_g +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_gs +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gt0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_gt0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gst0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_gst0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT) +#define TAG(x) x##_gf +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_gfs +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gft0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_gft0t1 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gfst0 +#include "mach64_native_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|\ + MACH64_TEX1_BIT) +#define TAG(x) x##_gfst0t1 +#include "mach64_native_vbtmp.h" + +#else + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT) +#define TAG(x) x##_wg +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_wgs +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_wgt0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_wgt0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_TEX0_BIT|MACH64_PTEX_BIT) +#define TAG(x) x##_wgpt0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_wgst0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|\ + MACH64_TEX1_BIT) +#define TAG(x) x##_wgst0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|\ + MACH64_PTEX_BIT) +#define TAG(x) x##_wgspt0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT) +#define TAG(x) x##_wgf +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_wgfs +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_wgft0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT|\ + MACH64_TEX1_BIT) +#define TAG(x) x##_wgft0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT|\ + MACH64_PTEX_BIT) +#define TAG(x) x##_wgfpt0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|\ + MACH64_TEX0_BIT) +#define TAG(x) x##_wgfst0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|\ + MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_wgfst0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_XYZW_BIT|MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|\ + MACH64_TEX0_BIT|MACH64_PTEX_BIT) +#define TAG(x) x##_wgfspt0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_TEX0_BIT) +#define TAG(x) x##_t0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_t0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_FOG_BIT) +#define TAG(x) x##_f +#include "mach64_vbtmp.h" + +#define IND (MACH64_FOG_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_ft0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_FOG_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_ft0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT) +#define TAG(x) x##_g +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_gs +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gt0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_gt0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gst0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_gst0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT) +#define TAG(x) x##_gf +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT) +#define TAG(x) x##_gfs +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gft0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_TEX0_BIT|MACH64_TEX1_BIT) +#define TAG(x) x##_gft0t1 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT) +#define TAG(x) x##_gfst0 +#include "mach64_vbtmp.h" + +#define IND (MACH64_RGBA_BIT|MACH64_FOG_BIT|MACH64_SPEC_BIT|MACH64_TEX0_BIT|\ + MACH64_TEX1_BIT) +#define TAG(x) x##_gfst0t1 +#include "mach64_vbtmp.h" + +#endif + +static void init_setup_tab( void ) +{ + init_wg(); + init_wgs(); + init_wgt0(); + init_wgt0t1(); + init_wgpt0(); + init_wgst0(); + init_wgst0t1(); + init_wgspt0(); + init_wgf(); + init_wgfs(); + init_wgft0(); + init_wgft0t1(); + init_wgfpt0(); + init_wgfst0(); + init_wgfst0t1(); + init_wgfspt0(); + init_t0(); + init_t0t1(); + init_f(); + init_ft0(); + init_ft0t1(); + init_g(); + init_gs(); + init_gt0(); + init_gt0t1(); + init_gst0(); + init_gst0t1(); + init_gf(); + init_gfs(); + init_gft0(); + init_gft0t1(); + init_gfst0(); + init_gfst0t1(); +} + + + +void mach64PrintSetupFlags( char *msg, GLuint flags ) +{ + fprintf( stderr, "%s: %d %s%s%s%s%s%s%s\n", + msg, + (int)flags, + (flags & MACH64_XYZW_BIT) ? " xyzw," : "", + (flags & MACH64_RGBA_BIT) ? " rgba," : "", + (flags & MACH64_SPEC_BIT) ? " spec," : "", + (flags & MACH64_FOG_BIT) ? " fog," : "", + (flags & MACH64_TEX0_BIT) ? " tex-0," : "", + (flags & MACH64_TEX1_BIT) ? " tex-1," : "", + (flags & MACH64_PTEX_BIT) ? " ptex," : ""); +} + + + + +void mach64CheckTexSizes( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); + + if (!setup_tab[mmesa->SetupIndex].check_tex_sizes(ctx)) { + TNLcontext *tnl = TNL_CONTEXT(ctx); + + /* Invalidate stored verts + */ + mmesa->SetupNewInputs = ~0; + mmesa->SetupIndex |= MACH64_PTEX_BIT; + + if (!mmesa->Fallback && + !(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) { + tnl->Driver.Render.Interp = setup_tab[mmesa->SetupIndex].interp; + tnl->Driver.Render.CopyPV = setup_tab[mmesa->SetupIndex].copy_pv; + } + } +} + +void mach64BuildVertices( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint newinputs ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); + GLuint stride = mmesa->vertex_size * sizeof(int); + GLubyte *v = ((GLubyte *)mmesa->verts + (start * stride)); + + newinputs |= mmesa->SetupNewInputs; + mmesa->SetupNewInputs = 0; + + if (!newinputs) + return; + + if (newinputs & VERT_BIT_POS) { + setup_tab[mmesa->SetupIndex].emit( ctx, start, count, v, stride ); + } else { + GLuint ind = 0; + + if (newinputs & VERT_BIT_COLOR0) + ind |= MACH64_RGBA_BIT; + + if (newinputs & VERT_BIT_COLOR1) + ind |= MACH64_SPEC_BIT; + + if (newinputs & VERT_BIT_TEX0) + ind |= MACH64_TEX0_BIT; + + if (newinputs & VERT_BIT_TEX1) + ind |= MACH64_TEX1_BIT; + + if (newinputs & VERT_BIT_FOG) + ind |= MACH64_FOG_BIT; + + if (mmesa->SetupIndex & MACH64_PTEX_BIT) + ind = ~0; + + ind &= mmesa->SetupIndex; + + if (ind) { + setup_tab[ind].emit( ctx, start, count, v, stride ); + } + } +} + +void mach64ChooseVertexState( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + mach64ContextPtr mmesa = MACH64_CONTEXT( ctx ); + GLuint ind = MACH64_XYZW_BIT|MACH64_RGBA_BIT; + + if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) + ind |= MACH64_SPEC_BIT; + + if (ctx->Fog.Enabled) + ind |= MACH64_FOG_BIT; + + if (ctx->Texture._EnabledUnits) { + ind |= MACH64_TEX0_BIT; + if (ctx->Texture.Unit[0]._ReallyEnabled && + ctx->Texture.Unit[1]._ReallyEnabled) { + ind |= MACH64_TEX1_BIT; + } + } + + mmesa->SetupIndex = ind; + + if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) { + tnl->Driver.Render.Interp = mach64_interp_extras; + tnl->Driver.Render.CopyPV = mach64_copy_pv_extras; + } else { + tnl->Driver.Render.Interp = setup_tab[ind].interp; + tnl->Driver.Render.CopyPV = setup_tab[ind].copy_pv; + } + +#if 0 + if (MACH64_DEBUG & DEBUG_VERBOSE_MSG) { + mach64PrintSetupFlags( __FUNCTION__, ind ); + } +#endif + + if (setup_tab[ind].vertex_format != mmesa->vertex_format) { + FLUSH_BATCH(mmesa); + mmesa->vertex_format = setup_tab[ind].vertex_format; + mmesa->vertex_size = setup_tab[ind].vertex_size; + } +} + + +#if 0 +void mach64_emit_contiguous_verts( GLcontext *ctx, + GLuint start, + GLuint count ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint vertex_size = mmesa->vertex_size * 4; + GLuint *dest = mach64AllocDmaLow( mmesa, (count-start) * vertex_size); + setup_tab[mmesa->SetupIndex].emit( ctx, start, count, dest, vertex_size ); +} +#endif + + +void mach64InitVB( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + GLuint size = TNL_CONTEXT(ctx)->vb.Size; + + mmesa->verts = (GLubyte *)ALIGN_MALLOC(size * 4 * 16, 32); + + { + static int firsttime = 1; + if (firsttime) { + init_setup_tab(); + firsttime = 0; + } + } +} + + +void mach64FreeVB( GLcontext *ctx ) +{ + mach64ContextPtr mmesa = MACH64_CONTEXT(ctx); + if (mmesa->verts) { + ALIGN_FREE(mmesa->verts); + mmesa->verts = 0; + } +} diff --git a/src/mach64_vb.h b/src/mach64_vb.h new file mode 100644 index 0000000..bcc4759 --- /dev/null +++ b/src/mach64_vb.h @@ -0,0 +1,77 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + +#ifndef __MACH64_VB_H__ +#define __MACH64_VB_H__ + +#include "mtypes.h" +#include "swrast/swrast.h" +#include "mach64_context.h" + +/* premultiply texture coordinates by homogenous coordinate */ +#define MACH64_PREMULT_TEXCOORDS + +#define _MACH64_NEW_VERTEX_STATE (_DD_NEW_SEPARATE_SPECULAR | \ + _DD_NEW_TRI_LIGHT_TWOSIDE | \ + _DD_NEW_TRI_UNFILLED | \ + _NEW_TEXTURE | \ + _NEW_FOG) + + +extern void mach64CheckTexSizes( GLcontext *ctx ); +extern void mach64ChooseVertexState( GLcontext *ctx ); + +extern void mach64BuildVertices( GLcontext *ctx, GLuint start, GLuint count, + GLuint newinputs ); + +extern void mach64PrintSetupFlags(char *msg, GLuint flags ); + +extern void mach64InitVB( GLcontext *ctx ); +extern void mach64FreeVB( GLcontext *ctx ); + +#if 0 +extern void mach64_emit_contiguous_verts( GLcontext *ctx, + GLuint start, + GLuint count ); + +extern void mach64_emit_indexed_verts( GLcontext *ctx, + GLuint start, + GLuint count ); +#endif + +extern void mach64_translate_vertex( GLcontext *ctx, + const mach64Vertex *src, + SWvertex *dst ); + +extern void mach64_print_vertex( GLcontext *ctx, const mach64Vertex *v ); + + +#endif /* __MACH64_VB_H__ */ diff --git a/src/mach64_vbtmp.h b/src/mach64_vbtmp.h new file mode 100644 index 0000000..c1207ca --- /dev/null +++ b/src/mach64_vbtmp.h @@ -0,0 +1,770 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Mesa 3-D graphics library + * Version: 3.5 + * + * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL 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> + * + * Modified for mach64 by: + * Leif Delgass <ldelgass@retinalburn.net> + * José Fonseca <j_r_fonseca@yahoo.co.uk> + */ + + +/* Unlike the other templates here, this assumes quite a bit about the + * underlying hardware. Specifically it assumes a d3d-like vertex + * format, with a layout more or less constrained to look like the + * following: + * + * union { + * struct { + * float x, y, z, w; + * struct { char r, g, b, a; } color; + * struct { char r, g, b, fog; } spec; + * float u0, v0; + * float u1, v1; + * float u2, v2; + * float u3, v3; + * } v; + * struct { + * float x, y, z, w; + * struct { char r, g, b, a; } color; + * struct { char r, g, b, fog; } spec; + * float u0, v0, q0; + * float u1, v1, q1; + * float u2, v2, q2; + * float u3, v3, q3; + * } pv; + * struct { + * float x, y, z; + * struct { char r, g, b, a; } color; + * } tv; + * float f[16]; + * unsigned int ui[16]; + * unsigned char ub4[4][16]; + * } + * + + * DO_XYZW: Emit xyz and maybe w coordinates. + * DO_RGBA: Emit color. + * DO_SPEC: Emit specular color. + * DO_FOG: Emit fog coordinate in specular alpha. + * DO_TEX0: Emit tex0 u,v coordinates. + * DO_TEX1: Emit tex1 u,v coordinates. + * DO_TEX2: Emit tex2 u,v coordinates. + * DO_TEX3: Emit tex3 u,v coordinates. + * DO_PTEX: Emit tex0,1,2,3 q coordinates where possible. + * + * HAVE_RGBA_COLOR: Hardware takes color in rgba order (else bgra). + * + * HAVE_HW_VIEWPORT: Hardware performs viewport transform. + * HAVE_HW_DIVIDE: Hardware performs perspective divide. + * + * HAVE_TINY_VERTICES: Hardware understands v.tv format. + * HAVE_PTEX_VERTICES: Hardware understands v.pv format. + * HAVE_NOTEX_VERTICES: Hardware understands v.v format with texcount 0. + * + * Additionally, this template assumes it is emitting *transformed* + * vertices; the modifications to emit untransformed vertices (ie. to + * t&l hardware) are probably too great to cooexist with the code + * already in this file. + * + * NOTE: The PTEX vertex format always includes TEX0 and TEX1, even if + * only TEX0 is enabled, in order to maintain a vertex size which is + * an exact number of quadwords. + */ + +#if (HAVE_HW_VIEWPORT) +#define VIEWPORT_X(dst,x) dst = x +#define VIEWPORT_Y(dst,y) dst = y +#define VIEWPORT_Z(dst,z) dst = z +#else +#define VIEWPORT_X(dst,x) dst = s[0] * x + s[12] +#define VIEWPORT_Y(dst,y) dst = s[5] * y + s[13] +#define VIEWPORT_Z(dst,z) dst = s[10] * z + s[14] +#endif + +#if (HAVE_HW_DIVIDE && !HAVE_PTEX_VERTICES) +#error "can't cope with this combination" +#endif + +#ifndef LOCALVARS +#define LOCALVARS +#endif + +#ifndef CHECK_HW_DIVIDE +#define CHECK_HW_DIVIDE 1 +#endif + +#if (HAVE_HW_DIVIDE || DO_SPEC || DO_TEX0 || DO_FOG || !HAVE_TINY_VERTICES) + +static void TAG(emit)( GLcontext *ctx, + GLuint start, GLuint end, + void *dest, + GLuint stride ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLfloat (*tc0)[4], (*tc1)[4], (*fog)[4]; + GLfloat (*tc2)[4], (*tc3)[4]; + GLfloat (*spec)[4]; + GLfloat (*col)[4]; + GLuint col_stride; + GLuint tc0_stride, tc1_stride, spec_stride, fog_stride; + GLuint tc2_stride, tc3_stride; + GLuint tc0_size, tc1_size; + GLuint tc2_size, tc3_size; + GLfloat (*coord)[4]; + GLuint coord_stride; + VERTEX *v = (VERTEX *)dest; + const GLfloat *s = GET_VIEWPORT_MAT(); + const GLubyte *mask = VB->ClipMask; + int i; + +/* fprintf(stderr, "%s(big) importable %d %d..%d\n", */ +/* __FUNCTION__, VB->importable_data, start, end); */ + + if (HAVE_HW_VIEWPORT && HAVE_HW_DIVIDE && CHECK_HW_DIVIDE) { + (void) s; + coord = VB->ClipPtr->data; + coord_stride = VB->ClipPtr->stride; + } + else { + coord = VB->NdcPtr->data; + coord_stride = VB->NdcPtr->stride; + } + + if (DO_TEX3) { + const GLuint t3 = GET_TEXSOURCE(3); + tc3 = VB->TexCoordPtr[t3]->data; + tc3_stride = VB->TexCoordPtr[t3]->stride; + if (DO_PTEX) + tc3_size = VB->TexCoordPtr[t3]->size; + } + + if (DO_TEX2) { + const GLuint t2 = GET_TEXSOURCE(2); + tc2 = VB->TexCoordPtr[t2]->data; + tc2_stride = VB->TexCoordPtr[t2]->stride; + if (DO_PTEX) + tc2_size = VB->TexCoordPtr[t2]->size; + } + + if (DO_TEX1) { + const GLuint t1 = GET_TEXSOURCE(1); + tc1 = VB->TexCoordPtr[t1]->data; + tc1_stride = VB->TexCoordPtr[t1]->stride; + if (DO_PTEX) + tc1_size = VB->TexCoordPtr[t1]->size; + } + + if (DO_TEX0) { + const GLuint t0 = GET_TEXSOURCE(0); + tc0_stride = VB->TexCoordPtr[t0]->stride; + tc0 = VB->TexCoordPtr[t0]->data; + if (DO_PTEX) + tc0_size = VB->TexCoordPtr[t0]->size; + } + + if (DO_RGBA) { + col = VB->ColorPtr[0]->data; + col_stride = VB->ColorPtr[0]->stride; + } + + if (DO_SPEC) { + spec = VB->SecondaryColorPtr[0]->data; + spec_stride = VB->SecondaryColorPtr[0]->stride; + } else { + spec = (GLfloat (*)[4])ctx->Current.Attrib[VERT_ATTRIB_COLOR1]; + spec_stride = 0; + } + + if (DO_FOG) { + if (VB->FogCoordPtr) { + fog = VB->FogCoordPtr->data; + fog_stride = VB->FogCoordPtr->stride; + } else { + static GLfloat tmp[4] = {0, 0, 0, 0}; + fog = &tmp; + fog_stride = 0; + } + } + + /* May have nonstandard strides: + */ + if (start) { + coord = (GLfloat (*)[4])((GLubyte *)coord + start * coord_stride); + if (DO_TEX0) + tc0 = (GLfloat (*)[4])((GLubyte *)tc0 + start * tc0_stride); + if (DO_TEX1) + tc1 = (GLfloat (*)[4])((GLubyte *)tc1 + start * tc1_stride); + if (DO_TEX2) + tc2 = (GLfloat (*)[4])((GLubyte *)tc2 + start * tc2_stride); + if (DO_TEX3) + tc3 = (GLfloat (*)[4])((GLubyte *)tc3 + start * tc3_stride); + if (DO_RGBA) + STRIDE_4F(col, start * col_stride); + if (DO_SPEC) + STRIDE_4F(spec, start * spec_stride); + if (DO_FOG) + STRIDE_4F(fog, start * fog_stride); + // fog = (GLfloat (*)[4])((GLubyte *)fog + start * fog_stride); + /* STRIDE_F(fog, start * fog_stride); */ + } + + for (i=start; i < end; i++, v = (VERTEX *)((GLubyte *)v + stride)) { + if (DO_XYZW) { + if (HAVE_HW_VIEWPORT || mask[i] == 0) { + /* unclipped */ + VIEWPORT_X(v->v.x, coord[0][0]); + VIEWPORT_Y(v->v.y, coord[0][1]); + VIEWPORT_Z(v->v.z, coord[0][2]); + v->v.w = coord[0][3]; + } else { + /* clipped */ + v->v.w = 1.0; + } + if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { + fprintf(stderr, "%s: vert (importable) %d: %.2f %.2f %.2f %f\n", + __FUNCTION__, i, v->v.x, v->v.y, v->v.z, v->v.w); + } + coord = (GLfloat (*)[4])((GLubyte *)coord + coord_stride); + } + if (DO_RGBA) { + if (HAVE_RGBA_COLOR) { + *(GLuint *)&v->v.color = *(GLuint *)&col[0]; + STRIDE_4F(col, col_stride); + } else { + v->v.color.blue = col[0][2]; + v->v.color.green = col[0][1]; + v->v.color.red = col[0][0]; + v->v.color.alpha = col[0][3]; + STRIDE_4F(col, col_stride); + } + } + if (DO_SPEC) { + v->v.specular.red = spec[0][0]; + v->v.specular.green = spec[0][1]; + v->v.specular.blue = spec[0][2]; + STRIDE_4F(spec, spec_stride); + } + if (DO_FOG) { + v->v.specular.alpha = fog[0][0] * 255.0; + /* STRIDE_F(fog, fog_stride); */ + fog = (GLfloat (*)[4])((GLubyte *)fog + fog_stride); + } + if (DO_TEX0) { + v->v.u0 = tc0[0][0]; + v->v.v0 = tc0[0][1]; + if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { + fprintf(stderr, "%s: vert (importable) %d: u0: %.2f, v0: %.2f, w: %f\n", + __FUNCTION__, i, v->v.u0, v->v.v0, v->v.w); + } +#ifdef MACH64_PREMULT_TEXCOORDS + v->v.u0 *= v->v.w; + v->v.v0 *= v->v.w; +#endif + if (DO_PTEX) { + if (HAVE_PTEX_VERTICES) { + if (tc0_size == 4) + v->pv.q0 = tc0[0][3]; + else + v->pv.q0 = 1.0; + } + else if (tc0_size == 4) { +#ifdef MACH64_PREMULT_TEXCOORDS + v->v.w *= tc0[0][3]; +#else + float rhw = 1.0 / tc0[0][3]; + v->v.w *= tc0[0][3]; + v->v.u0 *= rhw; + v->v.v0 *= rhw; +#endif + } + } + tc0 = (GLfloat (*)[4])((GLubyte *)tc0 + tc0_stride); + } + if (DO_TEX1) { + if (DO_PTEX) { + v->pv.u1 = tc1[0][0]; + v->pv.v1 = tc1[0][1]; + if (tc1_size == 4) + v->pv.q1 = tc1[0][3]; + else + v->pv.q1 = 1.0; + } + else { + v->v.u1 = tc1[0][0]; + v->v.v1 = tc1[0][1]; + } +#ifdef MACH64_PREMULT_TEXCOORDS + v->v.u1 *= v->v.w; + v->v.v1 *= v->v.w; +#endif + tc1 = (GLfloat (*)[4])((GLubyte *)tc1 + tc1_stride); + } + else if (DO_PTEX) { + *(GLuint *)&v->pv.q1 = 0; /* avoid culling on radeon */ + } + if (DO_TEX2) { + if (DO_PTEX) { + v->pv.u2 = tc2[0][0]; + v->pv.v2 = tc2[0][1]; + if (tc2_size == 4) + v->pv.q2 = tc2[0][3]; + else + v->pv.q2 = 1.0; + } + else { + v->v.u2 = tc2[0][0]; + v->v.v2 = tc2[0][1]; + } + tc2 = (GLfloat (*)[4])((GLubyte *)tc2 + tc2_stride); + } + if (DO_TEX3) { + if (DO_PTEX) { + v->pv.u3 = tc3[0][0]; + v->pv.v3 = tc3[0][1]; + if (tc3_size == 4) + v->pv.q3 = tc3[0][3]; + else + v->pv.q3 = 1.0; + } + else { + v->v.u3 = tc3[0][0]; + v->v.v3 = tc3[0][1]; + } + tc3 = (GLfloat (*)[4])((GLubyte *)tc3 + tc3_stride); + } + } +} + +#else +#if DO_XYZW + +#if HAVE_HW_DIVIDE +#error "cannot use tiny vertices with hw perspective divide" +#endif + +static void TAG(emit)( GLcontext *ctx, GLuint start, GLuint end, + void *dest, GLuint stride ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLfloat (*col)[4]; + GLuint col_stride; + GLfloat (*coord)[4] = VB->NdcPtr->data; + GLuint coord_stride = VB->NdcPtr->stride; + GLfloat *v = (GLfloat *)dest; + const GLubyte *mask = VB->ClipMask; + const GLfloat *s = GET_VIEWPORT_MAT(); + int i; + + (void) s; + + ASSERT(stride == 4); + + col = VB->ColorPtr[0]->data; + col_stride = VB->ColorPtr[0]->stride; + + /* Pack what's left into a 4-dword vertex. Color is in a different + * place, and there is no 'w' coordinate. + */ + if (start) { + coord = (GLfloat (*)[4])((GLubyte *)coord + start * coord_stride); + STRIDE_4F(col, start * col_stride); + } + + for (i=start; i < end; i++, v+=4) { + if (HAVE_HW_VIEWPORT || mask[i] == 0) { + VIEWPORT_X(v[0], coord[0][0]); + VIEWPORT_Y(v[1], coord[0][1]); + VIEWPORT_Z(v[2], coord[0][2]); + } + coord = (GLfloat (*)[4])((GLubyte *)coord + coord_stride); + if (DO_RGBA) { + if (HAVE_RGBA_COLOR) { + *(GLuint *)&v[3] = *(GLuint *)col; + } + else { + GLubyte *b = (GLubyte *)&v[3]; + UNCLAMPED_FLOAT_TO_UBYTE(b[0], col[0][2]); + UNCLAMPED_FLOAT_TO_UBYTE(b[1], col[0][1]); + UNCLAMPED_FLOAT_TO_UBYTE(b[2], col[0][0]); + UNCLAMPED_FLOAT_TO_UBYTE(b[3], col[0][3]); + } + STRIDE_4F( col, col_stride ); + } + if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { + fprintf(stderr, "vert (importable) %d: %.2f %.2f %.2f %x\n", + i, v[0], v[1], v[2], *(int *)&v[3]); + } + } +} +#else +static void TAG(emit)( GLcontext *ctx, GLuint start, GLuint end, + void *dest, GLuint stride ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLfloat (*col)[4]; + GLuint col_stride; + GLfloat *v = (GLfloat *)dest; + int i; + + col = VB->ColorPtr[0]->data; + col_stride = VB->ColorPtr[0]->stride; + + if (start) + STRIDE_4F(col, col_stride * start); + + /* Need to figure out where color is: + */ + if (GET_VERTEX_FORMAT() == TINY_VERTEX_FORMAT) + v += 3; + else + v += 4; + + for (i=start; i < end; i++, STRIDE_F(v, stride)) { + if (HAVE_RGBA_COLOR) { + *(GLuint *)v = *(GLuint *)col[0]; + } + else { + GLubyte *b = (GLubyte *)v; + UNCLAMPED_FLOAT_TO_UBYTE(b[0], col[0][2]); + UNCLAMPED_FLOAT_TO_UBYTE(b[1], col[0][1]); + UNCLAMPED_FLOAT_TO_UBYTE(b[2], col[0][0]); + UNCLAMPED_FLOAT_TO_UBYTE(b[3], col[0][3]); + } + STRIDE_4F( col, col_stride ); + } +} +#endif /* emit */ +#endif /* emit */ + +#if (DO_XYZW) && (DO_RGBA) + + +#if (HAVE_PTEX_VERTICES) +static GLboolean TAG(check_tex_sizes)( GLcontext *ctx ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + /* Force 'missing' texcoords to something valid. + */ + if (DO_TEX3 && VB->TexCoordPtr[2] == 0) + VB->TexCoordPtr[2] = VB->TexCoordPtr[3]; + + if (DO_TEX2 && VB->TexCoordPtr[1] == 0) + VB->TexCoordPtr[1] = VB->TexCoordPtr[2]; + + if (DO_TEX1 && VB->TexCoordPtr[0] == 0) + VB->TexCoordPtr[0] = VB->TexCoordPtr[1]; + + if (DO_PTEX) + return GL_TRUE; + + if ((DO_TEX3 && VB->TexCoordPtr[GET_TEXSOURCE(3)]->size == 4) || + (DO_TEX2 && VB->TexCoordPtr[GET_TEXSOURCE(2)]->size == 4) || + (DO_TEX1 && VB->TexCoordPtr[GET_TEXSOURCE(1)]->size == 4) || + (DO_TEX0 && VB->TexCoordPtr[GET_TEXSOURCE(0)]->size == 4)) + return GL_FALSE; + + return GL_TRUE; +} +#else +static GLboolean TAG(check_tex_sizes)( GLcontext *ctx ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + /* Force 'missing' texcoords to something valid. + */ + if (DO_TEX3 && VB->TexCoordPtr[2] == 0) + VB->TexCoordPtr[2] = VB->TexCoordPtr[3]; + + if (DO_TEX2 && VB->TexCoordPtr[1] == 0) + VB->TexCoordPtr[1] = VB->TexCoordPtr[2]; + + if (DO_TEX1 && VB->TexCoordPtr[0] == 0) + VB->TexCoordPtr[0] = VB->TexCoordPtr[1]; + + if (DO_PTEX) + return GL_TRUE; + + /* No hardware support for projective texture. Can fake it for + * TEX0 only. + */ + if ((DO_TEX3 && VB->TexCoordPtr[GET_TEXSOURCE(3)]->size == 4) || + (DO_TEX2 && VB->TexCoordPtr[GET_TEXSOURCE(2)]->size == 4) || + (DO_TEX1 && VB->TexCoordPtr[GET_TEXSOURCE(1)]->size == 4)) { + PTEX_FALLBACK(); + return GL_FALSE; + } + + if (DO_TEX0 && VB->TexCoordPtr[GET_TEXSOURCE(0)]->size == 4) { + if (DO_TEX1 || DO_TEX2 || DO_TEX3) { + PTEX_FALLBACK(); + } + return GL_FALSE; + } + + return GL_TRUE; +} +#endif /* ptex */ + + +static void TAG(interp)( GLcontext *ctx, + GLfloat t, + GLuint edst, GLuint eout, GLuint ein, + GLboolean force_boundary ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLubyte *ddverts = GET_VERTEX_STORE(); + GLuint size = GET_VERTEX_SIZE(); + const GLfloat *dstclip = VB->ClipPtr->data[edst]; + GLfloat w; + const GLfloat *s = GET_VIEWPORT_MAT(); + + VERTEX *dst = (VERTEX *)(ddverts + (edst * size)); + VERTEX *in = (VERTEX *)(ddverts + (ein * size)); + VERTEX *out = (VERTEX *)(ddverts + (eout * size)); + + (void)s; + + if (HAVE_HW_DIVIDE && CHECK_HW_DIVIDE) { + VIEWPORT_X( dst->v.x, dstclip[0] ); + VIEWPORT_Y( dst->v.y, dstclip[1] ); + VIEWPORT_Z( dst->v.z, dstclip[2] ); + w = dstclip[3]; + } + else { + w = (dstclip[3] == 0.0F) ? 1.0 : (1.0 / dstclip[3]); + VIEWPORT_X( dst->v.x, dstclip[0] * w ); + VIEWPORT_Y( dst->v.y, dstclip[1] * w ); + VIEWPORT_Z( dst->v.z, dstclip[2] * w ); + } + + if (MACH64_DEBUG & DEBUG_VERBOSE_PRIMS) { + fprintf( stderr, "%s: dst vert: %.2f %.2f %.2f %f\n", + __FUNCTION__, + dst->v.x, + dst->v.y, + dst->v.z, + w ); + } + + if ((HAVE_HW_DIVIDE && CHECK_HW_DIVIDE) || + DO_FOG || DO_SPEC || DO_TEX0 || DO_TEX1 || + DO_TEX2 || DO_TEX3 || !HAVE_TINY_VERTICES) { + + dst->v.w = w; + + INTERP_UB( t, dst->ub4[4][0], out->ub4[4][0], in->ub4[4][0] ); + INTERP_UB( t, dst->ub4[4][1], out->ub4[4][1], in->ub4[4][1] ); + INTERP_UB( t, dst->ub4[4][2], out->ub4[4][2], in->ub4[4][2] ); + INTERP_UB( t, dst->ub4[4][3], out->ub4[4][3], in->ub4[4][3] ); + + if (DO_SPEC) { + INTERP_UB( t, dst->ub4[5][0], out->ub4[5][0], in->ub4[5][0] ); + INTERP_UB( t, dst->ub4[5][1], out->ub4[5][1], in->ub4[5][1] ); + INTERP_UB( t, dst->ub4[5][2], out->ub4[5][2], in->ub4[5][2] ); + } + if (DO_FOG) { + INTERP_UB( t, dst->ub4[5][3], out->ub4[5][3], in->ub4[5][3] ); + } + if (DO_TEX0) { + if (DO_PTEX) { + if (HAVE_PTEX_VERTICES) { + INTERP_F( t, dst->pv.u0, out->pv.u0, in->pv.u0 ); + INTERP_F( t, dst->pv.v0, out->pv.v0, in->pv.v0 ); + INTERP_F( t, dst->pv.q0, out->pv.q0, in->pv.q0 ); + } else { + GLfloat wout = VB->NdcPtr->data[eout][3]; + GLfloat win = VB->NdcPtr->data[ein][3]; + GLfloat qout = out->pv.w / wout; + GLfloat qin = in->pv.w / win; + GLfloat qdst, rqdst; + + ASSERT( !HAVE_HW_DIVIDE ); + + INTERP_F( t, dst->v.u0, out->v.u0 * qout, in->v.u0 * qin ); + INTERP_F( t, dst->v.v0, out->v.v0 * qout, in->v.v0 * qin ); + INTERP_F( t, qdst, qout, qin ); + + rqdst = 1.0 / qdst; + dst->v.u0 *= rqdst; + dst->v.v0 *= rqdst; + dst->v.w *= rqdst; + } + } + else { +#ifdef MACH64_PREMULT_TEXCOORDS + GLfloat qout = 1 / out->v.w; + GLfloat qin = 1 / in->v.w; + + INTERP_F( t, dst->v.u0, out->v.u0 * qout, in->v.u0 * qin); + INTERP_F( t, dst->v.v0, out->v.v0 * qout, in->v.v0 * qin); + + dst->v.u0 *= w; + dst->v.v0 *= w; +#else + INTERP_F( t, dst->v.u0, out->v.u0, in->v.u0 ); + INTERP_F( t, dst->v.v0, out->v.v0, in->v.v0 ); +#endif + } + } + if (DO_TEX1) { + if (DO_PTEX) { + INTERP_F( t, dst->pv.u1, out->pv.u1, in->pv.u1 ); + INTERP_F( t, dst->pv.v1, out->pv.v1, in->pv.v1 ); + INTERP_F( t, dst->pv.q1, out->pv.q1, in->pv.q1 ); + } else { +#ifdef MACH64_PREMULT_TEXCOORDS + GLfloat qout = 1 / out->v.w; + GLfloat qin = 1 / in->v.w; + + INTERP_F( t, dst->v.u1, out->v.u1 * qout, in->v.u1 * qin ); + INTERP_F( t, dst->v.v1, out->v.v1 * qout, in->v.v1 * qin ); + + dst->v.u1 *= w; + dst->v.v1 *= w; +#else + INTERP_F( t, dst->v.u1, out->v.u1, in->v.u1 ); + INTERP_F( t, dst->v.v1, out->v.v1, in->v.v1 ); +#endif + } + } + else if (DO_PTEX) { + dst->pv.q0 = 0.0; /* must be a valid float on radeon */ + } + if (DO_TEX2) { + if (DO_PTEX) { + INTERP_F( t, dst->pv.u2, out->pv.u2, in->pv.u2 ); + INTERP_F( t, dst->pv.v2, out->pv.v2, in->pv.v2 ); + INTERP_F( t, dst->pv.q2, out->pv.q2, in->pv.q2 ); + } else { + INTERP_F( t, dst->v.u2, out->v.u2, in->v.u2 ); + INTERP_F( t, dst->v.v2, out->v.v2, in->v.v2 ); + } + } + if (DO_TEX3) { + if (DO_PTEX) { + INTERP_F( t, dst->pv.u3, out->pv.u3, in->pv.u3 ); + INTERP_F( t, dst->pv.v3, out->pv.v3, in->pv.v3 ); + INTERP_F( t, dst->pv.q3, out->pv.q3, in->pv.q3 ); + } else { + INTERP_F( t, dst->v.u3, out->v.u3, in->v.u3 ); + INTERP_F( t, dst->v.v3, out->v.v3, in->v.v3 ); + } + } + } else { + /* 4-dword vertex. Color is in v[3] and there is no oow coordinate. + */ + INTERP_UB( t, dst->ub4[3][0], out->ub4[3][0], in->ub4[3][0] ); + INTERP_UB( t, dst->ub4[3][1], out->ub4[3][1], in->ub4[3][1] ); + INTERP_UB( t, dst->ub4[3][2], out->ub4[3][2], in->ub4[3][2] ); + INTERP_UB( t, dst->ub4[3][3], out->ub4[3][3], in->ub4[3][3] ); + } +} + +#endif /* rgba && xyzw */ + + +static void TAG(init)( void ) +{ + setup_tab[IND].emit = TAG(emit); + +#if (DO_XYZW && DO_RGBA) + setup_tab[IND].check_tex_sizes = TAG(check_tex_sizes); + setup_tab[IND].interp = TAG(interp); +#endif + + if (DO_SPEC) + setup_tab[IND].copy_pv = copy_pv_rgba4_spec5; + else if (HAVE_HW_DIVIDE || DO_SPEC || DO_FOG || DO_TEX0 || DO_TEX1 || + DO_TEX2 || DO_TEX3 || !HAVE_TINY_VERTICES) + setup_tab[IND].copy_pv = copy_pv_rgba4; + else + setup_tab[IND].copy_pv = copy_pv_rgba3; + + if (DO_TEX3) { + if (DO_PTEX) { + ASSERT(HAVE_PTEX_VERTICES); + setup_tab[IND].vertex_format = PROJ_TEX3_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 18; + } + else { + setup_tab[IND].vertex_format = TEX3_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 14; + } + } + else if (DO_TEX2) { + if (DO_PTEX) { + ASSERT(HAVE_PTEX_VERTICES); + setup_tab[IND].vertex_format = PROJ_TEX3_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 18; + } + else { + setup_tab[IND].vertex_format = TEX2_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 12; + } + } + else if (DO_TEX1) { + if (DO_PTEX) { + ASSERT(HAVE_PTEX_VERTICES); + setup_tab[IND].vertex_format = PROJ_TEX1_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 12; + } + else { + setup_tab[IND].vertex_format = TEX1_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 10; + } + } + else if (DO_TEX0) { + if (DO_PTEX && HAVE_PTEX_VERTICES) { + setup_tab[IND].vertex_format = PROJ_TEX1_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 12; + } else { + setup_tab[IND].vertex_format = TEX0_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 8; + } + } + else if (!HAVE_HW_DIVIDE && !DO_SPEC && !DO_FOG && HAVE_TINY_VERTICES) { + setup_tab[IND].vertex_format = TINY_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 4; + } else if (HAVE_NOTEX_VERTICES) { + setup_tab[IND].vertex_format = NOTEX_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 6; + } else { + setup_tab[IND].vertex_format = TEX0_VERTEX_FORMAT; + setup_tab[IND].vertex_size = 8; + } + +} + + +#undef IND +#undef TAG diff --git a/src/server/mach64_dri.h b/src/server/mach64_dri.h new file mode 100644 index 0000000..139668e --- /dev/null +++ b/src/server/mach64_dri.h @@ -0,0 +1,126 @@ +/* $XFree86$ */ /* -*- mode: c; c-basic-offset: 3 -*- */ +/* + * Copyright 2000 Gareth Hughes + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GARETH HUGHES 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> + * Leif Delgass <ldelgass@retinalburn.net> + */ + +#ifndef __MACH64_DRI_H__ +#define __MACH64_DRI_H__ 1 + +#include "xf86drm.h" + +typedef struct { + drm_handle_t fbHandle; + + drm_handle_t regsHandle; + drmSize regsSize; + + int IsPCI; + + drm_handle_t agpHandle; /* Handle from drmAgpAlloc */ + unsigned long agpOffset; + drmSize agpSize; + int agpMode; + + /* DMA descriptor ring */ + unsigned long ringStart; /* Offset into AGP space */ + drm_handle_t ringHandle; /* Handle from drmAddMap */ + drmSize ringMapSize; /* Size of map */ + int ringSize; /* Size of ring (in kB) */ + drmAddress ringMap; /* Map */ + + /* vertex buffer data */ + unsigned long bufferStart; /* Offset into AGP space */ + drm_handle_t bufferHandle; /* Handle from drmAddMap */ + drmSize bufferMapSize; /* Size of map */ + int bufferSize; /* Size of buffers (in MB) */ + drmAddress bufferMap; /* Map */ + + drmBufMapPtr drmBuffers; /* Buffer map */ + int numBuffers; /* Number of buffers */ + + /* AGP Texture data */ + unsigned long agpTexStart; /* Offset into AGP space */ + drm_handle_t agpTexHandle; /* Handle from drmAddMap */ + drmSize agpTexMapSize; /* Size of map */ + int agpTexSize; /* Size of AGP tex space (in MB) */ + drmAddress agpTexMap; /* Map */ + int log2AGPTexGran; + + int fbX; + int fbY; + int backX; + int backY; + int depthX; + int depthY; + + int frontOffset; + int frontPitch; + int backOffset; + int backPitch; + int depthOffset; + int depthPitch; + + int textureOffset; + int textureSize; + int logTextureGranularity; +} ATIDRIServerInfoRec, *ATIDRIServerInfoPtr; + +typedef struct { + int chipset; + int width; + int height; + int mem; + int cpp; + + int IsPCI; + int AGPMode; + + unsigned int frontOffset; + unsigned int frontPitch; + + unsigned int backOffset; + unsigned int backPitch; + + unsigned int depthOffset; + unsigned int depthPitch; + + unsigned int textureOffset; + unsigned int textureSize; + int logTextureGranularity; + + drm_handle_t regs; + drmSize regsSize; + + drm_handle_t agp; + drmSize agpSize; + unsigned int agpTextureOffset; + unsigned int agpTextureSize; + int logAgpTextureGranularity; +} ATIDRIRec, *ATIDRIPtr; + +#endif /* __MACH64_DRI_H__ */ |