Merge branch 'mesa_7_6_branch' into mesa_7_7_branch
[mesa.git] / src / gallium / state_trackers / xorg / xorg_driver.c
index e01e5294b11a060deb62964354b4bea217f3f45b..8a24aa10a3cf7b08397d31a1ad1f0eeaca73c691 100644 (file)
 #include "xf86.h"
 #include "xf86_OSproc.h"
 #include "compiler.h"
-#include "xf86RAC.h"
 #include "xf86PciInfo.h"
 #include "xf86Pci.h"
-#include "xf86Resources.h"
 #include "mipointer.h"
 #include "micmap.h"
 #include <X11/extensions/randr.h>
 
 #include <pciaccess.h>
 
+#include "pipe/p_context.h"
 #include "xorg_tracker.h"
 #include "xorg_winsys.h"
 
-static void AdjustFrame(int scrnIndex, int x, int y, int flags);
-static Bool CloseScreen(int scrnIndex, ScreenPtr pScreen);
-static Bool EnterVT(int scrnIndex, int flags);
-static Bool SaveHWState(ScrnInfoPtr pScrn);
-static Bool RestoreHWState(ScrnInfoPtr pScrn);
+#ifdef HAVE_LIBKMS
+#include "libkms.h"
+#endif
 
+/*
+ * Functions and symbols exported to Xorg via pointers.
+ */
 
-static ModeStatus ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose,
-                           int flags);
-static void FreeScreen(int scrnIndex, int flags);
-static void LeaveVT(int scrnIndex, int flags);
-static Bool SwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
-static Bool ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
-                      char **argv);
-static Bool PreInit(ScrnInfoPtr pScrn, int flags);
+static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags);
+static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc,
+                           char **argv);
+static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags);
+static void drv_adjust_frame(int scrnIndex, int x, int y, int flags);
+static Bool drv_enter_vt(int scrnIndex, int flags);
+static void drv_leave_vt(int scrnIndex, int flags);
+static void drv_free_screen(int scrnIndex, int flags);
+static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose,
+                                int flags);
 
 typedef enum
 {
     OPTION_SW_CURSOR,
-} modesettingOpts;
+    OPTION_2D_ACCEL,
+} drv_option_enums;
 
-static const OptionInfoRec Options[] = {
+static const OptionInfoRec drv_options[] = {
     {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
+    {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE},
     {-1, NULL, OPTV_NONE, {0}, FALSE}
 };
 
-/*
- * Functions that might be needed
- */
-
-static const char *exaSymbols[] = {
-    "exaGetVersion",
-    "exaDriverInit",
-    "exaDriverFini",
-    "exaOffscreenAlloc",
-    "exaOffscreenFree",
-    "exaWaitSync",
-    NULL
-};
-
-static const char *fbSymbols[] = {
-    "fbPictureInit",
-    "fbScreenInit",
-    NULL
-};
-
-static const char *ddcSymbols[] = {
-    "xf86PrintEDID",
-    "xf86SetDDCproperties",
-    NULL
-};
 
 /*
  * Exported Xorg driver functions to winsys
  */
 
-void
-xorg_tracker_loader_ref_sym_lists()
-{
-    LoaderRefSymLists(exaSymbols, fbSymbols, ddcSymbols, NULL);
-}
-
 const OptionInfoRec *
 xorg_tracker_available_options(int chipid, int busid)
 {
-    return Options;
+    return drv_options;
 }
 
 void
 xorg_tracker_set_functions(ScrnInfoPtr scrn)
 {
-    scrn->PreInit = PreInit;
-    scrn->ScreenInit = ScreenInit;
-    scrn->SwitchMode = SwitchMode;
-    scrn->AdjustFrame = AdjustFrame;
-    scrn->EnterVT = EnterVT;
-    scrn->LeaveVT = LeaveVT;
-    scrn->FreeScreen = FreeScreen;
-    scrn->ValidMode = ValidMode;
+    scrn->PreInit = drv_pre_init;
+    scrn->ScreenInit = drv_screen_init;
+    scrn->SwitchMode = drv_switch_mode;
+    scrn->AdjustFrame = drv_adjust_frame;
+    scrn->EnterVT = drv_enter_vt;
+    scrn->LeaveVT = drv_leave_vt;
+    scrn->FreeScreen = drv_free_screen;
+    scrn->ValidMode = drv_valid_mode;
 }
 
+
+/*
+ * Internal function definitions
+ */
+
+static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn);
+static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen);
+static Bool drv_save_hw_state(ScrnInfoPtr pScrn);
+static Bool drv_restore_hw_state(ScrnInfoPtr pScrn);
+
+
 /*
- * Static Xorg funtctions
+ * Internal functions
  */
 
 static Bool
