summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas White <taw@bitwiz.org.uk>2009-07-22 17:29:18 +0100
committerThomas White <taw@bitwiz.org.uk>2009-07-22 17:29:18 +0100
commit477353734de273195ee777eeace44f50aab00e47 (patch)
treee21606e082466f073053a17c0a17f203021b9c3a /src
parentc9f31330d7847820a9cabebc193f22a176690a67 (diff)
Drop in most of the rest of the code
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am4
-rw-r--r--src/glamo-dri2.c128
-rw-r--r--src/glamo-kms-driver.c265
-rw-r--r--src/glamo-kms-exa.c872
-rw-r--r--src/glamo-kms-exa.h25
5 files changed, 1268 insertions, 26 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 28da384..447784f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,4 +38,6 @@ glamo_drv_la_SOURCES = \
glamo-engine.c \
glamo-kms-driver.c \
crtc.c \
- output.c
+ output.c \
+ glamo-dri2.c \
+ glamo-kms-exa.c
diff --git a/src/glamo-dri2.c b/src/glamo-dri2.c
new file mode 100644
index 0000000..fccf2ed
--- /dev/null
+++ b/src/glamo-dri2.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ *
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+
+#include "driver.h"
+
+#include "dri2.h"
+
+extern unsigned int
+driGetPixmapHandle(PixmapPtr pPixmap, unsigned int *flags);
+
+void
+driLock(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+
+ if (!pGlamo->lock_held)
+ DRM_LOCK(pGlamo->drm_fd, pGlamo->lock, pGlamo->context, 0);
+
+ pGlamo->lock_held = 1;
+}
+
+void
+driUnlock(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+
+ if (pGlamo->lock_held)
+ DRM_UNLOCK(pGlamo->drm_fd, pGlamo->lock, pGlamo->context);
+
+ pGlamo->lock_held = 0;
+}
+
+static void
+driBeginClipNotify(ScreenPtr pScreen)
+{
+ driLock(pScreen);
+}
+
+static void
+driEndClipNotify(ScreenPtr pScreen)
+{
+ driUnlock(pScreen);
+}
+
+struct __DRILock
+{
+ unsigned int block_header;
+ drm_hw_lock_t lock;
+ unsigned int next_id;
+};
+
+#define DRI2_SAREA_BLOCK_HEADER(type, size) (((type) << 16) | (size))
+#define DRI2_SAREA_BLOCK_LOCK 0x0001
+
+void
+driScreenInit(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ DRI2InfoRec dri2info;
+ const char *driverName;
+ unsigned int sarea_handle;
+ struct __DRILock *DRILock;
+ void *p;
+
+ dri2info.version = 1;
+ dri2info.fd = pGlamo->drm_fd;
+ dri2info.driverSareaSize = sizeof(struct __DRILock);
+ dri2info.driverName = "i915"; /* FIXME */
+ dri2info.getPixmapHandle = driGetPixmapHandle;
+ dri2info.beginClipNotify = driBeginClipNotify;
+ dri2info.endClipNotify = driEndClipNotify;
+
+ p = DRI2ScreenInit(pScreen, &dri2info);
+ if (!p)
+ return;
+
+ DRILock = p;
+ DRILock->block_header =
+ DRI2_SAREA_BLOCK_HEADER(DRI2_SAREA_BLOCK_LOCK, sizeof *DRILock);
+ pGlamo->lock = &DRILock->lock;
+ pGlamo->context = 1;
+ DRILock->next_id = 2;
+ driLock(pScreen);
+
+ DRI2Connect(pScreen, &pGlamo->drm_fd, &driverName, &sarea_handle);
+}
+
+void
+driCloseScreen(ScreenPtr pScreen)
+{
+ driUnlock(pScreen);
+ DRI2CloseScreen(pScreen);
+}
diff --git a/src/glamo-kms-driver.c b/src/glamo-kms-driver.c
index c04a62f..1d9bac8 100644
--- a/src/glamo-kms-driver.c
+++ b/src/glamo-kms-driver.c
@@ -53,6 +53,7 @@
#include <sys/types.h>
#include <dirent.h>
+#include <stdint.h>
#include <xorg-server.h>
#include <drm.h>
@@ -66,6 +67,8 @@
#include "xf86drm.h"
#include "glamo.h"
+#include "glamo-kms-driver.h"
+#include "glamo-kms-exa.h"
static const char *fbSymbols[] = {
@@ -103,37 +106,68 @@ Bool GlamoKernelModesettingAvailable()
}
-static Bool crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+static Bool CreateFrontBuffer(ScrnInfoPtr pScrn)
{
-#if 0
- modesettingPtr ms = modesettingPTR(pScrn);
- ScreenPtr pScreen = pScrn->pScreen;
- PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
- Bool fbAccessDisabled;
- CARD8 *fbstart;
-
- if (width == pScrn->virtualX && height == pScrn->virtualY)
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ Bool fbAccessDisabled;
+ int flags;
+
+ pGlamo->noEvict = TRUE;
+ pScreen->ModifyPixmapHeader(rootPixmap,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->depth, pScrn->bitsPerPixel,
+ pScrn->displayWidth * pScrn->bitsPerPixel/8,
+ NULL);
+ pGlamo->noEvict = FALSE;
+
+ drmModeAddFB(ms->fd,
+ pScrn->virtualX,
+ pScrn->virtualY,
+ pScrn->depth,
+ pScrn->bitsPerPixel,
+ pScrn->displayWidth * pScrn->bitsPerPixel / 8,
+ driGetPixmapHandle(rootPixmap, &flags), &ms->fb_id);
+
+ pScrn->frameX0 = 0;
+ pScrn->frameY0 = 0;
+ GlamoKMSAdjustFrame(pScrn->scrnIndex,
+ pScrn->frameX0, pScrn->frameY0,
+ 0);
+
return TRUE;
+}
- ErrorF("RESIZING TO %dx%d\n", width, height);
- pScrn->virtualX = width;
- pScrn->virtualY = height;
+static Bool crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+{
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ ScreenPtr pScreen = pScrn->pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ Bool fbAccessDisabled;
+ CARD8 *fbstart;
- /* HW dependent - FIXME */
- pScrn->displayWidth = pScrn->virtualX;
+ if ( (width == pScrn->virtualX) && (height == pScrn->virtualY) )
+ return TRUE; /* Nothing to do */
- drmModeRmFB(ms->fd, ms->fb_id);
+ ErrorF("RESIZING TO %dx%d\n", width, height);
- /* now create new frontbuffer */
- return CreateFrontBuffer(pScrn);
-#endif
- return FALSE;
+ pScrn->virtualX = width;
+ pScrn->virtualY = height;
+
+ /* HW dependent - FIXME */
+ pScrn->displayWidth = pScrn->virtualX;
+
+ drmModeRmFB(pGlamo->drm_fd, pGlamo->fb_id);
+
+ /* now create new frontbuffer */
+ return CreateFrontBuffer(pScrn);
}
static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
- crtc_resize
+ crtc_resize
};
@@ -224,33 +258,214 @@ Bool GlamoKMSPreInit(ScrnInfoPtr pScrn, int flags)
}
+static Bool GlamoKMSCloseScreen(int scrnIndex, ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+
+ if ( pScrn->vtSema ) {
+ GlamoKMSLeaveVT(scrnIndex, 0);
+ }
+ driCloseScreen(pScreen);
+
+ pScreen->CreateScreenResources = pGlamo->createScreenResources;
+
+ if ( pGlamo->exa ) {
+ ExaClose(pScrn);
+ }
+
+ drmClose(pGlamo->drm_fd);
+ pGlamo->drm_fd = -1;
+
+ pScrn->vtSema = FALSE;
+ pScreen->CloseScreen = pGlamo->CloseScreen;
+ return (*pScreen->CloseScreen)(scrnIndex, pScreen);
+}
+
+
Bool GlamoKMSScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
char **argv)
{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ VisualPtr visual;
+ unsigned long sys_mem;
+ int c;
+ MessageType from;
+
+ /* Deal with server regeneration */
+ if ( pGlamo->drm_fd < 0 ) {
+ pGlamo->drm_fd = drmOpen(NULL, "platform:glamo-fb");
+ if ( pGlamo->drm_fd < 0 ) return FALSE;
+ }
+
+ pScrn->pScreen = pScreen;
+
+ /* HW dependent - FIXME */
+ pScrn->displayWidth = pScrn->virtualX;
+
+ miClearVisualTypes();
+
+ if ( !miSetVisualTypes(pScrn->depth,
+ miGetDefaultVisualMask(pScrn->depth),
+ pScrn->rgbBits, pScrn->defaultVisual) ) {
+ return FALSE;
+ }
+
+ if ( !miSetPixmapDepths() ) return FALSE;
+
+ pScrn->memPhysBase = 0;
+ pScrn->fbOffset = 0;
+
+ if ( !fbScreenInit(pScreen, NULL,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->xDpi, pScrn->yDpi,
+ pScrn->displayWidth, pScrn->bitsPerPixel) ) {
+ return FALSE;
+ }
+
+ if (pScrn->bitsPerPixel > 8) {
+ /* Fixup RGB ordering */
+ visual = pScreen->visuals + pScreen->numVisuals;
+ while (--visual >= pScreen->visuals) {
+ if ((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = pScrn->offset.red;
+ visual->offsetGreen = pScrn->offset.green;
+ visual->offsetBlue = pScrn->offset.blue;
+ visual->redMask = pScrn->mask.red;
+ visual->greenMask = pScrn->mask.green;
+ visual->blueMask = pScrn->mask.blue;
+ }
+ }
+ }
+
+ fbPictureInit(pScreen, NULL, 0);
+
+ pGlamo->createScreenResources = pScreen->CreateScreenResources;
+ pScreen->CreateScreenResources = CreateScreenResources;
+
+ xf86SetBlackWhitePixels(pScreen);
+
+ pGlamo->exa = GlamoKMSExaInit(pScrn);
+
+ miInitializeBackingStore(pScreen);
+ xf86SetBackingStore(pScreen);
+ xf86SetSilkenMouse(pScreen);
+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+ /* Need to extend HWcursor support to handle mask interleave */
+ if (!ms->SWCursor) {
+ xf86_cursors_init(pScreen, 64, 64,
+ HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
+ HARDWARE_CURSOR_ARGB);
+ }
+
+ /* Must force it before EnterVT, so we are in control of VT and
+ * later memory should be bound when allocating, e.g rotate_mem */
+ pScrn->vtSema = TRUE;
+
+ pScreen->SaveScreen = xf86SaveScreen;
+ pGlamo->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = GlamoKMSCloseScreen;
+
+ if ( !xf86CrtcScreenInit(pScreen) ) return FALSE;
+
+ if ( !miCreateDefColormap(pScreen) ) return FALSE;
+
+ xf86DPMSInit(pScreen, xf86DPMSSet, 0);
+
+ if ( serverGeneration == 1 ) {
+ xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
+ }
+
+ driScreenInit(pScreen);
+
+ return GlamoKMSEnterVT(scrnIndex, 1);
}
-Bool GlamoSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+Bool GlamoKMSSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
}
-void GlamoAdjustFrame(int scrnIndex, int x, int y, int flags)
+void GlamoKMSAdjustFrame(int scrnIndex, int x, int y, int flags)
{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ xf86OutputPtr output = config->output[config->compat_output];
+ xf86CrtcPtr crtc = output->crtc;
+
+ if (crtc && crtc->enabled) {
+ crtc->funcs->mode_set(crtc,
+ pScrn->currentMode,
+ pScrn->currentMode,
+ x, y);
+ crtc->x = output->initial_x + x;
+ crtc->y = output->initial_y + y;
+ }
}
-Bool GlamoEnterVT(int scrnIndex, int flags)
+Bool GlamoKMSEnterVT(int scrnIndex, int flags)
{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+
+ driUnlock(pScrn->pScreen);
+
+ /* Only save state once per server generation since that's what most
+ * drivers do. Could change this to save state at each VT enter. */
+ if ( pGlamo->SaveGeneration != serverGeneration ) {
+ pGlamo->SaveGeneration = serverGeneration;
+ /* ...except there is no hardware state to save */
+ }
+
+ if ( !flags ) {
+ /* signals startup as we'll do this in CreateScreenResources */
+ CreateFrontBuffer(pScrn);
+ }
+
+ if ( !xf86SetDesiredModes(pScrn) ) return FALSE;
+
+ return TRUE;
}
-void GlamoLeaveVT(int scrnIndex, int flags)
+void GlamoKMSLeaveVT(int scrnIndex, int flags)
{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ GlamoPtr pGlamo = GlamoPTR(pScrn);
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int o;
+
+ for (o = 0; o < config->num_crtc; o++) {
+
+ xf86CrtcPtr crtc = config->crtc[o];
+
+ cursor_destroy(crtc);
+
+ if ( crtc->rotatedPixmap || crtc->rotatedData ) {
+ crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
+ crtc->rotatedData);
+ crtc->rotatedPixmap = NULL;
+ crtc->rotatedData = NULL;
+ }
+
+ }
+
+ drmModeRmFB(pGlamo->drm_fd, pGlamo->fb_id);
+
+ driLock(pScrn->pScreen);
+
+ pScrn->vtSema = FALSE;
}
-ModeStatus GlamoValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose,
+ModeStatus GlamoKMSValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose,
int flags)
{
+ return MODE_OK;
}
diff --git a/src/glamo-kms-exa.c b/src/glamo-kms-exa.c
new file mode 100644
index 0000000..6d84c59
--- /dev/null
+++ b/src/glamo-kms-exa.c
@@ -0,0 +1,872 @@
+/*
+ * EXA via DRI for the SMedia Glamo3362 X.org Driver
+ *
+ * Copyright 2009 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * The KMS parts of this driver are based on xf86-video-modesetting, to
+ * which the following notice applies:
+ *
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Author: Alan Hourihane <alanh@tungstengraphics.com>
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* FIXME ! */
+#define DRI_DRIVER_PATH "/ISO/X.Org/modular/i386/lib/dri"
+
+#include "xf86.h"
+#include "xf86_OSproc.h"
+#include "driver.h"
+#include <dlfcn.h>
+
+#include "pipe/p_winsys.h"
+#include "pipe/p_format.h"
+#include "pipe/p_context.h"
+#include "pipe/p_util.h"
+#include "pipe/p_state.h"
+#include "pipe/p_inlines.h"
+
+/* EXA winsys */
+struct exa_context
+{
+};
+
+struct exa_winsys
+{
+ struct pipe_winsys base;
+ modesettingPtr ms;
+};
+
+struct exa_buffer
+{
+ struct pipe_buffer base;
+ drmBO bo;
+ boolean userBuffer; /** Is this a user-space buffer? */
+ //void *data;
+ //void *mapped;
+};
+
+struct exa_surface
+{
+ struct pipe_surface surface;
+};
+
+struct exa_entity
+{
+ ExaDriverPtr pExa;
+ struct exa_context *c;
+ struct pipe_winsys *ws;
+ struct pipe_context *ctx;
+ struct pipe_screen *scrn;
+};
+
+static INLINE struct exa_winsys *
+exa_get_winsys(struct pipe_winsys *ws)
+{
+ return (struct exa_winsys *)ws;
+}
+
+static INLINE struct exa_surface *
+exa_get_surface(struct pipe_surface *ps)
+{
+ return (struct exa_surface *)ps;
+}
+
+static INLINE struct exa_buffer *
+exa_get_buffer(struct pipe_buffer *buf)
+{
+ return (struct exa_buffer *)buf;
+}
+
+static void *
+exa_buffer_map(struct pipe_winsys *pws, struct pipe_buffer *buf,
+ unsigned flags)
+{
+ struct exa_buffer *exa_buf = exa_get_buffer(buf);
+ struct exa_winsys *exa_winsys = exa_get_winsys(pws);
+ void *virtual;
+
+ drmBOMap(exa_winsys->ms->fd,
+ &exa_buf->bo, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, &virtual);
+
+ return virtual;
+}
+
+static void
+exa_buffer_unmap(struct pipe_winsys *pws, struct pipe_buffer *buf)
+{
+ struct exa_buffer *exa_buf = exa_get_buffer(buf);
+ struct exa_winsys *exa_winsys = exa_get_winsys(pws);
+
+ drmBOUnmap(exa_winsys->ms->fd, &exa_buf->bo);
+}
+
+static void
+exa_buffer_destroy(struct pipe_winsys *pws, struct pipe_buffer *buf)
+{
+ struct exa_winsys *exa_winsys = exa_get_winsys(pws);
+ struct exa_buffer *exa_buf = exa_get_buffer(buf);
+
+ drmBOUnreference(exa_winsys->ms->fd, &exa_buf->bo);
+
+ free(exa_buf);
+}
+
+static void
+exa_flush_frontbuffer(struct pipe_winsys *pws,
+ struct pipe_surface *surf, void *context_private)
+{
+ struct exa_buffer *exa_buf = exa_get_buffer(surf->buffer);
+
+ ErrorF("WANT TO FLUSH\n");
+}
+
+static const char *
+exa_get_name(struct pipe_winsys *pws)
+{
+ return "EXA";
+}
+
+static struct pipe_buffer *
+exa_buffer_create(struct pipe_winsys *pws,
+ unsigned alignment, unsigned usage, unsigned size)
+{
+ struct exa_buffer *buffer = xcalloc(1, sizeof(struct exa_buffer));
+ struct exa_winsys *exa_winsys = exa_get_winsys(pws);
+ unsigned int flags = 0;
+
+ buffer->base.refcount = 1;
+ buffer->base.alignment = alignment;
+ buffer->base.usage = usage;
+ buffer->base.size = size;
+
+ if (exa_winsys->ms->noEvict) {
+ flags = DRM_BO_FLAG_NO_EVICT;
+ ErrorF("DISPLAY TARGET\n");
+ }
+
+ ErrorF("SIZE %d %d\n", size, alignment);
+ if (!buffer->bo.handle) {
+ // buffer->data = align_malloc(size, alignment);
+ drmBOCreate(exa_winsys->ms->fd, size, 0, NULL,
+ DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE |
+ DRM_BO_FLAG_SHAREABLE | DRM_BO_FLAG_MEM_TT |
+ DRM_BO_FLAG_MAPPABLE | flags,
+ 0, &buffer->bo);
+ }
+
+ return &buffer->base;
+}
+
+static struct pipe_buffer *
+exa_user_buffer_create(struct pipe_winsys *pws, void *ptr, unsigned bytes)
+{
+ struct exa_buffer *buffer = xcalloc(1, sizeof(struct exa_buffer));
+
+ buffer->base.refcount = 1;
+ buffer->base.size = bytes;
+ buffer->userBuffer = TRUE;
+ //buffer->data = ptr;
+ ErrorF("USERBUFFER\n");
+
+ return &buffer->base;
+}
+
+/**
+ * Round n up to next multiple.
+ */
+static INLINE unsigned
+round_up(unsigned n, unsigned multiple)
+{
+ return (n + multiple - 1) & ~(multiple - 1);
+}
+
+static int
+exa_surface_alloc_storage(struct pipe_winsys *winsys,
+ struct pipe_surface *surf,
+ unsigned width, unsigned height,
+ enum pipe_format format,
+ unsigned flags, unsigned tex_usage)
+{
+ const unsigned alignment = 64;
+
+ surf->width = width;
+ surf->height = height;
+ surf->format = format;
+ pf_get_block(format, &surf->block);
+ surf->stride = round_up(surf->nblocksx * surf->block.size, alignment);
+
+ assert(!surf->buffer);
+ surf->buffer = winsys->buffer_create(winsys, alignment,
+ PIPE_BUFFER_USAGE_PIXEL,
+ surf->stride * height);
+ if (!surf->buffer)
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Called via winsys->surface_alloc() to create new surfaces.
+ */
+static struct pipe_surface *
+exa_surface_alloc(struct pipe_winsys *ws)
+{
+ struct exa_surface *wms = xcalloc(1, sizeof(struct exa_surface));
+
+ assert(ws);
+
+ wms->surface.refcount = 1;
+ wms->surface.winsys = ws;
+
+ return &wms->surface;
+}
+
+static void
+exa_surface_release(struct pipe_winsys *winsys, struct pipe_surface **s)
+{
+ struct pipe_surface *surf = *s;
+
+ surf->refcount--;
+ if (surf->refcount == 0) {
+ if (surf->buffer)
+ pipe_buffer_reference(winsys, &surf->buffer, NULL);
+ free(surf);
+ }
+ *s = NULL;
+}
+
+/*
+ * Fence functions - basically nothing to do, as we don't create any actual
+ * fence objects.
+ */
+static void
+exa_fence_reference(struct pipe_winsys *sws, struct pipe_fence_handle **ptr,
+ struct pipe_fence_handle *fence)
+{
+}
+
+static int
+exa_fence_signalled(struct pipe_winsys *sws, struct pipe_fence_handle *fence,
+ unsigned flag)
+{
+ return 0;
+}
+
+static int
+exa_fence_finish(struct pipe_winsys *sws, struct pipe_fence_handle *fence,
+ unsigned flag)
+{
+ return 0;
+}
+
+struct pipe_winsys *
+exa_get_pipe_winsys(modesettingPtr ms)
+{
+ static struct exa_winsys *ws = NULL;
+
+ if (!ws) {
+ ws = xcalloc(1, sizeof(struct exa_winsys));
+
+ /* Fill in this struct with callbacks that pipe will need to
+ * communicate with the window system, buffer manager, etc.
+ */
+ ws->base.buffer_create = exa_buffer_create;
+ ws->base.user_buffer_create = exa_user_buffer_create;
+ ws->base.buffer_map = exa_buffer_map;
+ ws->base.buffer_unmap = exa_buffer_unmap;
+ ws->base.buffer_destroy = exa_buffer_destroy;
+
+ ws->base.surface_alloc = exa_surface_alloc;
+ ws->base.surface_alloc_storage = exa_surface_alloc_storage;
+ ws->base.surface_release = exa_surface_release;
+
+ ws->base.fence_reference = exa_fence_reference;
+ ws->base.fence_signalled = exa_fence_signalled;
+ ws->base.fence_finish = exa_fence_finish;
+
+ ws->base.flush_frontbuffer = exa_flush_frontbuffer;
+ ws->base.get_name = exa_get_name;
+
+ ws->ms = ms;
+ }
+
+ return &ws->base;
+}
+
+/* EXA functions */
+
+struct PixmapPriv
+{
+ drmBO bo;
+#if 0
+ dri_fence *fence;
+#endif
+ int flags;
+
+ struct pipe_texture *tex;
+ unsigned int color;
+ struct pipe_surface *src_surf; /* for copies */
+};
+
+static enum pipe_format
+exa_get_pipe_format(int depth)
+{
+ switch (depth) {
+ case 32:
+ case 24:
+ return PIPE_FORMAT_A8R8G8B8_UNORM;
+ case 16:
+ return PIPE_FORMAT_R5G6B5_UNORM;
+ case 15:
+ return PIPE_FORMAT_A1R5G5B5_UNORM;
+ case 8:
+ case 4:
+ case 1:
+ return PIPE_FORMAT_A8R8G8B8_UNORM; /* bad bad bad */
+ default:
+ assert(0);
+ return 0;
+ }
+}
+
+/*
+ * EXA functions
+ */
+
+static void
+ExaWaitMarker(ScreenPtr pScreen, int marker)
+{
+}
+
+static int
+ExaMarkSync(ScreenPtr pScreen)
+{
+ return 1;
+}
+
+Bool
+ExaPrepareAccess(PixmapPtr pPix, int index)
+{
+ ScreenPtr pScreen = pPix->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ struct exa_entity *exa = ms->exa;
+ struct PixmapPriv *priv;
+ int ret;
+
+ priv = exaGetPixmapDriverPrivate(pPix);
+
+ if (!priv)
+ return FALSE;
+
+ if (!priv->tex)
+ return FALSE;
+ {
+ struct pipe_surface *surf =
+ exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
+ PIPE_BUFFER_USAGE_CPU_READ |
+ PIPE_BUFFER_USAGE_CPU_WRITE);
+ pPix->devPrivate.ptr =
+ exa->scrn->surface_map(exa->scrn, surf,
+ PIPE_BUFFER_USAGE_CPU_READ |
+ PIPE_BUFFER_USAGE_CPU_WRITE);
+ exa->scrn->tex_surface_release(exa->scrn, &surf);
+ }
+
+ return TRUE;
+}
+
+void
+ExaFinishAccess(PixmapPtr pPix, int index)
+{
+ ScreenPtr pScreen = pPix->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ struct PixmapPriv *priv;
+ struct exa_entity *exa = ms->exa;
+ int ret;
+
+ priv = exaGetPixmapDriverPrivate(pPix);
+
+ if (!priv)
+ return;
+
+ if (!priv->tex)
+ return;
+ {
+ struct pipe_surface *surf =
+ exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
+ PIPE_BUFFER_USAGE_CPU_READ |
+ PIPE_BUFFER_USAGE_CPU_WRITE);
+ exa->scrn->surface_unmap(exa->scrn, surf);
+ exa->scrn->tex_surface_release(exa->scrn, &surf);
+ pPix->devPrivate.ptr = NULL;
+ }
+}
+
+static void
+ExaDone(PixmapPtr pPixmap)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct PixmapPriv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ struct exa_entity *exa = ms->exa;
+
+ if (!priv)
+ return;
+
+ if (priv->src_surf)
+ exa->scrn->tex_surface_release(exa->scrn, &priv->src_surf);
+ priv->src_surf = NULL;
+}
+
+static void
+ExaDoneComposite(PixmapPtr pPixmap)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+}
+
+static Bool
+ExaPrepareSolid(PixmapPtr pPixmap, int alu, Pixel planeMask, Pixel fg)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct PixmapPriv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ struct exa_entity *exa = ms->exa;
+
+ if (pPixmap->drawable.depth < 15)
+ return FALSE;
+
+ if (!EXA_PM_IS_SOLID(&pPixmap->drawable, planeMask))
+ return FALSE;
+
+ if (!priv || !priv->tex)
+ return FALSE;
+
+ if (alu != GXcopy)
+ return FALSE;
+
+ if (!exa->ctx || !exa->ctx->surface_fill)
+ return FALSE;
+
+ priv->color = fg;
+
+ return TRUE;
+}
+
+static void
+ExaSolid(PixmapPtr pPixmap, int x0, int y0, int x1, int y1)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_entity *exa = ms->exa;
+ struct PixmapPriv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ struct pipe_surface *surf =
+ exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
+ PIPE_BUFFER_USAGE_GPU_READ |
+ PIPE_BUFFER_USAGE_GPU_WRITE);
+
+ exa->ctx->surface_fill(exa->ctx, surf, x0, y0, x1 - x0, y1 - y0,
+ priv->color);
+
+ exa->scrn->tex_surface_release(exa->scrn, &surf);
+}
+
+static Bool
+ExaPrepareCopy(PixmapPtr pSrcPixmap, PixmapPtr pDstPixmap, int xdir,
+ int ydir, int alu, Pixel planeMask)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_entity *exa = ms->exa;
+ struct pipe_surface *src_surf;
+ struct PixmapPriv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
+ struct PixmapPriv *src_priv = exaGetPixmapDriverPrivate(pSrcPixmap);
+
+ if (alu != GXcopy)
+ return FALSE;
+
+ if (pSrcPixmap->drawable.depth < 15 || pDstPixmap->drawable.depth < 15)
+ return FALSE;
+
+ if (!EXA_PM_IS_SOLID(&pSrcPixmap->drawable, planeMask))
+ return FALSE;
+
+ if (!priv || !src_priv)
+ return FALSE;
+
+ if (!priv->tex || !src_priv->tex)
+ return FALSE;
+
+ if (!exa->ctx || !exa->ctx->surface_copy)
+ return FALSE;
+
+ priv->src_surf =
+ exa->scrn->get_tex_surface(exa->scrn, src_priv->tex, 0, 0, 0,
+ PIPE_BUFFER_USAGE_GPU_READ |
+ PIPE_BUFFER_USAGE_GPU_WRITE);
+
+ return FALSE;
+}
+
+static void
+ExaCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY,
+ int width, int height)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_entity *exa = ms->exa;
+ struct PixmapPriv *priv = exaGetPixmapDriverPrivate(pDstPixmap);
+ struct pipe_surface *surf =
+ exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
+ PIPE_BUFFER_USAGE_GPU_READ |
+ PIPE_BUFFER_USAGE_GPU_WRITE);
+
+ exa->ctx->surface_copy(exa->ctx, 0, surf, dstX, dstY, priv->src_surf,
+ srcX, srcY, width, height);
+ exa->scrn->tex_surface_release(exa->scrn, &surf);
+}
+
+static Bool
+ExaPrepareComposite(int op, PicturePtr pSrcPicture,
+ PicturePtr pMaskPicture, PicturePtr pDstPicture,
+ PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
+{
+ ScreenPtr pScreen = pDst->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+
+ return FALSE;
+}
+
+static Bool
+ExaUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h, char *src,
+ int src_pitch)
+{
+ ScreenPtr pScreen = pDst->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+
+ ErrorF("UPLOAD\n");
+
+ return FALSE;
+}
+
+static void
+ExaComposite(PixmapPtr pDst, int srcX, int srcY, int maskX, int maskY,
+ int dstX, int dstY, int width, int height)
+{
+ ScreenPtr pScreen = pDst->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+}
+
+static Bool
+ExaCheckComposite(int op,
+ PicturePtr pSrcPicture, PicturePtr pMaskPicture,
+ PicturePtr pDstPicture)
+{
+ DrawablePtr pDraw = pSrcPicture->pDrawable;
+ int w = pDraw->width;
+ int h = pDraw->height;
+
+ return FALSE;
+}
+
+static void *
+ExaCreatePixmap(ScreenPtr pScreen, int size, int align)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct PixmapPriv *priv;
+ void *virtual;
+
+ priv = xcalloc(1, sizeof(struct PixmapPriv));
+ if (!priv)
+ return NULL;
+
+ return priv;
+}
+
+static void
+ExaDestroyPixmap(ScreenPtr pScreen, void *dPriv)
+{
+ struct PixmapPriv *priv = (struct PixmapPriv *)dPriv;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_entity *exa = ms->exa;
+
+ if (!priv)
+ return;
+
+ if (priv->tex)
+ exa->scrn->texture_release(exa->scrn, &priv->tex);
+
+ xfree(priv);
+}
+
+static Bool
+ExaPixmapIsOffscreen(PixmapPtr pPixmap)
+{
+ struct PixmapPriv *priv;
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+
+ priv = exaGetPixmapDriverPrivate(pPixmap);
+
+ if (!priv)
+ return FALSE;
+
+ if (priv->tex)
+ return TRUE;
+
+ return FALSE;
+}
+
+/* FIXME !! */
+unsigned int
+driGetPixmapHandle(PixmapPtr pPixmap, unsigned int *flags)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_entity *exa = ms->exa;
+ struct exa_buffer *exa_buf;
+ struct pipe_surface *surf;
+ struct PixmapPriv *priv;
+
+ *flags = 0;
+
+ if (!ms->exa) {
+ FatalError("NO MS->EXA\n");
+ return 0;
+ }
+
+ priv = exaGetPixmapDriverPrivate(pPixmap);
+
+ if (!priv) {
+ FatalError("NO PIXMAP PRIVATE\n");
+ return 0;
+ }
+
+ surf =
+ exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
+ PIPE_BUFFER_USAGE_CPU_READ |
+ PIPE_BUFFER_USAGE_CPU_WRITE);
+ exa_buf = exa_get_buffer(surf->buffer);
+ exa->scrn->tex_surface_release(exa->scrn, &surf);
+
+ if (exa_buf->bo.handle)
+ return exa_buf->bo.handle;
+
+ return 0;
+}
+
+static Bool
+ExaModifyPixmapHeader(PixmapPtr pPixmap, int width, int height,
+ int depth, int bitsPerPixel, int devKind,
+ pointer pPixData)
+{
+ ScreenPtr pScreen = pPixmap->drawable.pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ struct PixmapPriv *priv = exaGetPixmapDriverPrivate(pPixmap);
+ modesettingPtr ms = modesettingPTR(pScrn);
+ PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+ struct exa_entity *exa = ms->exa;
+
+ if (!priv)
+ return FALSE;
+
+ if (depth <= 0)
+ depth = pPixmap->drawable.depth;
+
+ if (bitsPerPixel <= 0)
+ bitsPerPixel = pPixmap->drawable.bitsPerPixel;
+
+ if (width <= 0)
+ width = pPixmap->drawable.width;
+
+ if (height <= 0)
+ height = pPixmap->drawable.height;
+
+ if (width <= 0 || height <= 0 || depth <= 0)
+ return FALSE;
+
+ miModifyPixmapHeader(pPixmap, width, height, depth,
+ bitsPerPixel, devKind, NULL);
+
+ /* Deal with screen resize */
+ if (priv->tex) {
+ struct pipe_surface *surf =
+ exa->scrn->get_tex_surface(exa->scrn, priv->tex, 0, 0, 0,
+ PIPE_BUFFER_USAGE_CPU_READ |
+ PIPE_BUFFER_USAGE_CPU_WRITE);
+
+ ErrorF("RESIZE %d %d to %d %d\n", surf->width, surf->height, width,
+ height);
+ if (surf->width != width || surf->height != height) {
+ exa->scrn->texture_release(exa->scrn, &priv->tex);
+ priv->tex = NULL;
+ }
+ exa->scrn->tex_surface_release(exa->scrn, &surf);
+ }
+
+ if (!priv->tex) {
+ struct pipe_texture template;
+
+ memset(&template, 0, sizeof(template));
+ template.target = PIPE_TEXTURE_2D;
+ template.compressed = 0;
+ template.format = exa_get_pipe_format(depth);
+ pf_get_block(template.format, &template.block);
+ template.width[0] = width;
+ template.height[0] = height;
+ template.depth[0] = 1;
+ template.last_level = 0;
+ template.tex_usage = PIPE_TEXTURE_USAGE_RENDER_TARGET;
+ priv->tex = exa->scrn->texture_create(exa->scrn, &template);
+ }
+
+ return TRUE;
+}
+
+void
+ExaClose(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_entity *exa = ms->exa;
+
+ exaDriverFini(pScrn->pScreen);
+
+ dlclose(ms->driver);
+}
+
+void *GlamoKMSExaInit(ScrnInfoPtr pScrn)
+{
+ modesettingPtr ms = modesettingPTR(pScrn);
+ struct exa_entity *exa;
+ ExaDriverPtr pExa;
+
+ exa = xcalloc(1, sizeof(struct exa_entity));
+ if (!exa)
+ return NULL;
+
+ pExa = exaDriverAlloc();
+ if (!pExa) {
+ goto out_err;
+ }
+
+ memset(pExa, 0, sizeof(*pExa));
+ pExa->exa_major = 2;
+ pExa->exa_minor = 4;
+ pExa->memoryBase = 0;
+ pExa->memorySize = 0;
+ pExa->offScreenBase = 0;
+ pExa->pixmapOffsetAlign = 0;
+ pExa->pixmapPitchAlign = 1;
+ pExa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_HANDLES_PIXMAPS;
+ pExa->maxX = 8191; /* FIXME */
+ pExa->maxY = 8191; /* FIXME */
+ pExa->WaitMarker = ExaWaitMarker;
+ pExa->MarkSync = ExaMarkSync;
+ pExa->PrepareSolid = ExaPrepareSolid;
+ pExa->Solid = ExaSolid;
+ pExa->DoneSolid = ExaDone;
+ pExa->PrepareCopy = ExaPrepareCopy;
+ pExa->Copy = ExaCopy;
+ pExa->DoneCopy = ExaDone;
+ pExa->CheckComposite = ExaCheckComposite;
+ pExa->PrepareComposite = ExaPrepareComposite;
+ pExa->Composite = ExaComposite;
+ pExa->DoneComposite = ExaDoneComposite;
+ pExa->PixmapIsOffscreen = ExaPixmapIsOffscreen;
+ pExa->PrepareAccess = ExaPrepareAccess;
+ pExa->FinishAccess = ExaFinishAccess;
+ pExa->UploadToScreen = ExaUploadToScreen;
+ pExa->CreatePixmap = ExaCreatePixmap;
+ pExa->DestroyPixmap = ExaDestroyPixmap;
+ pExa->ModifyPixmapHeader = ExaModifyPixmapHeader;
+
+ if (!exaDriverInit(pScrn->pScreen, pExa)) {
+ goto out_err;
+ }
+
+ {
+ char filename[128];
+ char dri_driver_path[] = DRI_DRIVER_PATH;
+
+ snprintf(filename, sizeof filename,
+ "%s/%s_dri.so", dri_driver_path, "i915");
+
+ ms->driver = dlopen(filename, RTLD_NOW | RTLD_DEEPBIND | RTLD_GLOBAL);
+ if (!ms->driver)
+ FatalError("failed to initialize i915 - for softpipe only.\n");
+
+ exa->c = xcalloc(1, sizeof(struct exa_context));
+
+ exa->ws = exa_get_pipe_winsys(ms);
+ if (!exa->ws)
+ FatalError("BAD WINSYS\n");
+
+ exa->scrn = softpipe_create_screen(exa->ws);
+ if (!exa->scrn)
+ FatalError("BAD SCREEN\n");
+
+ exa->ctx = softpipe_create(exa->scrn, exa->ws, NULL);
+ if (!exa->ctx)
+ FatalError("BAD CTX\n");
+
+ exa->ctx->priv = exa->c;
+ }
+
+ return (void *)exa;
+
+ out_err:
+ ExaClose(pScrn);
+
+ return NULL;
+}
diff --git a/src/glamo-kms-exa.h b/src/glamo-kms-exa.h
new file mode 100644
index 0000000..6649892
--- /dev/null
+++ b/src/glamo-kms-exa.h
@@ -0,0 +1,25 @@
+/*
+ * EXA via DRI for the SMedia Glamo3362 X.org Driver
+ *
+ * Copyright 2009 Thomas White <taw@bitwiz.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include "xf86.h"
+
+extern void *GlamoKMSExaInit(ScrnInfoPtr pScrn);