blob: bb6ae61bd7e09c0333aecff1e29a10767ab2a5e8 [file] [log] [blame]
/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */
/*
* Copyright © 2011 Texas Instruments, Inc
*
* 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, sublicense,
* 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 NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS 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.
*
* Authors:
* Rob Clark <rob@ti.com>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "omap_driver.h"
#include "omap_exa.h"
#include <time.h>
#include "xf86drmMode.h"
#include "dri2.h"
/* any point to support earlier? */
#if DRI2INFOREC_VERSION < 4
# error "Requires newer DRI2"
#endif
typedef struct {
DRI2BufferRec base;
/**
* Pixmap that is backing the buffer
*
* NOTE: don't track the pixmap ptr for the front buffer if it is
* a window.. this could get reallocated from beneath us, so we should
* always use draw2pix to be sure to have the correct one
*/
PixmapPtr pPixmap;
/**
* The value of canflip() for the previous frame. Used so that we can tell
* whether the buffer should be re-allocated, e.g into scanout-able
* memory if the buffer can now be flipped.
*
* We don't want to re-allocate every frame because it is unnecessary
* overhead most of the time apart from when we switch from flipping
* to blitting or vice versa.
*
* We should bump the serial number of the drawable if canflip() returns
* something different to what is stored here, so that the DRI2 buffers
* will get re-allocated.
*/
int previous_canflip;
} OMAPDRI2BufferRec, *OMAPDRI2BufferPtr;
#define OMAPBUF(p) ((OMAPDRI2BufferPtr)(p))
#define DRIBUF(p) ((DRI2BufferPtr)(&(p)->base))
static inline DrawablePtr
dri2draw(DrawablePtr pDraw, DRI2BufferPtr buf)
{
if (buf->attachment == DRI2BufferFrontLeft) {
return pDraw;
} else {
return &(OMAPBUF(buf)->pPixmap->drawable);
}
}
/*
* Returns true if drawable is potentially flippable.
* A drawable may be flippable if it:
* (a) is a WINDOW
* (b) has a buffer object, and the buffer object size exactly matches
* the drawable size.
* (c) has the same dimensions as one of the scanouts
*
* Note: Even if a drawable may be flippable, it will not actually be flipped
* if it is clipped.
*/
static Bool
mayflip(DrawablePtr pDraw, struct omap_bo *back_bo)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
OMAPPtr pOMAP = OMAPPTR(pScrn);
Bool ret;
if (pDraw->type != DRAWABLE_WINDOW) {
ret = FALSE;
goto out;
}
if (back_bo && (omap_bo_width(back_bo) != pDraw->width ||
omap_bo_height(back_bo) != pDraw->height)) {
ret = FALSE;
goto out;
}
if (!drmmode_scanout_from_drawable(pOMAP->scanouts, pDraw)) {
ret = FALSE;
goto out;
}
ret = TRUE;
out:
DEBUG_MSG("pDraw %ux%u WINDOW? %d, back_bo %ux%u canflip: %d",
pDraw->width, pDraw->height,
(pDraw->type == DRAWABLE_WINDOW),
(back_bo) ? omap_bo_width(back_bo) : 0,
(back_bo) ? omap_bo_height(back_bo) : 0,
ret);
return ret;
}
/*
* Returns true if drawable can be flipped.
* A drawable can be flipped if it:
* (a) is a WINDOW
* (b) has a buffer object, and the buffer object size exactly matches
* the drawable size.
* (c) has the same dimensions as one of the scanouts
* (d) has exactly one clip region
* (e) has exactly one clip region, and the regions dimensions match its own
*/
static Bool
canflip(DrawablePtr pDraw, struct omap_bo *back_bo)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
Bool ret;
WindowPtr pWindow = NULL;
BoxPtr pBox = NULL;
int num_rects = -1;
int width = 0;
int height = 0;
if (!mayflip(pDraw, back_bo)) {
ret = FALSE;
goto out;
}
pWindow = (WindowPtr)pDraw;
num_rects = RegionNumRects(&pWindow->clipList);
if (num_rects != 1) {
ret = FALSE;
goto out;
}
pBox = RegionRects(&pWindow->clipList);
width = pBox->x2 - pBox->x1;
height = pBox->y2 - pBox->y1;
if (width != pDraw->width || height != pDraw->height) {
ret = FALSE;
goto out;
}
ret = TRUE;
out:
DEBUG_MSG("pDraw %ux%u clipList numRects: %d rect[0]: %dx%d noclip: %d",
pDraw->width, pDraw->height, num_rects, width, height, ret);
return ret;
}
/**
* Create Buffer.
*
* Note that 'format' is used from the client side to specify the DRI buffer
* format, which could differ from the drawable format. For example, the
* drawable could be 32b RGB, but the DRI buffer some YUV format (video) or
* perhaps lower bit depth RGB (GL). The color conversion is handled when
* blitting to front buffer, and page-flipping (overlay or flipchain) can
* only be used if the display supports.
*/
static DRI2BufferPtr
OMAPDRI2CreateBuffer(DrawablePtr pDraw, unsigned int attachment,
unsigned int format)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
OMAPDRI2BufferPtr buf;
PixmapPtr pPixmap;
struct omap_bo *bo;
DEBUG_MSG("pDraw=%p, attachment=%d, format=%08x",
pDraw, attachment, format);
buf = calloc(1, sizeof *buf);
if (!buf)
return NULL;
if (attachment == DRI2BufferFrontLeft) {
pPixmap = draw2pix(pDraw);
/* to do flipping, if we don't have DMM, then we need a scanout
* capable (physically contiguous) buffer.. this bit of gymnastics
* ensures that.
*
* TODO we may want to re-allocate and switch back to non-scanout
* buffer when client disconnects from drawable..
*/
pPixmap->refcnt++;
} else {
pPixmap = pScreen->CreatePixmap(pScreen, pDraw->width,
pDraw->height, pDraw->depth, 0);
}
bo = OMAPPixmapBo(pPixmap);
if (!bo)
{
ERROR_MSG("Attempting to DRI2 wrap a pixmap with no DRM buffer object backing");
/* TODO: Returning NULL here ends up in a segfault all the way in pixman which has no backtrace. We get
* a more friendly segfault if we just let it be dereferenced in a few lines */
}
DRIBUF(buf)->attachment = attachment;
DRIBUF(buf)->pitch = exaGetPixmapPitch(pPixmap);
DRIBUF(buf)->cpp = pPixmap->drawable.bitsPerPixel / 8;
DRIBUF(buf)->format = format;
DRIBUF(buf)->flags = omap_bo_get_dirty(bo) ? DRI2_ARMSOC_PRIVATE_CRC_DIRTY : 0;
buf->pPixmap = pPixmap;
buf->previous_canflip = -1;
DRIBUF(buf)->name = omap_bo_get_name(bo);
if (!DRIBUF(buf)->name) {
ERROR_MSG("could not get global buffer name");
/* TODO cleanup */
return NULL;
}
return DRIBUF(buf);
}
/**
* Destroy Buffer
*
* TODO: depending on how flipping ends up working, we may need a refcnt or
* something like this to defer destroying a buffer that is currently being
* scanned out..
*/
static void
OMAPDRI2DestroyBuffer(DrawablePtr pDraw, DRI2BufferPtr buffer)
{
OMAPDRI2BufferPtr buf = OMAPBUF(buffer);
/* Note: pDraw may already be deleted, so use the pPixmap here
* instead (since it is at least refcntd)
*/
ScreenPtr pScreen = buf->pPixmap->drawable.pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
DEBUG_MSG("pDraw=%p, buffer=%p", pDraw, buffer);
pScreen->DestroyPixmap(buf->pPixmap);
free(buf);
}
/**
*
*/
static void
OMAPDRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
DrawablePtr pSrcDraw = dri2draw(pDraw, pSrcBuffer);
DrawablePtr pDstDraw = dri2draw(pDraw, pDstBuffer);
RegionPtr pCopyClip;
GCPtr pGC;
DEBUG_MSG("pDraw=%p, pDstBuffer=%p (%p), pSrcBuffer=%p (%p)",
pDraw, pDstBuffer, pSrcDraw, pSrcBuffer, pDstDraw);
pGC = GetScratchGC(pDstDraw->depth, pScreen);
if (!pGC) {
return;
}
pCopyClip = REGION_CREATE(pScreen, NULL, 0);
RegionCopy(pCopyClip, pRegion);
(*pGC->funcs->ChangeClip) (pGC, CT_REGION, pCopyClip, 0);
ValidateGC(pDstDraw, pGC);
/* If the dst is the framebuffer, and we had a way to
* schedule a deferred blit synchronized w/ vsync, that
* would be a nice thing to do utilize here to avoid
* tearing.. when we have sync object support for GEM
* buffers, I think we could do something more clever
* here.
*/
pGC->ops->CopyArea(pSrcDraw, pDstDraw, pGC,
0, 0, pDraw->width, pDraw->height, 0, 0);
FreeScratchGC(pGC);
}
static uint64_t gettime_us(void)
{
struct timespec tv;
if (clock_gettime(CLOCK_MONOTONIC, &tv))
return 0;
return (uint64_t)tv.tv_sec * 1000000 + tv.tv_nsec / 1000;
}
/**
* Get current frame count and frame count timestamp, based on drawable's
* crtc.
*/
static int
OMAPDRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
OMAPPtr pOMAP = OMAPPTR(pScrn);
int crtc_index = drmmode_crtc_index_from_drawable(pScrn, pDraw);
drmVBlank vbl = { .request = {
.type = DRM_VBLANK_RELATIVE |
(crtc_index << DRM_VBLANK_HIGH_CRTC_SHIFT),
.sequence = 0,
} };
int ret;
/*
* Drawable not full screen, use *monotonic* ust value.
* Note, this is slightly different than other drivers which try harder
* to match a Drawable to a crtc.
*/
if (crtc_index == -1) {
if (ust)
*ust = gettime_us();
if (msc)
*msc = 0;
return TRUE;
}
ret = drmWaitVBlank(pOMAP->drmFD, &vbl);
if (ret) {
static int limit = 5;
if (limit) {
ERROR_MSG("get vblank counter failed: %s",
strerror(errno));
limit--;
}
return FALSE;
}
if (ust) {
*ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
}
if (msc) {
*msc = vbl.reply.sequence;
}
return TRUE;
}
#define OMAP_SWAP_FAKE_FLIP (1 << 0)
#define OMAP_SWAP_FAIL (1 << 1)
struct _OMAPDRISwapCmd {
int type;
ClientPtr client;
ScreenPtr pScreen;
/* Note: store drawable ID, rather than drawable. It's possible that
* the drawable can be destroyed while we wait for page flip event:
*/
XID draw_id;
PixmapPtr pDstPixmap;
PixmapPtr pSrcPixmap;
DRI2SwapEventPtr func;
int swapCount;
int flags;
int x;
int y;
void *data;
};
void
OMAPDRI2SwapComplete(OMAPDRISwapCmd *cmd)
{
ScreenPtr pScreen = cmd->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
OMAPPtr pOMAP = OMAPPTR(pScrn);
DrawablePtr pDraw = NULL;
int status, i;
OMAPPixmapPrivPtr dst_priv;
if (--cmd->swapCount > 0)
return;
if ((cmd->flags & OMAP_SWAP_FAIL) == 0) {
if (cmd->type != DRI2_BLIT_COMPLETE && (cmd->flags & OMAP_SWAP_FAKE_FLIP) == 0) {
assert(cmd->type == DRI2_FLIP_COMPLETE);
OMAPPixmapExchange(cmd->pSrcPixmap, cmd->pDstPixmap);
}
status = dixLookupDrawable(&pDraw, cmd->draw_id, serverClient,
M_ANY, DixWriteAccess);
if (status == Success) {
DRI2SwapComplete(cmd->client, pDraw, 0, 0, 0, cmd->type,
cmd->func, cmd->data);
} else {
DEBUG_MSG("dixLookupDrawable failed: %d", status);
}
if (cmd->type == DRI2_BLIT_COMPLETE) {
/* For blits, invalidate the per-crtc scanouts.
*/
for (i = 0; i < MAX_SCANOUTS; i++) {
pOMAP->scanouts[i].valid = FALSE;
}
} else {
assert(cmd->type == DRI2_FLIP_COMPLETE);
dst_priv = exaGetPixmapDriverPrivate(cmd->pDstPixmap);
/* For flips, validate the per-crtc scanout.
*/
for (i = 0; i < MAX_SCANOUTS; i++) {
if (pOMAP->scanouts[i].bo == dst_priv->bo) {
pOMAP->scanouts[i].valid = TRUE;
break;
}
}
if ((cmd->flags & OMAP_SWAP_FAKE_FLIP) == 0) {
drmmode_scanout_set(pOMAP->scanouts, cmd->x, cmd->y, dst_priv->bo);
}
}
}
/* drop extra refcnt we obtained prior to swap:
*/
pScreen->DestroyPixmap(cmd->pSrcPixmap);
pScreen->DestroyPixmap(cmd->pDstPixmap);
if (cmd->type != DRI2_BLIT_COMPLETE) {
pOMAP->pending_flips--;
}
free(cmd);
}
/**
* ScheduleSwap is responsible for requesting a DRM vblank event for the
* appropriate frame.
*
* In the case of a blit (e.g. for a windowed swap) or buffer exchange,
* the vblank requested can simply be the last queued swap frame + the swap
* interval for the drawable.
*
* In the case of a page flip, we request an event for the last queued swap
* frame + swap interval - 1, since we'll need to queue the flip for the frame
* immediately following the received event.
*/
static int
OMAPDRI2ScheduleSwap(ClientPtr client, DrawablePtr pDraw,
DRI2BufferPtr pDstBuffer, DRI2BufferPtr pSrcBuffer,
CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
DRI2SwapEventPtr func, void *data)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
OMAPPtr pOMAP = OMAPPTR(pScrn);
OMAPDRI2BufferPtr src = OMAPBUF(pSrcBuffer);
OMAPDRI2BufferPtr dst = OMAPBUF(pDstBuffer);
OMAPDRISwapCmd *cmd;
OMAPPixmapPrivPtr src_priv, dst_priv;
int new_canflip, ret, num_flipped;
RegionRec region;
cmd = calloc(1, sizeof *cmd);
if (!cmd)
return FALSE;
cmd->client = client;
cmd->pScreen = pScreen;
cmd->draw_id = pDraw->id;
cmd->pSrcPixmap = draw2pix(dri2draw(pDraw, pSrcBuffer));
cmd->pDstPixmap = draw2pix(dri2draw(pDraw, pDstBuffer));
cmd->swapCount = 0;
cmd->flags = 0;
cmd->func = func;
cmd->data = data;
cmd->x = pDraw->x;
cmd->y = pDraw->y;
region.extents.x1 = region.extents.y1 = 0;
region.extents.x2 = cmd->pDstPixmap->drawable.width;
region.extents.y2 = cmd->pDstPixmap->drawable.height;
region.data = NULL;
DamageRegionAppend(&cmd->pDstPixmap->drawable, &region);
DEBUG_MSG("%d -> %d", pSrcBuffer->attachment, pDstBuffer->attachment);
src_priv = exaGetPixmapDriverPrivate(src->pPixmap);
dst_priv = exaGetPixmapDriverPrivate(dst->pPixmap);
/* src bo was just rendered to by GPU so it is not dirty */
omap_bo_clear_dirty(src_priv->bo);
new_canflip = canflip(pDraw, src_priv->bo);
/* If we can flip using a crtc scanout, switch the front buffer bo */
if (new_canflip && !pOMAP->has_resized) {
struct omap_bo *old_bo;
old_bo = dst_priv->bo;
dst_priv->bo = drmmode_scanout_from_drawable(pOMAP->scanouts,
pDraw)->bo;
omap_bo_reference(dst_priv->bo);
if (!drmmode_set_flip_mode(pScrn)) {
ERROR_MSG("Could not set flip mode");
new_canflip = FALSE;
omap_bo_unreference(dst_priv->bo);
dst_priv->bo = old_bo;
} else {
omap_bo_unreference(old_bo);
}
} else {
struct omap_bo *old_bo;
old_bo = dst_priv->bo;
omap_bo_reference(pOMAP->scanout);
dst_priv->bo = pOMAP->scanout;
if (!drmmode_set_blit_mode(pScrn)) {
ERROR_MSG("Could not set blit mode");
omap_bo_unreference(pOMAP->scanout);
DamageRegionProcessPending(&cmd->pDstPixmap->drawable);
return FALSE;
}
omap_bo_unreference(old_bo);
}
DamageRegionProcessPending(&cmd->pDstPixmap->drawable);
/* obtain extra ref on pixmaps to avoid them going away while we await
* the page flip event:
*/
cmd->pSrcPixmap->refcnt++;
cmd->pDstPixmap->refcnt++;
if ((src->previous_canflip != -1 && src->previous_canflip != new_canflip) ||
(dst->previous_canflip != -1 && dst->previous_canflip != new_canflip) ||
(pOMAP->has_resized))
{
/* The drawable has transitioned between being flippable and non-flippable
* or vice versa. Bump the serial number to force the DRI2 buffers to be
* re-allocated during the next frame so that:
* - It is able to be scanned out (if drawable is now flippable), or
* - It is not taking up possibly scarce scanout-able memory (if drawable
* is now not flippable)
*
* has_resized: On hotplugging back buffer needs to be invalidates as well
* as Xsever invalidates only the front buffer.
*/
PixmapPtr pPix = pScreen->GetWindowPixmap((WindowPtr)pDraw);
pPix->drawable.serialNumber = NEXT_SERIAL_NUMBER;
}
src->previous_canflip = new_canflip;
dst->previous_canflip = new_canflip;
if (new_canflip && !(pOMAP->has_resized)) {
uint32_t src_fb_id;
/* has_resized: On hotplug the fb size and crtc sizes arent updated
* hence on this event we do a copyb but flip from the next frame
* when the sizes are updated.
*/
src_fb_id = omap_bo_fb(src_priv->bo);
DEBUG_MSG("can flip: %d", src_fb_id);
cmd->type = DRI2_FLIP_COMPLETE;
/* TODO: handle rollback if only multiple CRTC flip is only partially successful
*/
pOMAP->pending_flips++;
ret = drmmode_page_flip(pDraw, src_fb_id, cmd, &num_flipped);
/* If using page flip events, we'll trigger an immediate completion in
* the case that no CRTCs were enabled to be flipped. If not using page
* flip events, trigger immediate completion unconditionally.
*/
if (ret) {
/*
* Error while flipping; bail.
*/
cmd->flags |= OMAP_SWAP_FAIL;
#if !OMAP_USE_PAGE_FLIP_EVENTS
cmd->swapCount = 0;
#else
cmd->swapCount = num_flipped;
if (cmd->swapCount == 0)
#endif
{
OMAPDRI2SwapComplete(cmd);
}
return FALSE;
} else {
if (num_flipped == 0)
cmd->flags |= OMAP_SWAP_FAKE_FLIP;
#if !OMAP_USE_PAGE_FLIP_EVENTS
cmd->swapCount = 0;
#else
cmd->swapCount = num_flipped;
if (cmd->swapCount == 0)
#endif
{
OMAPDRI2SwapComplete(cmd);
}
}
} else {
/* fallback to blit: */
BoxRec box = {
.x1 = 0,
.y1 = 0,
.x2 = pDraw->width,
.y2 = pDraw->height,
};
RegionRec region;
RegionInit(&region, &box, 0);
OMAPDRI2CopyRegion(pDraw, &region, pDstBuffer, pSrcBuffer);
cmd->type = DRI2_BLIT_COMPLETE;
OMAPDRI2SwapComplete(cmd);
pOMAP->has_resized = FALSE;
}
return TRUE;
}
/**
* Request a DRM event when the requested conditions will be satisfied.
*
* We need to handle the event and ask the server to wake up the client when
* we receive it.
*/
static int
OMAPDRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
CARD64 divisor, CARD64 remainder)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
ERROR_MSG("not implemented");
return FALSE;
}
/**
* Sync up X's view of a DRI2BufferPtr with our internal reckoning of it.
*
* We do some BO renaming and other tricksy businesses that X needs to know
* about. Do the sync-up here.
*/
static void
OMAPDRI2ReuseBufferNotify(DrawablePtr pDraw, DRI2BufferPtr buffer)
{
OMAPDRI2BufferPtr omap_buffer = OMAPBUF(buffer);
PixmapPtr pPixmap = omap_buffer->pPixmap;
OMAPPixmapPrivPtr omap_priv = exaGetPixmapDriverPrivate(pPixmap);
buffer->name = omap_bo_get_name(omap_priv->bo);
buffer->flags = omap_bo_get_dirty(omap_priv->bo) ? DRI2_ARMSOC_PRIVATE_CRC_DIRTY : 0;
}
/**
* The DRI2 ScreenInit() function.. register our handler fxns w/ DRI2 core
*/
Bool
OMAPDRI2ScreenInit(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
OMAPPtr pOMAP = OMAPPTR(pScrn);
DRI2InfoRec info = {
.version = 6,
.fd = pOMAP->drmFD,
.driverName = "armsoc",
.deviceName = pOMAP->deviceName,
.CreateBuffer = &OMAPDRI2CreateBuffer,
.DestroyBuffer = &OMAPDRI2DestroyBuffer,
.CopyRegion = &OMAPDRI2CopyRegion,
.Wait = NULL,
.ScheduleSwap = &OMAPDRI2ScheduleSwap,
.GetMSC = &OMAPDRI2GetMSC,
.ScheduleWaitMSC = &OMAPDRI2ScheduleWaitMSC,
.numDrivers = 0,
.driverNames = NULL,
.AuthMagic = &drmAuthMagic,
.ReuseBufferNotify = &OMAPDRI2ReuseBufferNotify,
.SwapLimitValidate = NULL,
};
int minor = 1, major = 0;
if (xf86LoaderCheckSymbol("DRI2Version")) {
DRI2Version(&major, &minor);
}
if (minor < 1) {
WARNING_MSG("DRI2 requires DRI2 module version 1.1.0 or later");
return FALSE;
}
return DRI2ScreenInit(pScreen, &info);
}
/**
* The DRI2 CloseScreen() function.. unregister ourself w/ DRI2 core.
*/
void
OMAPDRI2CloseScreen(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
OMAPPtr pOMAP = OMAPPTR(pScrn);
while (pOMAP->pending_flips > 0) {
DEBUG_MSG("waiting..");
drmmode_wait_for_event(pScrn);
}
DRI2CloseScreen(pScreen);
}