-GetRec(ScrnInfoPtr pScrn)
+drv_get_rec(ScrnInfoPtr pScrn)
 {
     if (pScrn->driverPrivate)
        return TRUE;
@@ -154,7 +138,7 @@ GetRec(ScrnInfoPtr pScrn)
 }
 
 static void
-FreeRec(ScrnInfoPtr pScrn)
+drv_free_rec(ScrnInfoPtr pScrn)
 {
     if (!pScrn)
        return;
@@ -168,80 +152,128 @@ FreeRec(ScrnInfoPtr pScrn)
 }
 
 static void
-ProbeDDC(ScrnInfoPtr pScrn, int index)
+drv_probe_ddc(ScrnInfoPtr pScrn, int index)
 {
     ConfiguredMonitor = NULL;
 }
 
 static Bool
-CreateFrontBuffer(ScrnInfoPtr pScrn)
+drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height)
 {
     modesettingPtr ms = modesettingPTR(pScrn);
+    PixmapPtr rootPixmap;
     ScreenPtr pScreen = pScrn->pScreen;
-    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
 
-    ms->noEvict = TRUE;
-    pScreen->ModifyPixmapHeader(rootPixmap,
-                               pScrn->virtualX, pScrn->virtualY,
-                               pScrn->depth, pScrn->bitsPerPixel,
-                               pScrn->displayWidth * pScrn->bitsPerPixel / 8,
-                               NULL);
-    ms->noEvict = FALSE;
+    if (width == pScrn->virtualX && height == pScrn->virtualY)
+       return TRUE;
 
-    drmModeAddFB(ms->fd,
-                pScrn->virtualX,
-                pScrn->virtualY,
-                pScrn->depth,
-                pScrn->bitsPerPixel,
-                pScrn->displayWidth * pScrn->bitsPerPixel / 8,
-                xorg_exa_get_pixmap_handle(rootPixmap), &ms->fb_id);
+    pScrn->virtualX = width;
+    pScrn->virtualY = height;
 
-    pScrn->frameX0 = 0;
-    pScrn->frameY0 = 0;
-    AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+    /*
+     * Remove the old framebuffer & texture.
+     */
+    drmModeRmFB(ms->fd, ms->fb_id);
+    if (!ms->destroy_front_buffer(pScrn))
+       FatalError("failed to destroy front buffer\n");
+
+    rootPixmap = pScreen->GetScreenPixmap(pScreen);
+    if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL))
+       return FALSE;
+
+    /* HW dependent - FIXME */
+    pScrn->displayWidth = pScrn->virtualX;
+
+    /* now create new frontbuffer */
+    return ms->create_front_buffer(pScrn) && ms->bind_front_buffer(pScrn);
+}
+
+static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
+    .resize = drv_crtc_resize
+};
+
+static Bool
+drv_init_drm(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+
+    /* deal with server regeneration */
+    if (ms->fd < 0) {
+       char *BusID;
+
+       BusID = xalloc(64);
+       sprintf(BusID, "PCI:%d:%d:%d",
+               ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
+               ms->PciInfo->dev, ms->PciInfo->func
+           );
+
+       ms->fd = drmOpen(NULL, BusID);
+
+       if (ms->fd < 0)
+           return FALSE;
+    }
 
     return TRUE;
 }
 
 static Bool
