df03e80ae9
- Add libdrm and libdri. Portions of the DRI extension are stubbed out. - Use the DRM in the ATI driver when available. This provides a minor performance improvement in x11perf, and opens the possibility of using the 3d hardware for acceleration in the future. - Implement solid fill acceleration for Composite in KAA. - Implement Blend hook for Composite and use it on r128. - Fix a bug of mine that resulted in overuse of offscreen memory. - Fix many miscellaneous bugs in ATI driver and add PCI IDs.
930 lines
27 KiB
C
930 lines
27 KiB
C
/*
|
|
* $Id$
|
|
*
|
|
* Copyright © 2003 Eric Anholt
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of Eric Anholt not be used in
|
|
* advertising or publicity pertaining to distribution of the software without
|
|
* specific, written prior permission. Eric Anholt makes no
|
|
* representations about the suitability of this software for any purpose. It
|
|
* is provided "as is" without express or implied warranty.
|
|
*
|
|
* ERIC ANHOLT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
|
* EVENT SHALL ERIC ANHOLT BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
/* $Header$ */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
#include "ati.h"
|
|
#include "ati_reg.h"
|
|
#include "ati_dri.h"
|
|
#include "ati_dripriv.h"
|
|
#include "sarea.h"
|
|
#include "ati_sarea.h"
|
|
#include "ati_draw.h"
|
|
#include "r128_common.h"
|
|
#include "radeon_common.h"
|
|
|
|
/* ?? HACK - for now, put this here... */
|
|
/* ?? Alpha - this may need to be a variable to handle UP1x00 vs TITAN */
|
|
#if defined(__alpha__)
|
|
# define DRM_PAGE_SIZE 8192
|
|
#elif defined(__ia64__)
|
|
# define DRM_PAGE_SIZE getpagesize()
|
|
#else
|
|
# define DRM_PAGE_SIZE 4096
|
|
#endif
|
|
|
|
void XFree86DRIExtensionInit(void);
|
|
|
|
static Bool ATIDRIFinishScreenInit(ScreenPtr pScreen);
|
|
|
|
/* Compute log base 2 of val. */
|
|
static int
|
|
ATILog2(int val)
|
|
{
|
|
int bits;
|
|
|
|
if (!val)
|
|
return 1;
|
|
for (bits = 0; val != 0; val >>= 1, ++bits)
|
|
;
|
|
return bits;
|
|
}
|
|
|
|
static void
|
|
ATIDRIInitGARTValues(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
int s, l;
|
|
|
|
atis->gartOffset = 0;
|
|
|
|
/* Initialize the ring buffer data */
|
|
atis->ringStart = atis->gartOffset;
|
|
atis->ringMapSize = atis->ringSize*1024*1024 + DRM_PAGE_SIZE;
|
|
|
|
atis->ringReadOffset = atis->ringStart + atis->ringMapSize;
|
|
atis->ringReadMapSize = DRM_PAGE_SIZE;
|
|
|
|
/* Reserve space for vertex/indirect buffers */
|
|
atis->bufStart = atis->ringReadOffset + atis->ringReadMapSize;
|
|
atis->bufMapSize = atis->bufSize*1024*1024;
|
|
|
|
/* Reserve the rest for GART textures */
|
|
atis->gartTexStart = atis->bufStart + atis->bufMapSize;
|
|
s = (atis->gartSize*1024*1024 - atis->gartTexStart);
|
|
l = ATILog2((s-1) / ATI_NR_TEX_REGIONS);
|
|
if (l < ATI_LOG_TEX_GRANULARITY) l = ATI_LOG_TEX_GRANULARITY;
|
|
atis->gartTexMapSize = (s >> l) << l;
|
|
atis->log2GARTTexGran = l;
|
|
}
|
|
|
|
static int
|
|
ATIDRIAddAndMap(int fd, drmHandle offset, drmSize size,
|
|
drmMapType type, drmMapFlags flags, drmHandlePtr handle,
|
|
drmAddressPtr address, char *desc)
|
|
{
|
|
char *name;
|
|
|
|
name = (type == DRM_AGP) ? "agp" : "pci";
|
|
|
|
if (drmAddMap(fd, offset, size, type, flags, handle) < 0) {
|
|
ErrorF("[%s] Could not add %s mapping\n", name, desc);
|
|
return FALSE;
|
|
}
|
|
ErrorF("[%s] %s handle = 0x%08lx\n", name, desc, *handle);
|
|
|
|
if (drmMap(fd, *handle, size, address) < 0) {
|
|
ErrorF("[agp] Could not map %s\n", name, desc);
|
|
return FALSE;
|
|
}
|
|
ErrorF("[%s] %s mapped at 0x%08lx\n", name, desc, address);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Initialize the AGP state. Request memory for use in AGP space, and
|
|
initialize the Rage 128 registers to point to that memory. */
|
|
static Bool
|
|
ATIDRIAgpInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
unsigned char *mmio = atic->reg_base;
|
|
unsigned long mode;
|
|
int ret;
|
|
unsigned long agpBase;
|
|
CARD32 cntl, chunk;
|
|
|
|
if (drmAgpAcquire(atic->drmFd) < 0) {
|
|
ErrorF("[agp] AGP not available\n");
|
|
return FALSE;
|
|
}
|
|
|
|
ATIDRIInitGARTValues(pScreen);
|
|
|
|
/* Modify the mode if the default mode is not appropriate for this
|
|
* particular combination of graphics card and AGP chipset.
|
|
*/
|
|
|
|
/* XXX: Disable fast writes? */
|
|
|
|
mode = drmAgpGetMode(atic->drmFd);
|
|
if (mode > 4)
|
|
mode = 4;
|
|
/* Set all mode bits below the chosen one so fallback can happen */
|
|
mode = (mode * 2) - 1;
|
|
|
|
if (drmAgpEnable(atic->drmFd, mode) < 0) {
|
|
ErrorF("[agp] AGP not enabled\n");
|
|
drmAgpRelease(atic->drmFd);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Workaround for some hardware bugs */
|
|
/* XXX: Magic numbers */
|
|
if (!atic->is_r200) {
|
|
cntl = MMIO_IN32(mmio, RADEON_REG_AGP_CNTL) | 0x000e0000;
|
|
MMIO_OUT32(mmio, RADEON_REG_AGP_CNTL, cntl);
|
|
}
|
|
|
|
if ((ret = drmAgpAlloc(atic->drmFd, atis->gartSize*1024*1024, 0, NULL,
|
|
&atis->agpMemHandle)) < 0) {
|
|
ErrorF("[agp] Out of memory (%d)\n", ret);
|
|
drmAgpRelease(atic->drmFd);
|
|
return FALSE;
|
|
}
|
|
ErrorF("[agp] %d kB allocated with handle 0x%08lx\n",
|
|
atis->gartSize*1024, (long)atis->agpMemHandle);
|
|
|
|
if (drmAgpBind(atic->drmFd, atis->agpMemHandle, atis->gartOffset) < 0) {
|
|
ErrorF("[agp] Could not bind\n");
|
|
drmAgpFree(atic->drmFd, atis->agpMemHandle);
|
|
drmAgpRelease(atic->drmFd);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringStart, atis->ringMapSize,
|
|
DRM_AGP, DRM_READ_ONLY, &atis->ringHandle,
|
|
(drmAddressPtr)&atis->ring, "ring"))
|
|
return FALSE;
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringReadOffset,
|
|
atis->ringReadMapSize, DRM_AGP, DRM_READ_ONLY,
|
|
&atis->ringReadPtrHandle, (drmAddressPtr)&atis->ringReadPtr,
|
|
"ring read ptr"))
|
|
return FALSE;
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->bufStart, atis->bufMapSize,
|
|
DRM_AGP, 0, &atis->bufHandle, (drmAddressPtr)&atis->buf,
|
|
"vertex/indirect buffers"))
|
|
return FALSE;
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->gartTexStart,
|
|
atis->gartTexMapSize, DRM_AGP, 0, &atis->gartTexHandle,
|
|
(drmAddressPtr)&atis->gartTex, "AGP texture map"))
|
|
return FALSE;
|
|
|
|
/* Initialize radeon/r128 AGP registers */
|
|
cntl = MMIO_IN32(mmio, RADEON_REG_AGP_CNTL);
|
|
cntl &= ~RADEON_AGP_APER_SIZE_MASK;
|
|
switch (atis->gartSize) {
|
|
case 256: cntl |= RADEON_AGP_APER_SIZE_256MB; break;
|
|
case 128: cntl |= RADEON_AGP_APER_SIZE_128MB; break;
|
|
case 64: cntl |= RADEON_AGP_APER_SIZE_64MB; break;
|
|
case 32: cntl |= RADEON_AGP_APER_SIZE_32MB; break;
|
|
case 16: cntl |= RADEON_AGP_APER_SIZE_16MB; break;
|
|
case 8: cntl |= RADEON_AGP_APER_SIZE_8MB; break;
|
|
case 4: cntl |= RADEON_AGP_APER_SIZE_4MB; break;
|
|
default:
|
|
ErrorF("[agp] Illegal aperture size %d kB\n", atis->gartSize*1024);
|
|
return FALSE;
|
|
}
|
|
agpBase = drmAgpBase(atic->drmFd);
|
|
MMIO_OUT32(mmio, RADEON_REG_AGP_BASE, agpBase);
|
|
MMIO_OUT32(mmio, RADEON_REG_AGP_CNTL, cntl);
|
|
|
|
if (!atic->is_radeon) {
|
|
/* Disable Rage 128 PCIGART registers */
|
|
chunk = MMIO_IN32(mmio, R128_REG_BM_CHUNK_0_VAL);
|
|
chunk &= ~(R128_BM_PTR_FORCE_TO_PCI |
|
|
R128_BM_PM4_RD_FORCE_TO_PCI |
|
|
R128_BM_GLOBAL_FORCE_TO_PCI);
|
|
MMIO_OUT32(mmio, R128_REG_BM_CHUNK_0_VAL, chunk);
|
|
|
|
/* Ensure AGP GART is used (for now) */
|
|
MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 1);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
ATIDRIPciInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
unsigned char *mmio = atic->reg_base;
|
|
CARD32 chunk;
|
|
int ret;
|
|
|
|
ATIDRIInitGARTValues(pScreen);
|
|
|
|
ret = drmScatterGatherAlloc(atic->drmFd, atis->gartSize*1024*1024,
|
|
&atis->pciMemHandle);
|
|
if (ret < 0) {
|
|
ErrorF("[pci] Out of memory (%d)\n", ret);
|
|
return FALSE;
|
|
}
|
|
ErrorF("[pci] %d kB allocated with handle 0x%08lx\n",
|
|
atis->gartSize*1024, (long)atis->pciMemHandle);
|
|
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringStart, atis->ringMapSize,
|
|
DRM_SCATTER_GATHER, DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL,
|
|
&atis->ringHandle, (drmAddressPtr)&atis->ring, "ring"))
|
|
return FALSE;
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->ringReadOffset,
|
|
atis->ringReadMapSize, DRM_SCATTER_GATHER,
|
|
DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL,
|
|
&atis->ringReadPtrHandle, (drmAddressPtr)&atis->ringReadPtr,
|
|
"ring read ptr"))
|
|
return FALSE;
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->bufStart, atis->bufMapSize,
|
|
DRM_SCATTER_GATHER, 0, &atis->bufHandle, (drmAddressPtr)&atis->buf,
|
|
"vertex/indirect buffers"))
|
|
return FALSE;
|
|
|
|
if (!ATIDRIAddAndMap(atic->drmFd, atis->gartTexStart,
|
|
atis->gartTexMapSize, DRM_SCATTER_GATHER, 0, &atis->gartTexHandle,
|
|
(drmAddressPtr)&atis->gartTex, "PCI texture map"))
|
|
return FALSE;
|
|
|
|
if (!atic->is_radeon) {
|
|
/* Force PCI GART mode */
|
|
chunk = MMIO_IN32(mmio, R128_REG_BM_CHUNK_0_VAL);
|
|
chunk |= (R128_BM_PTR_FORCE_TO_PCI |
|
|
R128_BM_PM4_RD_FORCE_TO_PCI | R128_BM_GLOBAL_FORCE_TO_PCI);
|
|
MMIO_OUT32(mmio, R128_REG_BM_CHUNK_0_VAL, chunk);
|
|
MMIO_OUT32(mmio, R128_REG_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* Initialize the kernel data structures. */
|
|
static int
|
|
R128DRIKernelInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
drmR128Init drmInfo;
|
|
|
|
memset(&drmInfo, 0, sizeof(drmR128Init) );
|
|
|
|
drmInfo.func = DRM_R128_INIT_CCE;
|
|
drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
|
|
drmInfo.is_pci = !atis->IsAGP;
|
|
drmInfo.cce_mode = atis->CCEMode;
|
|
drmInfo.cce_secure = TRUE;
|
|
drmInfo.ring_size = atis->ringSize*1024*1024;
|
|
drmInfo.usec_timeout = atis->DMAusecTimeout;
|
|
|
|
drmInfo.fb_bpp = pScreenPriv->screen->fb[0].depth;
|
|
drmInfo.depth_bpp = pScreenPriv->screen->fb[0].depth;
|
|
|
|
/* XXX: pitches are in pixels on r128. */
|
|
drmInfo.front_offset = atis->frontOffset;
|
|
drmInfo.front_pitch = atis->frontPitch;
|
|
|
|
drmInfo.back_offset = atis->backOffset;
|
|
drmInfo.back_pitch = atis->backPitch;
|
|
|
|
drmInfo.depth_offset = atis->depthOffset;
|
|
drmInfo.depth_pitch = atis->depthPitch;
|
|
drmInfo.span_offset = atis->spanOffset;
|
|
|
|
drmInfo.fb_offset = atis->fbHandle;
|
|
drmInfo.mmio_offset = atis->registerHandle;
|
|
drmInfo.ring_offset = atis->ringHandle;
|
|
drmInfo.ring_rptr_offset = atis->ringReadPtrHandle;
|
|
drmInfo.buffers_offset = atis->bufHandle;
|
|
drmInfo.agp_textures_offset = atis->gartTexHandle;
|
|
|
|
if (drmCommandWrite(atic->drmFd, DRM_R128_INIT, &drmInfo,
|
|
sizeof(drmR128Init)) < 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Initialize the kernel data structures */
|
|
static int
|
|
RadeonDRIKernelInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
drmRadeonInit drmInfo;
|
|
|
|
memset(&drmInfo, 0, sizeof(drmRadeonInit));
|
|
|
|
if (atic->is_r200)
|
|
drmInfo.func = DRM_RADEON_INIT_R200_CP;
|
|
else
|
|
drmInfo.func = DRM_RADEON_INIT_CP;
|
|
|
|
drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec);
|
|
drmInfo.is_pci = !atis->IsAGP;
|
|
drmInfo.cp_mode = atis->CPMode;
|
|
drmInfo.gart_size = atis->gartSize*1024*1024;
|
|
drmInfo.ring_size = atis->ringSize*1024*1024;
|
|
drmInfo.usec_timeout = atis->DMAusecTimeout;
|
|
|
|
drmInfo.fb_bpp = pScreenPriv->screen->fb[0].depth;
|
|
drmInfo.depth_bpp = pScreenPriv->screen->fb[0].depth;
|
|
|
|
drmInfo.front_offset = atis->frontOffset;
|
|
drmInfo.front_pitch = atis->frontPitch;
|
|
drmInfo.back_offset = atis->backOffset;
|
|
drmInfo.back_pitch = atis->backPitch;
|
|
drmInfo.depth_offset = atis->depthOffset;
|
|
drmInfo.depth_pitch = atis->depthPitch;
|
|
|
|
drmInfo.fb_offset = atis->fbHandle;
|
|
drmInfo.mmio_offset = atis->registerHandle;
|
|
drmInfo.ring_offset = atis->ringHandle;
|
|
drmInfo.ring_rptr_offset = atis->ringReadPtrHandle;
|
|
drmInfo.buffers_offset = atis->bufHandle;
|
|
drmInfo.gart_textures_offset = atis->gartTexHandle;
|
|
|
|
if (drmCommandWrite(atic->drmFd, DRM_RADEON_CP_INIT,
|
|
&drmInfo, sizeof(drmRadeonInit)) < 0)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Add a map for the vertex buffers that will be accessed by any
|
|
DRI-based clients. */
|
|
static Bool
|
|
ATIDRIBufInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
int type, size;
|
|
|
|
if (atic->is_radeon)
|
|
size = RADEON_BUFFER_SIZE;
|
|
else
|
|
size = R128_BUFFER_SIZE;
|
|
|
|
if (atis->IsAGP)
|
|
type = DRM_AGP_BUFFER;
|
|
else
|
|
type = DRM_SG_BUFFER;
|
|
|
|
/* Initialize vertex buffers */
|
|
atis->bufNumBufs = drmAddBufs(atic->drmFd, atis->bufMapSize / size,
|
|
size, type, atis->bufStart);
|
|
|
|
if (atis->bufNumBufs <= 0) {
|
|
ErrorF("[drm] Could not create vertex/indirect buffers list\n");
|
|
return FALSE;
|
|
}
|
|
ErrorF("[drm] Added %d %d byte vertex/indirect buffers\n",
|
|
atis->bufNumBufs, size);
|
|
|
|
atis->buffers = drmMapBufs(atic->drmFd);
|
|
if (atis->buffers == NULL) {
|
|
ErrorF("[drm] Failed to map vertex/indirect buffers list\n");
|
|
return FALSE;
|
|
}
|
|
ErrorF("[drm] Mapped %d vertex/indirect buffers\n",
|
|
atis->buffers->count);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
ATIDRIIrqInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
|
|
if (atis->irqEnabled)
|
|
return FALSE;
|
|
|
|
atis->irqEnabled = drmCtlInstHandler(atic->drmFd, 0);
|
|
|
|
if (!atis->irqEnabled)
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void ATIDRISwapContext(ScreenPtr pScreen, DRISyncType syncType,
|
|
DRIContextType oldContextType, void *oldContext,
|
|
DRIContextType newContextType, void *newContext)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
|
|
if ((syncType==DRI_3D_SYNC) && (oldContextType==DRI_2D_CONTEXT) &&
|
|
(newContextType==DRI_2D_CONTEXT)) {
|
|
/* Entering from Wakeup */
|
|
/* XXX: XFree86 sets NeedToSync */
|
|
|
|
}
|
|
if ((syncType==DRI_2D_SYNC) && (oldContextType==DRI_NO_CONTEXT) &&
|
|
(newContextType==DRI_2D_CONTEXT)) {
|
|
/* Exiting from Block Handler */
|
|
if (atis->using_dma)
|
|
ATIDMAFlushIndirect(1);
|
|
}
|
|
}
|
|
|
|
/* Initialize the screen-specific data structures for the DRI and the
|
|
Rage 128. This is the main entry point to the device-specific
|
|
initialization code. It calls device-independent DRI functions to
|
|
create the DRI data structures and initialize the DRI state. */
|
|
Bool
|
|
ATIDRIScreenInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
void *scratch_ptr;
|
|
int scratch_int;
|
|
DRIInfoPtr pDRIInfo;
|
|
int devSareaSize;
|
|
drmSetVersion sv;
|
|
|
|
/* XXX: Disable DRI clients for unsupported depths */
|
|
|
|
if (atic->is_radeon) {
|
|
atis->CPMode = RADEON_CSQ_PRIBM_INDBM;
|
|
}
|
|
else {
|
|
atis->CCEMode = R128_PM4_64BM_64VCBM_64INDBM;
|
|
atis->CCEFifoSize = 64;
|
|
}
|
|
|
|
atis->IsAGP = FALSE; /* XXX */
|
|
atis->agpMode = 1;
|
|
atis->gartSize = 8;
|
|
atis->ringSize = 1;
|
|
atis->bufSize = 2;
|
|
atis->gartTexSize = 1;
|
|
atis->DMAusecTimeout = 10000;
|
|
|
|
atis->frontOffset = 0;
|
|
atis->frontPitch = pScreenPriv->screen->fb[0].byteStride;
|
|
atis->backOffset = 0; /* XXX */
|
|
atis->backPitch = pScreenPriv->screen->fb[0].byteStride;
|
|
atis->depthOffset = 0; /* XXX */
|
|
atis->depthPitch = 0; /* XXX */
|
|
atis->spanOffset = 0; /* XXX */
|
|
|
|
if (atic->drmFd < 0)
|
|
return FALSE;
|
|
|
|
sv.drm_di_major = -1;
|
|
sv.drm_dd_major = -1;
|
|
drmSetInterfaceVersion(atic->drmFd, &sv);
|
|
if (atic->is_radeon) {
|
|
if (sv.drm_dd_major != 1 || sv.drm_dd_minor < 6) {
|
|
ErrorF("[dri] radeon kernel module version is %d.%d "
|
|
"but version 1.6 or greater is needed.\n",
|
|
sv.drm_dd_major, sv.drm_dd_minor);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
if (sv.drm_dd_major != 2 || sv.drm_dd_minor < 2) {
|
|
ErrorF("[dri] r128 kernel module version is %d.%d "
|
|
"but version 2.2 or greater is needed.\n",
|
|
sv.drm_dd_major, sv.drm_dd_minor);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Create the DRI data structure, and fill it in before calling the
|
|
* DRIScreenInit().
|
|
*/
|
|
pDRIInfo = DRICreateInfoRec();
|
|
if (!pDRIInfo)
|
|
return FALSE;
|
|
|
|
atis->pDRIInfo = pDRIInfo;
|
|
pDRIInfo->busIdString = atic->busid;
|
|
if (atic->is_radeon) {
|
|
pDRIInfo->drmDriverName = "radeon";
|
|
if (atic->is_r200)
|
|
pDRIInfo->clientDriverName = "radeon";
|
|
else
|
|
pDRIInfo->clientDriverName = "r200";
|
|
} else {
|
|
pDRIInfo->drmDriverName = "r128";
|
|
pDRIInfo->clientDriverName = "r128";
|
|
}
|
|
pDRIInfo->ddxDriverMajorVersion = 4;
|
|
pDRIInfo->ddxDriverMinorVersion = 0;
|
|
pDRIInfo->ddxDriverPatchVersion = 0;
|
|
pDRIInfo->frameBufferPhysicalAddress =
|
|
(unsigned long)pScreenPriv->screen->memory_base;
|
|
pDRIInfo->frameBufferSize = pScreenPriv->screen->memory_size;
|
|
pDRIInfo->frameBufferStride = pScreenPriv->screen->fb[0].byteStride;
|
|
pDRIInfo->ddxDrawableTableEntry = SAREA_MAX_DRAWABLES;
|
|
pDRIInfo->maxDrawableTableEntry = SAREA_MAX_DRAWABLES;
|
|
|
|
/* For now the mapping works by using a fixed size defined
|
|
* in the SAREA header
|
|
*/
|
|
pDRIInfo->SAREASize = SAREA_MAX;
|
|
|
|
if (atic->is_radeon) {
|
|
pDRIInfo->devPrivateSize = sizeof(R128DRIRec);
|
|
devSareaSize = sizeof(R128SAREAPriv);
|
|
} else {
|
|
pDRIInfo->devPrivateSize = sizeof(RADEONDRIRec);
|
|
devSareaSize = sizeof(RADEONSAREAPriv);
|
|
}
|
|
|
|
if (sizeof(XF86DRISAREARec) + devSareaSize > SAREA_MAX) {
|
|
ErrorF("[dri] Data does not fit in SAREA. Disabling DRI.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
pDRIInfo->devPrivate = xcalloc(pDRIInfo->devPrivateSize, 1);
|
|
if (pDRIInfo->devPrivate == NULL) {
|
|
DRIDestroyInfoRec(atis->pDRIInfo);
|
|
atis->pDRIInfo = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
pDRIInfo->contextSize = sizeof(ATIDRIContextRec);
|
|
|
|
pDRIInfo->SwapContext = ATIDRISwapContext;
|
|
/*pDRIInfo->InitBuffers = R128DRIInitBuffers;*/ /* XXX Appears unnecessary */
|
|
/*pDRIInfo->MoveBuffers = R128DRIMoveBuffers;*/ /* XXX Badness */
|
|
pDRIInfo->bufferRequests = DRI_ALL_WINDOWS;
|
|
/*pDRIInfo->TransitionTo2d = R128DRITransitionTo2d;
|
|
pDRIInfo->TransitionTo3d = R128DRITransitionTo3d;
|
|
pDRIInfo->TransitionSingleToMulti3D = R128DRITransitionSingleToMulti3d;
|
|
pDRIInfo->TransitionMultiToSingle3D = R128DRITransitionMultiToSingle3d;*/
|
|
|
|
pDRIInfo->createDummyCtx = TRUE;
|
|
pDRIInfo->createDummyCtxPriv = FALSE;
|
|
|
|
if (!DRIScreenInit(pScreen, pDRIInfo, &atic->drmFd)) {
|
|
ErrorF("[dri] DRIScreenInit failed. Disabling DRI.\n");
|
|
xfree(pDRIInfo->devPrivate);
|
|
pDRIInfo->devPrivate = NULL;
|
|
DRIDestroyInfoRec(pDRIInfo);
|
|
pDRIInfo = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
/* Add a map for the MMIO registers that will be accessed by any
|
|
* DRI-based clients.
|
|
*/
|
|
atis->registerSize = RADEON_REG_SIZE(atic);
|
|
if (drmAddMap(atic->drmFd, RADEON_REG_BASE(pScreenPriv->screen->card),
|
|
atis->registerSize, DRM_REGISTERS, DRM_READ_ONLY,
|
|
&atis->registerHandle) < 0) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
ErrorF("[drm] register handle = 0x%08lx\n", atis->registerHandle);
|
|
|
|
/* DRIScreenInit adds the frame buffer map, but we need it as well */
|
|
DRIGetDeviceInfo(pScreen, &atis->fbHandle, &scratch_int, &scratch_int,
|
|
&scratch_int, &scratch_int, &scratch_ptr);
|
|
|
|
/* Initialize AGP */
|
|
if (atis->IsAGP && !ATIDRIAgpInit(pScreen)) {
|
|
atis->IsAGP = FALSE;
|
|
ErrorF("[agp] AGP failed to initialize; falling back to PCI mode.\n");
|
|
ErrorF("[agp] Make sure your kernel's AGP support is loaded and functioning.");
|
|
}
|
|
|
|
/* Initialize PCIGART */
|
|
if (!atis->IsAGP && !ATIDRIPciInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef GLXEXT
|
|
if (!R128InitVisualConfigs(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
ErrorF("[dri] Visual configs initialized\n");
|
|
#endif
|
|
|
|
atis->serverContext = DRIGetContext(pScreen);
|
|
|
|
return ATIDRIFinishScreenInit(pScreen);
|
|
}
|
|
|
|
/* Finish initializing the device-dependent DRI state, and call
|
|
DRIFinishScreenInit() to complete the device-independent DRI
|
|
initialization. */
|
|
static Bool
|
|
R128DRIFinishScreenInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
R128SAREAPrivPtr pSAREAPriv;
|
|
R128DRIPtr pR128DRI;
|
|
|
|
/* Initialize the kernel data structures */
|
|
if (!R128DRIKernelInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Initialize the vertex buffers list */
|
|
if (!ATIDRIBufInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Initialize IRQ */
|
|
ATIDRIIrqInit(pScreen);
|
|
|
|
/* Initialize and start the CCE if required */
|
|
ATIDMAStart(pScreen);
|
|
|
|
pSAREAPriv = (R128SAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
|
|
memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
|
|
|
|
pR128DRI = (R128DRIPtr)atis->pDRIInfo->devPrivate;
|
|
|
|
pR128DRI->deviceID = pScreenPriv->screen->card->attr.deviceID;
|
|
pR128DRI->width = pScreenPriv->screen->width;
|
|
pR128DRI->height = pScreenPriv->screen->height;
|
|
pR128DRI->depth = pScreenPriv->screen->fb[0].depth;
|
|
pR128DRI->bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
|
|
|
|
pR128DRI->IsPCI = !atis->IsAGP;
|
|
pR128DRI->AGPMode = atis->agpMode;
|
|
|
|
pR128DRI->frontOffset = atis->frontOffset;
|
|
pR128DRI->frontPitch = atis->frontPitch;
|
|
pR128DRI->backOffset = atis->backOffset;
|
|
pR128DRI->backPitch = atis->backPitch;
|
|
pR128DRI->depthOffset = atis->depthOffset;
|
|
pR128DRI->depthPitch = atis->depthPitch;
|
|
pR128DRI->spanOffset = atis->spanOffset;
|
|
pR128DRI->textureOffset = atis->textureOffset;
|
|
pR128DRI->textureSize = atis->textureSize;
|
|
pR128DRI->log2TexGran = atis->log2TexGran;
|
|
|
|
pR128DRI->registerHandle = atis->registerHandle;
|
|
pR128DRI->registerSize = atis->registerSize;
|
|
|
|
pR128DRI->gartTexHandle = atis->gartTexHandle;
|
|
pR128DRI->gartTexMapSize = atis->gartTexMapSize;
|
|
pR128DRI->log2AGPTexGran = atis->log2GARTTexGran;
|
|
pR128DRI->gartTexOffset = atis->gartTexStart;
|
|
pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* Finish initializing the device-dependent DRI state, and call
|
|
* DRIFinishScreenInit() to complete the device-independent DRI
|
|
* initialization.
|
|
*/
|
|
static Bool
|
|
RadeonDRIFinishScreenInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo(pScreenPriv);
|
|
RADEONSAREAPrivPtr pSAREAPriv;
|
|
RADEONDRIPtr pRADEONDRI;
|
|
drmRadeonMemInitHeap drmHeap;
|
|
|
|
/* Initialize the kernel data structures */
|
|
if (!RadeonDRIKernelInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Initialize the vertex buffers list */
|
|
if (!ATIDRIBufInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Initialize IRQ */
|
|
ATIDRIIrqInit(pScreen);
|
|
|
|
drmHeap.region = RADEON_MEM_REGION_GART;
|
|
drmHeap.start = 0;
|
|
drmHeap.size = atis->gartTexMapSize;
|
|
|
|
if (drmCommandWrite(atic->drmFd, DRM_RADEON_INIT_HEAP, &drmHeap,
|
|
sizeof(drmHeap))) {
|
|
ErrorF("[drm] Failed to initialize GART heap manager\n");
|
|
}
|
|
|
|
ATIDMAStart(pScreen);
|
|
|
|
/* Initialize the SAREA private data structure */
|
|
pSAREAPriv = (RADEONSAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
|
|
memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
|
|
|
|
pRADEONDRI = (RADEONDRIPtr)atis->pDRIInfo->devPrivate;
|
|
|
|
pRADEONDRI->deviceID = pScreenPriv->screen->card->attr.deviceID;
|
|
pRADEONDRI->width = pScreenPriv->screen->width;
|
|
pRADEONDRI->height = pScreenPriv->screen->height;
|
|
pRADEONDRI->depth = pScreenPriv->screen->fb[0].depth;
|
|
pRADEONDRI->bpp = pScreenPriv->screen->fb[0].bitsPerPixel;
|
|
|
|
pRADEONDRI->IsPCI = !atis->IsAGP;
|
|
pRADEONDRI->AGPMode = atis->agpMode;
|
|
|
|
pRADEONDRI->frontOffset = atis->frontOffset;
|
|
pRADEONDRI->frontPitch = atis->frontPitch;
|
|
pRADEONDRI->backOffset = atis->backOffset;
|
|
pRADEONDRI->backPitch = atis->backPitch;
|
|
pRADEONDRI->depthOffset = atis->depthOffset;
|
|
pRADEONDRI->depthPitch = atis->depthPitch;
|
|
pRADEONDRI->textureOffset = atis->textureOffset;
|
|
pRADEONDRI->textureSize = atis->textureSize;
|
|
pRADEONDRI->log2TexGran = atis->log2TexGran;
|
|
|
|
pRADEONDRI->registerHandle = atis->registerHandle;
|
|
pRADEONDRI->registerSize = atis->registerSize;
|
|
|
|
pRADEONDRI->statusHandle = atis->ringReadPtrHandle;
|
|
pRADEONDRI->statusSize = atis->ringReadMapSize;
|
|
|
|
pRADEONDRI->gartTexHandle = atis->gartTexHandle;
|
|
pRADEONDRI->gartTexMapSize = atis->gartTexMapSize;
|
|
pRADEONDRI->log2GARTTexGran = atis->log2GARTTexGran;
|
|
pRADEONDRI->gartTexOffset = atis->gartTexStart;
|
|
|
|
pRADEONDRI->sarea_priv_offset = sizeof(XF86DRISAREARec);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static Bool
|
|
ATIDRIFinishScreenInit(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv(pScreen);
|
|
ATIScreenInfo(pScreenPriv);
|
|
ATICardInfo (pScreenPriv);
|
|
|
|
atis->pDRIInfo->driverSwapMethod = DRI_HIDE_X_CONTEXT;
|
|
|
|
/* NOTE: DRIFinishScreenInit must be called before *DRIKernelInit
|
|
* because *DRIKernelInit requires that the hardware lock is held by
|
|
* the X server, and the first time the hardware lock is grabbed is
|
|
* in DRIFinishScreenInit.
|
|
*/
|
|
if (!DRIFinishScreenInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
|
|
if (atic->is_radeon) {
|
|
if (!RadeonDRIFinishScreenInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
if (!R128DRIFinishScreenInit(pScreen)) {
|
|
ATIDRICloseScreen(pScreen);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
XFree86DRIExtensionInit();
|
|
|
|
atis->using_dri = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* The screen is being closed, so clean up any state and free any
|
|
resources used by the DRI. */
|
|
void
|
|
ATIDRICloseScreen(ScreenPtr pScreen)
|
|
{
|
|
KdScreenPriv (pScreen);
|
|
ATIScreenInfo (pScreenPriv);
|
|
ATICardInfo (pScreenPriv);
|
|
drmR128Init drmR128Info;
|
|
drmRadeonInit drmRadeonInfo;
|
|
|
|
if (atis->indirectBuffer != NULL) {
|
|
ATIDMADispatchIndirect(1);
|
|
atis->indirectBuffer = NULL;
|
|
atis->indirectStart = 0;
|
|
}
|
|
ATIDMAStop(pScreen);
|
|
|
|
if (atis->irqEnabled) {
|
|
drmCtlUninstHandler(atic->drmFd);
|
|
atis->irqEnabled = FALSE;
|
|
}
|
|
|
|
/* De-allocate vertex buffers */
|
|
if (atis->buffers) {
|
|
drmUnmapBufs(atis->buffers);
|
|
atis->buffers = NULL;
|
|
}
|
|
|
|
/* De-allocate all kernel resources */
|
|
if (atic->is_radeon) {
|
|
memset(&drmR128Info, 0, sizeof(drmR128Init));
|
|
drmR128Info.func = DRM_R128_CLEANUP_CCE;
|
|
drmCommandWrite(atic->drmFd, DRM_R128_INIT, &drmR128Info,
|
|
sizeof(drmR128Init));
|
|
} else {
|
|
memset(&drmRadeonInfo, 0, sizeof(drmRadeonInfo));
|
|
drmRadeonInfo.func = DRM_RADEON_CLEANUP_CP;
|
|
drmCommandWrite(atic->drmFd, DRM_RADEON_CP_INIT, &drmRadeonInfo,
|
|
sizeof(drmR128Init));
|
|
}
|
|
|
|
/* De-allocate all AGP resources */
|
|
if (atis->gartTex) {
|
|
drmUnmap(atis->gartTex, atis->gartTexMapSize);
|
|
atis->gartTex = NULL;
|
|
}
|
|
if (atis->buf) {
|
|
drmUnmap(atis->buf, atis->bufMapSize);
|
|
atis->buf = NULL;
|
|
}
|
|
if (atis->ringReadPtr) {
|
|
drmUnmap(atis->ringReadPtr, atis->ringReadMapSize);
|
|
atis->ringReadPtr = NULL;
|
|
}
|
|
if (atis->ring) {
|
|
drmUnmap(atis->ring, atis->ringMapSize);
|
|
atis->ring = NULL;
|
|
}
|
|
if (atis->agpMemHandle != DRM_AGP_NO_HANDLE) {
|
|
drmAgpUnbind(atic->drmFd, atis->agpMemHandle);
|
|
drmAgpFree(atic->drmFd, atis->agpMemHandle);
|
|
atis->agpMemHandle = DRM_AGP_NO_HANDLE;
|
|
drmAgpRelease(atic->drmFd);
|
|
}
|
|
if (atis->pciMemHandle) {
|
|
drmScatterGatherFree(atic->drmFd, atis->pciMemHandle);
|
|
atis->pciMemHandle = 0;
|
|
}
|
|
|
|
/* De-allocate all DRI resources */
|
|
DRICloseScreen(pScreen);
|
|
|
|
/* De-allocate all DRI data structures */
|
|
if (atis->pDRIInfo) {
|
|
if (atis->pDRIInfo->devPrivate) {
|
|
xfree(atis->pDRIInfo->devPrivate);
|
|
atis->pDRIInfo->devPrivate = NULL;
|
|
}
|
|
DRIDestroyInfoRec(atis->pDRIInfo);
|
|
atis->pDRIInfo = NULL;
|
|
}
|
|
atis->using_dri = FALSE;
|
|
#ifdef GLXEXT
|
|
if (atis->pVisualConfigs) {
|
|
xfree(atis->pVisualConfigs);
|
|
atis->pVisualConfigs = NULL;
|
|
}
|
|
if (atis->pVisualConfigsPriv) {
|
|
xfree(atis->pVisualConfigsPriv);
|
|
atis->pVisualConfigsPriv = NULL;
|
|
}
|
|
#endif /* GLXEXT */
|
|
atic->drmFd = -1;
|
|
}
|