DRI2: support new DRI2 APIs

The new interfaces allow for improved buffer swap, and support for the
SGI_swap_control, SGI_video_sync and OML_sync_control GLX extensions.

The Intel implementation allows page flipping to occur for swaps that
are full screen and not rotated.

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
This commit is contained in:
Jesse Barnes 2009-05-01 14:52:26 -07:00
parent 4902f546be
commit 51c7590632
4 changed files with 646 additions and 6 deletions

View File

@ -34,6 +34,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <poll.h>
#include "xorgVersion.h"
@ -47,6 +48,11 @@ typedef struct {
uint32_t fb_id;
drmModeResPtr mode_res;
int cpp;
drmEventContext event_context;
void *event_data;
int old_fb_id;
int flip_count;
} drmmode_rec, *drmmode_ptr;
typedef struct {
@ -500,6 +506,7 @@ static PixmapPtr
drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
{
ScrnInfoPtr scrn = crtc->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
unsigned long rotate_pitch;
@ -532,12 +539,16 @@ drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
if (drmmode_crtc->rotate_bo)
i830_set_pixmap_bo(rotate_pixmap, drmmode_crtc->rotate_bo);
intel->shadow_present = TRUE;
return rotate_pixmap;
}
static void
drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
{
ScrnInfoPtr scrn = crtc->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
@ -555,6 +566,7 @@ drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *dat
dri_bo_unreference(drmmode_crtc->rotate_bo);
drmmode_crtc->rotate_bo = NULL;
}
intel->shadow_present = FALSE;
}
static void
@ -1376,15 +1388,119 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
return FALSE;
}
Bool
drmmode_do_pageflip(ScreenPtr screen, dri_bo *new_front, dri_bo *old_front,
void *data)
{
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
intel_screen_private *intel = intel_get_screen_private(scrn);
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
unsigned int pitch = scrn->displayWidth * intel->cpp;
int i, old_fb_id;
unsigned int crtc_id;
/*
* Create a new handle for the back buffer
*/
old_fb_id = drmmode->fb_id;
if (drmModeAddFB(drmmode->fd, scrn->virtualX, scrn->virtualY,
scrn->depth, scrn->bitsPerPixel, pitch,
new_front->handle, &drmmode->fb_id))
goto error_out;
/*
* Queue flips on all enabled CRTCs
* Note that if/when we get per-CRTC buffers, we'll have to update this.
* Right now it assumes a single shared fb across all CRTCs, with the
* kernel fixing up the offset of each CRTC as necessary.
*
* Also, flips queued on disabled or incorrectly configured displays
* may never complete; this is a configuration error.
*/
for (i = 0; i < config->num_crtc; i++) {
xf86CrtcPtr crtc = config->crtc[i];
if (!crtc->enabled)
continue;
drmmode_crtc = crtc->driver_private;
crtc_id = drmmode_crtc->mode_crtc->crtc_id;
drmmode->event_data = data;
drmmode->flip_count++;
if (drmModePageFlip(drmmode->fd, crtc_id, drmmode->fb_id,
DRM_MODE_PAGE_FLIP_EVENT, drmmode)) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"flip queue failed: %s\n", strerror(errno));
goto error_undo;
}
}
dri_bo_pin(new_front, 0);
dri_bo_unpin(new_front);
scrn->fbOffset = new_front->offset;
intel->front_buffer->bo = new_front;
intel->front_buffer->offset = new_front->offset;
drmmode->old_fb_id = old_fb_id;
return TRUE;
error_undo:
drmModeRmFB(drmmode->fd, drmmode->fb_id);
drmmode->fb_id = old_fb_id;
error_out:
xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
strerror(errno));
return FALSE;
}
static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
drmmode_xf86crtc_resize
};
static void
drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
I830DRI2FrameEventHandler(frame, tv_sec, tv_usec, event_data);
}
static void
drmmode_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
drmmode_ptr drmmode = event_data;
drmmode->flip_count--;
if (drmmode->flip_count > 0)
return;
drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
I830DRI2FlipEventHandler(frame, tv_sec, tv_usec, drmmode->event_data);
}
static void
drm_wakeup_handler(pointer data, int err, pointer p)
{
drmmode_ptr drmmode = data;
fd_set *read_mask = p;
if (err >= 0 && FD_ISSET(drmmode->fd, read_mask))
drmHandleEvent(drmmode->fd, &drmmode->event_context);
}
Bool drmmode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
{
intel_screen_private *intel = intel_get_screen_private(scrn);
xf86CrtcConfigPtr xf86_config;
struct drm_i915_getparam gp;
drmmode_ptr drmmode;
int i;
unsigned int i;
int has_flipping = 0;
drmmode = xnfalloc(sizeof *drmmode);
drmmode->fd = fd;
@ -1411,6 +1527,23 @@ Bool drmmode_pre_init(ScrnInfoPtr scrn, int fd, int cpp)
xf86InitialConfiguration(scrn, TRUE);
gp.param = I915_PARAM_HAS_PAGEFLIPPING;
gp.value = &has_flipping;
(void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp,
sizeof(gp));
if (has_flipping) {
xf86DrvMsg(scrn->scrnIndex, X_INFO,
"Kernel page flipping support detected, enabling\n");
intel->use_pageflipping = TRUE;
drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
drmmode->event_context.vblank_handler = drmmode_vblank_handler;
drmmode->event_context.page_flip_handler =
drmmode_page_flip_handler;
AddGeneralSocket(fd);
RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
drm_wakeup_handler, drmmode);
}
return TRUE;
}