-crtc_resize(ScrnInfoPtr pScrn, int width, int height)
+drv_init_resource_management(ScrnInfoPtr pScrn)
 {
     modesettingPtr ms = modesettingPTR(pScrn);
-    //ScreenPtr pScreen = pScrn->pScreen;
-    //PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
-    //Bool fbAccessDisabled;
-    //CARD8 *fbstart;
 
-    if (width == pScrn->virtualX && height == pScrn->virtualY)
+    if (ms->screen || ms->kms)
        return TRUE;
 
-    ErrorF("RESIZING TO %dx%d\n", width, height);
+    ms->api = drm_api_create();
+    if (ms->api) {
+       ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL);
 
-    pScrn->virtualX = width;
-    pScrn->virtualY = height;
+       if (ms->screen)
+           return TRUE;
 
-    /* HW dependent - FIXME */
-    pScrn->displayWidth = pScrn->virtualX;
+       if (ms->api->destroy)
+           ms->api->destroy(ms->api);
 
-    drmModeRmFB(ms->fd, ms->fb_id);
+       ms->api = NULL;
+    }
 
-    /* now create new frontbuffer */
-    return CreateFrontBuffer(pScrn);
+#ifdef HAVE_LIBKMS
+    if (!kms_create(ms->fd, &ms->kms))
+       return TRUE;
+#endif
+
+    return FALSE;
 }
 
-static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
-    crtc_resize
-};
+static Bool
+drv_close_resource_management(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+
+    if (ms->screen)
+       ms->screen->destroy(ms->screen);
+    ms->screen = NULL;
+
+    if (ms->api && ms->api->destroy)
+       ms->api->destroy(ms->api);
+    ms->api = NULL;
+
+#ifdef HAVE_LIBKMS
+    if (ms->kms)
+       kms_destroy(&ms->kms);
+#endif
+
+    return TRUE;
+}
 
 static Bool
-PreInit(ScrnInfoPtr pScrn, int flags)
+drv_pre_init(ScrnInfoPtr pScrn, int flags)
 {
     xf86CrtcConfigPtr xf86_config;
     modesettingPtr ms;
     rgb defaultWeight = { 0, 0, 0 };
     EntityInfoPtr pEnt;
     EntPtr msEnt = NULL;
-    char *BusID;
     int max_width, max_height;
 
     if (pScrn->numEntities != 1)
@@ -250,12 +282,12 @@ PreInit(ScrnInfoPtr pScrn, int flags)
     pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
 
     if (flags & PROBE_DETECT) {
-       ProbeDDC(pScrn, pEnt->index);
+       drv_probe_ddc(pScrn, pEnt->index);
        return TRUE;
     }
 
     /* Allocate driverPrivate */
-    if (!GetRec(pScrn))
+    if (!drv_get_rec(pScrn))
        return FALSE;
 
     ms = modesettingPTR(pScrn);
@@ -282,10 +314,6 @@ PreInit(ScrnInfoPtr pScrn, int flags)
     } else
        ms->entityPrivate = NULL;
 
-    if (xf86RegisterResources(ms->pEnt->index, NULL, ResNone)) {
-       return FALSE;
-    }
-
     if (xf86IsEntityShared(pScrn->entityList[0])) {
        if (xf86IsPrimInitDone(pScrn->entityList[0])) {
            /* do something */
@@ -294,19 +322,11 @@ PreInit(ScrnInfoPtr pScrn, int flags)
        }
     }
 
-    BusID = xalloc(64);
-    sprintf(BusID, "PCI:%d:%d:%d",
-           ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
-           ms->PciInfo->dev, ms->PciInfo->func
-       );
-
-    ms->api = drm_api_create();
-    ms->fd = drmOpen(NULL, BusID);
-
-    if (ms->fd < 0)
+    ms->fd = -1;
+    ms->api = NULL;
+    if (!drv_init_drm(pScrn))
        return FALSE;
 
-    pScrn->racMemFlags = RAC_FB | RAC_COLORMAP;
     pScrn->monitor = pScrn->confScreen->monitor;
     pScrn->progClock = TRUE;
     pScrn->rgbBits = 8;
