blob: c271c8ef59ddf0ac25d5500a68611681e47d3df8 [file] [log] [blame]
/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mga_xmesa.c,v 1.19 2003/03/26 20:43:49 tsi Exp $ */
/*
* Copyright 2000-2001 VA Linux Systems, 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
* 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
* VA LINUX SYSTEMS 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.
*/
/**
* \file mga_xmesa.c
* MGA screen and context initialization / creation code.
*
* \author Keith Whitwell <keith@tungstengraphics.com>
*/
#include <stdlib.h>
#include <stdint.h>
#include "drm.h"
#include "mga_drm.h"
#include "mga_xmesa.h"
#include "context.h"
#include "matrix.h"
#include "simple_list.h"
#include "imports.h"
#include "framebuffer.h"
#include "renderbuffer.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 "mgadd.h"
#include "mgastate.h"
#include "mgatex.h"
#include "mgaspan.h"
#include "mgaioctl.h"
#include "mgatris.h"
#include "mgavb.h"
#include "mgapixel.h"
#include "mga_xmesa.h"
#include "mga_dri.h"
#include "utils.h"
#include "vblank.h"
#include "extensions.h"
#include "drirenderbuffer.h"
#include "GL/internal/dri_interface.h"
#define need_GL_ARB_multisample
#define need_GL_ARB_texture_compression
#define need_GL_ARB_vertex_buffer_object
#define need_GL_ARB_vertex_program
#define need_GL_EXT_fog_coord
#define need_GL_EXT_gpu_program_parameters
#define need_GL_EXT_multi_draw_arrays
#define need_GL_EXT_secondary_color
#if 0
#define need_GL_EXT_paletted_texture
#endif
#define need_GL_APPLE_vertex_array_object
#define need_GL_NV_vertex_program
#include "extension_helper.h"
/* MGA 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_QUALITY
DRI_CONF_TEXTURE_DEPTH(DRI_CONF_TEXTURE_DEPTH_FB)
DRI_CONF_COLOR_REDUCTION(DRI_CONF_COLOR_REDUCTION_DITHER)
DRI_CONF_SECTION_END
DRI_CONF_SECTION_SOFTWARE
DRI_CONF_ARB_VERTEX_PROGRAM(true)
DRI_CONF_NV_VERTEX_PROGRAM(true)
DRI_CONF_SECTION_END
DRI_CONF_SECTION_DEBUG
DRI_CONF_NO_RAST(false)
DRI_CONF_SECTION_END
DRI_CONF_END;
static const GLuint __driNConfigOptions = 6;
#ifndef MGA_DEBUG
int MGA_DEBUG = 0;
#endif
static const __DRIconfig **
mgaFillInModes( __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;
/* GLX_SWAP_COPY_OML is only supported because the MGA driver doesn't
* support pageflipping at all.
*/
static const GLenum back_buffer_modes[] = {
GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML
};
u_int8_t depth_bits_array[3];
u_int8_t stencil_bits_array[3];
depth_bits_array[0] = 0;
depth_bits_array[1] = depth_bits;
depth_bits_array[2] = 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] = 0;
stencil_bits_array[2] = (stencil_bits == 0) ? 8 : stencil_bits;
depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 3 : 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;
}
const __DRIextension *mgaScreenExtensions[] = {
&driReadDrawableExtension,
&driSwapControlExtension.base,
&driFrameTrackingExtension.base,
&driMediaStreamCounterExtension.base,
NULL
};
static GLboolean
mgaInitDriver(__DRIscreenPrivate *sPriv)
{
mgaScreenPrivate *mgaScreen;
MGADRIPtr serverInfo = (MGADRIPtr)sPriv->pDevPriv;
if (sPriv->devPrivSize != sizeof(MGADRIRec)) {
fprintf(stderr,"\nERROR! sizeof(MGADRIRec) does not match passed size from device driver\n");
return GL_FALSE;
}
/* Allocate the private area */
mgaScreen = (mgaScreenPrivate *)MALLOC(sizeof(mgaScreenPrivate));
if (!mgaScreen) {
__driUtilMessage("Couldn't malloc screen struct");
return GL_FALSE;
}
mgaScreen->sPriv = sPriv;
sPriv->private = (void *)mgaScreen;
if (sPriv->drm_version.minor >= 1) {
int ret;
drm_mga_getparam_t gp;
gp.param = MGA_PARAM_IRQ_NR;
gp.value = &mgaScreen->irq;
mgaScreen->irq = 0;
ret = drmCommandWriteRead( sPriv->fd, DRM_MGA_GETPARAM,
&gp, sizeof(gp));
if (ret) {
fprintf(stderr, "drmMgaGetParam (MGA_PARAM_IRQ_NR): %d\n", ret);
FREE(mgaScreen);
sPriv->private = NULL;
return GL_FALSE;
}
}
sPriv->extensions = mgaScreenExtensions;
if (serverInfo->chipset != MGA_CARD_TYPE_G200 &&
serverInfo->chipset != MGA_CARD_TYPE_G400) {
FREE(mgaScreen);
sPriv->private = NULL;
__driUtilMessage("Unrecognized chipset");
return GL_FALSE;
}
mgaScreen->chipset = serverInfo->chipset;
mgaScreen->cpp = serverInfo->cpp;
mgaScreen->agpMode = serverInfo->agpMode;
mgaScreen->frontPitch = serverInfo->frontPitch;
mgaScreen->frontOffset = serverInfo->frontOffset;
mgaScreen->backOffset = serverInfo->backOffset;
mgaScreen->backPitch = serverInfo->backPitch;
mgaScreen->depthOffset = serverInfo->depthOffset;
mgaScreen->depthPitch = serverInfo->depthPitch;
/* The only reason that the MMIO region needs to be accessable and the
* primary DMA region base address needs to be known is so that the driver
* can busy wait for certain DMA operations to complete (see
* mgaWaitForFrameCompletion in mgaioctl.c).
*
* Starting with MGA DRM version 3.2, these are completely unneeded as
* there is a new, in-kernel mechanism for handling the wait.
*/
if (mgaScreen->sPriv->drm_version.minor < 2) {
mgaScreen->mmio.handle = serverInfo->registers.handle;
mgaScreen->mmio.size = serverInfo->registers.size;
if ( drmMap( sPriv->fd,
mgaScreen->mmio.handle, mgaScreen->mmio.size,
&mgaScreen->mmio.map ) < 0 ) {
FREE( mgaScreen );
sPriv->private = NULL;
__driUtilMessage( "Couldn't map MMIO registers" );
return GL_FALSE;
}
mgaScreen->primary.handle = serverInfo->primary.handle;
mgaScreen->primary.size = serverInfo->primary.size;
}
else {
(void) memset( & mgaScreen->primary, 0, sizeof( mgaScreen->primary ) );
(void) memset( & mgaScreen->mmio, 0, sizeof( mgaScreen->mmio ) );
}
mgaScreen->textureOffset[MGA_CARD_HEAP] = serverInfo->textureOffset;
mgaScreen->textureOffset[MGA_AGP_HEAP] = (serverInfo->agpTextureOffset |
PDEA_pagpxfer_enable | 1);
mgaScreen->textureSize[MGA_CARD_HEAP] = serverInfo->textureSize;
mgaScreen->textureSize[MGA_AGP_HEAP] = serverInfo->agpTextureSize;
/* The texVirtual array stores the base addresses in the CPU's address
* space of the texture memory pools. The base address of the on-card
* memory pool is calculated as an offset of the base of video memory. The
* AGP texture pool has to be mapped into the processes address space by
* the DRM.
*/
mgaScreen->texVirtual[MGA_CARD_HEAP] = (char *)(mgaScreen->sPriv->pFB +
serverInfo->textureOffset);
if ( serverInfo->agpTextureSize > 0 ) {
if (drmMap(sPriv->fd, serverInfo->agpTextureOffset,
serverInfo->agpTextureSize,
(drmAddress *)&mgaScreen->texVirtual[MGA_AGP_HEAP]) != 0) {
FREE(mgaScreen);
sPriv->private = NULL;
__driUtilMessage("Couldn't map agptexture region");
return GL_FALSE;
}
}
/* For calculating setupdma addresses.
*/
mgaScreen->bufs = drmMapBufs(sPriv->fd);
if (!mgaScreen->bufs) {
FREE(mgaScreen);
sPriv->private = NULL;
__driUtilMessage("Couldn't map dma buffers");
return GL_FALSE;
}
mgaScreen->sarea_priv_offset = serverInfo->sarea_priv_offset;
/* parse information in __driConfigOptions */
driParseOptionInfo (&mgaScreen->optionCache,
__driConfigOptions, __driNConfigOptions);
return GL_TRUE;
}
static void
mgaDestroyScreen(__DRIscreenPrivate *sPriv)
{
mgaScreenPrivate *mgaScreen = (mgaScreenPrivate *) sPriv->private;
if (MGA_DEBUG&DEBUG_VERBOSE_DRI)
fprintf(stderr, "mgaDestroyScreen\n");
drmUnmapBufs(mgaScreen->bufs);
/* free all option information */
driDestroyOptionInfo (&mgaScreen->optionCache);
FREE(mgaScreen);
sPriv->private = NULL;
}
extern const struct tnl_pipeline_stage _mga_render_stage;
static const struct tnl_pipeline_stage *mga_pipeline[] = {
&_tnl_vertex_transform_stage,
&_tnl_normal_transform_stage,
&_tnl_lighting_stage,
&_tnl_fog_coordinate_stage,
&_tnl_texgen_stage,
&_tnl_texture_transform_stage,
&_tnl_vertex_program_stage,
/* REMOVE: point attenuation stage */
#if 0
&_mga_render_stage, /* ADD: unclipped rastersetup-to-dma */
/* Need new ioctl for wacceptseq */
#endif
&_tnl_render_stage,
0,
};
static const struct dri_extension g400_extensions[] =
{
{ "GL_ARB_multitexture", NULL },
{ "GL_ARB_texture_env_add", NULL },
{ "GL_ARB_texture_env_combine", NULL },
{ "GL_ARB_texture_env_crossbar", NULL },
{ "GL_EXT_texture_env_combine", NULL },
{ "GL_EXT_texture_edge_clamp", NULL },
{ "GL_ATI_texture_env_combine3", NULL },
{ NULL, NULL }
};
static const struct dri_extension card_extensions[] =
{
{ "GL_ARB_multisample", GL_ARB_multisample_functions },
{ "GL_ARB_texture_compression", GL_ARB_texture_compression_functions },
{ "GL_ARB_texture_rectangle", NULL },
{ "GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions },
{ "GL_EXT_blend_logic_op", NULL },
{ "GL_EXT_fog_coord", GL_EXT_fog_coord_functions },
{ "GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions },
/* paletted_textures currently doesn't work, but we could fix them later */
#if defined( need_GL_EXT_paletted_texture )
{ "GL_EXT_shared_texture_palette", NULL },
{ "GL_EXT_paletted_texture", GL_EXT_paletted_texture_functions },
#endif
{ "GL_EXT_secondary_color", GL_EXT_secondary_color_functions },
{ "GL_EXT_stencil_wrap", NULL },
{ "GL_APPLE_vertex_array_object", GL_APPLE_vertex_array_object_functions },
{ "GL_MESA_ycbcr_texture", NULL },
{ "GL_SGIS_generate_mipmap", NULL },
{ NULL, NULL }
};
static const struct dri_extension ARB_vp_extensions[] = {
{ "GL_ARB_vertex_program", GL_ARB_vertex_program_functions },
{ "GL_EXT_gpu_program_parameters", GL_EXT_gpu_program_parameters_functions },
{ NULL, NULL }
};
static const struct dri_extension NV_vp_extensions[] = {
{ "GL_NV_vertex_program", GL_NV_vertex_program_functions },
{ "GL_NV_vertex_program1_1", NULL },
{ NULL, NULL }
};
static const struct dri_debug_control debug_control[] =
{
{ "fall", DEBUG_VERBOSE_FALLBACK },
{ "tex", DEBUG_VERBOSE_TEXTURE },
{ "ioctl", DEBUG_VERBOSE_IOCTL },
{ "verb", DEBUG_VERBOSE_MSG },
{ "dri", DEBUG_VERBOSE_DRI },
{ NULL, 0 }
};
static GLboolean
mgaCreateContext( const __GLcontextModes *mesaVis,
__DRIcontextPrivate *driContextPriv,
void *sharedContextPrivate )
{
int i;
unsigned maxlevels;
GLcontext *ctx, *shareCtx;
mgaContextPtr mmesa;
__DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
mgaScreenPrivate *mgaScreen = (mgaScreenPrivate *)sPriv->private;
drm_mga_sarea_t *saPriv = (drm_mga_sarea_t *)(((char*)sPriv->pSAREA)+
mgaScreen->sarea_priv_offset);
struct dd_function_table functions;
if (MGA_DEBUG&DEBUG_VERBOSE_DRI)
fprintf(stderr, "mgaCreateContext\n");
/* allocate mga context */
mmesa = (mgaContextPtr) CALLOC(sizeof(mgaContext));
if (!mmesa) {
return GL_FALSE;
}
/* Init default driver functions then plug in our Radeon-specific functions
* (the texture functions are especially important)
*/
_mesa_init_driver_functions( &functions );
mgaInitDriverFuncs( &functions );
mgaInitTextureFuncs( &functions );
mgaInitIoctlFuncs( &functions );
/* Allocate the Mesa context */
if (sharedContextPrivate)
shareCtx = ((mgaContextPtr) sharedContextPrivate)->glCtx;
else
shareCtx = NULL;
mmesa->glCtx = _mesa_create_context(mesaVis, shareCtx,
&functions, (void *) mmesa);
if (!mmesa->glCtx) {
FREE(mmesa);
return GL_FALSE;
}
driContextPriv->driverPrivate = mmesa;
/* Init mga state */
mmesa->hHWContext = driContextPriv->hHWContext;
mmesa->driFd = sPriv->fd;
mmesa->driHwLock = &sPriv->pSAREA->lock;
mmesa->mgaScreen = mgaScreen;
mmesa->driScreen = sPriv;
mmesa->sarea = (void *)saPriv;
/* Parse configuration files */
driParseConfigFiles (&mmesa->optionCache, &mgaScreen->optionCache,
sPriv->myNum, "mga");
(void) memset( mmesa->texture_heaps, 0, sizeof( mmesa->texture_heaps ) );
make_empty_list( & mmesa->swapped );
mmesa->nr_heaps = mgaScreen->texVirtual[MGA_AGP_HEAP] ? 2 : 1;
for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) {
mmesa->texture_heaps[i] = driCreateTextureHeap( i, mmesa,
mgaScreen->textureSize[i],
6,
MGA_NR_TEX_REGIONS,
(drmTextureRegionPtr)mmesa->sarea->texList[i],
&mmesa->sarea->texAge[i],
&mmesa->swapped,
sizeof( mgaTextureObject_t ),
(destroy_texture_object_t *) mgaDestroyTexObj );
}
/* Set the maximum texture size small enough that we can guarentee
* that both texture units can bind a maximal texture and have them
* on the card at once.
*/
ctx = mmesa->glCtx;
if ( mgaScreen->chipset == MGA_CARD_TYPE_G200 ) {
ctx->Const.MaxTextureUnits = 1;
ctx->Const.MaxTextureImageUnits = 1;
ctx->Const.MaxTextureCoordUnits = 1;
maxlevels = G200_TEX_MAXLEVELS;
}
else {
ctx->Const.MaxTextureUnits = 2;
ctx->Const.MaxTextureImageUnits = 2;
ctx->Const.MaxTextureCoordUnits = 2;
maxlevels = G400_TEX_MAXLEVELS;
}
driCalculateMaxTextureLevels( mmesa->texture_heaps,
mmesa->nr_heaps,
& ctx->Const,
4,
11, /* max 2D texture size is 2048x2048 */
0, /* 3D textures unsupported. */
0, /* cube textures unsupported. */
11, /* max texture rect size is 2048x2048 */
maxlevels,
GL_FALSE,
0 );
ctx->Const.MinLineWidth = 1.0;
ctx->Const.MinLineWidthAA = 1.0;
ctx->Const.MaxLineWidth = 10.0;
ctx->Const.MaxLineWidthAA = 10.0;
ctx->Const.LineWidthGranularity = 1.0;
mmesa->texture_depth = driQueryOptioni (&mmesa->optionCache,
"texture_depth");
if (mmesa->texture_depth == DRI_CONF_TEXTURE_DEPTH_FB)
mmesa->texture_depth = ( mesaVis->rgbBits >= 24 ) ?
DRI_CONF_TEXTURE_DEPTH_32 : DRI_CONF_TEXTURE_DEPTH_16;
mmesa->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24;
switch (mesaVis->depthBits) {
case 16:
mmesa->depth_scale = 1.0/(GLdouble)0xffff;
mmesa->depth_clear_mask = ~0;
mmesa->ClearDepth = 0xffff;
break;
case 24:
mmesa->depth_scale = 1.0/(GLdouble)0xffffff;
if (mmesa->hw_stencil) {
mmesa->depth_clear_mask = 0xffffff00;
mmesa->stencil_clear_mask = 0x000000ff;
} else
mmesa->depth_clear_mask = ~0;
mmesa->ClearDepth = 0xffffff00;
break;
case 32:
mmesa->depth_scale = 1.0/(GLdouble)0xffffffff;
mmesa->depth_clear_mask = ~0;
mmesa->ClearDepth = 0xffffffff;
break;
};
mmesa->haveHwStipple = GL_FALSE;
mmesa->RenderIndex = -1; /* impossible value */
mmesa->dirty = ~0;
mmesa->vertex_format = 0;
mmesa->CurrentTexObj[0] = 0;
mmesa->CurrentTexObj[1] = 0;
mmesa->tmu_source[0] = 0;
mmesa->tmu_source[1] = 1;
mmesa->texAge[0] = 0;
mmesa->texAge[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, mga_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 );
mmesa->primary_offset = mmesa->mgaScreen->primary.handle;
ctx->DriverCtx = (void *) mmesa;
mmesa->glCtx = ctx;
driInitExtensions( ctx, card_extensions, GL_FALSE );
if (MGA_IS_G400(MGA_CONTEXT(ctx))) {
driInitExtensions( ctx, g400_extensions, GL_FALSE );
}
if ( driQueryOptionb( &mmesa->optionCache, "arb_vertex_program" ) ) {
driInitExtensions(ctx, ARB_vp_extensions, GL_FALSE);
}
if ( driQueryOptionb( &mmesa->optionCache, "nv_vertex_program" ) ) {
driInitExtensions( ctx, NV_vp_extensions, GL_FALSE );
}
/* XXX these should really go right after _mesa_init_driver_functions() */
mgaDDInitStateFuncs( ctx );
mgaDDInitSpanFuncs( ctx );
mgaDDInitPixelFuncs( ctx );
mgaDDInitTriFuncs( ctx );
mgaInitVB( ctx );
mgaInitState( mmesa );
driContextPriv->driverPrivate = (void *) mmesa;
#if DO_DEBUG
MGA_DEBUG = driParseDebugString( getenv( "MGA_DEBUG" ),
debug_control );
#endif
(*sPriv->systemTime->getUST)( & mmesa->swap_ust );
if (driQueryOptionb(&mmesa->optionCache, "no_rast")) {
fprintf(stderr, "disabling 3D acceleration\n");
FALLBACK(mmesa->glCtx, MGA_FALLBACK_DISABLE, 1);
}
return GL_TRUE;
}
static void
mgaDestroyContext(__DRIcontextPrivate *driContextPriv)
{
mgaContextPtr mmesa = (mgaContextPtr) driContextPriv->driverPrivate;
if (MGA_DEBUG&DEBUG_VERBOSE_DRI)
fprintf( stderr, "[%s:%d] mgaDestroyContext start\n",
__FILE__, __LINE__ );
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 );
mgaFreeVB( mmesa->glCtx );
/* free the Mesa context */
mmesa->glCtx->DriverCtx = NULL;
_mesa_destroy_context(mmesa->glCtx);
if ( release_texture_heaps ) {
/* This share group is about to go away, free our private
* texture object data.
*/
int i;
for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) {
driDestroyTextureHeap( mmesa->texture_heaps[ i ] );
mmesa->texture_heaps[ i ] = NULL;
}
assert( is_empty_list( & mmesa->swapped ) );
}
/* free the option cache */
driDestroyOptionCache (&mmesa->optionCache);
FREE(mmesa);
}
if (MGA_DEBUG&DEBUG_VERBOSE_DRI)
fprintf( stderr, "[%s:%d] mgaDestroyContext done\n",
__FILE__, __LINE__ );
}
static GLboolean
mgaCreateBuffer( __DRIscreenPrivate *driScrnPriv,
__DRIdrawablePrivate *driDrawPriv,
const __GLcontextModes *mesaVis,
GLboolean isPixmap )
{
mgaScreenPrivate *screen = (mgaScreenPrivate *) driScrnPriv->private;
if (isPixmap) {
return GL_FALSE; /* not implemented */
}
else {
GLboolean swStencil = (mesaVis->stencilBits > 0 &&
mesaVis->depthBits != 24);
#if 0
driDrawPriv->driverPrivate = (void *)
_mesa_create_framebuffer(mesaVis,
GL_FALSE, /* software depth buffer? */
swStencil,
mesaVis->accumRedBits > 0,
mesaVis->alphaBits > 0 );
#else
struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis);
{
driRenderbuffer *frontRb
= driNewRenderbuffer(GL_RGBA,
NULL,
screen->cpp,
screen->frontOffset, screen->frontPitch,
driDrawPriv);
mgaSetSpanFunctions(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);
mgaSetSpanFunctions(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);
mgaSetSpanFunctions(depthRb, mesaVis);
_mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
}
else if (mesaVis->depthBits == 24) {
/* XXX is this right? */
if (mesaVis->stencilBits) {
driRenderbuffer *depthRb
= driNewRenderbuffer(GL_DEPTH_COMPONENT24,
NULL,
screen->cpp,
screen->depthOffset, screen->depthPitch,
driDrawPriv);
mgaSetSpanFunctions(depthRb, mesaVis);
_mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
}
else {
driRenderbuffer *depthRb
= driNewRenderbuffer(GL_DEPTH_COMPONENT32,
NULL,
screen->cpp,
screen->depthOffset, screen->depthPitch,
driDrawPriv);
mgaSetSpanFunctions(depthRb, mesaVis);
_mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
}
}
else if (mesaVis->depthBits == 32) {
driRenderbuffer *depthRb
= driNewRenderbuffer(GL_DEPTH_COMPONENT32,
NULL,
screen->cpp,
screen->depthOffset, screen->depthPitch,
driDrawPriv);
mgaSetSpanFunctions(depthRb, mesaVis);
_mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base);
}
if (mesaVis->stencilBits > 0 && !swStencil) {
driRenderbuffer *stencilRb
= driNewRenderbuffer(GL_STENCIL_INDEX8_EXT,
NULL,
screen->cpp,
screen->depthOffset, screen->depthPitch,
driDrawPriv);
mgaSetSpanFunctions(stencilRb, mesaVis);
_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;
#endif
return (driDrawPriv->driverPrivate != NULL);
}
}
static void
mgaDestroyBuffer(__DRIdrawablePrivate *driDrawPriv)
{
_mesa_unreference_framebuffer((GLframebuffer **)(&(driDrawPriv->driverPrivate)));
}
static void
mgaSwapBuffers(__DRIdrawablePrivate *dPriv)
{
if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
mgaContextPtr mmesa;
GLcontext *ctx;
mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
ctx = mmesa->glCtx;
if (ctx->Visual.doubleBufferMode) {
_mesa_notifySwapBuffers( ctx );
mgaCopyBuffer( 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!\n", __FUNCTION__);
}
}
static GLboolean
mgaUnbindContext(__DRIcontextPrivate *driContextPriv)
{
mgaContextPtr mmesa = (mgaContextPtr) driContextPriv->driverPrivate;
if (mmesa)
mmesa->dirty = ~0;
return GL_TRUE;
}
/* This looks buggy to me - the 'b' variable isn't used anywhere...
* Hmm - It seems that the drawable is already hooked in to
* driDrawablePriv.
*
* But why are we doing context initialization here???
*/
static GLboolean
mgaMakeCurrent(__DRIcontextPrivate *driContextPriv,
__DRIdrawablePrivate *driDrawPriv,
__DRIdrawablePrivate *driReadPriv)
{
if (driContextPriv) {
mgaContextPtr mmesa = (mgaContextPtr) driContextPriv->driverPrivate;
if (mmesa->driDrawable != driDrawPriv) {
if (driDrawPriv->swap_interval == (unsigned)-1) {
driDrawPriv->vblFlags = (mmesa->mgaScreen->irq == 0)
? VBLANK_FLAG_NO_IRQ
: driGetDefaultVBlankFlags(&mmesa->optionCache);
driDrawableInitVBlank( driDrawPriv );
}
mmesa->driDrawable = driDrawPriv;
mmesa->dirty = ~0;
mmesa->dirty_cliprects = (MGA_FRONT|MGA_BACK);
}
mmesa->driReadable = driReadPriv;
_mesa_make_current(mmesa->glCtx,
(GLframebuffer *) driDrawPriv->driverPrivate,
(GLframebuffer *) driReadPriv->driverPrivate);
}
else {
_mesa_make_current(NULL, NULL, NULL);
}
return GL_TRUE;
}
void mgaGetLock( mgaContextPtr mmesa, GLuint flags )
{
__DRIdrawablePrivate *dPriv = mmesa->driDrawable;
drm_mga_sarea_t *sarea = mmesa->sarea;
int me = mmesa->hHWContext;
int i;
drmGetLock(mmesa->driFd, mmesa->hHWContext, flags);
DRI_VALIDATE_DRAWABLE_INFO( mmesa->driScreen, dPriv );
if (*(dPriv->pStamp) != mmesa->lastStamp) {
mmesa->lastStamp = *(dPriv->pStamp);
mmesa->SetupNewInputs |= VERT_BIT_POS;
mmesa->dirty_cliprects = (MGA_FRONT|MGA_BACK);
mgaUpdateRects( mmesa, (MGA_FRONT|MGA_BACK) );
driUpdateFramebufferSize(mmesa->glCtx, dPriv);
}
mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS;
mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT;
if (sarea->ctxOwner != me) {
mmesa->dirty |= (MGA_UPLOAD_CONTEXT | MGA_UPLOAD_TEX0 |
MGA_UPLOAD_TEX1 | MGA_UPLOAD_PIPE);
sarea->ctxOwner=me;
}
for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) {
DRI_AGE_TEXTURES( mmesa->texture_heaps[ i ] );
}
}
/**
* 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 **mgaInitScreen(__DRIscreen *psp)
{
static const __DRIversion ddx_expected = { 1, 2, 0 };
static const __DRIversion dri_expected = { 4, 0, 0 };
static const __DRIversion drm_expected = { 3, 0, 0 };
MGADRIPtr dri_priv = (MGADRIPtr) psp->pDevPriv;
if ( ! driCheckDriDdxDrmVersions2( "MGA",
&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 );
driInitExtensions( NULL, g400_extensions, GL_FALSE );
driInitExtensions(NULL, ARB_vp_extensions, GL_FALSE);
driInitExtensions( NULL, NV_vp_extensions, GL_FALSE );
if (!mgaInitDriver(psp))
return NULL;
return mgaFillInModes( psp,
dri_priv->cpp * 8,
(dri_priv->cpp == 2) ? 16 : 24,
(dri_priv->cpp == 2) ? 0 : 8,
(dri_priv->backOffset != dri_priv->depthOffset) );
}
/**
* Get information about previous buffer swaps.
*/
static int
getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo )
{
mgaContextPtr mmesa;
if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL)
|| (dPriv->driContextPriv->driverPrivate == NULL)
|| (sInfo == NULL) ) {
return -1;
}
mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate;
sInfo->swap_count = mmesa->swap_count;
sInfo->swap_ust = mmesa->swap_ust;
sInfo->swap_missed_count = mmesa->swap_missed_count;
sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0)
? driCalculateSwapUsage( dPriv, 0, mmesa->swap_missed_ust )
: 0.0;
return 0;
}
const struct __DriverAPIRec driDriverAPI = {
.InitScreen = mgaInitScreen,
.DestroyScreen = mgaDestroyScreen,
.CreateContext = mgaCreateContext,
.DestroyContext = mgaDestroyContext,
.CreateBuffer = mgaCreateBuffer,
.DestroyBuffer = mgaDestroyBuffer,
.SwapBuffers = mgaSwapBuffers,
.MakeCurrent = mgaMakeCurrent,
.UnbindContext = mgaUnbindContext,
.GetSwapInfo = getSwapInfo,
.GetDrawableMSC = driDrawableGetMSC32,
.WaitForMSC = driWaitForMSC32,
.WaitForSBC = NULL,
.SwapBuffersMSC = NULL
};