/* -*- 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 * Leif Delgass * Jos�Fonseca */ #include "main/glheader.h" #include "main/context.h" #include "main/simple_list.h" #include "main/imports.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" #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 } }; static const struct dri_extension card_extensions[] = { { "GL_ARB_multitexture", NULL }, { "GL_EXT_texture_edge_clamp", NULL }, { "GL_MESA_ycbcr_texture", NULL }, { NULL, NULL } }; /* Create the device specific context. */ GLboolean mach64CreateContext( gl_api api, const struct gl_config *glVisual, __DRIcontext *driContextPriv, void *sharedContextPrivate ) { struct gl_context *ctx, *shareCtx; __DRIscreen *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(API_OPENGL, 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; ctx->Const.MaxDrawBuffers = 1; 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 = _mesa_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")); 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( __DRIcontext *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 ) _mesa_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( __DRIcontext *driContextPriv, __DRIdrawable *driDrawPriv, __DRIdrawable *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; } if ( newMach64Ctx->driDrawable != driDrawPriv ) { if (driDrawPriv->swap_interval == (unsigned)-1) { driDrawPriv->vblFlags = (newMach64Ctx->do_irqs) ? driGetDefaultVBlankFlags(&newMach64Ctx->optionCache) : VBLANK_FLAG_NO_IRQ; driDrawableInitVBlank( driDrawPriv ); } newMach64Ctx->driDrawable = driDrawPriv; mach64CalcViewport( newMach64Ctx->glCtx ); } _mesa_make_current( newMach64Ctx->glCtx, (struct gl_framebuffer *) driDrawPriv->driverPrivate, (struct gl_framebuffer *) 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( __DRIcontext *driContextPriv ) { return GL_TRUE; }