@@ -336,9 +356,9 @@ PreInit(ScrnInfoPtr pScrn, int flags)
 
     /* Process the options */
     xf86CollectOptions(pScrn, NULL);
-    if (!(ms->Options = xalloc(sizeof(Options))))
+    if (!(ms->Options = xalloc(sizeof(drv_options))))
        return FALSE;
-    memcpy(ms->Options, Options, sizeof(Options));
+    memcpy(ms->Options, drv_options, sizeof(drv_options));
     xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
 
     /* Allocate an xf86CrtcConfig */
@@ -353,18 +373,18 @@ PreInit(ScrnInfoPtr pScrn, int flags)
        ms->SWCursor = TRUE;
     }
 
-    SaveHWState(pScrn);
+    drv_save_hw_state(pScrn);
 
-    crtc_init(pScrn);
-    output_init(pScrn);
+    xorg_crtc_init(pScrn);
+    xorg_output_init(pScrn);
 
     if (!xf86InitialConfiguration(pScrn, TRUE)) {
        xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
-       RestoreHWState(pScrn);
+       drv_restore_hw_state(pScrn);
        return FALSE;
     }
 
-    RestoreHWState(pScrn);
+    drv_restore_hw_state(pScrn);
 
     /*
      * If the driver can do gamma correction, it should call xf86SetGamma() here.
@@ -388,23 +408,23 @@ PreInit(ScrnInfoPtr pScrn, int flags)
     xf86SetDpi(pScrn, 0, 0);
 
     /* Load the required sub modules */
-    if (!xf86LoadSubModule(pScrn, "fb")) {
+    if (!xf86LoadSubModule(pScrn, "fb"))
        return FALSE;
-    }
-
-    xf86LoaderReqSymLists(fbSymbols, NULL);
 
-    xf86LoadSubModule(pScrn, "exa");
+    /* XXX: these aren't needed when we are using libkms */
+    if (!xf86LoadSubModule(pScrn, "exa"))
+       return FALSE;
 
 #ifdef DRI2
-    xf86LoadSubModule(pScrn, "dri2");
+    if (!xf86LoadSubModule(pScrn, "dri2"))
+       return FALSE;
 #endif
 
     return TRUE;
 }
 
 static Bool
-SaveHWState(ScrnInfoPtr pScrn)
+drv_save_hw_state(ScrnInfoPtr pScrn)
 {
     /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/
 
@@ -412,15 +432,79 @@ SaveHWState(ScrnInfoPtr pScrn)
 }
 
 static Bool
-RestoreHWState(ScrnInfoPtr pScrn)
+drv_restore_hw_state(ScrnInfoPtr pScrn)
 {
     /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/
 
     return TRUE;
 }
 
+static void drv_block_handler(int i, pointer blockData, pointer pTimeout,
+                              pointer pReadmask)
+{
+    ScreenPtr pScreen = screenInfo.screens[i];
+    modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
+
+    pScreen->BlockHandler = ms->blockHandler;
+    pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
+    pScreen->BlockHandler = drv_block_handler;
+
+    if (ms->ctx) {
+       int j;
+
+       ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, &ms->fence[XORG_NR_FENCES-1]);
+       
+       if (ms->fence[0])
+          ms->ctx->screen->fence_finish(ms->ctx->screen, ms->fence[0], 0);
+  
+       /* The amount of rendering generated by a block handler can be
+        * quite small.  Let us get a fair way ahead of hardware before
+        * throttling.
+        */
+       for (j = 0; j < XORG_NR_FENCES; j++)
+          ms->screen->fence_reference(ms->screen,
+                                      &ms->fence[j],
+                                      ms->fence[j+1]);
+
+       ms->screen->fence_reference(ms->screen,
+                                   &ms->fence[XORG_NR_FENCES-1],
+                                   NULL);
+    }
+        
+
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    {
+       RegionPtr dirty = DamageRegion(ms->damage);
+       unsigned num_cliprects = REGION_NUM_RECTS(dirty);
+
+       if (num_cliprects) {
+           drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
+           BoxPtr rect = REGION_RECTS(dirty);
+           int i, ret;
+
+           /* XXX no need for copy? */
+           for (i = 0; i < num_cliprects; i++, rect++) {
+               clip[i].x1 = rect->x1;
+               clip[i].y1 = rect->y1;
+               clip[i].x2 = rect->x2;
+               clip[i].y2 = rect->y2;
+           }
+
+           /* TODO query connector property to see if this is needed */
+           ret = drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects);
+           if (ret) {
+               debug_printf("%s: failed to send dirty (%i, %s)\n",
+                            __func__, ret, strerror(-ret));
+           }
+
+           DamageEmpty(ms->damage);
+       }
+    }
+#endif
+}
+
 static Bool