View File

@ -65,6 +65,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#include "sarea.h"
#define _XF86DRI_SERVER_
#include "dri.h"
#include "dri2.h"
#include "GL/glxint.h"
#include "i830_dri.h"
#include "intel_bufmgr.h"
@ -287,6 +288,8 @@ typedef struct intel_screen_private {
CreateScreenResourcesProcPtr CreateScreenResources;
Bool shadow_present;
Bool need_mi_flush;
Bool tiling;
@ -372,6 +375,8 @@ typedef struct intel_screen_private {
int drmSubFD;
char *deviceName;
Bool use_pageflipping;
/* Broken-out options. */
OptionInfoPtr Options;
@ -393,6 +398,11 @@ enum {
DEBUG_FLUSH_WAIT = 0x4,
};
extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp);
extern int drmmode_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
extern int drmmode_output_dpms_status(xf86OutputPtr output);
extern Bool drmmode_do_pageflip(ScreenPtr screen, dri_bo *new_front,
dri_bo *old_front, void *data);
static inline intel_screen_private *
intel_get_screen_private(ScrnInfoPtr scrn)
@ -424,6 +434,10 @@ extern xf86CrtcPtr i830_pipe_to_crtc(ScrnInfoPtr scrn, int pipe);
Bool I830DRI2ScreenInit(ScreenPtr pScreen);
void I830DRI2CloseScreen(ScreenPtr pScreen);
void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *user_data);
void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *user_data);
extern Bool drmmode_pre_init(ScrnInfoPtr scrn, int fd, int cpp);
extern void drmmode_closefb(ScrnInfoPtr scrn);

View File

