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:
parent
4902f546be
commit
51c7590632
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
14
src/i830.h
14
src/i830.h
|
|
@ -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);
|
||||
|
|
|
|||
497
src/i830_dri.c
497
src/i830_dri.c
|
|
@ -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, ®ion, &box, 0);
|
||||
|
||||
I830DRI2CopyRegion(pDraw, ®ion, 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, ®ion, &box, 0);
|
||||
|
||||
I830DRI2CopyRegion(draw, ®ion, 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue