summaryrefslogtreecommitdiff
path: root/radeon/server/radeon_egl.c
diff options
context:
space:
mode:
Diffstat (limited to 'radeon/server/radeon_egl.c')
-rw-r--r--radeon/server/radeon_egl.c1088
1 files changed, 1088 insertions, 0 deletions
diff --git a/radeon/server/radeon_egl.c b/radeon/server/radeon_egl.c
new file mode 100644
index 0000000..2f6ea55
--- /dev/null
+++ b/radeon/server/radeon_egl.c
@@ -0,0 +1,1088 @@
+/*
+ * EGL driver for radeon_dri.so
+ */
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include "eglconfig.h"
+#include "eglcontext.h"
+#include "egldisplay.h"
+#include "egldriver.h"
+#include "eglglobals.h"
+#include "egllog.h"
+#include "eglmode.h"
+#include "eglscreen.h"
+#include "eglsurface.h"
+#include "egldri.h"
+
+#include "mtypes.h"
+#include "memops.h"
+#include "drm.h"
+#include "drm_sarea.h"
+#include "radeon_drm.h"
+#include "radeon_dri.h"
+#include "radeon.h"
+
+static size_t radeon_drm_page_size;
+
+/**
+ * radeon driver-specific driver class derived from _EGLDriver
+ */
+typedef struct radeon_driver
+{
+ _EGLDriver Base; /* base class/object */
+ GLuint radeonStuff;
+} radeonDriver;
+
+static int
+RADEONSetParam(driDisplay *disp, int param, int value)
+{
+ drm_radeon_setparam_t sp;
+ int ret;
+
+ memset(&sp, 0, sizeof(sp));
+ sp.param = param;
+ sp.value = value;
+
+ if ((ret=drmCommandWrite(disp->drmFD, DRM_RADEON_SETPARAM, &sp, sizeof(sp)))) {
+ fprintf(stderr,"Set param failed\n", ret);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+RADEONCheckDRMVersion(driDisplay *disp, RADEONInfoPtr info)
+{
+ drmVersionPtr version;
+
+ version = drmGetVersion(disp->drmFD);
+ if (version) {
+ int req_minor, req_patch;
+
+ /* Need 1.21.x for card type detection getparam
+ */
+ req_minor = 21;
+ req_patch = 0;
+
+ if (version->version_major != 1 ||
+ version->version_minor < req_minor ||
+ (version->version_minor == req_minor &&
+ version->version_patchlevel < req_patch)) {
+ /* Incompatible drm version */
+ fprintf(stderr,
+ "[dri] RADEONDRIScreenInit failed because of a version "
+ "mismatch.\n"
+ "[dri] radeon.o kernel module version is %d.%d.%d "
+ "but version 1.%d.%d or newer is needed.\n"
+ "[dri] Disabling DRI.\n",
+ version->version_major,
+ version->version_minor,
+ version->version_patchlevel,
+ req_minor,
+ req_patch);
+ drmFreeVersion(version);
+ return 0;
+ }
+
+ info->drmMinor = version->version_minor;
+ drmFreeVersion(version);
+ }
+
+ return 1;
+}
+
+
+/**
+ * \brief Compute base 2 logarithm.
+ *
+ * \param val value.
+ *
+ * \return base 2 logarithm of \p val.
+ */
+static int RADEONMinBits(int val)
+{
+ int bits;
+
+ if (!val) return 1;
+ for (bits = 0; val; val >>= 1, ++bits);
+ return bits;
+}
+
+
+/* Initialize the PCI GART state. Request memory for use in PCI space,
+ * and initialize the Radeon registers to point to that memory.
+ */
+static int RADEONDRIPciInit(driDisplay *disp, RADEONInfoPtr info)
+{
+ int ret;
+ int flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL;
+ int s, l;
+
+ ret = drmScatterGatherAlloc(disp->drmFD, info->gartSize*1024*1024,
+ &info->gartMemHandle);
+ if (ret < 0) {
+ fprintf(stderr, "[pci] Out of memory (%d)\n", ret);
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] %d kB allocated with handle 0x%04lx\n",
+ info->gartSize*1024, (long) info->gartMemHandle);
+
+ info->gartOffset = 0;
+
+ /* Initialize the CP ring buffer data */
+ info->ringStart = info->gartOffset;
+ info->ringMapSize = info->ringSize*1024*1024 + radeon_drm_page_size;
+
+ info->ringReadOffset = info->ringStart + info->ringMapSize;
+ info->ringReadMapSize = radeon_drm_page_size;
+
+ /* Reserve space for vertex/indirect buffers */
+ info->bufStart = info->ringReadOffset + info->ringReadMapSize;
+ info->bufMapSize = info->bufSize*1024*1024;
+
+ /* Reserve the rest for AGP textures */
+ info->gartTexStart = info->bufStart + info->bufMapSize;
+ s = (info->gartSize*1024*1024 - info->gartTexStart);
+ l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS);
+ if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+ info->gartTexMapSize = (s >> l) << l;
+ info->log2GARTTexGran = l;
+
+ if (drmAddMap(disp->drmFD, info->ringStart, info->ringMapSize,
+ DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add ring mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] ring handle = 0x%08lx\n", info->ringHandle);
+
+ if (drmAddMap(disp->drmFD, info->ringReadOffset, info->ringReadMapSize,
+ DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add ring read ptr mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] ring read ptr handle = 0x%08lx\n",
+ info->ringReadPtrHandle);
+
+ if (drmAddMap(disp->drmFD, info->bufStart, info->bufMapSize,
+ DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add vertex/indirect buffers mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] vertex/indirect buffers handle = 0x%08lx\n",
+ info->bufHandle);
+
+ if (drmAddMap(disp->drmFD, info->gartTexStart, info->gartTexMapSize,
+ DRM_SCATTER_GATHER, 0, &info->gartTexHandle) < 0) {
+ fprintf(stderr,
+ "[pci] Could not add GART texture map mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[pci] GART texture map handle = 0x%08lx\n",
+ info->gartTexHandle);
+
+ return 1;
+}
+
+
+/**
+ * \brief Initialize the AGP state
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Acquires and enables the AGP device. Reserves memory in the AGP space for
+ * the ring buffer, vertex buffers and textures. Initialize the Radeon
+ * registers to point to that memory and add client mappings.
+ */
+static int RADEONDRIAgpInit( driDisplay *disp, RADEONInfoPtr info)
+{
+ int mode, ret;
+ int s, l;
+ int agpmode = 1;
+
+ if (drmAgpAcquire(disp->drmFD) < 0) {
+ fprintf(stderr, "[gart] AGP not available\n");
+ return 0;
+ }
+
+ mode = drmAgpGetMode(disp->drmFD); /* Default mode */
+ /* Disable fast write entirely - too many lockups.
+ */
+ mode &= ~RADEON_AGP_MODE_MASK;
+ switch (agpmode) {
+ case 4: mode |= RADEON_AGP_4X_MODE;
+ case 2: mode |= RADEON_AGP_2X_MODE;
+ case 1: default: mode |= RADEON_AGP_1X_MODE;
+ }
+
+ if (drmAgpEnable(disp->drmFD, mode) < 0) {
+ fprintf(stderr, "[gart] AGP not enabled\n");
+ drmAgpRelease(disp->drmFD);
+ return 0;
+ }
+
+#if 0
+ /* Workaround for some hardware bugs */
+ if (info->ChipFamily < CHIP_FAMILY_R200)
+ OUTREG(RADEON_AGP_CNTL, INREG(RADEON_AGP_CNTL) | 0x000e0000);
+#endif
+ info->gartOffset = 0;
+
+ if ((ret = drmAgpAlloc(disp->drmFD, info->gartSize*1024*1024, 0, NULL,
+ &info->gartMemHandle)) < 0) {
+ fprintf(stderr, "[gart] Out of memory (%d)\n", ret);
+ drmAgpRelease(disp->drmFD);
+ return 0;
+ }
+ fprintf(stderr,
+ "[gart] %d kB allocated with handle 0x%08x\n",
+ info->gartSize*1024, (unsigned)info->gartMemHandle);
+
+ if (drmAgpBind(disp->drmFD,
+ info->gartMemHandle, info->gartOffset) < 0) {
+ fprintf(stderr, "[gart] Could not bind\n");
+ drmAgpFree(disp->drmFD, info->gartMemHandle);
+ drmAgpRelease(disp->drmFD);
+ return 0;
+ }
+
+ /* Initialize the CP ring buffer data */
+ info->ringStart = info->gartOffset;
+ info->ringMapSize = info->ringSize*1024*1024 + radeon_drm_page_size;
+
+ info->ringReadOffset = info->ringStart + info->ringMapSize;
+ info->ringReadMapSize = radeon_drm_page_size;
+
+ /* Reserve space for vertex/indirect buffers */
+ info->bufStart = info->ringReadOffset + info->ringReadMapSize;
+ info->bufMapSize = info->bufSize*1024*1024;
+
+ /* Reserve the rest for AGP textures */
+ info->gartTexStart = info->bufStart + info->bufMapSize;
+ s = (info->gartSize*1024*1024 - info->gartTexStart);
+ l = RADEONMinBits((s-1) / RADEON_NR_TEX_REGIONS);
+ if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+ info->gartTexMapSize = (s >> l) << l;
+ info->log2GARTTexGran = l;
+
+ if (drmAddMap(disp->drmFD, info->ringStart, info->ringMapSize,
+ DRM_AGP, DRM_READ_ONLY, &info->ringHandle) < 0) {
+ fprintf(stderr, "[gart] Could not add ring mapping\n");
+ return 0;
+ }
+ fprintf(stderr, "[gart] ring handle = 0x%08lx\n", info->ringHandle);
+
+
+ if (drmAddMap(disp->drmFD, info->ringReadOffset, info->ringReadMapSize,
+ DRM_AGP, DRM_READ_ONLY, &info->ringReadPtrHandle) < 0) {
+ fprintf(stderr,
+ "[gart] Could not add ring read ptr mapping\n");
+ return 0;
+ }
+
+ fprintf(stderr,
+ "[gart] ring read ptr handle = 0x%08lx\n",
+ info->ringReadPtrHandle);
+
+ if (drmAddMap(disp->drmFD, info->bufStart, info->bufMapSize,
+ DRM_AGP, 0, &info->bufHandle) < 0) {
+ fprintf(stderr,
+ "[gart] Could not add vertex/indirect buffers mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[gart] vertex/indirect buffers handle = 0x%08lx\n",
+ info->bufHandle);
+
+ if (drmAddMap(disp->drmFD, info->gartTexStart, info->gartTexMapSize,
+ DRM_AGP, 0, &info->gartTexHandle) < 0) {
+ fprintf(stderr,
+ "[gart] Could not add AGP texture map mapping\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[gart] AGP texture map handle = 0x%08lx\n",
+ info->gartTexHandle);
+
+ return 1;
+}
+
+
+/**
+ * Initialize all the memory-related fields of the RADEONInfo object.
+ * This includes the various 'offset' and 'size' fields.
+ */
+static int
+RADEONMemoryInit(driDisplay *disp, RADEONInfoPtr info)
+{
+ int width_bytes = disp->virtualWidth * disp->cpp;
+ int cpp = disp->cpp;
+ int bufferSize = ((disp->virtualHeight * width_bytes
+ + RADEON_BUFFER_ALIGN)
+ & ~RADEON_BUFFER_ALIGN);
+ int depthSize = ((((disp->virtualHeight+15) & ~15) * width_bytes
+ + RADEON_BUFFER_ALIGN)
+ & ~RADEON_BUFFER_ALIGN);
+ int l;
+ int pcie_gart_table_size = 0;
+
+ info->frontOffset = 0;
+ info->frontPitch = disp->virtualWidth;
+
+ if (disp->card_type==RADEON_CARD_PCIE)
+ pcie_gart_table_size = RADEON_PCIGART_TABLE_SIZE;
+
+ /* Front, back and depth buffers - everything else texture??
+ */
+ info->textureSize = disp->fbSize - pcie_gart_table_size - 2 * bufferSize - depthSize;
+
+ if (info->textureSize < 0)
+ return 0;
+
+ l = RADEONMinBits((info->textureSize-1) / RADEON_NR_TEX_REGIONS);
+ if (l < RADEON_LOG_TEX_GRANULARITY) l = RADEON_LOG_TEX_GRANULARITY;
+
+ /* Round the texture size up to the nearest whole number of
+ * texture regions. Again, be greedy about this, don't
+ * round down.
+ */
+ info->log2TexGran = l;
+ info->textureSize = (info->textureSize >> l) << l;
+
+ /* Set a minimum usable local texture heap size. This will fit
+ * two 256x256x32bpp textures.
+ */
+ if (info->textureSize < 512 * 1024) {
+ info->textureOffset = 0;
+ info->textureSize = 0;
+ }
+
+ /* Reserve space for textures */
+ info->textureOffset = ((disp->fbSize - pcie_gart_table_size - info->textureSize +
+ RADEON_BUFFER_ALIGN) &
+ ~RADEON_BUFFER_ALIGN);
+
+ /* Reserve space for the shared depth
+ * buffer.
+ */
+ info->depthOffset = ((info->textureOffset - depthSize +
+ RADEON_BUFFER_ALIGN) &
+ ~RADEON_BUFFER_ALIGN);
+ info->depthPitch = disp->virtualWidth;
+
+ info->backOffset = ((info->depthOffset - bufferSize +
+ RADEON_BUFFER_ALIGN) &
+ ~RADEON_BUFFER_ALIGN);
+ info->backPitch = disp->virtualWidth;
+
+ if (pcie_gart_table_size)
+ info->pcieGartTableOffset = disp->fbSize - pcie_gart_table_size;
+
+ fprintf(stderr,
+ "Will use back buffer at offset 0x%x, pitch %d\n",
+ info->backOffset, info->backPitch);
+ fprintf(stderr,
+ "Will use depth buffer at offset 0x%x, pitch %d\n",
+ info->depthOffset, info->depthPitch);
+ fprintf(stderr,
+ "Will use %d kb for textures at offset 0x%x\n",
+ info->textureSize/1024, info->textureOffset);
+ if (pcie_gart_table_size)
+ {
+ fprintf(stderr,
+ "Will use %d kb for PCIE GART Table at offset 0x%x\n",
+ pcie_gart_table_size/1024, info->pcieGartTableOffset);
+ }
+
+ /* XXX I don't think these are needed. */
+#if 0
+ info->frontPitchOffset = (((info->frontPitch * cpp / 64) << 22) |
+ (info->frontOffset >> 10));
+
+ info->backPitchOffset = (((info->backPitch * cpp / 64) << 22) |
+ (info->backOffset >> 10));
+
+ info->depthPitchOffset = (((info->depthPitch * cpp / 64) << 22) |
+ (info->depthOffset >> 10));
+#endif
+
+ if (pcie_gart_table_size)
+ RADEONSetParam(disp, RADEON_SETPARAM_PCIGART_LOCATION, info->pcieGartTableOffset);
+
+ return 1;
+}
+
+
+/**
+ * \brief Initialize the kernel data structures and enable the CP engine.
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * This function is a wrapper around the DRM_RADEON_CP_INIT command, passing
+ * all the parameters in a drm_radeon_init_t structure.
+ */
+static int RADEONDRIKernelInit( driDisplay *disp,
+ RADEONInfoPtr info)
+{
+ int cpp = disp->bpp / 8;
+ drm_radeon_init_t drmInfo;
+ int ret;
+
+ memset(&drmInfo, 0, sizeof(drmInfo));
+
+ if ( (info->ChipFamily >= CHIP_FAMILY_R300) )
+ drmInfo.func = RADEON_INIT_R300_CP;
+ else if ( (info->ChipFamily == CHIP_FAMILY_R200) ||
+ (info->ChipFamily == CHIP_FAMILY_RV250) ||
+ (info->ChipFamily == CHIP_FAMILY_M9) ||
+ (info->ChipFamily == CHIP_FAMILY_RV280) )
+ drmInfo.func = RADEON_INIT_R200_CP;
+ else
+ drmInfo.func = RADEON_INIT_CP;
+
+ /* This is the struct passed to the kernel module for its initialization */
+ /* XXX problem here:
+ * The front/back/depth_offset/pitch fields may change depending upon
+ * which drawing surface we're using!!! They can't be set just once
+ * during initialization.
+ * Looks like we'll need a new ioctl to update these fields for drawing
+ * to other surfaces...
+ */
+ drmInfo.sarea_priv_offset = sizeof(drm_sarea_t);
+ drmInfo.cp_mode = RADEON_DEFAULT_CP_BM_MODE;
+ drmInfo.gart_size = info->gartSize*1024*1024;
+ drmInfo.ring_size = info->ringSize*1024*1024;
+ drmInfo.usec_timeout = 1000;
+ drmInfo.fb_bpp = disp->bpp;
+ drmInfo.depth_bpp = disp->bpp;
+ drmInfo.front_offset = info->frontOffset;
+ drmInfo.front_pitch = info->frontPitch * cpp;
+ drmInfo.back_offset = info->backOffset;
+ drmInfo.back_pitch = info->backPitch * cpp;
+ drmInfo.depth_offset = info->depthOffset;
+ drmInfo.depth_pitch = info->depthPitch * cpp;
+ drmInfo.ring_offset = info->ringHandle;
+ drmInfo.ring_rptr_offset = info->ringReadPtrHandle;
+ drmInfo.buffers_offset = info->bufHandle;
+ drmInfo.gart_textures_offset = info->gartTexHandle;
+
+ ret = drmCommandWrite(disp->drmFD, DRM_RADEON_CP_INIT, &drmInfo,
+ sizeof(drm_radeon_init_t));
+
+ return ret >= 0;
+}
+
+
+/**
+ * \brief Add a map for the vertex buffers that will be accessed by any
+ * DRI-based clients.
+ *
+ * \param ctx display handle.
+ * \param info driver private data.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Calls drmAddBufs() with the previously allocated vertex buffers.
+ */
+static int RADEONDRIBufInit( driDisplay *disp, RADEONInfoPtr info )
+{
+ /* Initialize vertex buffers */
+ info->bufNumBufs = drmAddBufs(disp->drmFD,
+ info->bufMapSize / RADEON_BUFFER_SIZE,
+ RADEON_BUFFER_SIZE,
+ (disp->card_type!=RADEON_CARD_AGP) ? DRM_SG_BUFFER : DRM_AGP_BUFFER,
+ info->bufStart);
+
+ if (info->bufNumBufs <= 0) {
+ fprintf(stderr,
+ "[drm] Could not create vertex/indirect buffers list\n");
+ return 0;
+ }
+ fprintf(stderr,
+ "[drm] Added %d %d byte vertex/indirect buffers\n",
+ info->bufNumBufs, RADEON_BUFFER_SIZE);
+
+ return 1;
+}
+
+
+/**
+ * \brief Install an IRQ handler.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * Attempts to install an IRQ handler via drmCtlInstHandler(), falling back to
+ * IRQ-free operation on failure.
+ */
+static void RADEONDRIIrqInit(driDisplay *disp, RADEONInfoPtr info)
+{
+ if ((drmCtlInstHandler(disp->drmFD, 0)) != 0)
+ fprintf(stderr, "[drm] failure adding irq handler, "
+ "there is a device already using that irq\n"
+ "[drm] falling back to irq-free operation\n");
+}
+
+
+/**
+ * \brief Initialize the AGP heap.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * This function is a wrapper around the DRM_RADEON_INIT_HEAP command, passing
+ * all the parameters in a drm_radeon_mem_init_heap structure.
+ */
+static void RADEONDRIAgpHeapInit(driDisplay *disp,
+ RADEONInfoPtr info)
+{
+ drm_radeon_mem_init_heap_t drmHeap;
+
+ /* Start up the simple memory manager for gart space */
+ drmHeap.region = RADEON_MEM_REGION_GART;
+ drmHeap.start = 0;
+ drmHeap.size = info->gartTexMapSize;
+
+ if (drmCommandWrite(disp->drmFD, DRM_RADEON_INIT_HEAP,
+ &drmHeap, sizeof(drmHeap))) {
+ fprintf(stderr,
+ "[drm] Failed to initialized gart heap manager\n");
+ } else {
+ fprintf(stderr,
+ "[drm] Initialized kernel gart heap manager, %d\n",
+ info->gartTexMapSize);
+ }
+}
+
+static int RADEONGetCardType(driDisplay *disp, RADEONInfoPtr info)
+{
+ drm_radeon_getparam_t gp;
+ int ret;
+
+ gp.param = RADEON_PARAM_CARD_TYPE;
+ gp.value = &disp->card_type;
+
+ ret=drmCommandWriteRead(disp->drmFD, DRM_RADEON_GETPARAM, &gp, sizeof(gp));
+ if (ret) {
+ fprintf(stderr, "drm_radeon_getparam_t (RADEON_PARAM_CARD_TYPE) : %d\n", ret);
+ return -1;
+ }
+
+ return disp->card_type;
+}
+
+/**
+ * Called at the start of each server generation.
+ *
+ * \param disp display handle.
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * Performs static frame buffer allocation. Opens the DRM device and add maps
+ * to the SAREA, framebuffer and MMIO regions. Fills in \p info with more
+ * information. Creates a \e server context to grab the lock for the
+ * initialization ioctls and calls the other initilization functions in this
+ * file. Starts the CP engine via the DRM_RADEON_CP_START command.
+ *
+ * Setups a RADEONDRIRec structure to be passed to radeon_dri.so for its
+ * initialization.
+ */
+static int
+RADEONScreenInit( driDisplay *disp, RADEONInfoPtr info,
+ RADEONDRIPtr pRADEONDRI)
+{
+ int i, err;
+
+ /* XXX this probably isn't needed here */
+ {
+ int width_bytes = (disp->virtualWidth * disp->cpp);
+ int maxy = disp->fbSize / width_bytes;
+
+ if (maxy <= disp->virtualHeight * 3) {
+ _eglLog(_EGL_WARNING,
+ "Static buffer allocation failed -- "
+ "need at least %d kB video memory (have %d kB)\n",
+ (disp->virtualWidth * disp->virtualHeight *
+ disp->cpp * 3 + 1023) / 1024,
+ disp->fbSize / 1024);
+ return 0;
+ }
+ }
+
+ /* Memory manager setup */
+ if (!RADEONMemoryInit(disp, info)) {
+ return 0;
+ }
+
+ /* Create a 'server' context so we can grab the lock for
+ * initialization ioctls.
+ */
+ if ((err = drmCreateContext(disp->drmFD, &disp->serverContext)) != 0) {
+ _eglLog(_EGL_WARNING, "%s: drmCreateContext failed %d\n",
+ __FUNCTION__, err);
+ return 0;
+ }
+
+ DRM_LOCK(disp->drmFD, disp->pSAREA, disp->serverContext, 0);
+
+ /* Initialize the kernel data structures */
+ if (!RADEONDRIKernelInit(disp, info)) {
+ _eglLog(_EGL_WARNING, "RADEONDRIKernelInit failed\n");
+ DRM_UNLOCK(disp->drmFD, disp->pSAREA, disp->serverContext);
+ return 0;
+ }
+
+ /* Initialize the vertex buffers list */
+ if (!RADEONDRIBufInit(disp, info)) {
+ fprintf(stderr, "RADEONDRIBufInit failed\n");
+ DRM_UNLOCK(disp->drmFD, disp->pSAREA, disp->serverContext);
+ return 0;
+ }
+
+ /* Initialize IRQ */
+ RADEONDRIIrqInit(disp, info);
+
+ /* Initialize kernel gart memory manager */
+ RADEONDRIAgpHeapInit(disp, info);
+
+ /* Initialize the SAREA private data structure */
+ {
+ drm_radeon_sarea_t *pSAREAPriv;
+ pSAREAPriv = (drm_radeon_sarea_t *)(((char*)disp->pSAREA) +
+ sizeof(drm_sarea_t));
+ memset(pSAREAPriv, 0, sizeof(*pSAREAPriv));
+ pSAREAPriv->pfState = info->page_flip_enable;
+ }
+
+ for ( i = 0;; i++ ) {
+ drmMapType type;
+ drmMapFlags flags;
+ drm_handle_t handle, offset;
+ drmSize size;
+ int rc, mtrr;
+
+ if ( ( rc = drmGetMap( disp->drmFD, i, &offset, &size, &type, &flags, &handle, &mtrr ) ) != 0 )
+ break;
+ if ( type == DRM_REGISTERS ) {
+ pRADEONDRI->registerHandle = offset;
+ pRADEONDRI->registerSize = size;
+ break;
+ }
+ }
+ /* Quick hack to clear the front & back buffers. Could also use
+ * the clear ioctl to do this, but would need to setup hw state
+ * first.
+ */
+ drimemsetio((char *)disp->pFB + info->frontOffset,
+ 0xEE,
+ info->frontPitch * disp->cpp * disp->virtualHeight );
+
+ drimemsetio((char *)disp->pFB + info->backOffset,
+ 0x30,
+ info->backPitch * disp->cpp * disp->virtualHeight );
+
+
+ /* This is the struct passed to radeon_dri.so for its initialization */
+ pRADEONDRI->deviceID = info->Chipset;
+ pRADEONDRI->width = disp->virtualWidth;
+ pRADEONDRI->height = disp->virtualHeight;
+ pRADEONDRI->depth = disp->bpp; /* XXX: depth */
+ pRADEONDRI->bpp = disp->bpp;
+ pRADEONDRI->IsPCI = (disp->card_type != RADEON_CARD_AGP);;
+ pRADEONDRI->frontOffset = info->frontOffset;
+ pRADEONDRI->frontPitch = info->frontPitch;
+ pRADEONDRI->backOffset = info->backOffset;
+ pRADEONDRI->backPitch = info->backPitch;
+ pRADEONDRI->depthOffset = info->depthOffset;
+ pRADEONDRI->depthPitch = info->depthPitch;
+ pRADEONDRI->textureOffset = info->textureOffset;
+ pRADEONDRI->textureSize = info->textureSize;
+ pRADEONDRI->log2TexGran = info->log2TexGran;
+ pRADEONDRI->statusHandle = info->ringReadPtrHandle;
+ pRADEONDRI->statusSize = info->ringReadMapSize;
+ pRADEONDRI->gartTexHandle = info->gartTexHandle;
+ pRADEONDRI->gartTexMapSize = info->gartTexMapSize;
+ pRADEONDRI->log2GARTTexGran = info->log2GARTTexGran;
+ pRADEONDRI->gartTexOffset = info->gartTexStart;
+ pRADEONDRI->sarea_priv_offset = sizeof(drm_sarea_t);
+
+ /* Don't release the lock now - let the VT switch handler do it. */
+
+ return 1;
+}
+
+
+/**
+ * \brief Get Radeon chip family from chipset number.
+ *
+ * \param info driver private data.
+ *
+ * \return non-zero on success, or zero on failure.
+ *
+ * Called by radeonInitFBDev() to set RADEONInfoRec::ChipFamily
+ * according to the value of RADEONInfoRec::Chipset. Fails if the
+ * chipset is unrecognized or not appropriate for this driver (i.e., not
+ * an r100 style radeon)
+ */
+static int get_chipfamily_from_chipset( RADEONInfoPtr info )
+{
+ switch (info->Chipset) {
+ case PCI_CHIP_RADEON_LY:
+ case PCI_CHIP_RADEON_LZ:
+ info->ChipFamily = CHIP_FAMILY_M6;
+ break;
+
+ case PCI_CHIP_RADEON_QY:
+ case PCI_CHIP_RADEON_QZ:
+ info->ChipFamily = CHIP_FAMILY_VE;
+ break;
+
+ case PCI_CHIP_R200_QL:
+ case PCI_CHIP_R200_QN:
+ case PCI_CHIP_R200_QO:
+ case PCI_CHIP_R200_Ql:
+ case PCI_CHIP_R200_BB:
+ info->ChipFamily = CHIP_FAMILY_R200;
+ break;
+
+ case PCI_CHIP_RV200_QW: /* RV200 desktop */
+ case PCI_CHIP_RV200_QX:
+ info->ChipFamily = CHIP_FAMILY_RV200;
+ break;
+
+ case PCI_CHIP_RADEON_LW:
+ case PCI_CHIP_RADEON_LX:
+ info->ChipFamily = CHIP_FAMILY_M7;
+ break;
+
+ case PCI_CHIP_RV250_Id:
+ case PCI_CHIP_RV250_Ie:
+ case PCI_CHIP_RV250_If:
+ case PCI_CHIP_RV250_Ig:
+ info->ChipFamily = CHIP_FAMILY_RV250;
+ break;
+
+ case PCI_CHIP_RV250_Ld:
+ case PCI_CHIP_RV250_Le:
+ case PCI_CHIP_RV250_Lf:
+ case PCI_CHIP_RV250_Lg:
+ info->ChipFamily = CHIP_FAMILY_M9;
+ break;
+
+ case PCI_CHIP_RV280_Y_:
+ case PCI_CHIP_RV280_Ya:
+ case PCI_CHIP_RV280_Yb:
+ case PCI_CHIP_RV280_Yc:
+ info->ChipFamily = CHIP_FAMILY_RV280;
+ break;
+
+ case PCI_CHIP_R300_ND:
+ case PCI_CHIP_R300_NE:
+ case PCI_CHIP_R300_NF:
+ case PCI_CHIP_R300_NG:
+ info->ChipFamily = CHIP_FAMILY_R300;
+ break;
+
+ case PCI_CHIP_RV370_5460:
+ info->ChipFamily = CHIP_FAMILY_RV380;
+ break;
+
+ default:
+ /* Original Radeon/7200 */
+ info->ChipFamily = CHIP_FAMILY_RADEON;
+ }
+
+ return 1;
+}
+
+
+/**
+ * \brief Initialize the framebuffer device mode
+ *
+ * \param disp display handle.
+ *
+ * \return one on success, or zero on failure.
+ *
+ * Fills in \p info with some default values and some information from \p disp
+ * and then calls RADEONScreenInit() for the screen initialization.
+ *
+ * Before exiting clears the framebuffer memory accessing it directly.
+ */
+static int radeonInitFBDev( driDisplay *disp, RADEONDRIPtr pRADEONDRI )
+{
+ int err;
+ RADEONInfoPtr info = calloc(1, sizeof(*info));
+
+ disp->driverPrivate = (void *)info;
+
+ info->gartFastWrite = RADEON_DEFAULT_AGP_FAST_WRITE;
+ info->gartSize = RADEON_DEFAULT_AGP_SIZE;
+ info->gartTexSize = RADEON_DEFAULT_AGP_TEX_SIZE;
+ info->bufSize = RADEON_DEFAULT_BUFFER_SIZE;
+ info->ringSize = RADEON_DEFAULT_RING_SIZE;
+ info->page_flip_enable = RADEON_DEFAULT_PAGE_FLIP;
+
+ fprintf(stderr,
+ "Using %d MB AGP aperture\n", info->gartSize);
+ fprintf(stderr,
+ "Using %d MB for the ring buffer\n", info->ringSize);
+ fprintf(stderr,
+ "Using %d MB for vertex/indirect buffers\n", info->bufSize);
+ fprintf(stderr,
+ "Using %d MB for AGP textures\n", info->gartTexSize);
+ fprintf(stderr,
+ "page flipping %sabled\n", info->page_flip_enable?"en":"dis");
+
+ info->Chipset = disp->chipset;
+
+ if (!get_chipfamily_from_chipset( info )) {
+ fprintf(stderr, "Unknown or non-radeon chipset -- cannot continue\n");
+ fprintf(stderr, "==> Verify PCI BusID is correct in miniglx.conf\n");
+ return 0;
+ }
+#if 0
+ if (info->ChipFamily >= CHIP_FAMILY_R300) {
+ fprintf(stderr,
+ "Direct rendering not yet supported on "
+ "Radeon 9700 and newer cards\n");
+ return 0;
+ }
+#endif
+
+#if 00
+ /* don't seem to need this here */
+ info->frontPitch = disp->virtualWidth;
+#endif
+
+ /* Check the radeon DRM version */
+ if (!RADEONCheckDRMVersion(disp, info)) {
+ return 0;
+ }
+
+ if (RADEONGetCardType(disp, info)<0)
+ return 0;
+
+ if (disp->card_type!=RADEON_CARD_AGP) {
+ /* Initialize PCI */
+ if (!RADEONDRIPciInit(disp, info))
+ return 0;
+ }
+ else {
+ /* Initialize AGP */
+ if (!RADEONDRIAgpInit(disp, info))
+ return 0;
+ }
+
+ if (!RADEONScreenInit( disp, info, pRADEONDRI))
+ return 0;
+
+ /* Initialize and start the CP if required */
+ if ((err = drmCommandNone(disp->drmFD, DRM_RADEON_CP_START)) != 0) {
+ fprintf(stderr, "%s: CP start %d\n", __FUNCTION__, err);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
+ * Create list of all supported surface configs, attach list to the display.
+ */
+static EGLBoolean
+radeonFillInConfigs(_EGLDisplay *disp, unsigned pixel_bits,
+ unsigned depth_bits,
+ unsigned stencil_bits, GLboolean have_back_buffer)
+{
+ _EGLConfig *configs;
+ _EGLConfig *c;
+ unsigned int i, num_configs;
+ unsigned int depth_buffer_factor;
+ unsigned int back_buffer_factor;
+ GLenum fb_format;
+ GLenum fb_type;
+
+ /* 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.
+ */
+ 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;
+
+ num_configs = depth_buffer_factor * back_buffer_factor * 2;
+
+ if (pixel_bits == 16) {
+ fb_format = GL_RGB;
+ fb_type = GL_UNSIGNED_SHORT_5_6_5;
+ } else {
+ fb_format = GL_RGBA;
+ fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+ }
+
+ configs = calloc(sizeof(*configs), num_configs);
+ c = configs;
+ if (!_eglFillInConfigs(c, fb_format, fb_type,
+ depth_bits_array, stencil_bits_array,
+ depth_buffer_factor,
+ back_buffer_modes, back_buffer_factor,
+ GLX_TRUE_COLOR)) {
+ fprintf(stderr, "[%s:%u] Error creating FBConfig!\n",
+ __func__, __LINE__);
+ return EGL_FALSE;
+ }
+
+ /* Mark the visual as slow if there are "fake" stencil bits.
+ */
+ for (i = 0, c = configs; i < num_configs; i++, c++) {
+ int stencil = GET_CONFIG_ATTRIB(c, EGL_STENCIL_SIZE);
+ if ((stencil != 0) && (stencil != stencil_bits)) {
+ SET_CONFIG_ATTRIB(c, EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG);
+ }
+ }
+
+ for (i = 0, c = configs; i < num_configs; i++, c++)
+ _eglAddConfig(disp, c);
+
+ free(configs);
+
+ return EGL_TRUE;
+}
+
+
+/**
+ * Show the given surface on the named screen.
+ * If surface is EGL_NO_SURFACE, disable the screen's output.
+ */
+static EGLBoolean
+radeonShowScreenSurfaceMESA(_EGLDriver *drv, EGLDisplay dpy, EGLScreenMESA screen,
+ EGLSurface surface, EGLModeMESA m)
+{
+ EGLBoolean b = _eglDRIShowScreenSurfaceMESA(drv, dpy, screen, surface, m);
+ return b;
+}
+
+
+/**
+ * Called via eglInitialize() by user.
+ */
+static EGLBoolean
+radeonInitialize(_EGLDriver *drv, EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+ __DRIframebuffer framebuffer;
+ driDisplay *display;
+
+ /* one-time init */
+ radeon_drm_page_size = getpagesize();
+
+ if (!_eglDRIInitialize(drv, dpy, major, minor))
+ return EGL_FALSE;
+
+ display = Lookup_driDisplay(dpy);
+
+ framebuffer.dev_priv_size = sizeof(RADEONDRIRec);
+ framebuffer.dev_priv = malloc(sizeof(RADEONDRIRec));
+
+ /* XXX we shouldn't hard-code values here! */
+ /* we won't know the screen surface size until the user calls
+ * eglCreateScreenSurfaceMESA().
+ */
+#if 0
+ display->virtualWidth = 1024;
+ display->virtualHeight = 768;
+#else
+ display->virtualWidth = 1280;
+ display->virtualHeight = 1024;
+#endif
+ display->bpp = 32;
+ display->cpp = 4;
+
+ if (!_eglDRIGetDisplayInfo(display))
+ return EGL_FALSE;
+
+ framebuffer.base = display->pFB;
+ framebuffer.width = display->virtualWidth;
+ framebuffer.height = display->virtualHeight;
+ framebuffer.stride = display->virtualWidth;
+ framebuffer.size = display->fbSize;
+ radeonInitFBDev( display, framebuffer.dev_priv );
+
+ if (!_eglDRICreateDisplay(display, &framebuffer))
+ return EGL_FALSE;
+
+ if (!_eglDRICreateScreens(display))
+ return EGL_FALSE;
+
+ /* create a variety of both 32 and 16-bit configurations */
+ radeonFillInConfigs(&display->Base, 32, 24, 8, GL_TRUE);
+ radeonFillInConfigs(&display->Base, 16, 16, 0, GL_TRUE);
+
+ drv->Initialized = EGL_TRUE;
+ return EGL_TRUE;
+}
+
+
+/**
+ * The bootstrap function. Return a new radeonDriver object and
+ * plug in API functions.
+ */
+_EGLDriver *
+_eglMain(_EGLDisplay *dpy)
+{
+ radeonDriver *radeon;
+
+ radeon = (radeonDriver *) calloc(1, sizeof(*radeon));
+ if (!radeon) {
+ return NULL;
+ }
+
+ /* First fill in the dispatch table with defaults */
+ _eglDRIInitDriverFallbacks(&radeon->Base);
+
+ /* then plug in our radeon-specific functions */
+ radeon->Base.API.Initialize = radeonInitialize;
+ radeon->Base.API.ShowScreenSurfaceMESA = radeonShowScreenSurfaceMESA;
+
+ return &radeon->Base;
+}