-CreateScreenResources(ScreenPtr pScreen)
+drv_create_screen_resources(ScreenPtr pScreen)
 {
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
     modesettingPtr ms = modesettingPTR(pScrn);
@@ -431,58 +515,55 @@ CreateScreenResources(ScreenPtr pScreen)
 
     pScreen->CreateScreenResources = ms->createScreenResources;
     ret = pScreen->CreateScreenResources(pScreen);
-    pScreen->CreateScreenResources = CreateScreenResources;
+    pScreen->CreateScreenResources = drv_create_screen_resources;
 
-    rootPixmap = pScreen->GetScreenPixmap(pScreen);
-
-    if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
-       FatalError("Couldn't adjust screen pixmap\n");
+    ms->bind_front_buffer(pScrn);
 
     ms->noEvict = FALSE;
 
-    drmModeAddFB(ms->fd,
-                pScrn->virtualX,
-                pScrn->virtualY,
-                pScrn->depth,
-                pScrn->bitsPerPixel,
-                pScrn->displayWidth * pScrn->bitsPerPixel / 8,
-                xorg_exa_get_pixmap_handle(rootPixmap), &ms->fb_id);
+    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
 
-    AdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    rootPixmap = pScreen->GetScreenPixmap(pScreen);
+    ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
+                              pScreen, rootPixmap);
+
+    if (ms->damage) {
+       DamageRegister(&rootPixmap->drawable, ms->damage);
+
+       xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
+    } else {
+       xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                  "Failed to create screen damage record\n");
+       return FALSE;
+    }
+#else
+    (void)rootPixmap;
+#endif
 
     return ret;
 }
 
 static Bool
-ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
+drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
 {
     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
     modesettingPtr ms = modesettingPTR(pScrn);
     VisualPtr visual;
 
-    /* deal with server regeneration */
-    if (ms->fd < 0) {
-       char *BusID;
-
-       BusID = xalloc(64);
-       sprintf(BusID, "PCI:%d:%d:%d",
-               ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
-               ms->PciInfo->dev, ms->PciInfo->func
-           );
-
-       ms->fd = drmOpen(NULL, BusID);
-
-       if (ms->fd < 0)
-           return FALSE;
+    if (!drv_init_drm(pScrn)) {
+       FatalError("Could not init DRM");
+       return FALSE;
     }
 
-    if (!ms->screen) {
-       ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL);
+    if (!drv_init_resource_management(pScrn)) {
+       FatalError("Could not init resource management (!pipe_screen && !libkms)");
+       return FALSE;
+    }
 
-       if (!ms->screen) {
-           FatalError("Could not init pipe_screen\n");
-           return FALSE;
-       }
+    if (!drv_init_front_buffer_functions(pScrn)) {
+       FatalError("Could not init front buffer manager");
+       return FALSE;
     }
 
     pScrn->pScreen = pScreen;
@@ -526,12 +607,23 @@ ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
 
     fbPictureInit(pScreen, NULL, 0);
 
+    ms->blockHandler = pScreen->BlockHandler;
+    pScreen->BlockHandler = drv_block_handler;
     ms->createScreenResources = pScreen->CreateScreenResources;
-    pScreen->CreateScreenResources = CreateScreenResources;
+    pScreen->CreateScreenResources = drv_create_screen_resources;
 
     xf86SetBlackWhitePixels(pScreen);
 
-    ms->exa = xorg_exa_init(pScrn);
+    if (ms->screen) {
+       ms->exa = xorg_exa_init(pScrn, xf86ReturnOptValBool(ms->Options,
+                                                           OPTION_2D_ACCEL, TRUE));
+       ms->debug_fallback = debug_get_bool_option("XORG_DEBUG_FALLBACK", TRUE);
+
+       xorg_xv_init(pScreen);
+#ifdef DRI2
+       xorg_dri2_init(pScreen);
+#endif
+    }
 
     miInitializeBackingStore(pScreen);
     xf86SetBackingStore(pScreen);
@@ -550,7 +642,7 @@ ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
 
     pScreen->SaveScreen = xf86SaveScreen;
     ms->CloseScreen = pScreen->CloseScreen;
-    pScreen->CloseScreen = CloseScreen;
+    pScreen->CloseScreen = drv_close_screen;
 
     if (!xf86CrtcScreenInit(pScreen))
        return FALSE;
@@ -563,17 +655,14 @@ ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
     if (serverGeneration == 1)
        xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
 
-#if 1
-#ifdef DRI2
-    driScreenInit(pScreen);
-#endif
-#endif
+    if (ms->winsys_screen_init)
+       ms->winsys_screen_init(pScrn);
 
-    return EnterVT(scrnIndex, 1);
+    return drv_enter_vt(scrnIndex, 1);
 }
 
 static void
-AdjustFrame(int scrnIndex, int x, int y, int flags)
+drv_adjust_frame(int scrnIndex, int x, int y, int flags)
 {
     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
@@ -581,35 +670,34 @@ AdjustFrame(int scrnIndex, int x, int y, int flags)
     xf86CrtcPtr crtc = output->crtc;
 
     if (crtc && crtc->enabled) {
-       crtc->funcs->mode_set(crtc, pScrn->currentMode, pScrn->currentMode, x,
-                             y);
+       crtc->funcs->set_mode_major(crtc, pScrn->currentMode,
+                                   RR_Rotate_0, x, y);
        crtc->x = output->initial_x + x;
        crtc->y = output->initial_y + y;
     }
 }
 
 static void
-FreeScreen(int scrnIndex, int flags)
+drv_free_screen(int scrnIndex, int flags)
 {
-    FreeRec(xf86Screens[scrnIndex]);
+    drv_free_rec(xf86Screens[scrnIndex]);
 }
 
-/* HACK */
-void
-cursor_destroy(xf86CrtcPtr crtc);
-
 static void
-LeaveVT(int scrnIndex, int flags)
+drv_leave_vt(int scrnIndex, int flags)
 {
     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
     modesettingPtr ms = modesettingPTR(pScrn);
     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
     int o;
 
+    if (ms->winsys_leave_vt)
+       ms->winsys_leave_vt(pScrn);
+
     for (o = 0; o < config->num_crtc; o++) {
        xf86CrtcPtr crtc = config->crtc[o];
 
-       cursor_destroy(crtc);
+       xorg_crtc_cursor_destroy(crtc);
 
        if (crtc->rotatedPixmap || crtc->rotatedData) {
            crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
@@ -621,7 +709,11 @@ LeaveVT(int scrnIndex, int flags)
 
     drmModeRmFB(ms->fd, ms->fb_id);
 
-    RestoreHWState(pScrn);
+    drv_restore_hw_state(pScrn);
+
+    if (drmDropMaster(ms->fd))
+       xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                  "drmDropMaster failed: %s\n", strerror(errno));
 
     pScrn->vtSema = FALSE;
 }
@@ -630,31 +722,48 @@ LeaveVT(int scrnIndex, int flags)
  * This gets called when gaining control of the VT, and from ScreenInit().
  */
 static Bool
-EnterVT(int scrnIndex, int flags)
+drv_enter_vt(int scrnIndex, int flags)
 {
     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
     modesettingPtr ms = modesettingPTR(pScrn);
 
+    if (drmSetMaster(ms->fd)) {
+       if (errno == EINVAL) {
+           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                      "drmSetMaster failed: 2.6.29 or newer kernel required for "
+                      "multi-server DRI\n");
+       } else {
+           xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                      "drmSetMaster failed: %s\n", strerror(errno));
+       }
+    }
+
     /*
      * 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 (ms->SaveGeneration != serverGeneration) {
        ms->SaveGeneration = serverGeneration;
-       SaveHWState(pScrn);
+       drv_save_hw_state(pScrn);
     }
 
-    if (!flags)                               /* signals startup as we'll do this in CreateScreenResources */
-       CreateFrontBuffer(pScrn);
+    if (!ms->create_front_buffer(pScrn))
+       return FALSE;
+
+    if (!flags && !ms->bind_front_buffer(pScrn))
+       return FALSE;
 
     if (!xf86SetDesiredModes(pScrn))
        return FALSE;
 
+    if (ms->winsys_enter_vt)
+       ms->winsys_enter_vt(pScrn);
+
     return TRUE;
 }
 
 static Bool
-SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
 {
     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
 
@@ -662,25 +771,43 @@ SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
 }
 
 static Bool
-CloseScreen(int scrnIndex, ScreenPtr pScreen)
+drv_close_screen(int scrnIndex, ScreenPtr pScreen)
 {
     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
     modesettingPtr ms = modesettingPTR(pScrn);
 
     if (pScrn->vtSema) {
-       LeaveVT(scrnIndex, 0);
+       drv_leave_vt(scrnIndex, 0);
     }
+
+    if (ms->winsys_screen_close)
+       ms->winsys_screen_close(pScrn);
+
 #ifdef DRI2
-    driCloseScreen(pScreen);
+    if (ms->screen)
+       xorg_dri2_close(pScreen);
 #endif
 
+    pScreen->BlockHandler = ms->blockHandler;
     pScreen->CreateScreenResources = ms->createScreenResources;
 
+#ifdef DRM_MODE_FEATURE_DIRTYFB
+    if (ms->damage) {
+       DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
+       DamageDestroy(ms->damage);
+       ms->damage = NULL;
+    }
+#endif
+
+    drmModeRmFB(ms->fd, ms->fb_id);
+    ms->destroy_front_buffer(pScrn);
+
     if (ms->exa)
        xorg_exa_close(pScrn);
+    ms->exa = NULL;
+
+    drv_close_resource_management(pScrn);
 
-       ms->api->destroy(ms->api);
-       ms->api = NULL;
     drmClose(ms->fd);
     ms->fd = -1;
 
@@ -690,9 +817,211 @@ CloseScreen(int scrnIndex, ScreenPtr pScreen)
 }
 
 static ModeStatus
-ValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
+drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
 {
     return MODE_OK;
 }
 