@ -44,6 +44,9 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.h>
#include <errno.h>
#include "xf86.h"
#include "xf86_OSproc.h"
@ -72,11 +75,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
extern XF86ModuleData dri2ModuleData;
#endif
typedef struct {
PixmapPtr pixmap;
unsigned int attachment;
} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
#ifndef USE_DRI2_1_1_0
static DRI2BufferPtr
I830DRI2CreateBuffers(DrawablePtr drawable, unsigned int *attachments,
@ -271,6 +269,29 @@ static void I830DRI2DestroyBuffer(DrawablePtr drawable, DRI2Buffer2Ptr buffer)
#endif
static int
I830DRI2DrawablePipe(DrawablePtr pDraw)
{
ScreenPtr pScreen = pDraw->pScreen;
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
BoxRec box, crtcbox;
xf86CrtcPtr crtc;
int pipe = -1;
box.x1 = pDraw->x;
box.y1 = pDraw->y;
box.x2 = box.x1 + pDraw->width;
box.y2 = box.y1 + pDraw->height;
crtc = i830_covering_crtc(pScrn, &box, NULL, &crtcbox);
/* Make sure the CRTC is valid and this is the real front buffer */
if (crtc != NULL && !crtc->rotatedData)
pipe = i830_crtc_to_pipe(crtc);
return pipe;
}
static void
I830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
DRI2BufferPtr destBuffer, DRI2BufferPtr sourceBuffer)
@ -359,6 +380,466 @@ I830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
}
#if DRI2INFOREC_VERSION >= 4
enum DRI2FrameEventType {
DRI2_SWAP,
DRI2_FLIP,
DRI2_WAITMSC,
};
typedef struct _DRI2FrameEvent {
DrawablePtr pDraw;
ClientPtr client;
enum DRI2FrameEventType type;
int frame;
/* for swaps & flips only */
DRI2SwapEventPtr event_complete;
void *event_data;
DRI2BufferPtr front;
DRI2BufferPtr back;
} DRI2FrameEventRec, *DRI2FrameEventPtr;
static void
I830DRI2ExchangeBuffers(DrawablePtr draw, DRI2BufferPtr front,
DRI2BufferPtr back)
{
I830DRI2BufferPrivatePtr front_priv, back_priv;
dri_bo *tmp_bo;
int tmp;
front_priv = front->driverPrivate;
back_priv = back->driverPrivate;
/* Swap BO names so DRI works */
tmp = front->name;
front->name = back->name;
back->name = tmp;
/* Swap pixmap bos */
dri_bo_reference(i830_get_pixmap_bo(front_priv->pixmap));
tmp_bo = i830_get_pixmap_bo(front_priv->pixmap);
i830_set_pixmap_bo(front_priv->pixmap,
i830_get_pixmap_bo(back_priv->pixmap));
i830_set_pixmap_bo(back_priv->pixmap, tmp_bo); /* should be screen */
}
/*
* Our internal swap routine takes care of actually exchanging, blitting, or
* flipping buffers as necessary.
*/
static Bool
I830DRI2ScheduleFlip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
DRI2BufferPtr back, DRI2SwapEventPtr func, void *data)
{
ScreenPtr screen = draw->pScreen;
I830DRI2BufferPrivatePtr front_priv, back_priv;
dri_bo *tmp_bo;
DRI2FrameEventPtr flip_info;
Bool ret;
flip_info = xcalloc(1, sizeof(DRI2FrameEventRec));
if (!flip_info)
return FALSE;
flip_info->pDraw = draw;
flip_info->client = client;
flip_info->type = DRI2_SWAP;
flip_info->event_complete = func;
flip_info->event_data = data;
front_priv = front->driverPrivate;
back_priv = back->driverPrivate;
tmp_bo = i830_get_pixmap_bo(front_priv->pixmap);
I830DRI2ExchangeBuffers(draw, front, back);
/* Page flip the full screen buffer */
ret = drmmode_do_pageflip(screen,
i830_get_pixmap_bo(front_priv->pixmap),
i830_get_pixmap_bo(back_priv->pixmap),
flip_info);
/* Unwind in case of failure */
if (!ret) {
i830_set_pixmap_bo(back_priv->pixmap,
i830_get_pixmap_bo(front_priv->pixmap));
i830_set_pixmap_bo(front_priv->pixmap, tmp_bo);
return FALSE;
}
return ret;
}
void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
DRI2FrameEventPtr event = event_data;
DrawablePtr pDraw = event->pDraw;
ScreenPtr screen = pDraw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
intel_screen_private *intel = intel_get_screen_private(scrn);
switch (event->type) {
case DRI2_FLIP:
/* If we can still flip... */
if (DRI2CanFlip(pDraw) && !intel->shadow_present &&
intel->use_pageflipping &&
I830DRI2ScheduleFlip(event->client, pDraw, event->front,
event->back, event->event_complete,
event->event_data)) {
break;
}
/* else fall through to exchange/blit */
case DRI2_SWAP: {
int swap_type;
if (DRI2CanExchange(pDraw)) {
I830DRI2ExchangeBuffers(pDraw, event->front, event->back);
swap_type = DRI2_EXCHANGE_COMPLETE;
} else {
BoxRec box;
RegionRec region;
box.x1 = 0;
box.y1 = 0;
box.x2 = pDraw->width;
box.y2 = pDraw->height;
REGION_INIT(pScreen, &region, &box, 0);
I830DRI2CopyRegion(pDraw, &region, event->front, event->back);
swap_type = DRI2_BLIT_COMPLETE;
}
DRI2SwapComplete(event->client, pDraw, frame, tv_sec, tv_usec,
swap_type, event->event_complete, event->event_data);
break;
}
case DRI2_WAITMSC:
DRI2WaitMSCComplete(event->client, pDraw, frame, tv_sec, tv_usec);
break;
default:
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
/* Unknown type */
break;
}
xfree(event);
}
void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
DRI2FrameEventPtr flip = event_data;
DrawablePtr pDraw = flip->pDraw;
ScreenPtr screen = pDraw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
/* We assume our flips arrive in order, so we don't check the frame */
switch (flip->type) {
case DRI2_SWAP:
DRI2SwapComplete(flip->client, pDraw, frame, tv_sec, tv_usec,
DRI2_FLIP_COMPLETE, flip->event_complete,
flip->event_data);
break;
default:
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
/* Unknown type */
break;
}
xfree(flip);
}
/*
* 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.
*
* The client will be blocked if it tries to perform further GL commands
* after queueing a swap, though in the Intel case after queueing a flip, the
* client is free to queue more commands; they'll block in the kernel if
* they access buffers busy with the flip.
*
* When the swap is complete, the driver should call into the server so it
* can send any swap complete events that have been requested.
*/
static int
I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
CARD64 remainder, DRI2SwapEventPtr func, void *data)
{
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
intel_screen_private *intel = intel_get_screen_private(scrn);
drmVBlank vbl;
int ret, pipe = I830DRI2DrawablePipe(draw), flip = 0;
DRI2FrameEventPtr swap_info;
enum DRI2FrameEventType swap_type = DRI2_SWAP;
swap_info = xcalloc(1, sizeof(DRI2FrameEventRec));
/* Drawable not displayed... just complete the swap */
if (pipe == -1 || !swap_info) {
BoxRec box;
RegionRec region;
box.x1 = 0;
box.y1 = 0;
box.x2 = draw->width;
box.y2 = draw->height;
REGION_INIT(pScreen, &region, &box, 0);
I830DRI2CopyRegion(draw, &region, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func,
data);
if (swap_info)
xfree(swap_info);
return TRUE;
}
swap_info->pDraw = draw;
swap_info->client = client;
swap_info->event_complete = func;
swap_info->event_data = data;
swap_info->front = front;
swap_info->back = back;
/* Get current count */
vbl.request.type = DRM_VBLANK_RELATIVE;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = 0;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"first get vblank counter failed: %s\n",
strerror(errno));
return FALSE;
}
/* Flips need to be submitted one frame before */
if (DRI2CanFlip(draw) && !intel->shadow_present &&
intel->use_pageflipping) {
swap_type = DRI2_FLIP;
flip = 1;
}
swap_info->type = swap_type;
/*
* If divisor is zero, we just need to make sure target_msc passes
* before waking up the client.
*/
if (divisor == 0) {
vbl.request.type = DRM_VBLANK_NEXTONMISS |
DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = *target_msc;
vbl.request.sequence -= flip;
vbl.request.signal = (unsigned long)swap_info;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"divisor 0 get vblank counter failed: %s\n",
strerror(errno));
return FALSE;
}
*target_msc = vbl.reply.sequence;
swap_info->frame = *target_msc;
return TRUE;
}
/*
* If we get here, target_msc has already passed or we don't have one,
* so we queue an event that will satisfy the divisor/remainderequation.
*/
if ((vbl.reply.sequence % divisor) == remainder)
return FALSE;
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
/*
* If we have no remainder, and the test above failed, it means we've
* passed the last point where seq % divisor == remainder, so we need
* to wait for the next time that will happen.
*/
if (!remainder)
vbl.request.sequence += divisor;
vbl.request.sequence = vbl.reply.sequence -
(vbl.reply.sequence % divisor) + remainder;
vbl.request.sequence -= flip;
vbl.request.signal = (unsigned long)swap_info;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"final get vblank counter failed: %s\n",
strerror(errno));
return FALSE;
}
*target_msc = vbl.reply.sequence;
swap_info->frame = *target_msc;
return TRUE;
}
/*
* Get current frame count and frame count timestamp, based on drawable's
* crtc.
*/
static int
I830DRI2GetMSC(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
{
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
intel_screen_private *intel = intel_get_screen_private(scrn);
drmVBlank vbl;
int ret, pipe = I830DRI2DrawablePipe(draw);
/* Drawable not displayed, make up a value */
if (pipe == -1) {
*ust = 0;
*msc = 0;
return TRUE;
}
vbl.request.type = DRM_VBLANK_RELATIVE;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = 0;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"get vblank counter failed: %s\n", strerror(errno));
return FALSE;
}
*ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
*msc = vbl.reply.sequence;
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
I830DRI2ScheduleWaitMSC(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
CARD64 divisor, CARD64 remainder)
{
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
intel_screen_private *intel = intel_get_screen_private(scrn);
DRI2FrameEventPtr wait_info;
drmVBlank vbl;
int ret, pipe = I830DRI2DrawablePipe(draw);
/* Drawable not visible, return immediately */
if (pipe == -1) {
DRI2WaitMSCComplete(client, draw, target_msc, 0, 0);
return TRUE;
}
wait_info = xcalloc(1, sizeof(DRI2FrameEventRec));
if (!wait_info) {
DRI2WaitMSCComplete(client, draw, 0, 0, 0);
return TRUE;
}
wait_info->pDraw = draw;
wait_info->client = client;
wait_info->type = DRI2_WAITMSC;
/* Get current count */
vbl.request.type = DRM_VBLANK_RELATIVE;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = 0;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"get vblank counter failed: %s\n", strerror(errno));
return FALSE;
}
/*
* If divisor is zero, we just need to make sure target_msc passes
* before waking up the client.
*/
if (divisor == 0) {
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = target_msc;
vbl.request.signal = (unsigned long)wait_info;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"get vblank counter failed: %s\n", strerror(errno));
return FALSE;
}
wait_info->frame = vbl.reply.sequence;
DRI2BlockClient(client, draw);
return TRUE;
}
/*
* If we get here, target_msc has already passed or we don't have one,
* so we queue an event that will satisfy the divisor/remainder equation.
*/
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
/*
* If we have no remainder and the condition isn't satisified, it means
* we've passed the last point where seq % divisor == remainder, so we need
* to wait for the next time that will happen.
*/
if (((vbl.reply.sequence % divisor) != remainder) && !remainder)
vbl.request.sequence += divisor;
vbl.request.sequence = vbl.reply.sequence - (vbl.reply.sequence % divisor) +
remainder;
vbl.request.signal = (unsigned long)wait_info;
ret = drmWaitVBlank(intel->drmSubFD, &vbl);
if (ret) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
"get vblank counter failed: %s\n", strerror(errno));
return FALSE;
}
wait_info->frame = vbl.reply.sequence;
DRI2BlockClient(client, draw);
return TRUE;
}
#endif
Bool I830DRI2ScreenInit(ScreenPtr screen)
{
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
@ -405,6 +886,12 @@ Bool I830DRI2ScreenInit(ScreenPtr screen)
#endif
info.CopyRegion = I830DRI2CopyRegion;
#if DRI2INFOREC_VERSION >= 4
info.version = 4;
info.ScheduleSwap = I830DRI2ScheduleSwap;
info.GetMSC = I830DRI2GetMSC;
info.ScheduleWaitMSC = I830DRI2ScheduleWaitMSC;
#endif
return DRI2ScreenInit(screen, &info);
}

View File

@ -2,6 +2,7 @@
#ifndef _I830_DRI_H
#define _I830_DRI_H
#include "xorg-server.h"
#include "xf86drm.h"
#include "i830_common.h"
@ -58,4 +59,9 @@ typedef struct {
int dummy;
} I830DRIContextRec, *I830DRIContextPtr;
typedef struct {
PixmapPtr pixmap;
unsigned int attachment;
} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr;
#endif