#include "glheader.h"
#include "api_arrayelt.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 "array_cache/acache.h"
#include "tnl/tnl.h"
#include "tnl/t_pipeline.h"
#include "radeon_context.h"
#include "radeon_ioctl.h"
#include "radeon_state.h"
#include "radeon_span.h"
#include "radeon_tex.h"
#include "radeon_swtcl.h"
#include "radeon_tcl.h"
#include "radeon_vtxfmt.h"
#include "radeon_maos.h"
#define DRIVER_DATE "20030328"
#include "vblank.h"
#include "utils.h"
#ifndef RADEON_DEBUG
int RADEON_DEBUG = (0);
#endif
static void radeonGetBufferSize( GLframebuffer *buffer,
GLuint *width, GLuint *height )
{
GET_CURRENT_CONTEXT(ctx);
radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
LOCK_HARDWARE( rmesa );
*width = rmesa->dri.drawable->w;
*height = rmesa->dri.drawable->h;
UNLOCK_HARDWARE( rmesa );
}
static const GLubyte *radeonGetString( GLcontext *ctx, GLenum name )
{
radeonContextPtr rmesa = RADEON_CONTEXT(ctx);
static char buffer[128];
unsigned offset;
GLuint agp_mode = rmesa->radeonScreen->IsPCI ? 0 :
rmesa->radeonScreen->AGPMode;
switch ( name ) {
case GL_VENDOR:
return (GLubyte *)"Tungsten Graphics, Inc.";
case GL_RENDERER:
offset = driGetRendererString( buffer, "Radeon", DRIVER_DATE,
agp_mode );
sprintf( & buffer[ offset ], " %sTCL",
!(rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE)
? "" : "NO-" );
return (GLubyte *)buffer;
default:
return NULL;
}
}
static const char * const card_extensions[] =
{
"GL_ARB_multisample",
"GL_ARB_multitexture",
"GL_ARB_texture_border_clamp",
"GL_ARB_texture_compression",
"GL_ARB_texture_env_add",
"GL_ARB_texture_env_combine",
"GL_ARB_texture_env_dot3",
"GL_ARB_texture_mirrored_repeat",
"GL_EXT_blend_logic_op",
"GL_EXT_blend_subtract",
"GL_EXT_secondary_color",
"GL_EXT_texture_edge_clamp",
"GL_EXT_texture_env_add",
"GL_EXT_texture_env_combine",
"GL_EXT_texture_env_dot3",
"GL_EXT_texture_filter_anisotropic",
"GL_EXT_texture_lod_bias",
"GL_ATI_texture_env_combine3",
"GL_ATI_texture_mirror_once",
"GL_IBM_texture_mirrored_repeat",
"GL_MESA_ycbcr_texture",
"GL_NV_blend_square",
"GL_SGIS_generate_mipmap",
"GL_SGIS_texture_border_clamp",
"GL_SGIS_texture_edge_clamp",
NULL
};
extern const struct gl_pipeline_stage _radeon_texrect_stage;
extern const struct gl_pipeline_stage _radeon_render_stage;
extern const struct gl_pipeline_stage _radeon_tcl_stage;
static const struct gl_pipeline_stage *radeon_pipeline[] = {
&_radeon_tcl_stage,
&_tnl_vertex_transform_stage,
&_tnl_normal_transform_stage,
&_tnl_lighting_stage,
&_tnl_fog_coordinate_stage,
&_tnl_texgen_stage,
&_tnl_texture_transform_stage,
&_radeon_texrect_stage,
&_radeon_render_stage,
&_tnl_render_stage,
0,
};
static void radeonInitDriverFuncs( GLcontext *ctx )
{
ctx->Driver.GetBufferSize = radeonGetBufferSize;
ctx->Driver.ResizeBuffers = _swrast_alloc_buffers;
ctx->Driver.GetString = radeonGetString;
ctx->Driver.Error = NULL;
ctx->Driver.DrawPixels = NULL;
ctx->Driver.Bitmap = NULL;
}
static const struct dri_debug_control debug_control[] =
{
{ "fall", DEBUG_FALLBACKS },
{ "tex", DEBUG_TEXTURE },
{ "ioctl", DEBUG_IOCTL },
{ "prim", DEBUG_PRIMS },
{ "vert", DEBUG_VERTS },
{ "state", DEBUG_STATE },
{ "code", DEBUG_CODEGEN },
{ "vfmt", DEBUG_VFMT },
{ "vtxf", DEBUG_VFMT },
{ "verb", DEBUG_VERBOSE },
{ "dri", DEBUG_DRI },
{ "dma", DEBUG_DMA },
{ "san", DEBUG_SANITY },
{ NULL, 0 }
};
static int
get_ust_nop( int64_t * ust )
{
*ust = 1;
return 0;
}
GLboolean
radeonCreateContext( const __GLcontextModes *glVisual,
__DRIcontextPrivate *driContextPriv,
void *sharedContextPrivate)
{
__DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv;
radeonScreenPtr screen = (radeonScreenPtr)(sPriv->private);
radeonContextPtr rmesa;
GLcontext *ctx, *shareCtx;
int i;
assert(glVisual);
assert(driContextPriv);
assert(screen);
rmesa = (radeonContextPtr) CALLOC( sizeof(*rmesa) );
if ( !rmesa )
return GL_FALSE;
if (sharedContextPrivate)
shareCtx = ((radeonContextPtr) sharedContextPrivate)->glCtx;
else
shareCtx = NULL;
rmesa->glCtx = _mesa_create_context(glVisual, shareCtx, (void *) rmesa, GL_TRUE);
if (!rmesa->glCtx) {
FREE(rmesa);
return GL_FALSE;
}
driContextPriv->driverPrivate = rmesa;
rmesa->dri.context = driContextPriv;
rmesa->dri.screen = sPriv;
rmesa->dri.drawable = NULL;
rmesa->dri.hwContext = driContextPriv->hHWContext;
rmesa->dri.hwLock = &sPriv->pSAREA->lock;
rmesa->dri.fd = sPriv->fd;
rmesa->dri.drmMinor = sPriv->drmMinor;
rmesa->radeonScreen = screen;
rmesa->sarea = (RADEONSAREAPrivPtr)((GLubyte *)sPriv->pSAREA +
screen->sarea_priv_offset);
rmesa->dma.buf0_address = rmesa->radeonScreen->buffers->list[0].address;
(void) memset( rmesa->texture_heaps, 0, sizeof( rmesa->texture_heaps ) );
make_empty_list( & rmesa->swapped );
rmesa->nr_heaps = screen->numTexHeaps;
for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
rmesa->texture_heaps[i] = driCreateTextureHeap( i, rmesa,
screen->texSize[i],
12,
RADEON_NR_TEX_REGIONS,
rmesa->sarea->texList[i],
& rmesa->sarea->texAge[i],
& rmesa->swapped,
sizeof( radeonTexObj ),
(destroy_texture_object_t *) radeonDestroyTexObj );
driSetTextureSwapCounterLocation( rmesa->texture_heaps[i],
& rmesa->c_textureSwaps );
}
rmesa->swtcl.RenderIndex = ~0;
rmesa->lost_context = 1;
ctx = rmesa->glCtx;
ctx->Const.MaxTextureUnits = 2;
driCalculateMaxTextureLevels( rmesa->texture_heaps,
rmesa->nr_heaps,
& ctx->Const,
4,
11,
0,
0,
11,
12,
GL_FALSE );
ctx->Const.MaxTextureMaxAnisotropy = 16.0;
ctx->Const.MinPointSize = 1.0;
ctx->Const.MinPointSizeAA = 1.0;
ctx->Const.MaxPointSize = 1.0;
ctx->Const.MaxPointSizeAA = 1.0;
ctx->Const.MinLineWidth = 1.0;
ctx->Const.MinLineWidthAA = 1.0;
ctx->Const.MaxLineWidth = 10.0;
ctx->Const.MaxLineWidthAA = 10.0;
ctx->Const.LineWidthGranularity = 0.0625;
ctx->Const.MaxArrayLockSize =
MIN2( ctx->Const.MaxArrayLockSize,
RADEON_BUFFER_SIZE / RADEON_MAX_TCL_VERTSIZE );
rmesa->boxes = (getenv("LIBGL_PERFORMANCE_BOXES") != NULL);
_swrast_CreateContext( ctx );
_ac_CreateContext( ctx );
_tnl_CreateContext( ctx );
_swsetup_CreateContext( ctx );
_ae_create_context( ctx );
_tnl_destroy_pipeline( ctx );
_tnl_install_pipeline( ctx, radeon_pipeline );
ctx->Driver.FlushVertices = radeonFlushVertices;
_tnl_isolate_materials( ctx, GL_TRUE );
_tnl_isolate_materials( ctx, GL_TRUE );
_swrast_allow_pixel_fog( ctx, GL_FALSE );
_swrast_allow_vertex_fog( ctx, GL_TRUE );
_math_matrix_ctr( &rmesa->TexGenMatrix[0] );
_math_matrix_ctr( &rmesa->TexGenMatrix[1] );
_math_matrix_ctr( &rmesa->tmpmat );
_math_matrix_set_identity( &rmesa->TexGenMatrix[0] );
_math_matrix_set_identity( &rmesa->TexGenMatrix[1] );
_math_matrix_set_identity( &rmesa->tmpmat );
driInitExtensions( ctx, card_extensions, GL_TRUE );
if (rmesa->dri.drmMinor >= 9)
_mesa_enable_extension( ctx, "GL_NV_texture_rectangle");
radeonInitDriverFuncs( ctx );
radeonInitIoctlFuncs( ctx );
radeonInitStateFuncs( ctx );
radeonInitSpanFuncs( ctx );
radeonInitTextureFuncs( ctx );
radeonInitState( rmesa );
radeonInitSwtcl( ctx );
rmesa->iw.irq_seq = -1;
rmesa->irqsEmitted = 0;
rmesa->do_irqs = (rmesa->radeonScreen->irq && !getenv("RADEON_NO_IRQS"));
rmesa->do_usleeps = !getenv("RADEON_NO_USLEEPS");
rmesa->vblank_flags = (rmesa->radeonScreen->irq != 0)
? driGetDefaultVBlankFlags() : VBLANK_FLAG_NO_IRQ;
rmesa->get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( (const GLubyte *) "__glXGetUST" );
if ( rmesa->get_ust == NULL ) {
rmesa->get_ust = get_ust_nop;
}
(*rmesa->get_ust)( & rmesa->swap_ust );
#if DO_DEBUG
RADEON_DEBUG = driParseDebugString( getenv( "RADEON_DEBUG" ),
debug_control );
#endif
if (getenv("RADEON_NO_RAST")) {
fprintf(stderr, "disabling 3D acceleration\n");
FALLBACK(rmesa, RADEON_FALLBACK_DISABLE, 1);
}
else if (getenv("RADEON_TCL_FORCE_ENABLE")) {
fprintf(stderr, "Enabling TCL support... this will probably crash\n");
fprintf(stderr, " your card if it isn't capable of TCL!\n");
rmesa->radeonScreen->chipset |= RADEON_CHIPSET_TCL;
} else if (getenv("RADEON_TCL_FORCE_DISABLE") ||
!(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) {
rmesa->radeonScreen->chipset &= ~RADEON_CHIPSET_TCL;
fprintf(stderr, "disabling TCL support\n");
TCL_FALLBACK(rmesa->glCtx, RADEON_TCL_FALLBACK_TCL_DISABLE, 1);
}
if (rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL) {
if (!getenv("RADEON_NO_VTXFMT"))
radeonVtxfmtInit( ctx );
_tnl_need_dlist_norm_lengths( ctx, GL_FALSE );
}
return GL_TRUE;
}
void radeonDestroyContext( __DRIcontextPrivate *driContextPriv )
{
GET_CURRENT_CONTEXT(ctx);
radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate;
radeonContextPtr current = ctx ? RADEON_CONTEXT(ctx) : NULL;
if (rmesa == current) {
RADEON_FIREVERTICES( rmesa );
_mesa_make_current2(NULL, NULL, NULL);
}
assert(rmesa);
if ( rmesa ) {
GLboolean release_texture_heaps;
release_texture_heaps = (rmesa->glCtx->Shared->RefCount == 1);
_swsetup_DestroyContext( rmesa->glCtx );
_tnl_DestroyContext( rmesa->glCtx );
_ac_DestroyContext( rmesa->glCtx );
_swrast_DestroyContext( rmesa->glCtx );
radeonDestroySwtcl( rmesa->glCtx );
radeonReleaseArrays( rmesa->glCtx, ~0 );
if (rmesa->dma.current.buf) {
radeonReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ );
radeonFlushCmdBuf( rmesa, __FUNCTION__ );
}
if (!rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE)
if (!getenv("RADEON_NO_VTXFMT"))
radeonVtxfmtDestroy( rmesa->glCtx );
rmesa->glCtx->DriverCtx = NULL;
_mesa_destroy_context( rmesa->glCtx );
if (rmesa->state.scissor.pClipRects) {
FREE(rmesa->state.scissor.pClipRects);
rmesa->state.scissor.pClipRects = 0;
}
if ( release_texture_heaps ) {
int i;
for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) {
driDestroyTextureHeap( rmesa->texture_heaps[ i ] );
rmesa->texture_heaps[ i ] = NULL;
}
assert( is_empty_list( & rmesa->swapped ) );
}
FREE( rmesa );
}
}
void
radeonSwapBuffers( __DRIdrawablePrivate *dPriv )
{
if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) {
radeonContextPtr rmesa;
GLcontext *ctx;
rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate;
ctx = rmesa->glCtx;
if (ctx->Visual.doubleBufferMode) {
_mesa_notifySwapBuffers( ctx );
if ( rmesa->doPageFlip ) {
radeonPageFlip( dPriv );
}
else {
radeonCopyBuffer( dPriv );
}
}
}
else {
_mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__);
}
}
GLboolean
radeonMakeCurrent( __DRIcontextPrivate *driContextPriv,
__DRIdrawablePrivate *driDrawPriv,
__DRIdrawablePrivate *driReadPriv )
{
if ( driContextPriv ) {
radeonContextPtr newCtx =
(radeonContextPtr) driContextPriv->driverPrivate;
if (RADEON_DEBUG & DEBUG_DRI)
fprintf(stderr, "%s ctx %p\n", __FUNCTION__, (void *)newCtx->glCtx);
if ( newCtx->dri.drawable != driDrawPriv ) {
newCtx->dri.drawable = driDrawPriv;
radeonUpdateWindow( newCtx->glCtx );
radeonUpdateViewportOffset( newCtx->glCtx );
}
_mesa_make_current2( newCtx->glCtx,
(GLframebuffer *) driDrawPriv->driverPrivate,
(GLframebuffer *) driReadPriv->driverPrivate );
if ( !newCtx->glCtx->Viewport.Width ) {
_mesa_set_viewport( newCtx->glCtx, 0, 0,
driDrawPriv->w, driDrawPriv->h );
}
if (newCtx->vb.enabled)
radeonVtxfmtMakeCurrent( newCtx->glCtx );
} else {
if (RADEON_DEBUG & DEBUG_DRI)
fprintf(stderr, "%s ctx is null\n", __FUNCTION__);
_mesa_make_current( 0, 0 );
}
if (RADEON_DEBUG & DEBUG_DRI)
fprintf(stderr, "End %s\n", __FUNCTION__);
return GL_TRUE;
}
GLboolean
radeonUnbindContext( __DRIcontextPrivate *driContextPriv )
{
radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate;
if (RADEON_DEBUG & DEBUG_DRI)
fprintf(stderr, "%s ctx %p\n", __FUNCTION__, (void *)rmesa->glCtx);
return GL_TRUE;
}