+
+/*
+ * Front buffer backing store functions.
+ */
+
+static Bool
+drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    pipe_texture_reference(&ms->root_texture, NULL);
+    return TRUE;
+}
+
+static Bool
+drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    unsigned handle, stride;
+    struct pipe_texture *tex;
+    int ret;
+
+    ms->noEvict = TRUE;
+
+    tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY,
+                                      pScrn->depth, pScrn->bitsPerPixel);
+
+    if (!tex)
+       return FALSE;
+
+    if (!ms->api->local_handle_from_texture(ms->api, ms->screen,
+                                           tex,
+                                           &stride,
+                                           &handle))
+       goto err_destroy;
+
+    ret = drmModeAddFB(ms->fd,
+                      pScrn->virtualX,
+                      pScrn->virtualY,
+                      pScrn->depth,
+                      pScrn->bitsPerPixel,
+                      stride,
+                      handle,
+                      &ms->fb_id);
+    if (ret) {
+       debug_printf("%s: failed to create framebuffer (%i, %s)",
+                    __func__, ret, strerror(-ret));
+       goto err_destroy;
+    }
+
+    pScrn->frameX0 = 0;
+    pScrn->frameY0 = 0;
+    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+    pipe_texture_reference(&ms->root_texture, tex);
+    pipe_texture_reference(&tex, NULL);
+
+    return TRUE;
+
+err_destroy:
+    pipe_texture_reference(&tex, NULL);
+    return FALSE;
+}
+
+static Bool
+drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    ScreenPtr pScreen = pScrn->pScreen;
+    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+    struct pipe_texture *check;
+
+    xorg_exa_set_displayed_usage(rootPixmap);
+    xorg_exa_set_shared_usage(rootPixmap);
+    xorg_exa_set_texture(rootPixmap, ms->root_texture);
+    if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
+       FatalError("Couldn't adjust screen pixmap\n");
+
+    check = xorg_exa_get_texture(rootPixmap);
+    if (ms->root_texture != check)
+       FatalError("Created new root texture\n");
+
+    pipe_texture_reference(&check, NULL);
+    return TRUE;
+}
+
+#ifdef HAVE_LIBKMS
+static Bool
+drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    ScreenPtr pScreen = pScrn->pScreen;
+    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+
+    if (!ms->root_bo)
+       return TRUE;
+
+    kms_bo_unmap(ms->root_bo);
+    kms_bo_destroy(&ms->root_bo);
+    return TRUE;
+}
+
+static Bool
+drv_create_front_buffer_kms(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    unsigned handle, stride;
+    struct kms_bo *bo;
+    unsigned attr[8];
+    int ret;
+
+    attr[0] = KMS_BO_TYPE;
+    attr[1] = KMS_BO_TYPE_SCANOUT;
+    attr[2] = KMS_WIDTH;
+    attr[3] = pScrn->virtualX;
+    attr[4] = KMS_HEIGHT;
+    attr[5] = pScrn->virtualY;
+    attr[6] = 0;
+
+    if (kms_bo_create(ms->kms, attr, &bo))
+       return FALSE;
+
+    if (kms_bo_get_prop(bo, KMS_PITCH, &stride))
+       goto err_destroy;
+
+    if (kms_bo_get_prop(bo, KMS_HANDLE, &handle))
+       goto err_destroy;
+
+    ret = drmModeAddFB(ms->fd,
+                      pScrn->virtualX,
+                      pScrn->virtualY,
+                      pScrn->depth,
+                      pScrn->bitsPerPixel,
+                      stride,
+                      handle,
+                      &ms->fb_id);
+    if (ret) {
+       debug_printf("%s: failed to create framebuffer (%i, %s)",
+                    __func__, ret, strerror(-ret));
+       goto err_destroy;
+    }
+
+    pScrn->frameX0 = 0;
+    pScrn->frameY0 = 0;
+    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+    ms->root_bo = bo;
+
+    return TRUE;
+
+err_destroy:
+    kms_bo_destroy(&bo);
+    return FALSE;
+}
+
+static Bool
+drv_bind_front_buffer_kms(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    ScreenPtr pScreen = pScrn->pScreen;
+    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
+    unsigned stride;
+    void *ptr;
+
+    if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride))
+       return FALSE;
+
+    if (kms_bo_map(ms->root_bo, &ptr))
+       goto err_destroy;
+
+    pScreen->ModifyPixmapHeader(rootPixmap,
+                               pScreen->width,
+                               pScreen->height,
+                               pScreen->rootDepth,
+                               pScrn->bitsPerPixel,
+                               stride,
+                               ptr);
+    return TRUE;
+
+err_destroy:
+    kms_bo_destroy(&ms->root_bo);
+    return FALSE;
+}
+#endif /* HAVE_LIBKMS */
+
+static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn)
+{
+    modesettingPtr ms = modesettingPTR(pScrn);
+    if (ms->screen) {
+       ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d;
+       ms->create_front_buffer = drv_create_front_buffer_ga3d;
+       ms->bind_front_buffer = drv_bind_front_buffer_ga3d;
+#ifdef HAVE_LIBKMS
+    } else if (ms->kms) {
+       ms->destroy_front_buffer = drv_destroy_front_buffer_kms;
+       ms->create_front_buffer = drv_create_front_buffer_kms;
+       ms->bind_front_buffer = drv_bind_front_buffer_kms;
+#endif
+    } else
+       return FALSE;
+
+    return TRUE;
+}
+
 /* vim: set sw=4 ts=8 sts=4: */