| /* |
| * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved. |
| * Copyright 2001-2003 S3 Graphics, Inc. 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, 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 |
| * VIA, S3 GRAPHICS, AND/OR ITS 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. |
| */ |
| |
| |
| #include <X11/Xlibint.h> |
| #include <stdio.h> |
| |
| #include "savagecontext.h" |
| #include "context.h" |
| #include "matrix.h" |
| #include "framebuffer.h" |
| #include "renderbuffer.h" |
| #include "simple_list.h" |
| |
| #include "utils.h" |
| |
| #include "extensions.h" |
| |
| #include "swrast/swrast.h" |
| #include "swrast_setup/swrast_setup.h" |
| #include "tnl/tnl.h" |
| #include "vbo/vbo.h" |
| |
| #include "tnl/t_pipeline.h" |
| |
| #include "drivers/common/driverfuncs.h" |
| |
| #include "savagedd.h" |
| #include "savagestate.h" |
| #include "savagetex.h" |
| #include "savagespan.h" |
| #include "savagetris.h" |
| #include "savageioctl.h" |
| #include "savage_bci.h" |
| |
| #include "savage_dri.h" |
| |
| #include "drirenderbuffer.h" |
| #include "texmem.h" |
| |
| #define need_GL_ARB_multisample |
| #define need_GL_ARB_texture_compression |
| #define need_GL_ARB_vertex_buffer_object |
| #define need_GL_EXT_secondary_color |
| #include "extension_helper.h" |
| |
| #include "xmlpool.h" |
| |
| /* Driver-specific options |
| */ |
| #define SAVAGE_ENABLE_VDMA(def) \ |
| DRI_CONF_OPT_BEGIN(enable_vdma,bool,def) \ |
| DRI_CONF_DESC(en,"Use DMA for vertex transfers") \ |
| DRI_CONF_DESC(de,"Benutze DMA für Vertextransfers") \ |
| DRI_CONF_OPT_END |
| #define SAVAGE_ENABLE_FASTPATH(def) \ |
| DRI_CONF_OPT_BEGIN(enable_fastpath,bool,def) \ |
| DRI_CONF_DESC(en,"Use fast path for unclipped primitives") \ |
| DRI_CONF_DESC(de,"Schneller Codepfad für ungeschnittene Polygone") \ |
| DRI_CONF_OPT_END |
| #define SAVAGE_SYNC_FRAMES(def) \ |
| DRI_CONF_OPT_BEGIN(sync_frames,bool,def) \ |
| DRI_CONF_DESC(en,"Synchronize with graphics hardware after each frame") \ |
| DRI_CONF_DESC(de,"Synchronisiere nach jedem Frame mit Grafikhardware") \ |
| DRI_CONF_OPT_END |
| |
| /* Configuration |
| */ |
| PUBLIC const char __driConfigOptions[] = |
| DRI_CONF_BEGIN |
| DRI_CONF_SECTION_QUALITY |
| DRI_CONF_TEXTURE_DEPTH(DRI_CONF_TEXTURE_DEPTH_FB) |
| DRI_CONF_COLOR_REDUCTION(DRI_CONF_COLOR_REDUCTION_DITHER) |
| DRI_CONF_FLOAT_DEPTH(false) |
| DRI_CONF_SECTION_END |
| DRI_CONF_SECTION_PERFORMANCE |
| SAVAGE_ENABLE_VDMA(true) |
| SAVAGE_ENABLE_FASTPATH(true) |
| SAVAGE_SYNC_FRAMES(false) |
| DRI_CONF_MAX_TEXTURE_UNITS(2,1,2) |
| DRI_CONF_TEXTURE_HEAPS(DRI_CONF_TEXTURE_HEAPS_ALL) |
| DRI_CONF_FORCE_S3TC_ENABLE(false) |
| DRI_CONF_SECTION_END |
| DRI_CONF_SECTION_DEBUG |
| DRI_CONF_NO_RAST(false) |
| DRI_CONF_SECTION_END |
| DRI_CONF_END; |
| static const GLuint __driNConfigOptions = 10; |
| |
| |
| static const struct dri_debug_control debug_control[] = |
| { |
| { "fall", DEBUG_FALLBACKS }, |
| { "api", DEBUG_VERBOSE_API }, |
| { "tex", DEBUG_VERBOSE_TEX }, |
| { "verb", DEBUG_VERBOSE_MSG }, |
| { "dma", DEBUG_DMA }, |
| { "state", DEBUG_STATE }, |
| { NULL, 0 } |
| }; |
| #ifndef SAVAGE_DEBUG |
| int SAVAGE_DEBUG = 0; |
| #endif |
| |
| |
| /*For time caculating test*/ |
| #if defined(DEBUG_TIME) && DEBUG_TIME |
| struct timeval tv_s,tv_f; |
| unsigned long time_sum=0; |
| struct timeval tv_s1,tv_f1; |
| #endif |
| |
| static const struct dri_extension card_extensions[] = |
| { |
| { "GL_ARB_multisample", GL_ARB_multisample_functions }, |
| { "GL_ARB_multitexture", NULL }, |
| { "GL_ARB_texture_compression", GL_ARB_texture_compression_functions }, |
| { "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions }, |
| { "GL_EXT_stencil_wrap", NULL }, |
| { "GL_EXT_texture_lod_bias", NULL }, |
| { "GL_EXT_secondary_color", GL_EXT_secondary_color_functions }, |
| { NULL, NULL } |
| }; |
| |
| static const struct dri_extension s4_extensions[] = |
| { |
| { "GL_ARB_texture_env_add", NULL }, |
| { "GL_ARB_texture_mirrored_repeat", NULL }, |
| { NULL, NULL } |
| }; |
| |
| extern struct tnl_pipeline_stage _savage_texnorm_stage; |
| extern struct tnl_pipeline_stage _savage_render_stage; |
| |
| static const struct tnl_pipeline_stage *savage_pipeline[] = { |
| |
| &_tnl_vertex_transform_stage, |
| &_tnl_normal_transform_stage, |
| &_tnl_lighting_stage, |
| &_tnl_fog_coordinate_stage, |
| &_tnl_texgen_stage, |
| &_tnl_texture_transform_stage, |
| &_savage_texnorm_stage, |
| &_savage_render_stage, |
| &_tnl_render_stage, |
| 0, |
| }; |
| |
| |
| PUBLIC const __DRIextension *savageScreenExtensions[] = { |
| &driCoreExtension.base, |
| &driLegacyExtension.base, |
| &driReadDrawableExtension, |
| }; |
| |
| static GLboolean |
| savageInitDriver(__DRIscreenPrivate *sPriv) |
| { |
| savageScreenPrivate *savageScreen; |
| SAVAGEDRIPtr gDRIPriv = (SAVAGEDRIPtr)sPriv->pDevPriv; |
| |
| if (sPriv->devPrivSize != sizeof(SAVAGEDRIRec)) { |
| fprintf(stderr,"\nERROR! sizeof(SAVAGEDRIRec) does not match passed size from device driver\n"); |
| return GL_FALSE; |
| } |
| |
| /* Allocate the private area */ |
| savageScreen = (savageScreenPrivate *)Xmalloc(sizeof(savageScreenPrivate)); |
| if (!savageScreen) |
| return GL_FALSE; |
| |
| savageScreen->driScrnPriv = sPriv; |
| sPriv->private = (void *)savageScreen; |
| |
| savageScreen->chipset=gDRIPriv->chipset; |
| savageScreen->width=gDRIPriv->width; |
| savageScreen->height=gDRIPriv->height; |
| savageScreen->mem=gDRIPriv->mem; |
| savageScreen->cpp=gDRIPriv->cpp; |
| savageScreen->zpp=gDRIPriv->zpp; |
| |
| savageScreen->agpMode=gDRIPriv->agpMode; |
| |
| savageScreen->bufferSize=gDRIPriv->bufferSize; |
| |
| if (gDRIPriv->cpp == 4) |
| savageScreen->frontFormat = DV_PF_8888; |
| else |
| savageScreen->frontFormat = DV_PF_565; |
| savageScreen->frontOffset=gDRIPriv->frontOffset; |
| savageScreen->backOffset = gDRIPriv->backOffset; |
| savageScreen->depthOffset=gDRIPriv->depthOffset; |
| |
| savageScreen->textureOffset[SAVAGE_CARD_HEAP] = |
| gDRIPriv->textureOffset; |
| savageScreen->textureSize[SAVAGE_CARD_HEAP] = |
| gDRIPriv->textureSize; |
| savageScreen->logTextureGranularity[SAVAGE_CARD_HEAP] = |
| gDRIPriv->logTextureGranularity; |
| |
| savageScreen->textureOffset[SAVAGE_AGP_HEAP] = |
| gDRIPriv->agpTextureHandle; |
| savageScreen->textureSize[SAVAGE_AGP_HEAP] = |
| gDRIPriv->agpTextureSize; |
| savageScreen->logTextureGranularity[SAVAGE_AGP_HEAP] = |
| gDRIPriv->logAgpTextureGranularity; |
| |
| savageScreen->agpTextures.handle = gDRIPriv->agpTextureHandle; |
| savageScreen->agpTextures.size = gDRIPriv->agpTextureSize; |
| if (gDRIPriv->agpTextureSize) { |
| if (drmMap(sPriv->fd, |
| savageScreen->agpTextures.handle, |
| savageScreen->agpTextures.size, |
| (drmAddress *)&(savageScreen->agpTextures.map)) != 0) { |
| Xfree(savageScreen); |
| sPriv->private = NULL; |
| return GL_FALSE; |
| } |
| } else |
| savageScreen->agpTextures.map = NULL; |
| |
| savageScreen->texVirtual[SAVAGE_CARD_HEAP] = |
| (drmAddress)(((GLubyte *)sPriv->pFB)+gDRIPriv->textureOffset); |
| savageScreen->texVirtual[SAVAGE_AGP_HEAP] = |
| (drmAddress)(savageScreen->agpTextures.map); |
| |
| savageScreen->aperture.handle = gDRIPriv->apertureHandle; |
| savageScreen->aperture.size = gDRIPriv->apertureSize; |
| savageScreen->aperturePitch = gDRIPriv->aperturePitch; |
| if (drmMap(sPriv->fd, |
| savageScreen->aperture.handle, |
| savageScreen->aperture.size, |
| (drmAddress *)&savageScreen->aperture.map) != 0) |
| { |
| Xfree(savageScreen); |
| sPriv->private = NULL; |
| return GL_FALSE; |
| } |
| |
| savageScreen->bufs = drmMapBufs(sPriv->fd); |
| |
| savageScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset; |
| |
| /* parse information in __driConfigOptions */ |
| driParseOptionInfo (&savageScreen->optionCache, |
| __driConfigOptions, __driNConfigOptions); |
| |
| sPriv->extensions = savageScreenExtensions; |
| |
| #if 0 |
| savageDDFastPathInit(); |
| savageDDTrifuncInit(); |
| savageDDSetupInit(); |
| #endif |
| return GL_TRUE; |
| } |
| |
| /* Accessed by dlsym from dri_mesa_init.c |
| */ |
| static void |
| savageDestroyScreen(__DRIscreenPrivate *sPriv) |
| { |
| savageScreenPrivate *savageScreen = (savageScreenPrivate *)sPriv->private; |
| |
| if (savageScreen->bufs) |
| drmUnmapBufs(savageScreen->bufs); |
| |
| /* free all option information */ |
| driDestroyOptionInfo (&savageScreen->optionCache); |
| |
| Xfree(savageScreen); |
| sPriv->private = NULL; |
| } |
| |
| static GLboolean |
| savageCreateContext( const __GLcontextModes *mesaVis, |
| __DRIcontextPrivate *driContextPriv, |
| void *sharedContextPrivate ) |
| { |
| GLcontext *ctx, *shareCtx; |
| savageContextPtr imesa; |
| __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; |
| struct dd_function_table functions; |
| savageScreenPrivate *savageScreen = (savageScreenPrivate *)sPriv->private; |
| drm_savage_sarea_t *saPriv=(drm_savage_sarea_t *)(((char*)sPriv->pSAREA)+ |
| savageScreen->sarea_priv_offset); |
| int textureSize[SAVAGE_NR_TEX_HEAPS]; |
| int i; |
| imesa = (savageContextPtr)Xcalloc(sizeof(savageContext), 1); |
| if (!imesa) { |
| return GL_FALSE; |
| } |
| |
| /* Init default driver functions then plug in savage-specific texture |
| * functions that are needed as early as during context creation. */ |
| _mesa_init_driver_functions( &functions ); |
| savageDDInitTextureFuncs( &functions ); |
| |
| /* Allocate the Mesa context */ |
| if (sharedContextPrivate) |
| shareCtx = ((savageContextPtr) sharedContextPrivate)->glCtx; |
| else |
| shareCtx = NULL; |
| ctx = _mesa_create_context(mesaVis, shareCtx, &functions, imesa); |
| if (!ctx) { |
| Xfree(imesa); |
| return GL_FALSE; |
| } |
| driContextPriv->driverPrivate = imesa; |
| |
| imesa->cmdBuf.size = SAVAGE_CMDBUF_SIZE; |
| imesa->cmdBuf.base = imesa->cmdBuf.write = |
| malloc(SAVAGE_CMDBUF_SIZE * sizeof(drm_savage_cmd_header_t)); |
| if (!imesa->cmdBuf.base) |
| return GL_FALSE; |
| |
| /* Parse configuration files */ |
| driParseConfigFiles (&imesa->optionCache, &savageScreen->optionCache, |
| sPriv->myNum, "savage"); |
| |
| imesa->float_depth = driQueryOptionb(&imesa->optionCache, "float_depth") && |
| savageScreen->chipset >= S3_SAVAGE4; |
| imesa->no_rast = driQueryOptionb(&imesa->optionCache, "no_rast"); |
| |
| #if 0 |
| ctx->Const.MinLineWidth = 1.0; |
| ctx->Const.MinLineWidthAA = 1.0; |
| ctx->Const.MaxLineWidth = 3.0; |
| ctx->Const.MaxLineWidthAA = 3.0; |
| ctx->Const.LineWidthGranularity = 1.0; |
| #endif |
| |
| /* Dri stuff |
| */ |
| imesa->hHWContext = driContextPriv->hHWContext; |
| imesa->driFd = sPriv->fd; |
| imesa->driHwLock = &sPriv->pSAREA->lock; |
| |
| imesa->savageScreen = savageScreen; |
| imesa->driScreen = sPriv; |
| imesa->sarea = saPriv; |
| imesa->glBuffer = NULL; |
| |
| /* DMA buffer */ |
| |
| for(i=0;i<5;i++) |
| { |
| imesa->apertureBase[i] = (GLubyte *)savageScreen->aperture.map + |
| 0x01000000 * i; |
| } |
| |
| imesa->aperturePitch = savageScreen->aperturePitch; |
| |
| /* change texHeap initialize to support two kind of texture heap*/ |
| /* here is some parts of initialization, others in InitDriver() */ |
| |
| (void) memset( imesa->textureHeaps, 0, sizeof( imesa->textureHeaps ) ); |
| make_empty_list( & imesa->swapped ); |
| |
| textureSize[SAVAGE_CARD_HEAP] = savageScreen->textureSize[SAVAGE_CARD_HEAP]; |
| textureSize[SAVAGE_AGP_HEAP] = savageScreen->textureSize[SAVAGE_AGP_HEAP]; |
| imesa->lastTexHeap = savageScreen->texVirtual[SAVAGE_AGP_HEAP] ? 2 : 1; |
| switch(driQueryOptioni (&imesa->optionCache, "texture_heaps")) { |
| case DRI_CONF_TEXTURE_HEAPS_CARD: /* only use card memory, if available */ |
| if (textureSize[SAVAGE_CARD_HEAP]) |
| imesa->lastTexHeap = 1; |
| break; |
| case DRI_CONF_TEXTURE_HEAPS_GART: /* only use gart memory, if available */ |
| if (imesa->lastTexHeap == 2 && textureSize[SAVAGE_AGP_HEAP]) |
| textureSize[SAVAGE_CARD_HEAP] = 0; |
| break; |
| /*default: Nothing to do, use all available memory. */ |
| } |
| |
| for (i = 0; i < imesa->lastTexHeap; i++) { |
| imesa->textureHeaps[i] = driCreateTextureHeap( |
| i, imesa, |
| textureSize[i], |
| 11, /* 2^11 = 2k alignment */ |
| SAVAGE_NR_TEX_REGIONS, |
| (drmTextureRegionPtr)imesa->sarea->texList[i], |
| &imesa->sarea->texAge[i], |
| &imesa->swapped, |
| sizeof( savageTexObj ), |
| (destroy_texture_object_t *) savageDestroyTexObj ); |
| /* If textureSize[i] == 0 textureHeaps[i] is NULL. This can happen |
| * if there is not enough card memory for a card texture heap. */ |
| if (imesa->textureHeaps[i]) |
| driSetTextureSwapCounterLocation( imesa->textureHeaps[i], |
| & imesa->c_textureSwaps ); |
| } |
| imesa->texture_depth = driQueryOptioni (&imesa->optionCache, |
| "texture_depth"); |
| if (imesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FB) |
| imesa->texture_depth = ( savageScreen->cpp == 4 ) ? |
| DRI_CONF_TEXTURE_DEPTH_32 : DRI_CONF_TEXTURE_DEPTH_16; |
| |
| if (savageScreen->chipset >= S3_SAVAGE4) |
| ctx->Const.MaxTextureUnits = 2; |
| else |
| ctx->Const.MaxTextureUnits = 1; |
| if (driQueryOptioni(&imesa->optionCache, "texture_units") < |
| ctx->Const.MaxTextureUnits) |
| ctx->Const.MaxTextureUnits = |
| driQueryOptioni(&imesa->optionCache, "texture_units"); |
| ctx->Const.MaxTextureImageUnits = ctx->Const.MaxTextureUnits; |
| ctx->Const.MaxTextureCoordUnits = ctx->Const.MaxTextureUnits; |
| |
| driCalculateMaxTextureLevels( imesa->textureHeaps, |
| imesa->lastTexHeap, |
| & ctx->Const, |
| 4, |
| 11, /* max 2D texture size is 2048x2048 */ |
| 0, /* 3D textures unsupported. */ |
| 0, /* cube textures unsupported. */ |
| 0, /* texture rectangles unsupported. */ |
| 12, |
| GL_FALSE, |
| 0 ); |
| if (ctx->Const.MaxTextureLevels <= 6) { /*spec requires at least 64x64*/ |
| __driUtilMessage("Not enough texture memory. " |
| "Falling back to indirect rendering."); |
| Xfree(imesa); |
| return GL_FALSE; |
| } |
| |
| imesa->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24; |
| imesa->depth_scale = (imesa->savageScreen->zpp == 2) ? |
| (1.0F/0xffff):(1.0F/0xffffff); |
| |
| imesa->bufferSize = savageScreen->bufferSize; |
| imesa->dmaVtxBuf.total = 0; |
| imesa->dmaVtxBuf.used = 0; |
| imesa->dmaVtxBuf.flushed = 0; |
| |
| imesa->clientVtxBuf.total = imesa->bufferSize / 4; |
| imesa->clientVtxBuf.used = 0; |
| imesa->clientVtxBuf.flushed = 0; |
| imesa->clientVtxBuf.buf = (u_int32_t *)malloc(imesa->bufferSize); |
| |
| imesa->vtxBuf = &imesa->clientVtxBuf; |
| |
| imesa->firstElt = -1; |
| |
| /* Uninitialized vertex format. Force setting the vertex state in |
| * savageRenderStart. |
| */ |
| imesa->vertex_size = 0; |
| |
| /* Utah stuff |
| */ |
| imesa->new_state = ~0; |
| imesa->new_gl_state = ~0; |
| imesa->RenderIndex = ~0; |
| imesa->dirty = ~0; |
| imesa->lostContext = GL_TRUE; |
| imesa->CurrentTexObj[0] = 0; |
| imesa->CurrentTexObj[1] = 0; |
| |
| /* 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, savage_pipeline ); |
| |
| imesa->enable_fastpath = driQueryOptionb(&imesa->optionCache, |
| "enable_fastpath"); |
| /* DRM versions before 2.1.3 would only render triangle lists. ELTS |
| * support was added in 2.2.0. */ |
| if (imesa->enable_fastpath && sPriv->drm_version.minor < 2) { |
| fprintf (stderr, |
| "*** Disabling fast path because your DRM version is buggy " |
| "or doesn't\n*** support ELTS. You need at least Savage DRM " |
| "version 2.2.\n"); |
| imesa->enable_fastpath = GL_FALSE; |
| } |
| |
| if (!savageScreen->bufs || savageScreen->chipset == S3_SUPERSAVAGE) |
| imesa->enable_vdma = GL_FALSE; |
| else |
| imesa->enable_vdma = driQueryOptionb(&imesa->optionCache, "enable_vdma"); |
| |
| imesa->sync_frames = driQueryOptionb(&imesa->optionCache, "sync_frames"); |
| |
| /* Configure swrast to match hardware characteristics: |
| */ |
| _tnl_allow_pixel_fog( ctx, GL_FALSE ); |
| _tnl_allow_vertex_fog( ctx, GL_TRUE ); |
| _swrast_allow_pixel_fog( ctx, GL_FALSE ); |
| _swrast_allow_vertex_fog( ctx, GL_TRUE ); |
| |
| ctx->DriverCtx = (void *) imesa; |
| imesa->glCtx = ctx; |
| |
| #ifndef SAVAGE_DEBUG |
| SAVAGE_DEBUG = driParseDebugString( getenv( "SAVAGE_DEBUG" ), |
| debug_control ); |
| #endif |
| |
| driInitExtensions( ctx, card_extensions, GL_TRUE ); |
| if (savageScreen->chipset >= S3_SAVAGE4) |
| driInitExtensions( ctx, s4_extensions, GL_FALSE ); |
| if (ctx->Mesa_DXTn || |
| driQueryOptionb (&imesa->optionCache, "force_s3tc_enable")) { |
| _mesa_enable_extension( ctx, "GL_S3_s3tc" ); |
| if (savageScreen->chipset >= S3_SAVAGE4) |
| /* This extension needs DXT3 and DTX5 support in hardware. |
| * Not available on Savage3D/MX/IX. */ |
| _mesa_enable_extension( ctx, "GL_EXT_texture_compression_s3tc" ); |
| } |
| |
| savageDDInitStateFuncs( ctx ); |
| savageDDInitSpanFuncs( ctx ); |
| savageDDInitDriverFuncs( ctx ); |
| savageDDInitIoctlFuncs( ctx ); |
| savageInitTriFuncs( ctx ); |
| |
| savageDDInitState( imesa ); |
| |
| driContextPriv->driverPrivate = (void *) imesa; |
| |
| return GL_TRUE; |
| } |
| |
| static void |
| savageDestroyContext(__DRIcontextPrivate *driContextPriv) |
| { |
| savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate; |
| GLuint i; |
| |
| assert (imesa); /* should never be NULL */ |
| if (imesa) { |
| savageFlushVertices(imesa); |
| savageReleaseIndexedVerts(imesa); |
| savageFlushCmdBuf(imesa, GL_TRUE); /* release DMA buffer */ |
| WAIT_IDLE_EMPTY(imesa); |
| |
| for (i = 0; i < imesa->lastTexHeap; i++) |
| driDestroyTextureHeap(imesa->textureHeaps[i]); |
| |
| free(imesa->cmdBuf.base); |
| free(imesa->clientVtxBuf.buf); |
| |
| _swsetup_DestroyContext(imesa->glCtx ); |
| _tnl_DestroyContext( imesa->glCtx ); |
| _vbo_DestroyContext( imesa->glCtx ); |
| _swrast_DestroyContext( imesa->glCtx ); |
| |
| /* free the Mesa context */ |
| imesa->glCtx->DriverCtx = NULL; |
| _mesa_destroy_context(imesa->glCtx); |
| |
| /* no longer use vertex_dma_buf*/ |
| Xfree(imesa); |
| } |
| } |
| |
| |
| static GLboolean |
| savageCreateBuffer( __DRIscreenPrivate *driScrnPriv, |
| __DRIdrawablePrivate *driDrawPriv, |
| const __GLcontextModes *mesaVis, |
| GLboolean isPixmap) |
| { |
| savageScreenPrivate *screen = (savageScreenPrivate *) driScrnPriv->private; |
| |
| if (isPixmap) { |
| return GL_FALSE; /* not implemented */ |
| } |
| else { |
| GLboolean swStencil = mesaVis->stencilBits > 0 && mesaVis->depthBits != 24; |
| struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis); |
| /* |
| * XXX: this value needs to be set according to the config file |
| * setting. But we don't get that until we create a rendering |
| * context!!!! |
| */ |
| GLboolean float_depth = GL_FALSE; |
| |
| { |
| driRenderbuffer *frontRb |
| = driNewRenderbuffer(GL_RGBA, |
| (GLubyte *) screen->aperture.map |
| + 0x01000000 * TARGET_FRONT, |
| screen->cpp, |
| screen->frontOffset, screen->aperturePitch, |
| driDrawPriv); |
| savageSetSpanFunctions(frontRb, mesaVis, float_depth); |
| assert(frontRb->Base.Data); |
| _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base); |
| } |
| |
| if (mesaVis->doubleBufferMode) { |
| driRenderbuffer *backRb |
| = driNewRenderbuffer(GL_RGBA, |
| (GLubyte *) screen->aperture.map |
| + 0x01000000 * TARGET_BACK, |
| screen->cpp, |
| screen->backOffset, screen->aperturePitch, |
| driDrawPriv); |
| savageSetSpanFunctions(backRb, mesaVis, float_depth); |
| assert(backRb->Base.Data); |
| _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base); |
| } |
| |
| if (mesaVis->depthBits == 16) { |
| driRenderbuffer *depthRb |
| = driNewRenderbuffer(GL_DEPTH_COMPONENT16, |
| (GLubyte *) screen->aperture.map |
| + 0x01000000 * TARGET_DEPTH, |
| screen->zpp, |
| screen->depthOffset, screen->aperturePitch, |
| driDrawPriv); |
| savageSetSpanFunctions(depthRb, mesaVis, float_depth); |
| _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base); |
| } |
| else if (mesaVis->depthBits == 24) { |
| driRenderbuffer *depthRb |
| = driNewRenderbuffer(GL_DEPTH_COMPONENT24, |
| (GLubyte *) screen->aperture.map |
| + 0x01000000 * TARGET_DEPTH, |
| screen->zpp, |
| screen->depthOffset, screen->aperturePitch, |
| driDrawPriv); |
| savageSetSpanFunctions(depthRb, mesaVis, float_depth); |
| _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base); |
| } |
| |
| if (mesaVis->stencilBits > 0 && !swStencil) { |
| driRenderbuffer *stencilRb |
| = driNewRenderbuffer(GL_STENCIL_INDEX8_EXT, |
| (GLubyte *) screen->aperture.map |
| + 0x01000000 * TARGET_DEPTH, |
| screen->zpp, |
| screen->depthOffset, screen->aperturePitch, |
| driDrawPriv); |
| savageSetSpanFunctions(stencilRb, mesaVis, float_depth); |
| _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &stencilRb->Base); |
| } |
| |
| _mesa_add_soft_renderbuffers(fb, |
| GL_FALSE, /* color */ |
| GL_FALSE, /* depth */ |
| swStencil, |
| mesaVis->accumRedBits > 0, |
| GL_FALSE, /* alpha */ |
| GL_FALSE /* aux */); |
| driDrawPriv->driverPrivate = (void *) fb; |
| |
| return (driDrawPriv->driverPrivate != NULL); |
| } |
| } |
| |
| static void |
| savageDestroyBuffer(__DRIdrawablePrivate *driDrawPriv) |
| { |
| _mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate))); |
| } |
| |
| #if 0 |
| void XMesaSwapBuffers(__DRIdrawablePrivate *driDrawPriv) |
| { |
| /* XXX should do swap according to the buffer, not the context! */ |
| savageContextPtr imesa = savageCtx; |
| |
| FLUSH_VB( imesa->glCtx, "swap buffers" ); |
| savageSwapBuffers(imesa); |
| } |
| #endif |
| |
| |
| void savageXMesaSetClipRects(savageContextPtr imesa) |
| { |
| __DRIdrawablePrivate *dPriv = imesa->driDrawable; |
| |
| if ((dPriv->numBackClipRects == 0) |
| || (imesa->glCtx->DrawBuffer->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT)) { |
| imesa->numClipRects = dPriv->numClipRects; |
| imesa->pClipRects = dPriv->pClipRects; |
| imesa->drawX = dPriv->x; |
| imesa->drawY = dPriv->y; |
| } else { |
| imesa->numClipRects = dPriv->numBackClipRects; |
| imesa->pClipRects = dPriv->pBackClipRects; |
| imesa->drawX = dPriv->backX; |
| imesa->drawY = dPriv->backY; |
| } |
| |
| savageCalcViewport( imesa->glCtx ); |
| } |
| |
| |
| static void savageXMesaWindowMoved( savageContextPtr imesa ) |
| { |
| __DRIdrawablePrivate *const drawable = imesa->driDrawable; |
| __DRIdrawablePrivate *const readable = imesa->driReadable; |
| |
| if (0) |
| fprintf(stderr, "savageXMesaWindowMoved\n\n"); |
| |
| savageXMesaSetClipRects(imesa); |
| |
| driUpdateFramebufferSize(imesa->glCtx, drawable); |
| if (drawable != readable) { |
| driUpdateFramebufferSize(imesa->glCtx, readable); |
| } |
| } |
| |
| |
| static GLboolean |
| savageUnbindContext(__DRIcontextPrivate *driContextPriv) |
| { |
| savageContextPtr savage = (savageContextPtr) driContextPriv->driverPrivate; |
| if (savage) |
| savage->dirty = ~0; |
| |
| return GL_TRUE; |
| } |
| |
| #if 0 |
| static GLboolean |
| savageOpenFullScreen(__DRIcontextPrivate *driContextPriv) |
| { |
| |
| |
| |
| if (driContextPriv) { |
| savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate; |
| imesa->IsFullScreen = GL_TRUE; |
| imesa->backup_frontOffset = imesa->savageScreen->frontOffset; |
| imesa->backup_backOffset = imesa->savageScreen->backOffset; |
| imesa->backup_frontBitmapDesc = imesa->savageScreen->frontBitmapDesc; |
| imesa->savageScreen->frontBitmapDesc = imesa->savageScreen->backBitmapDesc; |
| imesa->toggle = TARGET_BACK; |
| } |
| |
| return GL_TRUE; |
| } |
| |
| static GLboolean |
| savageCloseFullScreen(__DRIcontextPrivate *driContextPriv) |
| { |
| |
| if (driContextPriv) { |
| savageContextPtr imesa = (savageContextPtr) driContextPriv->driverPrivate; |
| WAIT_IDLE_EMPTY(imesa); |
| imesa->IsFullScreen = GL_FALSE; |
| imesa->savageScreen->frontOffset = imesa->backup_frontOffset; |
| imesa->savageScreen->backOffset = imesa->backup_backOffset; |
| imesa->savageScreen->frontBitmapDesc = imesa->backup_frontBitmapDesc; |
| } |
| return GL_TRUE; |
| } |
| #endif |
| |
| static GLboolean |
| savageMakeCurrent(__DRIcontextPrivate *driContextPriv, |
| __DRIdrawablePrivate *driDrawPriv, |
| __DRIdrawablePrivate *driReadPriv) |
| { |
| if (driContextPriv) { |
| savageContextPtr imesa |
| = (savageContextPtr) driContextPriv->driverPrivate; |
| struct gl_framebuffer *drawBuffer |
| = (GLframebuffer *) driDrawPriv->driverPrivate; |
| struct gl_framebuffer *readBuffer |
| = (GLframebuffer *) driReadPriv->driverPrivate; |
| driRenderbuffer *frontRb = (driRenderbuffer *) |
| drawBuffer->Attachment[BUFFER_FRONT_LEFT].Renderbuffer; |
| driRenderbuffer *backRb = (driRenderbuffer *) |
| drawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer; |
| |
| assert(frontRb->Base.Data); |
| if (imesa->glCtx->Visual.doubleBufferMode) { |
| assert(backRb->Base.Data); |
| } |
| |
| imesa->driReadable = driReadPriv; |
| imesa->driDrawable = driDrawPriv; |
| imesa->dirty = ~0; |
| |
| _mesa_make_current(imesa->glCtx, drawBuffer, readBuffer); |
| |
| savageXMesaWindowMoved( imesa ); |
| } |
| else |
| { |
| _mesa_make_current(NULL, NULL, NULL); |
| } |
| return GL_TRUE; |
| } |
| |
| |
| void savageGetLock( savageContextPtr imesa, GLuint flags ) |
| { |
| __DRIdrawablePrivate *const drawable = imesa->driDrawable; |
| __DRIdrawablePrivate *const readable = imesa->driReadable; |
| __DRIscreenPrivate *sPriv = imesa->driScreen; |
| drm_savage_sarea_t *sarea = imesa->sarea; |
| int me = imesa->hHWContext; |
| int stamp = drawable->lastStamp; |
| int heap; |
| unsigned int timestamp = 0; |
| |
| |
| |
| /* We know there has been contention. |
| */ |
| drmGetLock(imesa->driFd, imesa->hHWContext, flags); |
| |
| |
| /* Note contention for throttling hint |
| */ |
| imesa->any_contend = 1; |
| |
| /* If the window moved, may need to set a new cliprect now. |
| * |
| * NOTE: This releases and regains the hw lock, so all state |
| * checking must be done *after* this call: |
| */ |
| DRI_VALIDATE_DRAWABLE_INFO(sPriv, drawable); |
| if (drawable != readable) { |
| DRI_VALIDATE_DRAWABLE_INFO(sPriv, readable); |
| } |
| |
| |
| /* If we lost context, need to dump all registers to hardware. |
| * Note that we don't care about 2d contexts, even if they perform |
| * accelerated commands, so the DRI locking in the X server is even |
| * more broken than usual. |
| */ |
| if (sarea->ctxOwner != me) { |
| imesa->dirty |= (SAVAGE_UPLOAD_LOCAL | |
| SAVAGE_UPLOAD_GLOBAL | |
| SAVAGE_UPLOAD_FOGTBL | |
| SAVAGE_UPLOAD_TEX0 | |
| SAVAGE_UPLOAD_TEX1 | |
| SAVAGE_UPLOAD_TEXGLOBAL); |
| imesa->lostContext = GL_TRUE; |
| sarea->ctxOwner = me; |
| } |
| |
| for (heap = 0; heap < imesa->lastTexHeap; ++heap) { |
| /* If a heap was changed, update its timestamp. Do this before |
| * DRI_AGE_TEXTURES updates the local_age. */ |
| if (imesa->textureHeaps[heap] && |
| imesa->textureHeaps[heap]->global_age[0] > |
| imesa->textureHeaps[heap]->local_age) { |
| if (timestamp == 0) |
| timestamp = savageEmitEventLocked(imesa, 0); |
| imesa->textureHeaps[heap]->timestamp = timestamp; |
| } |
| DRI_AGE_TEXTURES( imesa->textureHeaps[heap] ); |
| } |
| |
| if (drawable->lastStamp != stamp) { |
| driUpdateFramebufferSize(imesa->glCtx, drawable); |
| savageXMesaWindowMoved( imesa ); |
| } |
| } |
| |
| static const __DRIconfig ** |
| savageFillInModes( __DRIscreenPrivate *psp, |
| unsigned pixel_bits, unsigned depth_bits, |
| unsigned stencil_bits, GLboolean have_back_buffer ) |
| { |
| __DRIconfig **configs; |
| __GLcontextModes * m; |
| unsigned depth_buffer_factor; |
| unsigned back_buffer_factor; |
| GLenum fb_format; |
| GLenum fb_type; |
| int 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. |
| * |
| * FK: What about drivers that don't use page flipping? Could they |
| * just expose GLX_SWAP_COPY_OML? |
| */ |
| static const GLenum back_buffer_modes[] = { |
| GLX_NONE, GLX_SWAP_UNDEFINED_OML /*, GLX_SWAP_COPY_OML */ |
| }; |
| |
| u_int8_t depth_bits_array[2]; |
| u_int8_t stencil_bits_array[2]; |
| |
| |
| depth_bits_array[0] = depth_bits; |
| depth_bits_array[1] = 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. |
| */ |
| stencil_bits_array[0] = 0; |
| stencil_bits_array[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; |
| |
| if ( pixel_bits == 16 ) { |
| fb_format = GL_RGB; |
| fb_type = GL_UNSIGNED_SHORT_5_6_5; |
| } |
| else { |
| fb_format = GL_BGR; |
| fb_type = GL_UNSIGNED_INT_8_8_8_8_REV; |
| } |
| |
| configs = driCreateConfigs(fb_format, fb_type, |
| depth_bits_array, stencil_bits_array, |
| depth_buffer_factor, |
| back_buffer_modes, back_buffer_factor); |
| if (configs == NULL) { |
| fprintf( stderr, "[%s:%u] Error creating FBConfig!\n", |
| __func__, __LINE__ ); |
| return NULL; |
| } |
| |
| /* Mark the visual as slow if there are "fake" stencil bits. |
| */ |
| for (i = 0; configs[i]; i++) { |
| m = &configs[i]->modes; |
| if ((m->stencilBits != 0) && (m->stencilBits != stencil_bits)) { |
| m->visualRating = GLX_SLOW_CONFIG; |
| } |
| } |
| |
| return (const __DRIconfig **) configs; |
| } |
| |
| |
| /** |
| * This is the driver specific part of the createNewScreen entry point. |
| * |
| * \todo maybe fold this into intelInitDriver |
| * |
| * \return the __GLcontextModes supported by this driver |
| */ |
| static const __DRIconfig ** |
| savageInitScreen(__DRIscreenPrivate *psp) |
| { |
| static const __DRIversion ddx_expected = { 2, 0, 0 }; |
| static const __DRIversion dri_expected = { 4, 0, 0 }; |
| static const __DRIversion drm_expected = { 2, 1, 0 }; |
| SAVAGEDRIPtr dri_priv = (SAVAGEDRIPtr)psp->pDevPriv; |
| |
| if ( ! driCheckDriDdxDrmVersions2( "Savage", |
| &psp->dri_version, & dri_expected, |
| &psp->ddx_version, & ddx_expected, |
| &psp->drm_version, & drm_expected ) ) |
| return NULL; |
| |
| /* 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 ); |
| |
| if (!savageInitDriver(psp)) |
| return NULL; |
| |
| return savageFillInModes( psp, |
| dri_priv->cpp*8, |
| (dri_priv->cpp == 2) ? 16 : 24, |
| (dri_priv->cpp == 2) ? 0 : 8, |
| (dri_priv->backOffset != dri_priv->depthOffset) ); |
| } |
| |
| const struct __DriverAPIRec driDriverAPI = { |
| savageInitScreen, |
| savageDestroyScreen, |
| savageCreateContext, |
| savageDestroyContext, |
| savageCreateBuffer, |
| savageDestroyBuffer, |
| savageSwapBuffers, |
| savageMakeCurrent, |
| savageUnbindContext |
| }; |