blob: 4171a9ff542be29fec25da10301f8f69615fda73 [file] [log] [blame]
From 78d8055191eafa06dc09f1bea18272bf15dccc9f Mon Sep 17 00:00:00 2001
From: Chris Wolfe <cwolfe@chromium.org>
Date: Fri, 22 Feb 2013 12:41:01 -0800
Subject: [PATCH] xf86-video-intel: Split framebuffer and flip crtcs.
Try to allocate a separate framebuffer for each CRTC and flip those
directly with the back-buffer of updated drawables. This avoids
blitting content when the drawable size matches the crtc size.
When CopyRegion is used top copy content into or out of the screen
buffer, it may be redirected to exactly one scanout buffer. This is
enough to support our one-drawable-per-crtc case, but not sufficient
in general.
This change also moves page flip state that was previously centralized
in the intel_mode structure into the intel_crtc structure associated
with the reference crtc for a flip. This allows flips to pending on
multiple pipes simultaneously.
Tested with the WebGL aquarium and space rocks demos, a Youtube
video and WebKit poster circle demo. Added and removed displays while
active and while suspended.
Signed-off-by: Dominik Behr <dbehr@chromium.org>
Signed-off-by: Shawn Nematbakhsh <shawnn@chromium.org>
Conflicts:
src/intel_options.c
src/intel_options.h
src/uxa/intel.h
---
src/intel_options.c | 1 +
src/intel_options.h | 1 +
src/uxa/intel.h | 55 +++-
src/uxa/intel_display.c | 706 +++++++++++++++++++++++++++++++++++++++---------
src/uxa/intel_dri.c | 191 +++++++++++--
src/uxa/intel_driver.c | 10 +
src/uxa/intel_uxa.c | 50 ++++
src/uxa/intel_video.c | 11 +-
8 files changed, 864 insertions(+), 161 deletions(-)
diff --git a/src/intel_options.c b/src/intel_options.c
index 02a4ae1..92a3bac 100644
--- a/src/intel_options.c
+++ b/src/intel_options.c
@@ -20,6 +20,7 @@ const OptionInfoRec intel_options[] = {
{OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, 0},
{OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, 1},
{OPTION_REPROBE, "ReprobeOutputs", OPTV_BOOLEAN, {0}, 0},
+ {OPTION_SPLIT_FRAMEBUFFER,"SplitFramebuffer", OPTV_BOOLEAN, {0}, TRUE},
#ifdef INTEL_XVMC
{OPTION_XVMC, "XvMC", OPTV_BOOLEAN, {0}, 1},
#endif
diff --git a/src/intel_options.h b/src/intel_options.h
index 77f0c45..d8e6fc0 100644
--- a/src/intel_options.h
+++ b/src/intel_options.h
@@ -27,6 +27,7 @@ enum intel_options {
OPTION_PREFER_OVERLAY,
OPTION_HOTPLUG,
OPTION_REPROBE,
+ OPTION_SPLIT_FRAMEBUFFER,
#if defined(XvMCExtension) && defined(ENABLE_XVMC)
OPTION_XVMC,
#define INTEL_XVMC 1
diff --git a/src/uxa/intel.h b/src/uxa/intel.h
index 0cbe68a..f5594a7 100644
--- a/src/uxa/intel.h
+++ b/src/uxa/intel.h
@@ -103,6 +103,7 @@ struct intel_pixmap {
#define PIN_DRI3 0x4
#define PIN_PRIME 0x8
#define PIN_GLAMOR 0x10
+ uint32_t fb;
};
#if HAS_DEVPRIVATEKEYREC
@@ -334,6 +335,7 @@ typedef struct intel_screen_private {
Bool force_fallback;
Bool has_kernel_flush;
Bool needs_flush;
+ Bool use_split_framebuffer;
struct _DRI2FrameEvent *pending_flip[2];
@@ -399,15 +401,44 @@ extern void intel_mode_remove_fb(intel_screen_private *intel);
extern void intel_mode_close(intel_screen_private *intel);
extern void intel_mode_fini(intel_screen_private *intel);
+extern void intel_pixmap_remove_fb(intel_screen_private *intel, PixmapPtr pixmap);
+extern void intel_set_front_fb_id(intel_screen_private *intel, PixmapPtr new_front_pixmap);
+
extern int intel_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc);
extern int intel_crtc_id(xf86CrtcPtr crtc);
extern int intel_output_dpms_status(xf86OutputPtr output);
extern void intel_copy_fb(ScrnInfoPtr scrn);
+struct intel_scanout {
+ PixmapPtr pixmap;
+ BoxRec area; /* area of the virtual screen provided by this scanout */
+};
+
+/* Splits the screen buffer into one scanout per distinct crtc region. */
+extern Bool intel_split_fb(intel_screen_private *intel);
+
+/* Merges any scanouts into the screen buffer. */
+extern void intel_merge_fb(intel_screen_private *intel);
+
+/* Finds a scanout that exactly matches the area, and stores it in |out_scanout|.
+ * Will return FALSE if any scanout partially intersects the area. If no scanout
+ * includes the area, will return TRUE with |out_scanout| set to NULL.
+ */
+extern Bool intel_find_scanout(intel_screen_private *intel, BoxPtr area,
+ struct intel_scanout **out_scanout);
+
+/* Finds a scanout that contains the area, and stores it in |out_scanout|.
+ * Will return FALSE if any scanout partially intersects the area. If no scanout
+ * includes the area, will return TRUE with |out_scanout| set to NULL.
+ */
+extern Bool intel_covering_scanout(intel_screen_private *intel, BoxPtr area,
+ struct intel_scanout **out_scanout);
+
enum DRI2FrameEventType {
DRI2_SWAP,
DRI2_SWAP_CHAIN,
- DRI2_FLIP,
+ DRI2_FLIP_FRONT,
+ DRI2_FLIP_SPLIT,
DRI2_WAITMSC,
};
@@ -432,13 +463,14 @@ typedef struct _DRI2FrameEvent {
void *event_data;
DRI2BufferPtr front;
DRI2BufferPtr back;
+ BoxRec area; /* screen rectangle being flipped */
struct _DRI2FrameEvent *chain;
} DRI2FrameEventRec, *DRI2FrameEventPtr;
extern Bool intel_do_pageflip(intel_screen_private *intel,
- dri_bo *new_front,
- DRI2FrameEventPtr flip_info, int ref_crtc_hw_id);
+ PixmapPtr new_front,
+ DRI2FrameEventPtr flip_info);
static inline intel_screen_private *
intel_get_screen_private(ScrnInfoPtr scrn)
@@ -474,6 +506,11 @@ extern void I915EmitInvarientState(ScrnInfoPtr scrn);
extern void I830EmitFlush(ScrnInfoPtr scrn);
extern void I830InitVideo(ScreenPtr pScreen);
+
+extern void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b);
+extern void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box);
+extern void intel_drawable_box(DrawablePtr draw, BoxPtr draw_box);
+
extern xf86CrtcPtr intel_covering_crtc(ScrnInfoPtr scrn, BoxPtr box,
xf86CrtcPtr desired, BoxPtr crtc_box_ret);
@@ -684,6 +721,18 @@ void intel_uxa_block_handler(intel_screen_private *intel);
Bool intel_get_aperture_space(ScrnInfoPtr scrn, drm_intel_bo ** bo_table,
int num_bos);
+/* Copies a box between pixmaps using intel->uxa_driver. */
+extern Bool intel_uxa_driver_copy_pixmap(intel_screen_private *intel,
+ PixmapPtr src, PixmapPtr dst,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ int w, int h);
+
+/* Fills a box of a pixmap using intel->uxa_driver. */
+extern Bool intel_uxa_driver_fill_pixmap(intel_screen_private *intel,
+ uint32_t src, PixmapPtr dst,
+ int x, int y, int w, int h);
+
static inline Bool intel_pixmap_is_offscreen(PixmapPtr pixmap)
{
struct intel_pixmap *priv = intel_get_pixmap_private(pixmap);
diff --git a/src/uxa/intel_display.c b/src/uxa/intel_display.c
index d7fb9a2..5767d25 100644
--- a/src/uxa/intel_display.c
+++ b/src/uxa/intel_display.c
@@ -60,27 +60,33 @@
#define KNOWN_MODE_FLAGS ((1<<14)-1)
+#define MAX_SCANOUTS (4)
+
+enum intel_scanout_state {
+ INTEL_SCANOUT_INVALID = 0,
+ INTEL_SCANOUT_FRONT,
+ INTEL_SCANOUT_SPLIT,
+};
+
struct intel_mode {
int fd;
- uint32_t fb_id;
drmModeResPtr mode_res;
int cpp;
drmEventContext event_context;
- DRI2FrameEventPtr flip_info;
- int old_fb_id;
- int flip_count;
- unsigned int fe_frame;
- unsigned int fe_tv_sec;
- unsigned int fe_tv_usec;
+
+ uint32_t front_fb_id;
+
+ int scanout_state;
+ struct intel_scanout scanouts[MAX_SCANOUTS];
struct list outputs;
struct list crtcs;
};
struct intel_pageflip {
- struct intel_mode *mode;
- Bool dispatch_me;
+ struct intel_crtc *reference_crtc;
+ struct intel_crtc *flipped_crtc;
};
struct intel_crtc {
@@ -88,10 +94,20 @@ struct intel_crtc {
drmModeModeInfo kmode;
drmModeCrtcPtr mode_crtc;
int pipe;
+
+ struct {
+ int pending; /* number of outstanding flip requests */
+ unsigned int frame;
+ unsigned int tv_sec;
+ unsigned int tv_usec;
+ DRI2FrameEventPtr info;
+ } flip;
+
dri_bo *cursor;
dri_bo *rotate_bo;
uint32_t rotate_pitch;
uint32_t rotate_fb_id;
+
xf86CrtcPtr crtc;
struct list link;
PixmapPtr scanout_pixmap;
@@ -128,6 +144,9 @@ struct intel_output {
};
static void
+intel_crtc_merge_scanouts(intel_screen_private *intel);
+
+static void
intel_output_dpms(xf86OutputPtr output, int mode);
static void
@@ -449,16 +468,97 @@ intel_mode_disable_unused_functions(ScrnInfoPtr scrn)
}
}
+/* Get a scratch pixmap attached to the current front buffer. This needs to be
+ * used rather than GetScreenPixmap before the screen is fully initialized,
+ * and during intel_xf86crtc_resize when the state is inconsistent.
+ */
+static PixmapPtr intel_get_scratch_front_pixmap(intel_screen_private *intel)
+{
+ ScrnInfoPtr scrn = intel->scrn;
+ PixmapPtr pixmap;
+
+ pixmap = GetScratchPixmapHeader(
+ scrn->pScreen,
+ scrn->virtualX,
+ scrn->virtualY,
+ scrn->depth,
+ scrn->bitsPerPixel,
+ intel->front_pitch,
+ NULL);
+
+ intel_set_pixmap_bo(pixmap, intel->front_buffer);
+ return pixmap;
+}
+
+static void intel_free_scratch_front_pixmap(PixmapPtr pixmap)
+{
+ if (pixmap == NULL)
+ return;
+ intel_set_pixmap_bo(pixmap, NULL);
+ FreeScratchPixmapHeader(pixmap);
+}
+
+static uint32_t
+intel_pixmap_ensure_fb(intel_screen_private *intel, PixmapPtr pixmap)
+{
+ struct intel_mode *mode = intel->modes;
+ struct intel_pixmap *intel_pixmap = intel_get_pixmap_private(pixmap);
+ int ret;
+
+ if (intel_pixmap->fb != 0)
+ return intel_pixmap->fb;
+
+ ret = drmModeAddFB(mode->fd,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ intel->scrn->depth,
+ intel->scrn->bitsPerPixel,
+ intel_pixmap_pitch(pixmap),
+ intel_get_pixmap_bo(pixmap)->handle,
+ &intel_pixmap->fb);
+ if (ret < 0) {
+ xf86DrvMsg(intel->scrn->scrnIndex, X_ERROR,
+ "failed to add fb for pixmap: %s\n",
+ strerror(-ret));
+ return FALSE;
+ }
+
+ return intel_pixmap->fb;
+}
+
+void intel_pixmap_remove_fb(intel_screen_private *intel, PixmapPtr pixmap)
+{
+ struct intel_mode *mode = intel->modes;
+ struct intel_pixmap *intel_pixmap = intel_get_pixmap_private(pixmap);
+ int ret;
+
+ if (intel_pixmap->fb == 0)
+ return;
+
+ ret = drmModeRmFB(mode->fd, intel_pixmap->fb);
+ if (ret < 0) {
+ xf86DrvMsg(intel->scrn->scrnIndex, X_ERROR,
+ "failed to remove fb for pixmap: %s\n",
+ strerror(-ret));
+ }
+
+ intel_pixmap->fb = 0;
+}
+
static Bool
intel_crtc_apply(xf86CrtcPtr crtc)
{
ScrnInfoPtr scrn = crtc->scrn;
+ intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct intel_mode *mode = intel->modes;
struct intel_crtc *intel_crtc = crtc->driver_private;
- struct intel_mode *mode = intel_crtc->mode;
+ BoxRec crtc_box;
+ struct intel_scanout *scanout;
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
uint32_t *output_ids;
int output_count = 0;
- int fb_id, x, y;
+ uint32_t fb_id;
+ int x, y;
int i, ret = FALSE;
output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
@@ -493,9 +593,21 @@ intel_crtc_apply(xf86CrtcPtr crtc)
crtc->gamma_blue, crtc->gamma_size);
#endif
+ fb_id = mode->front_fb_id;
x = crtc->x;
y = crtc->y;
- fb_id = mode->fb_id;
+
+ intel_crtc_box(crtc, &crtc_box);
+ if (!intel_find_scanout(intel, &crtc_box, &scanout)) {
+ /* partially intersects a scanout; merge everything */
+ intel_crtc_merge_scanouts(intel);
+ intel_batch_submit(scrn);
+ }
+ if (scanout != NULL) {
+ fb_id = intel_pixmap_ensure_fb(intel, scanout->pixmap);
+ x -= scanout->area.x1;
+ y -= scanout->area.y1;
+ }
if (intel_crtc->rotate_fb_id) {
fb_id = intel_crtc->rotate_fb_id;
x = 0;
@@ -521,7 +633,6 @@ intel_crtc_apply(xf86CrtcPtr crtc)
for (i = 0; i < xf86_config->num_output; i++) {
xf86OutputPtr output = xf86_config->output[i];
struct intel_output *intel_output;
-
if (output->crtc != crtc)
continue;
@@ -544,20 +655,20 @@ intel_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
{
ScrnInfoPtr scrn = crtc->scrn;
intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct intel_mode *intel_mode = intel->modes;
struct intel_crtc *intel_crtc = crtc->driver_private;
- struct intel_mode *intel_mode = intel_crtc->mode;
int saved_x, saved_y;
Rotation saved_rotation;
DisplayModeRec saved_mode;
- int ret = TRUE;
- unsigned int pitch = scrn->displayWidth * intel->cpp;
+ int ret;
- if (intel_mode->fb_id == 0) {
+ if (intel_mode->front_fb_id == 0) {
ret = drmModeAddFB(intel_mode->fd,
scrn->virtualX, scrn->virtualY,
scrn->depth, scrn->bitsPerPixel,
- pitch, intel->front_buffer->handle,
- &intel_mode->fb_id);
+ scrn->displayWidth * intel->cpp,
+ intel->front_buffer->handle,
+ &intel_mode->front_fb_id);
if (ret < 0) {
ErrorF("failed to add fb\n");
return FALSE;
@@ -580,14 +691,17 @@ intel_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
intel_batch_submit(crtc->scrn);
mode_to_kmode(crtc->scrn, &intel_crtc->kmode, mode);
- ret = intel_crtc_apply(crtc);
- if (!ret) {
- crtc->x = saved_x;
- crtc->y = saved_y;
- crtc->rotation = saved_rotation;
- crtc->mode = saved_mode;
- }
- return ret;
+ if (!intel_crtc_apply(crtc))
+ goto error_undo;
+
+ return TRUE;
+
+error_undo:
+ crtc->x = saved_x;
+ crtc->y = saved_y;
+ crtc->rotation = saved_rotation;
+ crtc->mode = saved_mode;
+ return FALSE;
}
static void
@@ -1507,33 +1621,53 @@ intel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, int num)
list_add(&intel_output->link, &mode->outputs);
}
+static void
+intel_destroy_scanout(struct intel_scanout *scanout)
+{
+ if (!scanout)
+ return;
+
+ if (scanout->pixmap) {
+ intel_set_pixmap_bo(scanout->pixmap, NULL);
+ FreeScratchPixmapHeader(scanout->pixmap);
+ }
+ memset(scanout, 0, sizeof(*scanout));
+}
+
static Bool
intel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
{
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
- struct intel_crtc *intel_crtc = xf86_config->crtc[0]->driver_private;
- struct intel_mode *mode = intel_crtc->mode;
intel_screen_private *intel = intel_get_screen_private(scrn);
+ struct intel_mode *mode = intel->modes;
drm_intel_bo *old_front = NULL;
- Bool ret;
+ int ret;
uint32_t old_fb_id;
int i, old_width, old_height, old_pitch;
unsigned long pitch;
uint32_t tiling;
ScreenPtr screen;
+ intel_batch_submit(scrn);
+
if (scrn->virtualX == width && scrn->virtualY == height)
return TRUE;
intel_glamor_flush(intel);
- intel_batch_submit(scrn);
+ for (i = 0; i < MAX_SCANOUTS; i++) {
+ intel_destroy_scanout(&mode->scanouts[i]);
+ }
+ mode->scanout_state = INTEL_SCANOUT_INVALID;
old_width = scrn->virtualX;
old_height = scrn->virtualY;
old_pitch = scrn->displayWidth;
- old_fb_id = mode->fb_id;
+ old_fb_id = mode->front_fb_id;
old_front = intel->front_buffer;
+ intel->front_buffer = NULL;
+ mode->front_fb_id = 0;
+
if (intel->back_pixmap) {
screen = intel->back_pixmap->drawable.pScreen;
screen->DestroyPixmap(intel->back_pixmap);
@@ -1556,7 +1690,7 @@ intel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
ret = drmModeAddFB(mode->fd, width, height, scrn->depth,
scrn->bitsPerPixel, pitch,
intel->front_buffer->handle,
- &mode->fb_id);
+ &mode->front_fb_id);
if (ret)
goto fail;
@@ -1593,102 +1727,415 @@ fail:
scrn->virtualX = old_width;
scrn->virtualY = old_height;
scrn->displayWidth = old_pitch;
- if (old_fb_id != mode->fb_id)
- drmModeRmFB(mode->fd, mode->fb_id);
- mode->fb_id = old_fb_id;
+ if (old_fb_id != mode->front_fb_id)
+ drmModeRmFB(mode->fd, mode->front_fb_id);
+ mode->front_fb_id = old_fb_id;
return FALSE;
}
+static PixmapPtr intel_create_split_fb(intel_screen_private *intel, int width, int height)
+{
+ ScrnInfoPtr scrn = intel->scrn;
+ drm_intel_bo *pixmap_bo = NULL;
+ PixmapPtr pixmap = NULL;
+ unsigned long pitch;
+ uint32_t tiling;
+
+ pixmap_bo = intel_allocate_framebuffer(scrn, width, height, intel->cpp,
+ &pitch, &tiling);
+ if (!pixmap_bo)
+ goto fail;
+
+ pixmap = GetScratchPixmapHeader(scrn->pScreen,
+ width, height,
+ scrn->depth,
+ scrn->bitsPerPixel,
+ pitch,
+ NULL);
+ if (!pixmap)
+ goto fail;
+
+ intel_set_pixmap_bo(pixmap, pixmap_bo);
+ drm_intel_bo_unreference(pixmap_bo);
+ pixmap_bo = NULL;
+
+ return pixmap;
+fail:
+ drm_intel_bo_unreference(pixmap_bo);
+ return NULL;
+}
+
Bool
-intel_do_pageflip(intel_screen_private *intel,
- dri_bo *new_front,
- DRI2FrameEventPtr flip_info, int ref_crtc_hw_id)
+intel_split_fb(intel_screen_private *intel)
+{
+ ScrnInfoPtr scrn = intel->scrn;
+ struct intel_mode *mode = intel->modes;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ struct intel_scanout *scanout;
+ PixmapPtr screen_pixmap;
+ BoxRec crtc_box;
+ int i, j, old_state;
+
+ if (mode->scanout_state == INTEL_SCANOUT_SPLIT)
+ return TRUE; /* nothing to do */
+
+ old_state = mode->scanout_state;
+ mode->scanout_state = INTEL_SCANOUT_SPLIT;
+
+ screen_pixmap = intel_get_scratch_front_pixmap(intel);
+
+ for (i = 0; i < config->num_crtc; i++) {
+ xf86CrtcPtr crtc = config->crtc[i];
+ if (!crtc->enabled)
+ continue;
+
+ intel_crtc_box(crtc, &crtc_box);
+
+ for (j = 0; j < MAX_SCANOUTS; j++) {
+ scanout = &mode->scanouts[j];
+ if (scanout->pixmap == NULL)
+ break; /* beyond the last valid entry */
+
+ if (crtc_box.x1 == scanout->area.x1 &&
+ crtc_box.y1 == scanout->area.y1 &&
+ crtc_box.x2 == scanout->area.x2 &&
+ crtc_box.y2 == scanout->area.y2)
+ break; /* already have a scanout for this crtc */
+ }
+ if (j == MAX_SCANOUTS) {
+ xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
+ "failed to split framebuffer: all scanouts in use\n");
+ goto fail;
+ }
+
+ if (scanout->pixmap)
+ continue; /* already have a complete scanout for this crtc */
+
+ /* need to allocate a new scanout bo for this crtc */
+ scanout->pixmap = intel_create_split_fb(intel,
+ crtc->mode.HDisplay, crtc->mode.VDisplay);
+ if (!scanout->pixmap) {
+ xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
+ "failed to split framebuffer: allocation failure\n");
+ goto fail;
+ }
+
+ scanout->area.x1 = crtc_box.x1;
+ scanout->area.y1 = crtc_box.y1;
+ scanout->area.x2 = crtc_box.x2;
+ scanout->area.y2 = crtc_box.y2;
+
+ if (old_state == INTEL_SCANOUT_FRONT) {
+ /* copy current content from the front buffer */
+ intel_uxa_driver_copy_pixmap(intel,
+ screen_pixmap, scanout->pixmap,
+ crtc_box.x1, crtc_box.y1, 0, 0,
+ crtc_box.x2 - crtc_box.x1,
+ crtc_box.y2 - crtc_box.y1);
+ }
+ }
+
+ intel_batch_submit(scrn);
+ for (i = 0; i < config->num_crtc; i++) {
+ xf86CrtcPtr crtc = config->crtc[i];
+ if (!crtc->enabled)
+ continue;
+
+ if (!intel_crtc_apply(crtc))
+ goto fail;
+ }
+
+ intel_free_scratch_front_pixmap(screen_pixmap);
+
+ return TRUE;
+
+fail:
+ mode->scanout_state = old_state;
+ intel_free_scratch_front_pixmap(screen_pixmap);
+ return FALSE;
+}
+
+static void
+intel_crtc_merge_scanouts(intel_screen_private *intel)
+{
+ struct intel_mode *mode = intel->modes;
+ PixmapPtr screen_pixmap;
+ int i, old_state;
+
+ old_state = mode->scanout_state;
+ mode->scanout_state = INTEL_SCANOUT_FRONT;
+
+ screen_pixmap = intel_get_scratch_front_pixmap(intel);
+
+ for (i = 0; i < MAX_SCANOUTS; i++) {
+ struct intel_scanout *scanout = &mode->scanouts[i];
+ if (scanout->pixmap == NULL)
+ continue;
+
+ if (old_state == INTEL_SCANOUT_SPLIT) {
+ /* copy current content from the split buffer */
+ intel_uxa_driver_copy_pixmap(intel,
+ scanout->pixmap, screen_pixmap,
+ 0, 0,
+ scanout->area.x1, scanout->area.y1,
+ scanout->area.x2 - scanout->area.x1,
+ scanout->area.y2 - scanout->area.y1);
+ }
+
+ intel_destroy_scanout(scanout);
+ }
+
+ intel_free_scratch_front_pixmap(screen_pixmap);
+}
+
+void
+intel_merge_fb(intel_screen_private *intel)
{
ScrnInfoPtr scrn = intel->scrn;
+ struct intel_mode *mode = intel->modes;
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
- struct intel_crtc *crtc = config->crtc[0]->driver_private;
- struct intel_mode *mode = crtc->mode;
- unsigned int pitch = scrn->displayWidth * intel->cpp;
- struct intel_pageflip *flip;
- uint32_t new_fb_id;
int i;
- /*
- * Create a new handle for the back buffer
- */
- if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
- scrn->depth, scrn->bitsPerPixel, pitch,
- new_front->handle, &new_fb_id))
- goto error_out;
+ if (mode->scanout_state == INTEL_SCANOUT_FRONT)
+ return; /* nothing to do */
- drm_intel_bo_disable_reuse(new_front);
- intel_glamor_flush(intel);
+ intel_crtc_merge_scanouts(intel);
intel_batch_submit(scrn);
- /*
- * 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.
- */
- mode->fe_frame = 0;
- mode->fe_tv_sec = 0;
- mode->fe_tv_usec = 0;
+ for (i = 0; i < config->num_crtc; i++) {
+ xf86CrtcPtr crtc = config->crtc[i];
+ if (!crtc->enabled)
+ continue;
+ if (!intel_crtc_apply(crtc))
+ continue; /* update as many crtcs as possible */
+ }
+}
+
+Bool
+intel_find_scanout(intel_screen_private *intel, BoxPtr area,
+ struct intel_scanout **out_scanout)
+{
+ struct intel_mode *mode = intel->modes;
+ BoxRec intersect_box;
+ int i;
+
+ *out_scanout = NULL;
+
+ if (mode->scanout_state != INTEL_SCANOUT_SPLIT)
+ return TRUE; /* always use screen buffer */
+
+ for (i = 0; i < MAX_SCANOUTS; i++) {
+ struct intel_scanout *scanout = &mode->scanouts[i];
+ if (scanout->pixmap == NULL)
+ continue;
+
+ if (scanout->area.x1 == area->x1 &&
+ scanout->area.y1 == area->y1 &&
+ scanout->area.x2 == area->x2 &&
+ scanout->area.y2 == area->y2) {
+ *out_scanout = scanout;
+ return TRUE;
+ }
+
+ intel_box_intersect(&intersect_box, &scanout->area, area);
+ if (intersect_box.x1 != intersect_box.x2 ||
+ intersect_box.y1 != intersect_box.y2) {
+ /* partial intersection; must merge to use area. */
+ return FALSE;
+ }
+ }
+
+ /* did not intersect any scanouts; use the screen. */
+ return TRUE;
+}
+
+Bool
+intel_covering_scanout(intel_screen_private *intel, BoxPtr area,
+ struct intel_scanout **out_scanout)
+{
+ struct intel_mode *mode = intel->modes;
+ BoxRec intersect_box;
+ int i;
+
+ *out_scanout = NULL;
+
+ if (mode->scanout_state != INTEL_SCANOUT_SPLIT)
+ return TRUE; /* always use screen buffer */
+
+ for (i = 0; i < MAX_SCANOUTS; i++) {
+ struct intel_scanout *scanout = &mode->scanouts[i];
+ if (scanout->pixmap == NULL)
+ continue;
+
+ if (scanout->area.x1 <= area->x1 &&
+ scanout->area.y1 <= area->y1 &&
+ scanout->area.x2 >= area->x2 &&
+ scanout->area.y2 >= area->y2) {
+ *out_scanout = scanout;
+ return TRUE;
+ }
+ intel_box_intersect(&intersect_box, &scanout->area, area);
+ if (intersect_box.x1 != intersect_box.x2 ||
+ intersect_box.y1 != intersect_box.y2) {
+ /* partial intersection; must merge to use area. */
+ return FALSE;
+ }
+ }
+
+ /* did not intersect any scanouts; use the screen. */
+ return TRUE;
+}
+
+Bool
+intel_do_pageflip(intel_screen_private *intel,
+ PixmapPtr new_front,
+ DRI2FrameEventPtr flip_info)
+{
+ struct intel_mode *mode = intel->modes;
+ ScrnInfoPtr scrn = intel->scrn;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ struct intel_pageflip **flip_data = NULL;
+ uint32_t new_front_fb_id;
+ struct intel_crtc *reference_crtc;
+ BoxRec crtc_box, intersect_box;
+ int i, ret;
+
+ if (mode->scanout_state == INTEL_SCANOUT_INVALID) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: scanout state not configured.\n");
+ return FALSE;
+ }
+
+ new_front_fb_id = intel_pixmap_ensure_fb(intel, new_front);
+ if (new_front_fb_id == 0)
+ goto error_undo;
+
+ flip_data = calloc(config->num_crtc, sizeof(*flip_data));
+ if (!flip_data) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: memory allocation error.\n");
+ goto error_undo;
+ }
+
+ /* Find the reference CRTC, check safety and allocate flip data. */
+ reference_crtc = NULL;
for (i = 0; i < config->num_crtc; i++) {
- if (!intel_crtc_on(config->crtc[i]))
+ xf86CrtcPtr crtc = config->crtc[i];
+ struct intel_crtc *intel_crtc = crtc->driver_private;
+ if (!crtc->enabled)
continue;
- mode->flip_info = flip_info;
- mode->flip_count++;
+ if (flip_info->pipe == intel_crtc->pipe)
+ reference_crtc = intel_crtc;
- crtc = config->crtc[i]->driver_private;
+ intel_crtc_box(crtc, &crtc_box);
+ intel_box_intersect(&intersect_box, &crtc_box, &flip_info->area);
+
+ if (intersect_box.x1 == intersect_box.x2 ||
+ intersect_box.y1 == intersect_box.y2) {
+ /* Skip crtcs unaffected by this update. */
+ if (reference_crtc == intel_crtc) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: updated area does "
+ "not include the reference crtc.\n");
+ goto error_undo;
+ }
+ continue;
+ }
- flip = calloc(1, sizeof(struct intel_pageflip));
- if (flip == NULL) {
+ if (intersect_box.x1 != crtc_box.x1 ||
+ intersect_box.y1 != crtc_box.y1 ||
+ intersect_box.x2 != crtc_box.x2 ||
+ intersect_box.y2 != crtc_box.y2) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
- "flip queue: carrier alloc failed.\n");
+ "flip queue failed: updated area partially "
+ "intersects crtc %d.\n",
+ crtc_id(intel_crtc));
goto error_undo;
}
+ flip_data[i] = calloc(1, sizeof(**flip_data));
+ if (!flip_data[i]) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: memory allocation error.\n");
+ goto error_undo;
+ }
+ }
+ if (reference_crtc == NULL) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: no reference crtc for pipe %d.\n",
+ flip_info->pipe);
+ goto error_undo;
+ }
+ if (reference_crtc->flip.info) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: reference crtc %d (for pipe %d) "
+ "already has a flip pending.\n",
+ crtc_id(reference_crtc),
+ flip_info->pipe);
+ goto error_undo;
+ }
- /* Only the reference crtc will finally deliver its page flip
- * completion event. All other crtc's events will be discarded.
- */
- flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id);
- flip->mode = mode;
+ intel_batch_submit(scrn);
- if (drmModePageFlip(mode->fd,
- crtc_id(crtc),
- new_fb_id,
- DRM_MODE_PAGE_FLIP_EVENT, flip)) {
+ reference_crtc->flip.pending = 0;
+ reference_crtc->flip.frame = 0;
+ reference_crtc->flip.tv_sec = 0;
+ reference_crtc->flip.tv_usec = 0;
+
+ /* Defer storing the flip info until we have successfully queued all of
+ * the flips. If this function returns FALSE, the caller will free the
+ * flip_info structure, so any successful flips must not access it.
+ */
+ reference_crtc->flip.info = NULL;
+
+ /*
+ * Queue flips on all updated CRTCs.
+ * Flips queued on disabled or incorrectly-configured crtcs may never
+ * complete. This type of configuration error will result in the
+ * flip never completing, and leak some objects.
+ */
+ for (i = 0; i < config->num_crtc; i++) {
+ struct intel_crtc *intel_crtc = config->crtc[i]->driver_private;
+ if (!flip_data[i])
+ continue;
+
+ flip_data[i]->reference_crtc = reference_crtc;
+ flip_data[i]->flipped_crtc = intel_crtc;
+ ret = drmModePageFlip(mode->fd,
+ crtc_id(intel_crtc),
+ new_front_fb_id,
+ DRM_MODE_PAGE_FLIP_EVENT,
+ flip_data[i]);
+ if (ret < 0) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
- "flip queue failed: %s\n", strerror(errno));
- free(flip);
+ "flip queue failed: error flipping crtc %d: %s\n",
+ crtc_id(intel_crtc), strerror(-ret));
goto error_undo;
}
+ /* The flip_data object will be freed when the flip completes. */
+ flip_data[i] = NULL;
+
+ reference_crtc->flip.pending++;
}
- mode->old_fb_id = mode->fb_id;
- mode->fb_id = new_fb_id;
+ reference_crtc->flip.info = flip_info;
+ free(flip_data);
return TRUE;
error_undo:
- drmModeRmFB(mode->fd, new_fb_id);
- for (i = 0; i < config->num_crtc; i++) {
- if (config->crtc[i]->enabled)
- intel_crtc_apply(config->crtc[i]);
+ if (flip_data) {
+ /* Free any unused flip data objects. */
+ for (i = 0; i < config->num_crtc; i++) {
+ free(flip_data[i]);
+ }
+ free(flip_data);
}
-
-error_out:
- xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
- strerror(errno));
return FALSE;
}
+
static const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = {
intel_xf86crtc_resize
};
@@ -1705,31 +2152,33 @@ intel_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
struct intel_pageflip *flip = event_data;
- struct intel_mode *mode = flip->mode;
+ struct intel_crtc *reference_crtc = flip->reference_crtc;
+ struct intel_crtc *flipped_crtc = flip->flipped_crtc;
- /* Is this the event whose info shall be delivered to higher level? */
- if (flip->dispatch_me) {
- /* Yes: Cache msc, ust for later delivery. */
- mode->fe_frame = frame;
- mode->fe_tv_sec = tv_sec;
- mode->fe_tv_usec = tv_usec;
+ if (reference_crtc == flipped_crtc) {
+ /* Cache information from the reference crtc's flip for the event handler. */
+ reference_crtc->flip.frame = frame;
+ reference_crtc->flip.tv_sec = tv_sec;
+ reference_crtc->flip.tv_usec = tv_usec;
}
+
free(flip);
- /* Last crtc completed flip? */
- mode->flip_count--;
- if (mode->flip_count > 0)
+ /* Was this the last pending flip? */
+ reference_crtc->flip.pending--;
+ if (reference_crtc->flip.pending > 0)
return;
- /* Release framebuffer */
- drmModeRmFB(mode->fd, mode->old_fb_id);
-
- if (mode->flip_info == NULL)
+ if (reference_crtc->flip.info == NULL)
return;
- /* Deliver cached msc, ust from reference crtc to flip event handler */
- I830DRI2FlipEventHandler(mode->fe_frame, mode->fe_tv_sec,
- mode->fe_tv_usec, mode->flip_info);
+ /* Deliver cached info from reference crtc to flip event handler */
+ I830DRI2FlipEventHandler(
+ reference_crtc->flip.frame,
+ reference_crtc->flip.tv_sec,
+ reference_crtc->flip.tv_usec,
+ reference_crtc->flip.info);
+ reference_crtc->flip.info = NULL;
}
static void
@@ -1873,7 +2322,6 @@ intel_mode_init(struct intel_screen_private *intel)
* feedback on every server generation, so perform the
* registration within ScreenInit and not PreInit.
*/
- mode->flip_count = 0;
AddGeneralSocket(mode->fd);
RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
drm_wakeup_handler, mode);
@@ -1884,9 +2332,9 @@ intel_mode_remove_fb(intel_screen_private *intel)
{
struct intel_mode *mode = intel->modes;
- if (mode->fb_id) {
- drmModeRmFB(mode->fd, mode->fb_id);
- mode->fb_id = 0;
+ if (mode->front_fb_id != 0) {
+ drmModeRmFB(mode->fd, mode->front_fb_id);
+ mode->front_fb_id = 0;
}
}
@@ -1918,6 +2366,7 @@ void
intel_mode_fini(intel_screen_private *intel)
{
struct intel_mode *mode = intel->modes;
+ int i;
if (mode == NULL)
return;
@@ -1934,8 +2383,9 @@ intel_mode_fini(intel_screen_private *intel)
link)->output);
}
- if (mode->fb_id)
- drmModeRmFB(mode->fd, mode->fb_id);
+ for (i = 0; i < MAX_SCANOUTS; i++) {
+ intel_destroy_scanout(&mode->scanouts[i]);
+ }
/* mode->rotate_fb_id should have been destroyed already */
@@ -1973,23 +2423,10 @@ Bool intel_crtc_on(xf86CrtcPtr crtc)
xf86OutputPtr output = xf86_config->output[i];
if (output->crtc == crtc &&
intel_output_dpms_status(output) == DPMSModeOn) {
- ret = TRUE;
- break;
+ return TRUE;
}
}
- if (!ret)
- return FALSE;
-
- /* And finally check with the kernel that the fb is bound */
- drm_crtc = drmModeGetCrtc(intel_crtc->mode->fd, crtc_id(intel_crtc));
- if (drm_crtc == NULL)
- return FALSE;
-
- ret = (drm_crtc->mode_valid &&
- intel_crtc->mode->fb_id == drm_crtc->buffer_id);
- free(drm_crtc);
-
- return ret;
+ return FALSE;
}
static PixmapPtr
@@ -2050,6 +2487,13 @@ intel_create_pixmap_for_fbcon(ScrnInfoPtr pScrn)
return pixmap;
}
+void intel_set_front_fb_id(intel_screen_private *intel, PixmapPtr new_front_pixmap)
+{
+ struct intel_mode *mode = intel->modes;
+ mode->front_fb_id = intel_pixmap_ensure_fb(intel, new_front_pixmap);
+}
+
+
void intel_copy_fb(ScrnInfoPtr pScrn)
{
ScreenPtr pScreen = screenInfo.screens[pScrn->scrnIndex];
diff --git a/src/uxa/intel_dri.c b/src/uxa/intel_dri.c
index 08a0bd4..b4c1a13 100644
--- a/src/uxa/intel_dri.c
+++ b/src/uxa/intel_dri.c
@@ -439,6 +439,12 @@ I830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
? drawable : &dstPrivate->pixmap->drawable;
RegionPtr pCopyClip;
GCPtr gc;
+ BoxRec draw_box;
+ struct intel_scanout *scanout;
+
+ if (pRegion->extents.x1 == pRegion->extents.x2 ||
+ pRegion->extents.y1 == pRegion->extents.y2)
+ return; /* nothing actually being copied */
gc = GetScratchGC(dst->depth, screen);
if (!gc)
@@ -525,6 +531,22 @@ I830DRI2CopyRegion(DrawablePtr drawable, RegionPtr pRegion,
}
}
+ if (pixmap_is_scanout(get_drawable_pixmap(dst))) {
+ intel_drawable_box(drawable, &draw_box);
+ if (!intel_find_scanout(intel, &draw_box, &scanout) || scanout == NULL)
+ intel_merge_fb(intel);
+ else
+ dst = &scanout->pixmap->drawable;
+ }
+
+ if (pixmap_is_scanout(get_drawable_pixmap(src))) {
+ intel_drawable_box(drawable, &draw_box);
+ if (!intel_find_scanout(intel, &draw_box, &scanout) || scanout == NULL)
+ intel_merge_fb(intel);
+ else
+ src = &scanout->pixmap->drawable;
+ }
+
/* It's important that this copy gets submitted before the
* direct rendering client submits rendering for the next
* frame, but we don't actually need to submit right now. The
@@ -790,9 +812,36 @@ I830DRI2ExchangeBuffers(struct intel_screen_private *intel, DRI2BufferPtr front,
back_priv->pixmap);
dri_bo_unreference (intel->front_buffer);
intel->front_buffer = new_front->bo;
+ intel_set_front_fb_id(intel, front_priv->pixmap);
dri_bo_reference (intel->front_buffer);
}
+static void
+I830DRI2ExchangeBuffersSplit(struct intel_screen_private *intel,
+ DrawablePtr draw,
+ DRI2BufferPtr front, DRI2BufferPtr back)
+{
+ I830DRI2BufferPrivatePtr back_priv;
+ struct intel_scanout *scanout;
+ BoxRec draw_box;
+
+ back_priv = back->driverPrivate;
+
+ intel_drawable_box(draw, &draw_box);
+ if (!intel_find_scanout(intel, &draw_box, &scanout) || scanout == NULL) {
+ xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
+ "failed to exchange with scanout");
+ return;
+ }
+
+ /* Swap pixmap bos */
+ intel_exchange_pixmap_buffers(intel,
+ scanout->pixmap,
+ back_priv->pixmap);
+
+ back->name = pixmap_flink(back_priv->pixmap);
+}
+
static PixmapPtr
intel_glamor_create_back_pixmap(ScreenPtr screen,
PixmapPtr front_pixmap,
@@ -825,13 +874,6 @@ intel_glamor_create_back_pixmap(ScreenPtr screen,
return back_pixmap;
}
-static drm_intel_bo *get_pixmap_bo(I830DRI2BufferPrivatePtr priv)
-{
- drm_intel_bo *bo = intel_get_pixmap_bo(priv->pixmap);
- assert(bo != NULL); /* guaranteed by construction of the DRI2 buffer */
- return bo;
-}
-
/*
* Our internal swap routine takes care of actually exchanging, blitting, or
* flipping buffers as necessary.
@@ -842,17 +884,20 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
DRI2FrameEventPtr info)
{
I830DRI2BufferPrivatePtr priv = info->back->driverPrivate;
- drm_intel_bo *new_back, *old_back;
+ drm_intel_bo *new_back;
int tmp_name;
if (!intel->use_triple_buffer) {
- info->type = DRI2_SWAP;
- if (!intel_do_pageflip(intel,
- get_pixmap_bo(priv),
- info, info->pipe))
+ if (!intel_do_pageflip(intel, priv->pixmap, info))
return FALSE;
- I830DRI2ExchangeBuffers(intel, info->front, info->back);
+ if (info->type == DRI2_FLIP_SPLIT) {
+ info->type = DRI2_SWAP;
+ I830DRI2ExchangeBuffersSplit(intel, draw, info->front, info->back);
+ } else {
+ info->type = DRI2_SWAP;
+ I830DRI2ExchangeBuffers(intel, info->front, info->back);
+ }
return TRUE;
}
@@ -903,8 +948,7 @@ I830DRI2ScheduleFlip(struct intel_screen_private *intel,
intel->back_buffer = NULL;
}
- old_back = get_pixmap_bo(priv);
- if (!intel_do_pageflip(intel, old_back, info, info->pipe)) {
+ if (!intel_do_pageflip(intel, priv->pixmap, info)) {
intel->back_buffer = new_back;
return FALSE;
}
@@ -990,6 +1034,79 @@ can_exchange(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
return TRUE;
}
+static Bool
+can_exchange_split(DrawablePtr drawable, DRI2BufferPtr front, DRI2BufferPtr back)
+{
+ struct intel_screen_private *intel = intel_get_screen_private(xf86Screens[drawable->pScreen->myNum]);
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(intel->scrn);
+ I830DRI2BufferPrivatePtr front_priv = front->driverPrivate;
+ I830DRI2BufferPrivatePtr back_priv = back->driverPrivate;
+ PixmapPtr front_pixmap = front_priv->pixmap;
+ PixmapPtr back_pixmap = back_priv->pixmap;
+ struct intel_pixmap *front_intel = intel_get_pixmap_private(front_pixmap);
+ struct intel_pixmap *back_intel = intel_get_pixmap_private(back_pixmap);
+ WindowPtr draw_win;
+ Bool found_match, found_conflict;
+ BoxRec draw_box, crtc_box, intersect_box;
+ int i;
+
+ if (drawable == NULL ||
+ drawable->type != DRAWABLE_WINDOW ||
+ intel->shadow_present ||
+ !intel->use_pageflipping ||
+ !intel->use_split_framebuffer)
+ return FALSE;
+
+ if (!pixmap_is_scanout(front_pixmap))
+ return FALSE;
+
+ /* Reject cases where the drawable and backing store have different
+ * sizes. This occurs occasionally when a resize and an update happen
+ * simultaneously. */
+ if (drawable->width != back_pixmap->drawable.width ||
+ drawable->height != back_pixmap->drawable.height)
+ return FALSE;
+
+ /* Reported depth differs because the scanout pixmap has no alpha,
+ * however the formats are still interchangeable. */
+ if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel ||
+ front_intel->tiling != back_intel->tiling)
+ return FALSE;
+
+ /* Can only do a split exchange if the window is completely exposed. */
+ draw_win = (WindowPtr)drawable;
+ if (!RegionEqual(&draw_win->clipList, &draw_win->winSize))
+ return FALSE;
+
+ /* Only split if the area matches at least one crtc, and does not
+ * partially intersect any crtcs. */
+ found_match = FALSE;
+ found_conflict = FALSE;
+ intel_drawable_box(drawable, &draw_box);
+ for (i = 0; i < config->num_crtc; i++) {
+ xf86CrtcPtr crtc = config->crtc[i];
+ if (!crtc->enabled)
+ continue;
+
+ intel_crtc_box(crtc, &crtc_box);
+ if (crtc_box.x1 == draw_box.x1 &&
+ crtc_box.y1 == draw_box.y1 &&
+ crtc_box.x2 == draw_box.x2 &&
+ crtc_box.y2 == draw_box.y2) {
+ /* regions are equal, so can flip with this crtc */
+ found_match = TRUE;
+ continue;
+ }
+
+ /* not equal, so any intersection indicates a conflict */
+ intel_box_intersect(&intersect_box, &draw_box, &crtc_box);
+ if (intersect_box.x1 != intersect_box.x2 &&
+ intersect_box.y1 != intersect_box.y2)
+ found_conflict = TRUE;
+ }
+ return found_match && !found_conflict;
+}
+
void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, DRI2FrameEventPtr swap_info)
{
@@ -1007,13 +1124,19 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
return;
}
-
switch (swap_info->type) {
- case DRI2_FLIP:
+ case DRI2_FLIP_SPLIT:
+ if (can_exchange_split(drawable, swap_info->front, swap_info->back)) {
+ if (I830DRI2ScheduleFlip(intel, drawable, swap_info))
+ return;
+ }
+
+ case DRI2_FLIP_FRONT:
/* If we can still flip... */
- if (can_exchange(drawable, swap_info->front, swap_info->back) &&
- I830DRI2ScheduleFlip(intel, drawable, swap_info))
- return;
+ if (can_exchange(drawable, swap_info->front, swap_info->back)) {
+ if (I830DRI2ScheduleFlip(intel, drawable, swap_info))
+ return;
+ }
/* else fall through to exchange/blit */
case DRI2_SWAP: {
@@ -1032,7 +1155,7 @@ void I830DRI2FrameEventHandler(unsigned int frame, unsigned int tv_sec,
break;
default:
xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
- "%s: unknown vblank event received\n", __func__);
+ "%s: unknown vblank event %d received\n", __func__, swap_info->type);
/* Unknown type */
break;
}
@@ -1116,7 +1239,7 @@ void I830DRI2FlipEventHandler(unsigned int frame, unsigned int tv_sec,
default:
xf86DrvMsg(intel->scrn->scrnIndex, X_WARNING,
- "%s: unknown vblank event received\n", __func__);
+ "%s: unknown vblank event %d received\n", __func__, flip_info->type);
/* Unknown type */
break;
}
@@ -1190,6 +1313,7 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
swap_info->front = front;
swap_info->back = back;
swap_info->pipe = pipe;
+ intel_drawable_box(draw, &swap_info->area);
if (!i830_dri2_add_frame_event(swap_info)) {
free(swap_info);
@@ -1215,13 +1339,19 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
/* Flips need to be submitted one frame before */
if (can_exchange(draw, front, back)) {
- swap_type = DRI2_FLIP;
- flip = 1;
+ intel_merge_fb(intel);
+ swap_type = DRI2_FLIP_FRONT;
+ flip = 1;
+ } else if (can_exchange_split(draw, front, back)) {
+ if (!intel_split_fb(intel))
+ goto blit_fallback;
+ swap_type = DRI2_FLIP_SPLIT;
+ flip = 1;
}
swap_info->type = swap_type;
- /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
+ /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP_*.
* Do it early, so handling of different timing constraints
* for divisor, remainder and msc vs. target_msc works.
*/
@@ -1322,6 +1452,17 @@ I830DRI2ScheduleSwap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
return TRUE;
blit_fallback:
+ /*
+ * If per-CRTC flips are enabled, I830DRI2CopyRegion will substitute a
+ destination Drawable with its origin at (0,0). This means the blit
+ will get clipped away on the second display in an extended desktop
+ configuration, since the clip region begins where the drawable lies
+ in the screen rather than at y=0. Since the common situation where
+ this happens is where the second display is powered off, just turn
+ off per-CRTC flips. They will be re-enabled again when the screen
+ is powered back on.
+ */
+ intel_merge_fb(intel);
I830DRI2FallbackBlitSwap(draw, front, back);
DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
if (swap_info)
diff --git a/src/uxa/intel_driver.c b/src/uxa/intel_driver.c
index f3758f9..6a18839 100644
--- a/src/uxa/intel_driver.c
+++ b/src/uxa/intel_driver.c
@@ -611,6 +611,14 @@ static Bool I830PreInit(ScrnInfoPtr scrn, int flags)
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Triple buffering? %s\n",
intel->use_triple_buffer ? "enabled" : "disabled");
+ intel->use_split_framebuffer =
+ xf86ReturnOptValBool(intel->Options,
+ OPTION_SPLIT_FRAMEBUFFER,
+ TRUE);
+ xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Split framebuffer? %s\n",
+ intel->use_split_framebuffer ? "enabled" : "disabled");
+
+
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Framebuffer %s\n",
intel->tiling & INTEL_TILING_FB ? "tiled" : "linear");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Pixmaps %s\n",
@@ -915,6 +923,7 @@ I830ScreenInit(SCREEN_INIT_ARGS_DECL)
#endif
struct pci_device *const device = intel->PciInfo;
int fb_bar = IS_GEN2(intel) ? 0 : 2;
+ int ret;
scrn->videoRam = device->regions[fb_bar].size / 1024;
@@ -1079,6 +1088,7 @@ I830ScreenInit(SCREEN_INIT_ARGS_DECL)
* later memory should be bound when allocating, e.g rotate_mem */
scrn->vtSema = TRUE;
+
return I830EnterVT(VT_FUNC_ARGS(0));
}
diff --git a/src/uxa/intel_uxa.c b/src/uxa/intel_uxa.c
index d4ba7fc..84ed551 100644
--- a/src/uxa/intel_uxa.c
+++ b/src/uxa/intel_uxa.c
@@ -633,6 +633,8 @@ dri_bo *intel_get_pixmap_bo(PixmapPtr pixmap)
void intel_set_pixmap_bo(PixmapPtr pixmap, dri_bo * bo)
{
+ ScrnInfoPtr scrn = xf86Screens[pixmap->drawable.pScreen->myNum];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
struct intel_pixmap *priv;
priv = intel_get_pixmap_private(pixmap);
@@ -643,6 +645,7 @@ void intel_set_pixmap_bo(PixmapPtr pixmap, dri_bo * bo)
if (priv->bo == bo)
return;
+ intel_pixmap_remove_fb(intel, pixmap);
dri_bo_unreference(priv->bo);
list_del(&priv->batch);
@@ -693,6 +696,9 @@ static Bool intel_uxa_prepare_access(PixmapPtr pixmap, uxa_access_t access)
dri_bo *bo = priv->bo;
int ret;
+ if (pixmap_is_scanout(pixmap))
+ intel_merge_fb(intel);
+
/* Transitioning to glamor acceleration, we need to flush all pending
* usage by UXA. */
if (access == UXA_GLAMOR_ACCESS_RW || access == UXA_GLAMOR_ACCESS_RO) {
@@ -778,8 +784,13 @@ static Bool intel_uxa_put_image(PixmapPtr pixmap,
int w, int h,
char *src, int src_pitch)
{
+ ScrnInfoPtr scrn = xf86Screens[pixmap->drawable.pScreen->myNum];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
struct intel_pixmap *priv;
+ if (pixmap_is_scanout(pixmap))
+ intel_merge_fb(intel);
+
priv = intel_get_pixmap_private(pixmap);
if (!intel_pixmap_is_busy(priv)) {
/* bo is not busy so can be replaced without a stall, upload in-place. */
@@ -895,6 +906,8 @@ static Bool intel_uxa_get_image(PixmapPtr pixmap,
int w, int h,
char *dst, int dst_pitch)
{
+ ScrnInfoPtr scrn = xf86Screens[pixmap->drawable.pScreen->myNum];
+ intel_screen_private *intel = intel_get_screen_private(scrn);
struct intel_pixmap *priv;
PixmapPtr scratch = NULL;
Bool ret;
@@ -906,6 +919,24 @@ static Bool intel_uxa_get_image(PixmapPtr pixmap,
* Also the gpu is much faster at detiling.
*/
+ if (pixmap_is_scanout(pixmap)) {
+ struct intel_scanout *scanout;
+ BoxRec get_box;
+
+ get_box.x1 = x;
+ get_box.x2 = x + w;
+ get_box.y1 = y;
+ get_box.y2 = y + h;
+ if (!intel_covering_scanout(intel, &get_box, &scanout) || scanout == NULL) {
+ intel_merge_fb(intel);
+ } else {
+ /* Adjust the copy to come from the scanout. */
+ pixmap = scanout->pixmap;
+ x -= scanout->area.x1;
+ y -= scanout->area.y1;
+ }
+ }
+
priv = intel_get_pixmap_private(pixmap);
if (intel_pixmap_is_busy(priv) || priv->tiling != I915_TILING_NONE) {
ScreenPtr screen = pixmap->drawable.pScreen;
@@ -1307,6 +1338,25 @@ static Bool intel_option_accel_blt(intel_screen_private *intel)
return strcasecmp(s, "blt") == 0;
}
+Bool
+intel_uxa_driver_copy_pixmap(intel_screen_private *intel,
+ PixmapPtr src, PixmapPtr dst,
+ int src_x, int src_y,
+ int dst_x, int dst_y,
+ int w, int h)
+{
+ if (!intel->uxa_driver->check_copy(src, dst, GXcopy, FB_ALLONES))
+ return FALSE;
+
+ if (!intel->uxa_driver->prepare_copy(src, dst, -1, -1,
+ GXcopy, FB_ALLONES))
+ return FALSE;
+
+ intel->uxa_driver->copy(dst, src_x, src_y, dst_x, dst_y, w, h);
+ intel->uxa_driver->done_copy(dst);
+ return TRUE;
+}
+
Bool intel_uxa_init(ScreenPtr screen)
{
ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
diff --git a/src/uxa/intel_video.c b/src/uxa/intel_video.c
index 238cd47..3249da9 100644
--- a/src/uxa/intel_video.c
+++ b/src/uxa/intel_video.c
@@ -1014,7 +1014,7 @@ I830CopyPlanarData(intel_adaptor_private *adaptor_priv,
return TRUE;
}
-static void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
+void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
{
dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1;
dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2;
@@ -1029,7 +1029,7 @@ static void intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b)
dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0;
}
-static void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
+void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
{
if (crtc->enabled) {
crtc_box->x1 = crtc->x;
@@ -1042,6 +1042,13 @@ static void intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
}
+void intel_drawable_box(DrawablePtr draw, BoxPtr draw_box) {
+ draw_box->x1 = draw->x;
+ draw_box->x2 = draw->x + draw->width;
+ draw_box->y1 = draw->y;
+ draw_box->y2 = draw->y + draw->height;
+}
+
static int intel_box_area(BoxPtr box)
{
return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1);
--
2.0.0.526.g5318336