summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-06-04 08:29:51 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2014-06-05 12:28:22 +0100
commit8369166349c92a20d9a2e7d0256e63f66fe2682b (patch)
treed8474a46e9b4fad974f36b1ddb0826d26555734b
parent08148896196443a8582c30b47ff546acca78d69c (diff)
sna/dri2: Enable immediate buffer exchanges
The primary benefit of this is avoid the extra blit when using a compositor and instead propagate the compositor flip on the frontbuffer to the scanout, or equivalently allows a fullscreen game to flip onto the scanout without intervention by TearFree. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/kgem.c8
-rw-r--r--src/sna/kgem.h1
-rw-r--r--src/sna/sna.h36
-rw-r--r--src/sna/sna_accel.c61
-rw-r--r--src/sna/sna_display.c480
-rw-r--r--src/sna/sna_dri2.c648
-rw-r--r--src/sna/sna_driver.c21
-rw-r--r--src/sna/sna_present.c41
-rw-r--r--src/sna/sna_render.c2
9 files changed, 713 insertions, 585 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index ea114f4c..a45dedda 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -2222,6 +2222,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
assert(list_is_empty(&bo->list));
assert(bo->refcnt == 0);
assert(bo->proxy == NULL);
+ assert(bo->active_scanout == 0);
assert_tiling(kgem, bo);
bo->binding.offset = 0;
@@ -5832,13 +5833,6 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
kgem_bo_unclean(kgem, bo);
- /* Henceforth, we need to broadcast all updates to clients and
- * flush our rendering before doing so.
- */
- bo->flush = true;
- if (bo->exec)
- kgem->flush = 1;
-
return flink.name;
}
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index ae258210..370894be 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -74,6 +74,7 @@ struct kgem_bo {
uint32_t handle;
uint32_t target_handle;
uint32_t delta;
+ uint32_t active_scanout;
union {
struct {
uint32_t count:27;
diff --git a/src/sna/sna.h b/src/sna/sna.h
index b9a40db1..7845cd11 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -111,6 +111,7 @@ void LogF(const char *f, ...);
#include "fb/fb.h"
struct sna_cursor;
+struct sna_crtc;
struct sna_client {
int is_compositor; /* only 4 bits used */
@@ -283,9 +284,10 @@ struct sna {
struct sna_mode {
DamagePtr shadow_damage;
struct kgem_bo *shadow;
- int shadow_active;
- int shadow_flip;
- int front_active;
+ unsigned front_active;
+ unsigned shadow_active;
+ unsigned flip_active;
+ bool dirty;
int max_crtc_width, max_crtc_height;
@@ -324,10 +326,6 @@ struct sna {
#if HAVE_DRI2
void *flip_pending;
- struct {
- struct kgem_bo *bo;
- uint32_t name;
- } scanout[2];
#endif
} dri2;
@@ -416,7 +414,7 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna);
bool sna_mode_fake_init(struct sna *sna, int num_fake);
void sna_mode_adjust_frame(struct sna *sna, int x, int y);
extern void sna_mode_discover(struct sna *sna);
-extern void sna_mode_update(struct sna *sna);
+extern void sna_mode_check(struct sna *sna);
extern void sna_mode_reset(struct sna *sna);
extern void sna_mode_wakeup(struct sna *sna);
extern void sna_mode_redisplay(struct sna *sna);
@@ -425,12 +423,18 @@ extern void sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv,
extern void sna_mode_close(struct sna *sna);
extern void sna_mode_fini(struct sna *sna);
+extern void sna_crtc_config_notify(ScreenPtr screen);
+
extern bool sna_cursors_init(ScreenPtr screen, struct sna *sna);
+typedef void (*sna_flip_handler_t)(struct sna *sna,
+ struct drm_event_vblank *e,
+ void *data);
+
extern int sna_page_flip(struct sna *sna,
struct kgem_bo *bo,
- void *data,
- int ref_crtc_hw_id);
+ sna_flip_handler_t handler,
+ void *data);
pure static inline struct sna *
to_sna(ScrnInfoPtr scrn)
@@ -523,17 +527,15 @@ static inline uint64_t ust64(int tv_sec, int tv_usec)
bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen);
void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event);
void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event);
-void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap);
+void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo);
void sna_dri2_destroy_window(WindowPtr win);
-void sna_dri2_reset_scanout(struct sna *sna);
void sna_dri2_close(struct sna *sna, ScreenPtr pScreen);
#else
static inline bool sna_dri2_open(struct sna *sna, ScreenPtr pScreen) { return false; }
static inline void sna_dri2_page_flip_handler(struct sna *sna, struct drm_event_vblank *event) { }
static inline void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event) { }
-static inline void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap) { }
+static inline void sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo) { }
static inline void sna_dri2_destroy_window(WindowPtr win) { }
-static inline void sna_dri2_reset_scanout(struct sna *sna) { }
static inline void sna_dri2_close(struct sna *sna, ScreenPtr pScreen) { }
#endif
@@ -549,15 +551,12 @@ static inline void sna_dri3_close(struct sna *sna, ScreenPtr pScreen) { }
bool sna_present_open(struct sna *sna, ScreenPtr pScreen);
void sna_present_update(struct sna *sna);
void sna_present_close(struct sna *sna, ScreenPtr pScreen);
-void sna_present_flip_handler(struct sna *sna,
- struct drm_event_vblank *event);
void sna_present_vblank_handler(struct sna *sna,
struct drm_event_vblank *event);
#else
static inline bool sna_present_open(struct sna *sna, ScreenPtr pScreen) { return false; }
static inline void sna_present_update(struct sna *sna) { }
static inline void sna_present_close(struct sna *sna, ScreenPtr pScreen) { }
-static inline void sna_present_flip_handler(struct sna *sna, struct drm_event_vblank *event) { }
static inline void sna_present_vblank_handler(struct sna *sna, struct drm_event_vblank *event) { }
#endif
@@ -832,7 +831,6 @@ region_subsumes_damage(const RegionRec *region, struct sna_damage *damage)
(BoxPtr)de) == PIXMAN_REGION_IN;
}
-
static inline bool
sna_drawable_is_clear(DrawablePtr d)
{
@@ -855,7 +853,7 @@ static inline struct kgem_bo *sna_pixmap_pin(PixmapPtr pixmap, unsigned flags)
{
struct sna_pixmap *priv;
- priv = sna_pixmap_force_to_gpu(pixmap, MOVE_READ | MOVE_WRITE);
+ priv = sna_pixmap_force_to_gpu(pixmap, MOVE_READ);
if (!priv)
return NULL;
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index 85c1c355..f77b4c60 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -1825,6 +1825,9 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags)
assert(priv->gpu_bo == cow->bo);
assert(cow->refcnt);
+ if (flags && (flags & MOVE_WRITE) == 0 && IS_COW_OWNER(priv->cow))
+ return true;
+
if (!IS_COW_OWNER(priv->cow))
list_del(&priv->cow_list);
@@ -3189,25 +3192,32 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
}
}
- if (priv->cow && (flags & MOVE_WRITE || priv->cpu_damage)) {
- unsigned cow = MOVE_READ;
+ if (priv->cow) {
+ unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
if ((flags & MOVE_READ) == 0) {
if (priv->gpu_damage) {
r.extents = *box;
r.data = NULL;
- if (region_subsumes_damage(&r,
- priv->gpu_damage))
- cow = 0;
- } else
- cow = 0;
+ if (!region_subsumes_damage(&r, priv->gpu_damage))
+ cow |= MOVE_READ;
+ }
+ } else {
+ if (priv->cpu_damage) {
+ r.extents = *box;
+ r.data = NULL;
+ if (region_overlaps_damage(&r, priv->cpu_damage, 0, 0))
+ cow |= MOVE_WRITE;
+ }
}
- if (!sna_pixmap_undo_cow(sna, priv, cow))
- return NULL;
+ if (cow) {
+ if (!sna_pixmap_undo_cow(sna, priv, cow))
+ return NULL;
- if (priv->gpu_bo == NULL)
- sna_damage_destroy(&priv->gpu_damage);
+ if (priv->gpu_bo == NULL)
+ sna_damage_destroy(&priv->gpu_damage);
+ }
}
if (sna_damage_is_all(&priv->gpu_damage,
@@ -3221,7 +3231,7 @@ sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int fl
}
if ((priv->gpu_bo && priv->gpu_bo->proxy) &&
- (flags & MOVE_WRITE || priv->gpu_bo->proxy->rq == NULL)) {
+ (flags & (MOVE_WRITE | __MOVE_FORCE) || priv->gpu_bo->proxy->rq == NULL)) {
DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
assert(priv->gpu_damage == NULL);
assert(!priv->pinned);
@@ -3437,7 +3447,7 @@ sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
}
if (priv->cow) {
- unsigned cow = MOVE_READ;
+ unsigned cow = MOVE_WRITE | MOVE_READ;
if (flags & IGNORE_CPU) {
if (priv->gpu_damage) {
@@ -3451,9 +3461,9 @@ sna_drawable_use_bo(DrawablePtr drawable, unsigned flags, const BoxRec *box,
region.data = NULL;
if (region_subsumes_damage(&region,
priv->gpu_damage))
- cow = 0;
+ cow &= ~MOVE_READ;
} else
- cow = 0;
+ cow &= ~MOVE_READ;
}
if (!sna_pixmap_undo_cow(to_sna_from_pixmap(pixmap), priv, cow))
@@ -3933,12 +3943,17 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
if ((flags & MOVE_READ) == 0 && UNDO)
kgem_bo_pair_undo(&sna->kgem, priv->gpu_bo, priv->cpu_bo);
- if (priv->cow && (flags & MOVE_WRITE || priv->cpu_damage)) {
- if (!sna_pixmap_undo_cow(sna, priv, flags & MOVE_READ))
- return NULL;
+ if (priv->cow) {
+ unsigned cow = flags & (MOVE_READ | MOVE_WRITE | __MOVE_FORCE);
+ if (flags & MOVE_READ && priv->cpu_damage)
+ cow |= MOVE_WRITE;
+ if (cow) {
+ if (!sna_pixmap_undo_cow(sna, priv, cow))
+ return NULL;
- if (priv->gpu_bo == NULL)
- sna_damage_destroy(&priv->gpu_damage);
+ if (priv->gpu_bo == NULL)
+ sna_damage_destroy(&priv->gpu_damage);
+ }
}
if (sna_damage_is_all(&priv->gpu_damage,
@@ -3955,7 +3970,7 @@ sna_pixmap_move_to_gpu(PixmapPtr pixmap, unsigned flags)
}
if ((priv->gpu_bo && priv->gpu_bo->proxy) &&
- (flags & MOVE_WRITE || priv->gpu_bo->proxy->rq == NULL)) {
+ (flags & (MOVE_WRITE | __MOVE_FORCE) || priv->gpu_bo->proxy->rq == NULL)) {
DBG(("%s: discarding cached upload buffer\n", __FUNCTION__));
assert(priv->gpu_damage == NULL);
assert(!priv->pinned);
@@ -11716,7 +11731,7 @@ sna_pixmap_get_source_bo(PixmapPtr pixmap)
if (priv->cpu_damage && priv->cpu_bo)
return kgem_bo_reference(priv->cpu_bo);
- if (!sna_pixmap_force_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT))
+ if (!sna_pixmap_move_to_gpu(pixmap, MOVE_READ | MOVE_ASYNC_HINT))
return NULL;
return kgem_bo_reference(priv->gpu_bo);
@@ -16643,7 +16658,7 @@ static bool has_shadow(struct sna *sna)
DBG(("%s: has pending damage? %d, outstanding flips: %d\n",
__FUNCTION__,
RegionNotEmpty(DamageRegion(damage)),
- sna->mode.shadow_flip));
+ sna->mode.flip_active));
return RegionNotEmpty(DamageRegion(damage));
}
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 13dbf641..470db869 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -98,13 +98,6 @@ union compat_mode_get_connector{
extern XF86ConfigPtr xf86configptr;
-struct rotation {
- uint32_t obj_id, obj_type;
- uint32_t prop_id;
- uint32_t supported;
- uint32_t current;
-};
-
struct sna_crtc {
struct drm_mode_modeinfo kmode;
int dpms_mode;
@@ -119,11 +112,19 @@ struct sna_crtc {
uint8_t pipe;
uint32_t rotation;
- struct rotation primary_rotation;
- struct rotation sprite_rotation;
+ struct rotation {
+ uint32_t obj_id, obj_type;
+ uint32_t prop_id;
+ uint32_t supported;
+ uint32_t current;
+ } primary_rotation, sprite_rotation;
uint32_t last_seq, wrap_seq;
struct ust_msc swap;
+
+ sna_flip_handler_t flip_handler;
+ struct kgem_bo *flip_bo;
+ void *flip_data;
};
struct sna_property {
@@ -802,7 +803,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
int output_count = 0;
int i;
- DBG(("%s CRTC:%d [pipe=%d]\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe));
+ DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, sna_crtc->id, sna_crtc->pipe, sna_crtc->bo->handle));
assert(config->num_output < ARRAY_SIZE(output_ids));
@@ -880,8 +881,8 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
DamagePtr damage;
bool ret = true;
- DBG(("%s: flags=%x, shadow_flip=%d, handle=%d, wait=%d, old=%d\n",
- __FUNCTION__, flags, sna->mode.shadow_flip,
+ DBG(("%s: flags=%x, flips=%d, handle=%d, wait=%d, old=%d\n",
+ __FUNCTION__, flags, sna->mode.flip_active,
priv->gpu_bo->handle, wait->bo->handle, sna->mode.shadow->handle));
assert(wait->bo != priv->gpu_bo);
@@ -893,18 +894,14 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
return true;
assert(sna->mode.shadow_active);
- assert(bo == sna->mode.shadow);
-
- assert(priv->gpu_bo->refcnt >= 1);
- sna->mode.shadow = priv->gpu_bo;
damage = sna->mode.shadow_damage;
sna->mode.shadow_damage = NULL;
- while (sna->mode.shadow_flip && sna_mode_has_pending_events(sna))
+ while (sna->mode.flip_active && sna_mode_has_pending_events(sna))
sna_mode_wakeup(sna);
- if (sna->mode.shadow_flip) {
+ if (sna->mode.flip_active) {
bo = kgem_create_2d(&sna->kgem,
pixmap->drawable.width,
pixmap->drawable.height,
@@ -915,16 +912,14 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
DBG(("%s: replacing still-attached GPU bo\n",
__FUNCTION__));
- kgem_bo_destroy(&sna->kgem, wait->bo);
RegionUninit(&wait->region);
-
wait->region.extents.x1 = 0;
wait->region.extents.y1 = 0;
wait->region.extents.x2 = pixmap->drawable.width;
wait->region.extents.y2 = pixmap->drawable.height;
wait->region.data = NULL;
} else {
- while (sna->mode.shadow_flip &&
+ while (sna->mode.flip_active &&
sna_mode_wait_for_event(sna))
sna_mode_wakeup(sna);
@@ -932,6 +927,27 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
}
}
+ if (bo->refcnt > 1) {
+ bo = kgem_create_2d(&sna->kgem,
+ pixmap->drawable.width,
+ pixmap->drawable.height,
+ pixmap->drawable.bitsPerPixel,
+ priv->gpu_bo->tiling,
+ CREATE_EXACT | CREATE_SCANOUT);
+ if (bo != NULL) {
+ DBG(("%s: replacing exported GPU bo\n",
+ __FUNCTION__));
+
+ RegionUninit(&wait->region);
+ wait->region.extents.x1 = 0;
+ wait->region.extents.y1 = 0;
+ wait->region.extents.x2 = pixmap->drawable.width;
+ wait->region.extents.y2 = pixmap->drawable.height;
+ wait->region.data = NULL;
+ } else
+ bo = wait->bo;
+ }
+
sna->mode.shadow_damage = damage;
if (flags & MOVE_READ && RegionNotEmpty(&wait->region)) {
@@ -951,9 +967,12 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
sna_pixmap_undo_cow(sna, priv, 0);
sna_pixmap_unmap(pixmap, priv);
- priv->gpu_bo = bo;
- sna_dri2_pixmap_update_bo(sna, pixmap);
+ DBG(("%s: setting front pixmap to handle=%d\n", __FUNCTION__, bo->handle));
+ kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
+ priv->gpu_bo = bo == wait->bo ? kgem_bo_reference(bo) : bo;
+
+ sna_dri2_pixmap_update_bo(sna, pixmap, bo);
done:
kgem_bo_destroy(&sna->kgem, wait->bo);
@@ -1099,8 +1118,14 @@ sna_crtc_disable(xf86CrtcPtr crtc)
sna_crtc_disable_shadow(sna, sna_crtc);
if (sna_crtc->bo) {
+ assert(sna_crtc->bo->active_scanout);
+ assert(sna_crtc->bo->refcnt >= sna_crtc->bo->active_scanout);
+ sna_crtc->bo->active_scanout--;
kgem_bo_destroy(&sna->kgem, sna_crtc->bo);
sna_crtc->bo = NULL;
+
+ sna->mode.front_active--;
+ sna->mode.dirty = true;
}
assert(sna_crtc->dpms_mode == DPMSModeOff);
@@ -1301,7 +1326,7 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
return true;
}
- priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ | MOVE_WRITE);
+ priv = sna_pixmap_force_to_gpu(sna->front, MOVE_READ);
if (priv == NULL)
return true; /* maybe we can create a bo for the scanout? */
@@ -1362,6 +1387,45 @@ static bool use_shadow(struct sna *sna, xf86CrtcPtr crtc)
return false;
}
+static void set_shadow(PixmapPtr pixmap, struct kgem_bo *bo, RegionPtr region)
+{
+ struct sna_pixmap *priv = sna_pixmap(pixmap);
+ struct wait_for_shadow *wait;
+
+ DBG(("%s: waiting for region %dx[(%d, %d), (%d, %d)] on handle=%d\n",
+ __FUNCTION__,
+ RegionNumRects(region),
+ region->extents.x1, region->extents.y1,
+ region->extents.x2, region->extents.y2,
+ bo->handle));
+
+ assert((priv->pinned & PIN_PRIME) == 0);
+ assert(bo != priv->gpu_bo);
+ assert(priv->gpu_bo);
+
+ wait = priv->move_to_gpu_data;
+ if (wait != NULL) {
+ assert(priv->move_to_gpu = wait_for_shadow);
+ assert(priv->pinned & PIN_SCANOUT);
+ assert(wait->bo == bo);
+ RegionUnion(&wait->region, &wait->region, region);
+ return;
+ }
+
+ assert(priv->move_to_gpu == NULL);
+ wait = malloc(sizeof(*wait));
+ if (wait != NULL) {
+ wait->bo = kgem_bo_reference(bo);
+ RegionNull(&wait->region);
+ RegionCopy(&wait->region, region);
+
+ priv->move_to_gpu = wait_for_shadow;
+ priv->move_to_gpu_data = wait;
+ }
+
+ priv->pinned |= PIN_SCANOUT;
+}
+
static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
{
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
@@ -1422,51 +1486,8 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
sna_crtc->transform = true;
return bo;
- } else if (sna->flags & SNA_TEAR_FREE) {
- DBG(("%s: tear-free updates requested\n", __FUNCTION__));
-
- if (!sna_crtc_enable_shadow(sna, sna_crtc))
- return NULL;
-
- DBG(("%s: attaching to single shadow pixmap\n", __FUNCTION__));
- if (sna->mode.shadow == NULL) {
- BoxRec box;
-
- bo = kgem_create_2d(&sna->kgem,
- sna->scrn->virtualX,
- sna->scrn->virtualY,
- scrn->bitsPerPixel,
- I915_TILING_X,
- CREATE_SCANOUT);
- if (bo == NULL)
- return NULL;
-
- box.x1 = box.y1 = 0;
- box.x2 = sna->scrn->virtualX;
- box.y2 = sna->scrn->virtualY;
-
- if (!sna->render.copy_boxes(sna, GXcopy,
- sna->front, sna_pixmap(sna->front)->gpu_bo, 0, 0,
- sna->front, bo, 0, 0,
- &box, 1, COPY_LAST)) {
- kgem_bo_destroy(&sna->kgem, bo);
- return NULL;
- }
-
- if (!get_fb(sna, bo,
- sna->scrn->virtualX,
- sna->scrn->virtualY)) {
- kgem_bo_destroy(&sna->kgem, bo);
- return NULL;
- }
-
- sna->mode.shadow = bo;
- }
-
- return kgem_bo_reference(sna->mode.shadow);
} else {
DBG(("%s: attaching to framebuffer\n", __FUNCTION__));
- sna_crtc_disable_shadow(sna, sna_crtc);
bo = sna_pixmap_pin(sna->front, PIN_SCANOUT);
if (bo == NULL)
return NULL;
@@ -1474,7 +1495,43 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
if (!get_fb(sna, bo, scrn->virtualX, scrn->virtualY))
return NULL;
- assert(!sna_crtc->shadow);
+ if (sna->flags & SNA_TEAR_FREE) {
+ DBG(("%s: creating TearFree shadow\n", __FUNCTION__));
+ if (!sna_crtc_enable_shadow(sna, sna_crtc))
+ return NULL;
+
+ if (sna->mode.shadow == NULL) {
+ RegionRec region;
+ struct kgem_bo *shadow;
+
+ region.extents.x1 = 0;
+ region.extents.y1 = 0;
+ region.extents.x2 = sna->scrn->virtualX;
+ region.extents.y2 = sna->scrn->virtualY;
+ region.data = NULL;
+
+ shadow = kgem_create_2d(&sna->kgem,
+ region.extents.x2,
+ region.extents.y2,
+ scrn->bitsPerPixel,
+ I915_TILING_X,
+ CREATE_SCANOUT);
+ if (shadow == NULL)
+ return NULL;
+
+ if (!get_fb(sna, shadow,
+ region.extents.x2,
+ region.extents.y2)) {
+ kgem_bo_destroy(&sna->kgem, shadow);
+ return NULL;
+ }
+
+ sna->mode.shadow = shadow;
+ set_shadow(sna->front, shadow, &region);
+ }
+ } else
+ sna_crtc_disable_shadow(sna, sna_crtc);
+
assert(sna_crtc->primary_rotation.supported & crtc->rotation);
sna_crtc->rotation = crtc->rotation;
return kgem_bo_reference(bo);
@@ -1690,12 +1747,19 @@ retry: /* Attach per-crtc pixmap or direct */
sna_crtc->kmode = saved_kmode;
return FALSE;
}
- if (saved_bo)
+ bo->active_scanout++;
+ if (saved_bo) {
+ assert(saved_bo->active_scanout);
+ assert(saved_bo->refcnt >= saved_bo->active_scanout);
+ saved_bo->active_scanout--;
kgem_bo_destroy(&sna->kgem, saved_bo);
+ }
sna_crtc_randr(crtc);
if (sna_crtc->shadow)
sna_crtc_damage(crtc);
+ sna->mode.front_active += saved_bo == NULL;
+ sna->mode.dirty = true;
return TRUE;
}
@@ -1731,23 +1795,28 @@ void sna_mode_adjust_frame(struct sna *sna, int x, int y)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
xf86CrtcPtr crtc;
+ int saved_x, saved_y;
if ((unsigned)config->compat_output >= config->num_output)
return;
crtc = config->output[config->compat_output]->crtc;
- if (crtc && crtc->enabled) {
- int saved_x = crtc->x;
- int saved_y = crtc->y;
-
- crtc->x = x;
- crtc->y = y;
- if (to_sna_crtc(crtc) &&
- !sna_crtc_set_mode_major(crtc, &crtc->mode,
- crtc->rotation, x, y)) {
- crtc->x = saved_x;
- crtc->y = saved_y;
- }
+ if (crtc == NULL || !crtc->enabled)
+ return;
+
+ if (crtc->x == x && crtc->y == y)
+ return;
+
+ saved_x = crtc->x;
+ saved_y = crtc->y;
+
+ crtc->x = x;
+ crtc->y = y;
+ if (to_sna_crtc(crtc) &&
+ !sna_crtc_set_mode_major(crtc, &crtc->mode,
+ crtc->rotation, x, y)) {
+ crtc->x = saved_x;
+ crtc->y = saved_y;
}
}
@@ -3298,10 +3367,10 @@ sna_mode_resize(ScrnInfoPtr scrn, int width, int height)
scrn->displayWidth = width;
/* Flush pending shadow updates */
- if (sna->mode.shadow_flip) {
+ if (sna->mode.flip_active) {
DBG(("%s: waiting for %d outstanding TearFree flips\n",
- __FUNCTION__, sna->mode.shadow_flip));
- while (sna->mode.shadow_flip && sna_mode_wait_for_event(sna))
+ __FUNCTION__, sna->mode.flip_active));
+ while (sna->mode.flip_active && sna_mode_wait_for_event(sna))
sna_mode_wakeup(sna);
}
@@ -4090,7 +4159,7 @@ sna_cursors_fini(struct sna *sna)
}
static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
- void *data, int pipe)
+ sna_flip_handler_t handler, void *data)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
int width = sna->scrn->virtualX;
@@ -4098,6 +4167,9 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
int count = 0;
int i;
+ assert((sna->flags & SNA_TEAR_FREE) == 0);
+ assert(sna->mode.flip_active == 0);
+
if ((sna->flags & (data ? SNA_HAS_FLIP : SNA_HAS_ASYNC_FLIP)) == 0)
return 0;
@@ -4116,10 +4188,10 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
DBG(("%s: crtc %d id=%d, pipe=%d active? %d\n",
__FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo != NULL));
- if (crtc->bo == NULL) {
- assert(crtc->pipe != pipe);
+ if (crtc->bo == NULL)
continue;
- }
+ assert(crtc->bo->active_scanout);
+ assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
arg.crtc_id = crtc->id;
arg.fb_id = get_fb(sna, bo, width, height);
@@ -4132,8 +4204,7 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
* completion event. All other crtc's events will be discarded.
*/
if (data) {
- arg.user_data = (uintptr_t)data;
- arg.user_data |= crtc->pipe == pipe;
+ arg.user_data = (uintptr_t)crtc;
arg.flags = DRM_MODE_PAGE_FLIP_EVENT;
} else {
arg.user_data = 0;
@@ -4141,9 +4212,8 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
}
arg.reserved = 0;
- DBG(("%s: crtc %d id=%d, pipe=%d, [ref? %d] --> fb %d\n",
- __FUNCTION__, i, crtc->id, crtc->pipe,
- crtc->pipe == pipe, arg.fb_id));
+ DBG(("%s: crtc %d id=%d, pipe=%d --> fb %d\n",
+ __FUNCTION__, i, crtc->id, crtc->pipe, arg.fb_id));
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
DBG(("%s: flip [fb=%d] on crtc %d id=%d pipe=%d failed - %d\n",
__FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno));
@@ -4161,9 +4231,13 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
return 0;
}
- if (crtc->bo != bo) {
- kgem_bo_destroy(&sna->kgem, crtc->bo);
- crtc->bo = kgem_bo_reference(bo);
+ if (data) {
+ assert(crtc->flip_bo == NULL);
+ crtc->flip_handler = handler;
+ crtc->flip_data = data;
+ crtc->flip_bo = kgem_bo_reference(bo);
+ crtc->flip_bo->active_scanout++;
+ sna->mode.flip_active++;
}
count++;
@@ -4175,8 +4249,8 @@ static int do_page_flip(struct sna *sna, struct kgem_bo *bo,
int
sna_page_flip(struct sna *sna,
struct kgem_bo *bo,
- void *data,
- int pipe)
+ sna_flip_handler_t handler,
+ void *data)
{
int count;
@@ -4195,7 +4269,7 @@ sna_page_flip(struct sna *sna,
* Also, flips queued on disabled or incorrectly configured displays
* may never complete; this is a configuration error.
*/
- count = do_page_flip(sna, bo, data, pipe);
+ count = do_page_flip(sna, bo, handler, data);
DBG(("%s: page flipped %d crtcs\n", __FUNCTION__, count));
return count;
@@ -4589,21 +4663,22 @@ probe_capabilities(struct sna *sna)
sna->flags & SNA_HAS_ASYNC_FLIP ? "enabled" : "disabled"));
}
-static void
+void
sna_crtc_config_notify(ScreenPtr screen)
{
struct sna *sna = to_sna_from_screen(screen);
- DBG(("%s\n", __FUNCTION__));
+ DBG(("%s(dirty?=%d)\n", __FUNCTION__, sna->mode.dirty));
+ if (!sna->mode.dirty)
+ return;
probe_capabilities(sna);
- sna_dri2_reset_scanout(sna);
-
- sna_mode_update(sna);
sna_cursors_reload(sna);
sna_present_update(sna);
+
+ sna->mode.dirty = false;
}
#if HAS_PIXMAP_SHARING
@@ -5129,7 +5204,7 @@ sna_wait_for_scanline(struct sna *sna,
return ret;
}
-void sna_mode_update(struct sna *sna)
+void sna_mode_check(struct sna *sna)
{
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
int i;
@@ -5140,35 +5215,32 @@ void sna_mode_update(struct sna *sna)
DBG(("%s\n", __FUNCTION__));
/* Validate CRTC attachments and force consistency upon the kernel */
- sna->mode.front_active = 0;
for (i = 0; i < sna->mode.num_real_crtc; i++) {
xf86CrtcPtr crtc = config->crtc[i];
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
struct drm_mode_crtc mode;
- uint32_t expected;
+ uint32_t expected[2];
assert(sna_crtc);
#if XF86_CRTC_VERSION >= 3
assert(sna_crtc->bo == NULL || crtc->active);
#endif
- expected = sna_crtc->bo ? fb_id(sna_crtc->bo) : 0;
+ expected[0] = sna_crtc->bo ? fb_id(sna_crtc->bo) : 0;
+ expected[1] = sna_crtc->flip_bo ? fb_id(sna_crtc->flip_bo) : -1;
VG_CLEAR(mode);
mode.crtc_id = sna_crtc->id;
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_GETCRTC, &mode))
continue;
- DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=%d\n",
+ DBG(("%s: crtc=%d, valid?=%d, fb attached?=%d, expected=(%d or %d)\n",
__FUNCTION__,
mode.crtc_id, mode.mode_valid,
- mode.fb_id, expected));
+ mode.fb_id, expected[0], expected[1]));
- if (mode.fb_id != expected)
+ if (mode.fb_id != expected[0] && mode.fb_id != expected[1])
sna_crtc_disable(crtc);
-
- if (sna->front && sna_crtc->bo == __sna_pixmap_get_bo(sna->front))
- sna->mode.front_active++;
}
for (i = 0; i < config->num_output; i++) {
@@ -5474,28 +5546,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region)
sna_crtc_redisplay__fallback(crtc, region, sna_crtc->bo);
}
-static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo, RegionPtr region)
-{
- struct sna_pixmap *priv = sna_pixmap(pixmap);
- struct wait_for_shadow *wait;
-
- assert((priv->pinned & PIN_PRIME) == 0);
- assert(bo != priv->gpu_bo);
- assert(priv->gpu_bo);
-
- assert(priv->move_to_gpu == NULL);
- wait = malloc(sizeof(*wait));
- if (wait != NULL) {
- wait->bo = kgem_bo_reference(bo);
- RegionNull(&wait->region);
- RegionCopy(&wait->region, region);
-
- priv->move_to_gpu = wait_for_shadow;
- priv->move_to_gpu_data = wait;
- }
-
- priv->pinned |= PIN_SCANOUT;
-}
+#define shadow_flip_handler (sna_flip_handler_t)sna_mode_redisplay
void sna_mode_redisplay(struct sna *sna)
{
@@ -5509,7 +5560,7 @@ void sna_mode_redisplay(struct sna *sna)
DBG(("%s: posting shadow damage? %d (flips pending? %d)\n",
__FUNCTION__,
!RegionNil(DamageRegion(sna->mode.shadow_damage)),
- sna->mode.shadow_flip));
+ sna->mode.flip_active));
assert((sna->flags & SNA_IS_HOSTED) == 0);
assert(sna->mode.shadow_active);
@@ -5522,19 +5573,19 @@ void sna_mode_redisplay(struct sna *sna)
region->extents.x1, region->extents.y1,
region->extents.x2, region->extents.y2));
- if (sna->mode.shadow_flip) {
+ if (sna->mode.flip_active) {
DamagePtr damage;
damage = sna->mode.shadow_damage;
sna->mode.shadow_damage = NULL;
- while (sna->mode.shadow_flip && sna_mode_has_pending_events(sna))
+ while (sna->mode.flip_active && sna_mode_has_pending_events(sna))
sna_mode_wakeup(sna);
sna->mode.shadow_damage = damage;
}
- if (sna->mode.shadow_flip)
+ if (sna->mode.flip_active)
return;
if (wedged(sna) || !sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT)) {
@@ -5594,16 +5645,13 @@ void sna_mode_redisplay(struct sna *sna)
RegionRec damage;
assert(sna_crtc != NULL);
- DBG(("%s: crtc[%d] shadow? %d, transformed? %d\n",
- __FUNCTION__, i,
- sna_crtc->shadow,
- sna_crtc->bo != sna->mode.shadow));
+ DBG(("%s: crtc[%d] transformed? %d\n",
+ __FUNCTION__, i, sna_crtc->transform));
- if (!sna_crtc->shadow || sna_crtc->bo == sna->mode.shadow)
+ if (!sna_crtc->transform)
continue;
assert(crtc->enabled);
- assert(sna_crtc->transform);
damage.extents = crtc->bounds;
damage.data = NULL;
@@ -5639,7 +5687,7 @@ void sna_mode_redisplay(struct sna *sna)
if (arg.fb_id == 0)
goto disable1;
- arg.user_data = 0;
+ arg.user_data = (uintptr_t)crtc;
arg.flags = DRM_MODE_PAGE_FLIP_EVENT;
arg.reserved = 0;
@@ -5666,11 +5714,14 @@ disable1:
continue;
}
+ sna->mode.flip_active++;
- sna_crtc->shadow_bo = sna_crtc->bo;
- sna_crtc->bo = bo;
+ assert(sna_crtc->flip_bo == NULL);
+ sna_crtc->flip_handler = shadow_flip_handler;
+ sna_crtc->flip_bo = bo;
+ sna_crtc->flip_bo->active_scanout++;
- sna->mode.shadow_flip++;
+ sna_crtc->shadow_bo = sna_crtc->bo;
} else {
sna_crtc_redisplay(crtc, &damage);
kgem_scanout_flush(&sna->kgem, sna_crtc->bo);
@@ -5682,56 +5733,62 @@ disable1:
if (sna->mode.shadow) {
struct kgem_bo *new = __sna_pixmap_get_bo(sna->front);
struct kgem_bo *old = sna->mode.shadow;
+ struct drm_mode_crtc_page_flip arg;
+
+ DBG(("%s: flipping tear-free outputs, current scanout handle=%d [active?=%d], new handle=%d [active=%d]\n",
+ __FUNCTION__, old->handle, old->active_scanout, new->handle, new->active_scanout));
+
+ assert(new != old);
+ assert(new->refcnt);
+ assert(new->active_scanout == 0);
+
+ arg.fb_id = get_fb(sna, new,
+ sna->scrn->virtualX,
+ sna->scrn->virtualY);
+ if (arg.fb_id == 0) {
+ BoxRec box;
+
+fixup_shadow:
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = sna->scrn->virtualX;
+ box.y2 = sna->scrn->virtualY;
+ if (sna->render.copy_boxes(sna, GXcopy,
+ sna->front, new, 0, 0,
+ sna->front, old, 0, 0,
+ &box, 1, COPY_LAST)) {
+ kgem_submit(&sna->kgem);
+ RegionEmpty(region);
+ }
+
+ return;
+ }
+
+ arg.flags = DRM_MODE_PAGE_FLIP_EVENT;
+ arg.reserved = 0;
- DBG(("%s: flipping tear-free outputs\n", __FUNCTION__));
kgem_bo_submit(&sna->kgem, new);
for (i = 0; i < sna->mode.num_real_crtc; i++) {
struct sna_crtc *crtc = config->crtc[i]->driver_private;
- struct drm_mode_crtc_page_flip arg;
assert(crtc != NULL);
- DBG(("%s: crtc %d [%d, pipe=%d] active? %d\n",
- __FUNCTION__, i, crtc->id, crtc->pipe, crtc && crtc->bo));
- if (crtc->bo != old)
+ DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n",
+ __FUNCTION__, i, crtc->id, crtc->pipe, crtc->bo ? crtc->bo->handle : 0, crtc->transform));
+ if (crtc->bo == NULL || crtc->transform)
continue;
assert(config->crtc[i]->enabled);
assert(crtc->dpms_mode <= DPMSModeOn);
arg.crtc_id = crtc->id;
- arg.fb_id = get_fb(sna, new,
- sna->scrn->virtualX,
- sna->scrn->virtualY);
- if (arg.fb_id == 0)
- goto disable2;
-
- arg.user_data = 0;
- arg.flags = DRM_MODE_PAGE_FLIP_EVENT;
- arg.reserved = 0;
+ arg.user_data = (uintptr_t)crtc;
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
- DBG(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
+ ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
__FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno));
-disable2:
- if (sna->mode.shadow_flip == 0) {
- BoxRec box;
-
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = sna->scrn->virtualX;
- box.y2 = sna->scrn->virtualY;
-
- if (sna->render.copy_boxes(sna, GXcopy,
- sna->front, new, 0, 0,
- sna->front, old, 0, 0,
- &box, 1, COPY_LAST)) {
- kgem_submit(&sna->kgem);
- RegionEmpty(region);
- }
-
- return;
- }
+ if (sna->mode.flip_active == 0)
+ goto fixup_shadow;
xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
"%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
@@ -5739,21 +5796,27 @@ disable2:
sna_crtc_disable(config->crtc[i]);
continue;
}
- sna->mode.shadow_flip++;
+ sna->mode.flip_active++;
- kgem_bo_destroy(&sna->kgem, old);
- crtc->bo = kgem_bo_reference(new);
+ assert(crtc->flip_bo == NULL);
+ crtc->flip_handler = shadow_flip_handler;
+ crtc->flip_bo = kgem_bo_reference(new);
+ crtc->flip_bo->active_scanout++;
}
DBG(("%s: flipped %d outputs, shadow active? %d\n",
__FUNCTION__,
- sna->mode.shadow_flip,
+ sna->mode.flip_active,
sna->mode.shadow ? sna->mode.shadow->handle : 0));
- if (sna->mode.shadow) {
+ if (sna->mode.flip_active) {
assert(old == sna->mode.shadow);
assert(old->refcnt >= 1);
- set_bo(sna->front, old, region);
+ set_shadow(sna->front, old, region);
+
+ assert(new->refcnt >= 1);
+ kgem_bo_destroy(&sna->kgem, old);
+ sna->mode.shadow = kgem_bo_reference(new);
}
} else
kgem_submit(&sna->kgem);
@@ -5786,14 +5849,35 @@ void sna_mode_wakeup(struct sna *sna)
sna_dri2_vblank_handler(sna, (struct drm_event_vblank *)e);
break;
case DRM_EVENT_FLIP_COMPLETE:
- if (((struct drm_event_vblank *)e)->user_data) {
- if (((uintptr_t)((struct drm_event_vblank *)e)->user_data) & 2)
- sna_present_flip_handler(sna, (struct drm_event_vblank *)e);
- else
- sna_dri2_page_flip_handler(sna, (struct drm_event_vblank *)e);
- } else {
- if (!--sna->mode.shadow_flip)
- sna_mode_redisplay(sna);
+ {
+ struct drm_event_vblank *vbl = (struct drm_event_vblank *)e;
+ struct sna_crtc *crtc = (void *)(uintptr_t)vbl->user_data;
+
+ crtc->swap.tv_sec = vbl->tv_sec;
+ crtc->swap.tv_usec = vbl->tv_usec;
+ crtc->swap.msc = msc64(crtc, vbl->sequence);
+
+ if (crtc->bo) {
+ assert(crtc->bo->active_scanout);
+ assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
+ crtc->bo->active_scanout--;
+ kgem_bo_destroy(&sna->kgem, crtc->bo);
+
+ assert(crtc->flip_bo->active_scanout >= 1);
+ assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout);
+ crtc->bo = crtc->flip_bo;
+ crtc->flip_bo = NULL;
+ } else {
+ assert(crtc->flip_bo->active_scanout);
+ assert(crtc->flip_bo->refcnt >= crtc->flip_bo->active_scanout);
+ crtc->flip_bo->active_scanout--;
+ kgem_bo_destroy(&sna->kgem, crtc->flip_bo);
+ crtc->flip_bo = NULL;
+ }
+
+ assert(sna->mode.flip_active);
+ if (--sna->mode.flip_active == 0)
+ crtc->flip_handler(sna, vbl, crtc->flip_data);
}
break;
default:
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c
index 317f5985..9e591be1 100644
--- a/src/sna/sna_dri2.c
+++ b/src/sna/sna_dri2.c
@@ -72,6 +72,7 @@ struct sna_dri2_private {
PixmapPtr pixmap;
struct kgem_bo *bo;
bool scanout;
+ bool stale;
uint32_t size;
int refcnt;
};
@@ -83,7 +84,7 @@ get_private(void *buffer)
}
#if DRI2INFOREC_VERSION >= 4
-enum frame_event_type {
+enum event_type {
WAITMSC = 0,
SWAP,
SWAP_WAIT,
@@ -100,13 +101,12 @@ struct dri_bo {
uint32_t name;
};
-struct sna_dri2_frame_event {
+struct sna_dri2_event {
DrawablePtr draw;
ClientPtr client;
- enum frame_event_type type;
+ enum event_type type;
xf86CrtcPtr crtc;
int pipe;
- int count;
bool queued;
/* for swaps & flips only */
@@ -116,53 +116,54 @@ struct sna_dri2_frame_event {
DRI2BufferPtr back;
struct kgem_bo *bo;
- struct sna_dri2_frame_event *chain;
+ struct sna_dri2_event *chain;
struct list cache;
int mode;
};
+static void sna_dri2_flip_event(struct sna *sna,
+ struct sna_dri2_event *flip);
+
static void
-sna_dri2_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
+sna_dri2_get_back(struct sna *sna,
+ DRI2BufferPtr back,
+ struct sna_dri2_event *info)
{
struct kgem_bo *bo;
uint32_t name;
- DBG(("%s: scanout=(%d, %d), back=%d, cache?=%d\n",
- __FUNCTION__,
- sna->dri2.scanout[0].bo ? sna->dri2.scanout[0].bo->handle : 0,
- sna->dri2.scanout[1].bo ? sna->dri2.scanout[1].bo->handle : 0,
- get_private(info->back)->bo->handle,
- !list_is_empty(&info->cache)));
+ get_private(back)->stale = false;
- bo = get_private(info->back)->bo;
+ bo = get_private(back)->bo;
assert(bo->refcnt);
- assert(bo->flush);
- if (!(bo == sna->dri2.scanout[0].bo || bo == sna->dri2.scanout[1].bo)) {
+ DBG(("%s: back buffer handle=%d, scanout?=%d\n",
+ __FUNCTION__, bo->handle, bo->active_scanout));
+ if (bo->active_scanout == 0) {
DBG(("%s: reuse unattached back\n", __FUNCTION__));
return;
}
bo = NULL;
- if (!list_is_empty(&info->cache)) {
- struct dri_bo *c = list_first_entry(&info->cache, struct dri_bo, link);
- if (c->bo) {
- bo = c->bo;
- name = c->name;
- DBG(("%s: reuse cache handle=%d,name=%d\n", __FUNCTION__,
- bo->handle, name));
- list_move_tail(&c->link, &info->cache);
- c->bo = NULL;
+ if (info) {
+ struct dri_bo *c;
+ list_for_each_entry(c, &info->cache, link) {
+ if (c->bo && c->bo->scanout == 0) {
+ bo = c->bo;
+ name = c->name;
+ DBG(("%s: reuse cache handle=%d\n", __FUNCTION__, bo->handle));
+ list_move_tail(&c->link, &info->cache);
+ c->bo = NULL;
+ }
}
}
if (bo == NULL) {
+ DrawablePtr draw = &sna->front->drawable;
DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
bo = kgem_create_2d(&sna->kgem,
- info->draw->width,
- info->draw->height,
- info->draw->bitsPerPixel,
- get_private(info->front)->bo->tiling,
+ draw->width, draw->height, draw->bitsPerPixel,
+ get_private(back)->bo->tiling,
CREATE_SCANOUT);
if (bo == NULL)
return;
@@ -173,29 +174,35 @@ sna_dri2_get_back(struct sna *sna, struct sna_dri2_frame_event *info)
return;
}
}
+ assert(bo->active_scanout == 0);
- assert(!(bo == sna->dri2.scanout[0].bo || bo == sna->dri2.scanout[1].bo));
- assert(name);
-
- unref(get_private(info->back)->bo);
- get_private(info->back)->bo = bo;
- info->back->name = name;
-
- assert(get_private(info->back)->bo != sna->dri2.scanout[0].bo);
- assert(get_private(info->back)->bo != sna->dri2.scanout[1].bo);
+ if (info) {
+ bool found = false;
+ struct dri_bo *c;
- assert(bo->refcnt == 1);
- assert(bo->flush);
-}
+ list_for_each_entry_reverse(c, &info->cache, link) {
+ if (c->bo == NULL) {
+ found = true;
+ _list_del(&c->link);
+ break;
+ }
+ }
+ if (!found)
+ c = malloc(sizeof(*c));
+ if (c != NULL) {
+ c->bo = kgem_bo_reference(get_private(back)->bo);
+ c->name = back->name;
+ list_add(&c->link, &info->cache);
+ }
+ }
-static inline struct sna_dri2_frame_event *
-to_frame_event(uintptr_t data)
-{
- return (struct sna_dri2_frame_event *)(data & ~3);
+ kgem_bo_destroy(&sna->kgem, get_private(back)->bo);
+ get_private(back)->bo = bo;
+ back->name = name;
}
struct dri2_window {
- struct sna_dri2_frame_event *chain;
+ struct sna_dri2_event *chain;
xf86CrtcPtr crtc;
int64_t msc_delta;
};
@@ -205,7 +212,7 @@ static struct dri2_window *dri2_window(WindowPtr win)
return ((void **)__get_private(win, sna_window_key))[1];
}
-static struct sna_dri2_frame_event *
+static struct sna_dri2_event *
sna_dri2_window_get_chain(WindowPtr win)
{
struct dri2_window *priv = dri2_window(win);
@@ -238,19 +245,12 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
if (buffer->attachment == DRI2BufferBackLeft &&
draw->type != DRAWABLE_PIXMAP) {
- struct sna_dri2_frame_event *info;
-
- info = sna_dri2_window_get_chain((WindowPtr)draw);
- DBG(("%s: draw->id=%lu, active? %d, current back? %d\n",
- __FUNCTION__, (long)draw->id, info!=NULL, info && info->back == buffer));
- if (info && info->back == buffer) {
- DBG(("%s: replacing back buffer\n", __FUNCTION__));
- sna_dri2_get_back(to_sna_from_drawable(draw), info);
- }
+ DBG(("%s: replacing back buffer\n", __FUNCTION__));
+ sna_dri2_get_back(to_sna_from_drawable(draw), buffer,
+ sna_dri2_window_get_chain((WindowPtr)draw));
assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
- assert(get_private(buffer)->bo != to_sna_from_drawable(draw)->dri2.scanout[0].bo);
- assert(get_private(buffer)->bo != to_sna_from_drawable(draw)->dri2.scanout[1].bo);
+ assert(get_private(buffer)->bo->active_scanout == 0);
}
}
@@ -315,19 +315,25 @@ static struct kgem_bo *sna_pixmap_set_dri(struct sna *sna,
}
priv = sna_pixmap_move_to_gpu(pixmap,
- MOVE_READ | MOVE_WRITE | __MOVE_FORCE | __MOVE_DRI);
+ MOVE_READ | __MOVE_FORCE | __MOVE_DRI);
if (priv == NULL) {
DBG(("%s: failed to move to GPU, BadAlloc\n", __FUNCTION__));
return NULL;
}
assert(priv->flush == false);
- assert(priv->cow == NULL);
assert(priv->cpu_damage == NULL);
assert(priv->gpu_bo);
assert(priv->gpu_bo->proxy == NULL);
assert(priv->gpu_bo->flush == false);
+ /* Henceforth, we need to broadcast all updates to clients and
+ * flush our rendering before doing so.
+ */
+ priv->gpu_bo->flush = true;
+ if (priv->gpu_bo->exec)
+ sna->kgem.flush = 1;
+
tiling = color_tiling(sna, &pixmap->drawable);
if (tiling < 0)
tiling = -tiling;
@@ -350,11 +356,10 @@ static inline void sna_pixmap_set_buffer(PixmapPtr pixmap, void *ptr)
}
void
-sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap)
+sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap, struct kgem_bo *bo)
{
DRI2BufferPtr buffer;
struct sna_dri2_private *private;
- struct kgem_bo *bo;
buffer = sna_pixmap_get_buffer(pixmap);
if (buffer == NULL)
@@ -368,7 +373,7 @@ sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap)
private = get_private(buffer);
assert(private->pixmap == pixmap);
- bo = sna_pixmap(pixmap)->gpu_bo;
+ assert(bo != private->bo);
if (private->bo == bo)
return;
@@ -378,7 +383,8 @@ sna_dri2_pixmap_update_bo(struct sna *sna, PixmapPtr pixmap)
buffer->name = kgem_bo_flink(&sna->kgem, bo);
private->bo = ref(bo);
- assert(bo->flush);
+ bo->flush = true;
+ assert(sna_pixmap(pixmap)->flush);
/* XXX DRI2InvalidateDrawable(&pixmap->drawable); */
}
@@ -562,8 +568,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
sna_accel_watch_flush(sna, 1);
}
- assert(bo->flush == true);
-
return buffer;
err:
@@ -667,14 +671,10 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
assert(pixmap->drawable.width * pixmap->drawable.bitsPerPixel <= 8*bo->pitch);
assert(pixmap->drawable.height * bo->pitch <= kgem_bo_size(bo));
assert(bo->proxy == NULL);
- assert(bo->flush);
assert(priv->pinned & PIN_DRI2);
assert((priv->pinned & (PIN_PRIME | PIN_DRI3)) == 0);
assert(priv->flush);
- if (priv->cow && priv->gpu_bo != bo)
- sna_pixmap_undo_cow(sna, priv, 0);
-
/* Post damage on the new front buffer so that listeners, such
* as DisplayLink know take a copy and shove it over the USB,
* also for software cursors and the like.
@@ -688,11 +688,19 @@ static void set_bo(PixmapPtr pixmap, struct kgem_bo *bo)
damage(pixmap, priv, NULL);
assert(bo->refcnt);
+ if (priv->move_to_gpu)
+ priv->move_to_gpu(sna, priv, 0);
if (priv->gpu_bo != bo) {
+ priv->gpu_bo->flush = false;
+ if (priv->cow)
+ sna_pixmap_undo_cow(sna, priv, 0);
if (priv->gpu_bo) {
sna_pixmap_unmap(pixmap, priv);
kgem_bo_destroy(&sna->kgem, priv->gpu_bo);
}
+ bo->flush = true;
+ if (bo->exec)
+ sna->kgem.flush = 1;
priv->gpu_bo = ref(bo);
}
if (bo->domain != DOMAIN_GPU)
@@ -1005,10 +1013,7 @@ sna_dri2_copy_region(DrawablePtr draw,
assert(get_private(dst)->refcnt);
assert(get_private(src)->bo->refcnt);
- assert(get_private(src)->bo->flush);
-
assert(get_private(dst)->bo->refcnt);
- assert(get_private(dst)->bo->flush);
DBG(("%s: region (%d, %d), (%d, %d) x %ld\n",
__FUNCTION__,
@@ -1119,11 +1124,10 @@ sna_dri2_get_crtc(DrawablePtr draw)
}
static void
-sna_dri2_remove_frame_event(WindowPtr win,
- struct sna_dri2_frame_event *info)
+sna_dri2_remove_event(WindowPtr win, struct sna_dri2_event *info)
{
struct dri2_window *priv;
- struct sna_dri2_frame_event *chain;
+ struct sna_dri2_event *chain;
assert(win->drawable.type == DRAWABLE_WINDOW);
DBG(("%s: remove[%p] from window %ld)\n",
@@ -1146,11 +1150,11 @@ sna_dri2_remove_frame_event(WindowPtr win,
chain->chain = info->chain;
}
-static struct sna_dri2_frame_event *
-sna_dri2_add_frame_event(DrawablePtr draw, ClientPtr client)
+static struct sna_dri2_event *
+sna_dri2_add_event(DrawablePtr draw, ClientPtr client)
{
struct dri2_window *priv;
- struct sna_dri2_frame_event *info, *chain;
+ struct sna_dri2_event *info, *chain;
assert(draw->type == DRAWABLE_WINDOW);
DBG(("%s: adding event to window %ld)\n",
@@ -1160,7 +1164,7 @@ sna_dri2_add_frame_event(DrawablePtr draw, ClientPtr client)
if (priv == NULL)
return NULL;
- info = calloc(1, sizeof(struct sna_dri2_frame_event));
+ info = calloc(1, sizeof(struct sna_dri2_event));
if (info == NULL)
return NULL;
@@ -1187,12 +1191,12 @@ sna_dri2_add_frame_event(DrawablePtr draw, ClientPtr client)
}
static void
-sna_dri2_frame_event_info_free(struct sna *sna,
- DrawablePtr draw,
- struct sna_dri2_frame_event *info)
+sna_dri2_event_free(struct sna *sna,
+ DrawablePtr draw,
+ struct sna_dri2_event *info)
{
if (draw && draw->type == DRAWABLE_WINDOW)
- sna_dri2_remove_frame_event((WindowPtr)draw, info);
+ sna_dri2_remove_event((WindowPtr)draw, info);
_sna_dri2_destroy_buffer(sna, info->front);
_sna_dri2_destroy_buffer(sna, info->back);
@@ -1202,10 +1206,8 @@ sna_dri2_frame_event_info_free(struct sna *sna,
c = list_first_entry(&info->cache, struct dri_bo, link);
list_del(&c->link);
- if (c->bo) {
- assert(c->bo->refcnt == 1);
+ if (c->bo)
kgem_bo_destroy(&sna->kgem, c->bo);
- }
free(c);
}
@@ -1228,7 +1230,7 @@ void sna_dri2_destroy_window(WindowPtr win)
if (priv->chain) {
struct sna *sna = to_sna_from_drawable(&win->drawable);
- struct sna_dri2_frame_event *info, *chain;
+ struct sna_dri2_event *info, *chain;
DBG(("%s: freeing chain\n", __FUNCTION__));
@@ -1238,13 +1240,13 @@ void sna_dri2_destroy_window(WindowPtr win)
chain = info->chain;
info->chain = NULL;
+ assert(info->queued);
while ((info = chain)) {
chain = info->chain;
- if (info->queued) {
- info->draw = NULL;
- info->chain = NULL;
- } else
- sna_dri2_frame_event_info_free(sna, NULL, info);
+ info->chain = NULL;
+ info->draw = NULL;
+ if (!info->queued)
+ sna_dri2_event_free(sna, NULL, info);
}
}
@@ -1252,95 +1254,33 @@ void sna_dri2_destroy_window(WindowPtr win)
}
static void
-update_scanout(struct sna *sna, struct kgem_bo *bo, int name)
-{
- assert(sna->dri2.scanout[1].bo == NULL);
- assert(sna->dri2.scanout[0].bo->scanout);
- assert(sna->dri2.scanout[0].bo->refcnt);
- sna->dri2.scanout[1] = sna->dri2.scanout[0];
- sna->dri2.scanout[0].bo = ref(bo);
- sna->dri2.scanout[0].name = name;
- assert(sna->dri2.scanout[0].bo->scanout);
-
- DBG(("%s: pending scanout handle=%d, active scanout handle=%d\n",
- __FUNCTION__, sna->dri2.scanout[0].bo->handle, sna->dri2.scanout[1].bo->handle));
- assert(sna->dri2.scanout[0].bo->handle != sna->dri2.scanout[1].bo->handle);
-}
-
-static void
-retire_scanout(struct sna *sna,
- struct sna_dri2_frame_event *flip)
+sna_dri2_flip_handler(struct sna *sna,
+ struct drm_event_vblank *event,
+ void *data)
{
- struct dri_bo *c = NULL;
-
- if (sna->dri2.scanout[1].bo == NULL)
- return;
-
- DBG(("%s: retiring previous scanout handle=%d, name=%d, refcnt=%d (current scanout handle=%d)\n",
- __FUNCTION__,
- sna->dri2.scanout[1].bo->handle,
- sna->dri2.scanout[1].name,
- sna->dri2.scanout[1].bo->refcnt,
- sna->dri2.scanout[0].bo->handle));
-
- if (flip &&
- sna->dri2.scanout[1].bo != sna->dri2.scanout[0].bo &&
- sna->dri2.scanout[1].bo->refcnt == 1) {
- DBG(("%s: adding old scanout to flip cache\n", __FUNCTION__));
- if (!list_is_empty(&flip->cache))
- c = list_last_entry(&flip->cache, struct dri_bo, link);
- if (c) {
- if (c->bo == NULL)
- _list_del(&c->link);
- else
- c = NULL;
- }
- if (c == NULL)
- c = malloc(sizeof(*c));
- if (c != NULL) {
- c->bo = sna->dri2.scanout[1].bo;
- c->name = sna->dri2.scanout[1].name;
- list_add(&c->link, &flip->cache);
- }
- }
-
- if (c == NULL) {
- DBG(("%s: not caching old scanout handle=%d, still busy\n",
- __FUNCTION__, sna->dri2.scanout[1].bo->handle));
- kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[1].bo);
- }
-
- sna->dri2.scanout[1].bo = NULL;
+ DBG(("%s: sequence=%d\n", __FUNCTION__, event->sequence));
+ sna_dri2_flip_event(sna, data);
}
static bool
-sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
+sna_dri2_flip(struct sna *sna, struct sna_dri2_event *info)
{
struct kgem_bo *bo = get_private(info->back)->bo;
- struct dri_bo tmp;
+ struct kgem_bo *tmp_bo;
+ uint32_t tmp_name;
DBG(("%s(type=%d)\n", __FUNCTION__, info->type));
assert(sna_pixmap_get_buffer(sna->front) == info->front);
assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
- assert(sna->dri2.scanout[0].bo);
- assert(sna->dri2.scanout[0].bo->scanout);
- assert(sna->dri2.scanout[1].bo == NULL);
assert(bo->refcnt);
- if (info->type == FLIP_ASYNC)
- info->count = sna_page_flip(sna, bo, NULL, -1);
- else
- info->count = sna_page_flip(sna, bo, info, info->pipe);
- if (!info->count)
+ if (!sna_page_flip(sna, bo, sna_dri2_flip_handler,
+ info->type == FLIP_ASYNC ? NULL : info))
return false;
- update_scanout(sna, bo, info->back->name);
-
assert(sna->dri2.flip_pending == NULL || sna->dri2.flip_pending == info);
- if (info->type == FLIP_ASYNC)
- retire_scanout(sna, NULL);
- else
+ if (info->type != FLIP_ASYNC)
sna->dri2.flip_pending = info;
DBG(("%s: marked handle=%d as scanout, swap front (handle=%d, name=%d) and back (handle=%d, name=%d)\n",
@@ -1348,16 +1288,17 @@ sna_dri2_page_flip(struct sna *sna, struct sna_dri2_frame_event *info)
get_private(info->front)->bo->handle, info->front->name,
get_private(info->back)->bo->handle, info->back->name));
- tmp.bo = get_private(info->front)->bo;
- tmp.name = info->front->name;
+ tmp_bo = get_private(info->front)->bo;
+ tmp_name = info->front->name;
set_bo(sna->front, bo);
info->front->name = info->back->name;
get_private(info->front)->bo = bo;
- info->back->name = tmp.name;
- get_private(info->back)->bo = tmp.bo;
+ info->back->name = tmp_name;
+ get_private(info->back)->bo = tmp_bo;
+ get_private(info->back)->stale = true;
info->queued = true;
return true;
@@ -1495,6 +1436,74 @@ can_flip(struct sna * sna,
return true;
}
+static bool
+can_xchg(struct sna * sna,
+ DrawablePtr draw,
+ DRI2BufferPtr front,
+ DRI2BufferPtr back)
+{
+ WindowPtr win = (WindowPtr)draw;
+ PixmapPtr pixmap;
+
+ if (draw->type == DRAWABLE_PIXMAP)
+ return false;
+
+ if (front->format != back->format) {
+ DBG(("%s: no, format mismatch, front = %d, back = %d\n",
+ __FUNCTION__, front->format, back->format));
+ return false;
+ }
+
+ if (front->attachment != DRI2BufferFrontLeft) {
+ DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
+ __FUNCTION__,
+ front->attachment,
+ DRI2BufferFrontLeft));
+ return false;
+ }
+
+ DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n",
+ __FUNCTION__,
+ win->drawable.width, win->drawable.height,
+ win->clipList.extents.x1, win->clipList.extents.y1,
+ win->clipList.extents.x2, win->clipList.extents.y2,
+ RegionNumRects(&win->clipList)));
+ if (is_clipped(&win->clipList, draw)) {
+ DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n",
+ __FUNCTION__,
+ draw->width, draw->height,
+ win->clipList.extents.x1,
+ win->clipList.extents.y1,
+ win->clipList.extents.x2,
+ win->clipList.extents.y2));
+ return false;
+ }
+
+ if (get_private(back)->size != get_private(front)->size) {
+ DBG(("%s: no, back buffer %dx%d does not match front buffer %dx%d\n",
+ __FUNCTION__,
+ get_private(back)->size & 0x7fff, (get_private(back)->size >> 16) & 0x7fff,
+ get_private(front)->size & 0x7fff, (get_private(front)->size >> 16) & 0x7fff));
+ return false;
+ }
+
+ pixmap = get_window_pixmap(win);
+ if (pixmap == sna->front && !(sna->flags & SNA_TEAR_FREE)) {
+ DBG(("%s: no, front buffer, requires flipping\n",
+ __FUNCTION__));
+ return false;
+ }
+
+ if (sna_pixmap(pixmap)->pinned & ~(PIN_DRI2 | PIN_SCANOUT)) {
+ DBG(("%s: no, pinned: %x\n",
+ __FUNCTION__, sna_pixmap(pixmap)->pinned));
+ return false;
+ }
+
+ DBG(("%s: yes\n", __FUNCTION__));
+ return true;
+}
+
static void
sna_dri2_exchange_buffers(DrawablePtr draw,
DRI2BufferPtr front,
@@ -1517,14 +1526,15 @@ sna_dri2_exchange_buffers(DrawablePtr draw,
pixmap->drawable.width,
pixmap->drawable.height));
- DBG(("%s: back_bo pitch=%d, size=%d, ref=%d\n",
- __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt));
- DBG(("%s: front_bo pitch=%d, size=%d, ref=%d\n",
- __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt));
+ DBG(("%s: back_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
+ __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo), back_bo->refcnt, back_bo->active_scanout));
+ DBG(("%s: front_bo pitch=%d, size=%d, ref=%d, active_scanout?=%d\n",
+ __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo), front_bo->refcnt, front_bo->active_scanout));
assert(front_bo->refcnt);
assert(back_bo->refcnt);
assert(sna_pixmap_get_buffer(pixmap) == front);
+
assert(pixmap->drawable.height * back_bo->pitch <= kgem_bo_size(back_bo));
assert(pixmap->drawable.height * front_bo->pitch <= kgem_bo_size(front_bo));
@@ -1532,14 +1542,20 @@ sna_dri2_exchange_buffers(DrawablePtr draw,
get_private(front)->bo = back_bo;
get_private(back)->bo = front_bo;
+ get_private(back)->stale = true;
tmp = front->name;
front->name = back->name;
back->name = tmp;
+
+ assert(front_bo->refcnt);
+ assert(back_bo->refcnt);
+
+ assert(get_private(front)->bo == sna_pixmap(pixmap)->gpu_bo);
}
static void frame_swap_complete(struct sna *sna,
- struct sna_dri2_frame_event *frame,
+ struct sna_dri2_event *frame,
int type)
{
const struct ust_msc *swap;
@@ -1579,17 +1595,22 @@ static void fake_swap_complete(struct sna *sna, ClientPtr client,
type, func, data);
}
-static void chain_swap(struct sna *sna, DrawablePtr draw, struct sna_dri2_frame_event *chain)
+static void chain_swap(struct sna *sna, struct sna_dri2_event *chain)
{
union drm_wait_vblank vbl;
- assert(chain == sna_dri2_window_get_chain((WindowPtr)draw));
+ if (chain->draw == NULL) {
+ sna_dri2_event_free(sna, NULL, chain);
+ return;
+ }
+
+ assert(chain == sna_dri2_window_get_chain((WindowPtr)chain->draw));
DBG(("%s: chaining draw=%ld, type=%d\n",
- __FUNCTION__, (long)draw->id, chain->type));
+ __FUNCTION__, (long)chain->draw->id, chain->type));
switch (chain->type) {
case SWAP_THROTTLE:
DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
- if (sna->mode.shadow_flip && !sna->mode.shadow_damage) {
+ if (sna->mode.shadow && !sna->mode.shadow_damage) {
/* recursed from wait_for_shadow(), simply requeue */
DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
VG_CLEAR(vbl);
@@ -1597,7 +1618,7 @@ static void chain_swap(struct sna *sna, DrawablePtr draw, struct sna_dri2_frame_
DRM_VBLANK_RELATIVE |
DRM_VBLANK_EVENT;
vbl.request.sequence = 1;
- vbl.request.signal = (unsigned long)chain;
+ vbl.request.signal = (uintptr_t)chain;
if (!sna_wait_vblank(sna, &vbl, chain->pipe)) {
chain->queued = true;
@@ -1607,9 +1628,13 @@ static void chain_swap(struct sna *sna, DrawablePtr draw, struct sna_dri2_frame_
DBG(("%s -- requeue failed, errno=%d\n", __FUNCTION__, errno));
}
- chain->bo = __sna_dri2_copy_region(sna, draw, NULL,
- chain->back, chain->front,
- true);
+ if (can_xchg(sna, chain->draw, chain->front, chain->back)) {
+ sna_dri2_exchange_buffers(chain->draw, chain->front, chain->back);
+ } else {
+ chain->bo = __sna_dri2_copy_region(sna, chain->draw, NULL,
+ chain->back, chain->front,
+ true);
+ }
case SWAP:
break;
default:
@@ -1621,14 +1646,14 @@ static void chain_swap(struct sna *sna, DrawablePtr draw, struct sna_dri2_frame_
DRM_VBLANK_RELATIVE |
DRM_VBLANK_EVENT;
vbl.request.sequence = 1;
- vbl.request.signal = (unsigned long)chain;
+ vbl.request.signal = (uintptr_t)chain;
chain->queued = true;
if (sna_wait_vblank(sna, &vbl, chain->pipe)) {
DBG(("%s: vblank wait failed, unblocking client\n", __FUNCTION__));
frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
- sna_dri2_frame_event_info_free(sna, draw, chain);
+ sna_dri2_event_free(sna, chain->draw, chain);
} else {
- if (chain->type == SWAP_THROTTLE && !swap_limit(draw, 2)) {
+ if (chain->type == SWAP_THROTTLE && !swap_limit(chain->draw, 2)) {
DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
}
@@ -1654,7 +1679,7 @@ static inline bool rq_is_busy(struct kgem *kgem, struct kgem_bo *bo)
}
static bool sna_dri2_blit_complete(struct sna *sna,
- struct sna_dri2_frame_event *info)
+ struct sna_dri2_event *info)
{
if (rq_is_busy(&sna->kgem, info->bo)) {
union drm_wait_vblank vbl;
@@ -1667,7 +1692,7 @@ static bool sna_dri2_blit_complete(struct sna *sna,
DRM_VBLANK_RELATIVE |
DRM_VBLANK_EVENT;
vbl.request.sequence = 1;
- vbl.request.signal = (unsigned long)info;
+ vbl.request.signal = (uintptr_t)info;
assert(info->queued);
if (!sna_wait_vblank(sna, &vbl, info->pipe))
return false;
@@ -1679,7 +1704,7 @@ static bool sna_dri2_blit_complete(struct sna *sna,
void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
{
- struct sna_dri2_frame_event *info = (void *)(uintptr_t)event->user_data;
+ struct sna_dri2_event *info = (void *)(uintptr_t)event->user_data;
DrawablePtr draw;
union drm_wait_vblank vbl;
uint64_t msc;
@@ -1698,18 +1723,21 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
case FLIP:
/* If we can still flip... */
if (can_flip(sna, draw, info->front, info->back, info->crtc) &&
- sna_dri2_page_flip(sna, info))
+ sna_dri2_flip(sna, info))
return;
/* else fall through to blit */
case SWAP:
- if (sna->mode.shadow_flip && !sna->mode.shadow_damage) {
+ if (sna->mode.shadow && !sna->mode.shadow_damage) {
/* recursed from wait_for_shadow(), simply requeue */
DBG(("%s -- recursed from wait_for_shadow(), requeuing\n", __FUNCTION__));
- } else {
+ } else if (can_xchg(sna, draw, info->front, info->back)) {
+ sna_dri2_exchange_buffers(draw, info->front, info->back);
+ info->type = SWAP_WAIT;
+ } else {
info->bo = __sna_dri2_copy_region(sna, draw, NULL,
- info->back, info->front, true);
+ info->back, info->front, true);
info->type = SWAP_WAIT;
}
@@ -1718,7 +1746,7 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
DRM_VBLANK_RELATIVE |
DRM_VBLANK_EVENT;
vbl.request.sequence = 1;
- vbl.request.signal = (unsigned long)info;
+ vbl.request.signal = (uintptr_t)info;
assert(info->queued);
if (!sna_wait_vblank(sna, &vbl, info->pipe))
@@ -1763,18 +1791,19 @@ void sna_dri2_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
if (info->chain) {
assert(info->chain != info);
- sna_dri2_remove_frame_event((WindowPtr)draw, info);
- chain_swap(sna, draw, info->chain);
+ assert(info->draw == draw);
+ sna_dri2_remove_event((WindowPtr)draw, info);
+ chain_swap(sna, info->chain);
draw = NULL;
}
done:
- sna_dri2_frame_event_info_free(sna, draw, info);
+ sna_dri2_event_free(sna, draw, info);
}
static bool
sna_dri2_immediate_blit(struct sna *sna,
- struct sna_dri2_frame_event *info,
+ struct sna_dri2_event *info,
bool sync, bool event)
{
DrawablePtr draw = info->draw;
@@ -1805,7 +1834,7 @@ sna_dri2_immediate_blit(struct sna *sna,
DRM_VBLANK_RELATIVE |
DRM_VBLANK_EVENT;
vbl.request.sequence = 1;
- vbl.request.signal = (unsigned long)info;
+ vbl.request.signal = (uintptr_t)info;
ret = !sna_wait_vblank(sna, &vbl, info->pipe);
if (ret) {
info->queued = true;
@@ -1827,7 +1856,7 @@ sna_dri2_immediate_blit(struct sna *sna,
}
static bool
-sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
+sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_event *info)
{
DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
@@ -1839,27 +1868,11 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
if (bo != sna_pixmap(sna->front)->gpu_bo)
return false;
- if (bo == sna->dri2.scanout[0].bo) {
- DBG(("%s: flip chain already complete\n", __FUNCTION__));
-
- if (info->draw) {
- sna_dri2_remove_frame_event((WindowPtr)info->draw, info);
- if (info->chain)
- chain_swap(sna, info->draw, info->chain);
- }
-
- info->draw = NULL;
+ if (!sna_page_flip(sna, bo, sna_dri2_flip_handler, info))
return false;
- } else {
- info->count = sna_page_flip(sna, bo, info, info->pipe);
- if (!info->count)
- return false;
-
- update_scanout(sna, bo, info->front->name);
- assert(sna->dri2.flip_pending == NULL || sna->dri2.flip_pending == info);
- sna->dri2.flip_pending = info;
- }
+ assert(sna->dri2.flip_pending == NULL || sna->dri2.flip_pending == info);
+ sna->dri2.flip_pending = info;
} else {
info->type = -info->mode;
@@ -1870,11 +1883,11 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
return false;
assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
- if (!sna_dri2_page_flip(sna, info))
+ if (!sna_dri2_flip(sna, info))
return false;
if (!XORG_CAN_TRIPLE_BUFFER) {
- sna_dri2_get_back(sna, info);
+ sna_dri2_get_back(sna, info->back, info);
DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
frame_swap_complete(sna, info, DRI2_FLIP_COMPLETE);
}
@@ -1886,7 +1899,7 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_frame_event *info)
static void chain_flip(struct sna *sna)
{
- struct sna_dri2_frame_event *chain = sna->dri2.flip_pending;
+ struct sna_dri2_event *chain = sna->dri2.flip_pending;
assert(chain->type == FLIP);
DBG(("%s: chaining type=%d, cancelled?=%d\n",
@@ -1894,14 +1907,14 @@ static void chain_flip(struct sna *sna)
sna->dri2.flip_pending = NULL;
if (chain->draw == NULL) {
- sna_dri2_frame_event_info_free(sna, NULL, chain);
+ sna_dri2_event_free(sna, NULL, chain);
return;
}
assert(chain == sna_dri2_window_get_chain((WindowPtr)chain->draw));
if (can_flip(sna, chain->draw, chain->front, chain->back, chain->crtc) &&
- sna_dri2_page_flip(sna, chain)) {
+ sna_dri2_flip(sna, chain)) {
DBG(("%s: performing chained flip\n", __FUNCTION__));
} else {
DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
@@ -1919,7 +1932,7 @@ static void chain_flip(struct sna *sna)
DRM_VBLANK_RELATIVE |
DRM_VBLANK_EVENT;
vbl.request.sequence = 1;
- vbl.request.signal = (unsigned long)chain;
+ vbl.request.signal = (uintptr_t)chain;
if (!sna_wait_vblank(sna, &vbl, chain->pipe)) {
chain->queued = true;
@@ -1929,18 +1942,15 @@ static void chain_flip(struct sna *sna)
DBG(("%s: fake triple buffering (or vblank wait failed), unblocking client\n", __FUNCTION__));
frame_swap_complete(sna, chain, DRI2_BLIT_COMPLETE);
- sna_dri2_frame_event_info_free(sna, chain->draw, chain);
+ sna_dri2_event_free(sna, chain->draw, chain);
}
}
static void sna_dri2_flip_event(struct sna *sna,
- struct sna_dri2_frame_event *flip)
+ struct sna_dri2_event *flip)
{
DBG(("%s(pipe=%d, event=%d)\n", __FUNCTION__, flip->pipe, flip->type));
- assert(!sna->mode.shadow_flip);
-
- retire_scanout(sna, flip);
if (sna->dri2.flip_pending == flip)
sna->dri2.flip_pending = NULL;
@@ -1949,7 +1959,7 @@ static void sna_dri2_flip_event(struct sna *sna,
case FLIP:
DBG(("%s: swap complete, unblocking client\n", __FUNCTION__));
frame_swap_complete(sna, flip, DRI2_FLIP_COMPLETE);
- sna_dri2_frame_event_info_free(sna, flip->draw, flip);
+ sna_dri2_event_free(sna, flip->draw, flip);
if (sna->dri2.flip_pending)
chain_flip(sna);
@@ -1960,56 +1970,36 @@ static void sna_dri2_flip_event(struct sna *sna,
frame_swap_complete(sna, flip, DRI2_FLIP_COMPLETE);
case FLIP_COMPLETE:
if (sna->dri2.flip_pending) {
- sna_dri2_frame_event_info_free(sna, flip->draw, flip);
+ sna_dri2_event_free(sna, flip->draw, flip);
chain_flip(sna);
} else if (!flip->mode) {
DBG(("%s: flip chain complete\n", __FUNCTION__));
if (flip->chain) {
- sna_dri2_remove_frame_event((WindowPtr)flip->draw,
- flip);
- chain_swap(sna, flip->draw, flip->chain);
+ sna_dri2_remove_event((WindowPtr)flip->draw,
+ flip);
+ chain_swap(sna, flip->chain);
flip->draw = NULL;
}
- sna_dri2_frame_event_info_free(sna, flip->draw, flip);
+ sna_dri2_event_free(sna, flip->draw, flip);
} else if (!sna_dri2_flip_continue(sna, flip)) {
DBG(("%s: no longer able to flip\n", __FUNCTION__));
if (flip->draw == NULL || !sna_dri2_immediate_blit(sna, flip, false, flip->mode < 0))
- sna_dri2_frame_event_info_free(sna, flip->draw, flip);
+ sna_dri2_event_free(sna, flip->draw, flip);
}
break;
default: /* Unknown type */
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
- sna_dri2_frame_event_info_free(sna, flip->draw, flip);
+ sna_dri2_event_free(sna, flip->draw, flip);
if (sna->dri2.flip_pending)
chain_flip(sna);
break;
}
}
-void
-sna_dri2_page_flip_handler(struct sna *sna,
- struct drm_event_vblank *event)
-{
- struct sna_dri2_frame_event *info = to_frame_event(event->user_data);
-
- DBG(("%s: pending flip_count=%d\n", __FUNCTION__, info->count));
- assert(info->count > 0);
-
- /* Is this the event whose info shall be delivered to higher level? */
- if (event->user_data & 1)
- sna_crtc_record_event(info->crtc, event);
-
- if (--info->count)
- return;
-
- DBG(("%s: sequence=%d\n", __FUNCTION__, event->sequence));
- sna_dri2_flip_event(sna, info);
-}
-
static uint64_t
get_current_msc(struct sna *sna, DrawablePtr draw, xf86CrtcPtr crtc)
{
@@ -2105,7 +2095,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
DRI2SwapEventPtr func, void *data)
{
struct sna *sna = to_sna_from_drawable(draw);
- struct sna_dri2_frame_event *info;
+ struct sna_dri2_event *info;
uint64_t current_msc;
if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
@@ -2142,7 +2132,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
}
}
- info = sna_dri2_add_frame_event(draw, client);
+ info = sna_dri2_add_event(draw, client);
if (info == NULL)
return false;
@@ -2153,13 +2143,6 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
info->front = sna_dri2_reference_buffer(front);
info->back = sna_dri2_reference_buffer(back);
- if (sna->dri2.scanout[0].bo == NULL) {
- sna->dri2.scanout[0].bo = ref(get_private(front)->bo);
- sna->dri2.scanout[0].name = info->front->name;
- }
- assert(sna->dri2.scanout[0].bo == get_private(front)->bo);
- assert(sna->dri2.scanout[0].bo->scanout);
-
if (sna->dri2.flip_pending) {
/* We need to first wait (one vblank) for the
* async flips to complete before this client
@@ -2172,9 +2155,9 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
current_msc++;
} else {
info->type = type = use_triple_buffer(sna, client, *target_msc == 0);
- if (!sna_dri2_page_flip(sna, info)) {
+ if (!sna_dri2_flip(sna, info)) {
DBG(("%s: flip failed, falling back\n", __FUNCTION__));
- sna_dri2_frame_event_info_free(sna, draw, info);
+ sna_dri2_event_free(sna, draw, info);
return false;
}
}
@@ -2183,11 +2166,11 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
if (type >= FLIP_COMPLETE) {
new_back:
if (!XORG_CAN_TRIPLE_BUFFER)
- sna_dri2_get_back(sna, info);
+ sna_dri2_get_back(sna, back, info);
DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
frame_swap_complete(sna, info, DRI2_EXCHANGE_COMPLETE);
if (info->type == FLIP_ASYNC)
- sna_dri2_frame_event_info_free(sna, draw, info);
+ sna_dri2_event_free(sna, draw, info);
}
out:
DBG(("%s: target_msc=%llu\n", __FUNCTION__, current_msc + 1));
@@ -2195,7 +2178,7 @@ out:
return true;
}
- info = sna_dri2_add_frame_event(draw, client);
+ info = sna_dri2_add_event(draw, client);
if (info == NULL)
return false;
@@ -2207,13 +2190,6 @@ out:
info->front = sna_dri2_reference_buffer(front);
info->back = sna_dri2_reference_buffer(back);
- if (sna->dri2.scanout[0].bo == NULL) {
- sna->dri2.scanout[0].bo = ref(get_private(front)->bo);
- sna->dri2.scanout[0].name = info->front->name;
- }
- assert(sna->dri2.scanout[0].bo == get_private(front)->bo);
- assert(sna->dri2.scanout[0].bo->scanout);
-
/*
* If divisor is zero, or current_msc is smaller than target_msc
* we just need to make sure target_msc passes before initiating
@@ -2233,8 +2209,8 @@ out:
}
if (*target_msc <= current_msc + 1) {
- if (!sna_dri2_page_flip(sna, info)) {
- sna_dri2_frame_event_info_free(sna, draw, info);
+ if (!sna_dri2_flip(sna, info)) {
+ sna_dri2_event_free(sna, draw, info);
return false;
}
*target_msc = current_msc + 1;
@@ -2249,10 +2225,10 @@ out:
/* Account for 1 frame extra pageflip delay */
vbl.reply.sequence = draw_target_seq(draw, *target_msc - 1);
- vbl.request.signal = (unsigned long)info;
+ vbl.request.signal = (uintptr_t)info;
if (sna_wait_vblank(sna, &vbl, info->pipe)) {
- sna_dri2_frame_event_info_free(sna, draw, info);
+ sna_dri2_event_free(sna, draw, info);
return false;
}
}
@@ -2263,6 +2239,67 @@ out:
return true;
}
+static bool
+sna_dri2_schedule_xchg(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
+ DRI2BufferPtr front, DRI2BufferPtr back,
+ CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
+ DRI2SwapEventPtr func, void *data)
+{
+ struct sna *sna = to_sna_from_drawable(draw);
+ uint64_t current_msc;
+ bool sync, event;
+
+ if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc))
+ return false;
+
+ sync = current_msc < *target_msc;
+ event = sna_dri2_window_get_chain((WindowPtr)draw) == NULL;
+ if (!sync || event) {
+ DBG(("%s: performing immediate xchg on pipe %d\n",
+ __FUNCTION__, sna_crtc_to_pipe(crtc)));
+ sna_dri2_exchange_buffers(draw, front, back);
+ }
+ if (sync) {
+ struct sna_dri2_event *info;
+
+ info = sna_dri2_add_event(draw, client);
+ if (!info)
+ goto complete;
+
+ info->event_complete = func;
+ info->event_data = data;
+
+ info->front = sna_dri2_reference_buffer(front);
+ info->back = sna_dri2_reference_buffer(back);
+ info->type = SWAP_THROTTLE;
+
+ if (event) {
+ union drm_wait_vblank vbl;
+
+ VG_CLEAR(vbl);
+ vbl.request.type =
+ DRM_VBLANK_RELATIVE |
+ DRM_VBLANK_EVENT;
+ vbl.request.sequence = 1;
+ vbl.request.signal = (uintptr_t)info;
+
+ if (sna_wait_vblank(sna, &vbl, info->pipe)) {
+ sna_dri2_event_free(sna, draw, info);
+ goto complete;
+ }
+
+ info->queued = true;
+ swap_limit(draw, 2);
+ }
+ } else {
+complete:
+ fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
+ }
+
+ *target_msc = current_msc + 1;
+ return true;
+}
+
/*
* ScheduleSwap is responsible for requesting a DRM vblank event for the
* appropriate frame.
@@ -2291,7 +2328,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
struct sna *sna = to_sna_from_drawable(draw);
union drm_wait_vblank vbl;
xf86CrtcPtr crtc = NULL;
- struct sna_dri2_frame_event *info = NULL;
+ struct sna_dri2_event *info = NULL;
CARD64 current_msc;
DBG(("%s: draw=%ld, pixmap=%ld, back=%u (refs=%d/%d, flush=%d) , fron=%u (refs=%d/%d, flush=%d)\n",
@@ -2319,11 +2356,13 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
assert(get_private(front)->bo->flush);
assert(get_private(back)->bo->refcnt);
- assert(get_private(back)->bo->flush);
if (get_private(front)->pixmap != get_drawable_pixmap(draw))
goto skip;
+ if (get_private(back)->stale)
+ goto skip;
+
assert(sna_pixmap_from_drawable(draw)->flush);
/* Drawable not displayed... just complete the swap */
@@ -2334,6 +2373,12 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
goto blit;
}
+ if (can_xchg(sna, draw, front, back) &&
+ sna_dri2_schedule_xchg(client, draw, crtc, front, back,
+ target_msc, divisor, remainder,
+ func, data))
+ return TRUE;
+
if (can_flip(sna, draw, front, back, crtc) &&
sna_dri2_schedule_flip(client, draw, crtc, front, back,
target_msc, divisor, remainder,
@@ -2342,7 +2387,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
VG_CLEAR(vbl);
- info = sna_dri2_add_frame_event(draw, client);
+ info = sna_dri2_add_event(draw, client);
if (!info)
goto blit;
@@ -2353,21 +2398,18 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
info->front = sna_dri2_reference_buffer(front);
info->back = sna_dri2_reference_buffer(back);
- info->type = SWAP;
-
if (immediate_swap(sna, *target_msc, divisor, draw, crtc, &current_msc)) {
bool sync = current_msc < *target_msc;
if (!sna_dri2_immediate_blit(sna, info, sync, true))
- sna_dri2_frame_event_info_free(sna, draw, info);
- if (*target_msc)
- *target_msc = current_msc + sync;
+ sna_dri2_event_free(sna, draw, info);
+ *target_msc = current_msc + sync;
return TRUE;
}
vbl.request.type =
DRM_VBLANK_ABSOLUTE |
DRM_VBLANK_EVENT;
- vbl.request.signal = (unsigned long)info;
+ vbl.request.signal = (uintptr_t)info;
/*
* If divisor is zero, or current_msc is smaller than target_msc
@@ -2391,7 +2433,7 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
if (*target_msc <= current_msc + 1) {
DBG(("%s: performing blit before queueing\n", __FUNCTION__));
info->bo = __sna_dri2_copy_region(sna, draw, NULL,
- info->back, info->front,
+ back, front,
true);
info->type = SWAP_WAIT;
@@ -2414,7 +2456,7 @@ blit:
DBG(("%s -- blit\n", __FUNCTION__));
__sna_dri2_copy_region(sna, draw, NULL, back, front, false);
if (info)
- sna_dri2_frame_event_info_free(sna, draw, info);
+ sna_dri2_event_free(sna, draw, info);
skip:
DBG(("%s: unable to show frame, unblocking client\n", __FUNCTION__));
if (crtc == NULL)
@@ -2469,7 +2511,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
CARD64 divisor, CARD64 remainder)
{
struct sna *sna = to_sna_from_drawable(draw);
- struct sna_dri2_frame_event *info = NULL;
+ struct sna_dri2_event *info = NULL;
xf86CrtcPtr crtc;
CARD64 current_msc;
union drm_wait_vblank vbl;
@@ -2508,14 +2550,14 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
if (divisor == 0 && current_msc >= target_msc)
goto out_complete;
- info = sna_dri2_add_frame_event(draw, client);
+ info = sna_dri2_add_event(draw, client);
if (!info)
goto out_complete;
assert(info->crtc == crtc);
info->type = WAITMSC;
- vbl.request.signal = (unsigned long)info;
+ vbl.request.signal = (uintptr_t)info;
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
/*
* If divisor is zero, or current_msc is smaller than target_msc,
@@ -2543,7 +2585,7 @@ sna_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc
return TRUE;
out_free_info:
- sna_dri2_frame_event_info_free(sna, draw, info);
+ sna_dri2_event_free(sna, draw, info);
out_complete:
if (crtc == NULL)
crtc = sna_mode_first_crtc(sna);
@@ -2719,18 +2761,6 @@ bool sna_dri2_open(struct sna *sna, ScreenPtr screen)
return DRI2ScreenInit(screen, &info);
}
-void sna_dri2_reset_scanout(struct sna *sna)
-{
- if (sna->dri2.scanout[1].bo != NULL) {
- kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[1].bo);
- sna->dri2.scanout[1].bo = NULL;
- }
- if (sna->dri2.scanout[0].bo != NULL) {
- kgem_bo_destroy(&sna->kgem, sna->dri2.scanout[0].bo);
- sna->dri2.scanout[0].bo = NULL;
- }
-}
-
void sna_dri2_close(struct sna *sna, ScreenPtr screen)
{
DBG(("%s()\n", __FUNCTION__));
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index 7a58a86d..b9232360 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -196,7 +196,7 @@ static Bool sna_set_desired_mode(struct sna *sna)
sna_set_fallback_mode(scrn);
}
- sna_mode_update(sna);
+ sna_mode_check(sna);
return TRUE;
}
@@ -281,6 +281,19 @@ static Bool sna_create_screen_resources(ScreenPtr screen)
return TRUE;
}
+static Bool sna_save_screen(ScreenPtr screen, int mode)
+{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+
+ DBG(("%s(mode=%d)\n", __FUNCTION__, mode));
+ if (!scrn->vtSema)
+ return FALSE;
+
+ xf86SaveScreen(screen, mode);
+ sna_crtc_config_notify(screen);
+ return TRUE;
+}
+
static void sna_selftest(void)
{
sna_damage_selftest();
@@ -671,7 +684,7 @@ static bool has_shadow(struct sna *sna)
if (RegionNil(DamageRegion(sna->mode.shadow_damage)))
return false;
- return sna->mode.shadow_flip == 0;
+ return sna->mode.flip_active == 0;
}
static void
@@ -756,7 +769,7 @@ sna_handle_uevents(int fd, void *closure)
DBG(("%s: hotplug event (vtSema?=%d)\n",
__FUNCTION__, sna->scrn->vtSema));
if (sna->scrn->vtSema) {
- sna_mode_update(sna);
+ sna_mode_check(sna);
RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
} else
sna->flags |= SNA_REPROBE;
@@ -1084,7 +1097,7 @@ sna_screen_init(SCREEN_INIT_ARGS_DECL)
sna->WakeupHandler = screen->WakeupHandler;
screen->WakeupHandler = sna_wakeup_handler;
- screen->SaveScreen = xf86SaveScreen;
+ screen->SaveScreen = sna_save_screen;
screen->CreateScreenResources = sna_create_screen_resources;
sna->CloseScreen = screen->CloseScreen;
diff --git a/src/sna/sna_present.c b/src/sna/sna_present.c
index cacef789..5379d1e8 100644
--- a/src/sna/sna_present.c
+++ b/src/sna/sna_present.c
@@ -39,10 +39,7 @@ static present_screen_info_rec present_info;
struct sna_present_event {
uint64_t event_id;
- unsigned int count;
xf86CrtcPtr crtc;
- uint64_t msc;
- uint64_t ust;
};
static inline struct sna_present_event *
@@ -287,7 +284,7 @@ page_flip__async(RRCrtcPtr crtc,
(long long)event_id,
bo->handle));
- if (!sna_page_flip(to_sna_from_screen(crtc->pScreen), bo, NULL, -1)) {
+ if (!sna_page_flip(to_sna_from_screen(crtc->pScreen), bo, NULL, NULL)) {
DBG(("%s: async pageflip failed\n", __FUNCTION__));
present_info.capabilities &= ~PresentCapabilityAsync;
return FALSE;
@@ -297,28 +294,27 @@ page_flip__async(RRCrtcPtr crtc,
return TRUE;
}
-void
-sna_present_flip_handler(struct sna *sna, struct drm_event_vblank *event)
+static void
+present_flip_handler(struct sna *sna,
+ struct drm_event_vblank *event,
+ void *data)
{
- struct sna_present_event *info = to_present_event(event->user_data);
+ struct sna_present_event *info = data;
+ struct ust_msc swap;
- DBG(("%s(count=%d, ref-pipe?=%d)\n", __FUNCTION__,
- info->count, event->user_data & 1));
-
- if (event->user_data & 1) {
- info->msc = sna_crtc_record_event(info->crtc, event);
- info->ust = ust64(event->tv_sec, event->tv_usec);
- }
+ DBG(("%s(sequence=%d)\n", __FUNCTION__, event->sequence));
- if (--info->count)
- return;
+ if (info->crtc == NULL) {
+ swap.tv_sec = event->tv_sec;
+ swap.tv_usec = event->tv_usec;
+ swap.msc = event->sequence;
+ } else
+ swap = *sna_crtc_last_swap(info->crtc);
DBG(("%s: pipe=%d, tv=%d.%06d msc %lld, complete\n", __FUNCTION__,
info->crtc ? sna_crtc_to_pipe(info->crtc) : -1,
- info->crtc ? (int)(info->ust / 1000000) : event->tv_sec,
- info->crtc ? (int)(info->ust % 1000000) : event->tv_usec,
- info->crtc ? (long long)info->msc : (long long)event->sequence));
- present_event_notify(info->event_id, info->ust, info->msc);
+ swap.tv_sec, swap.tv_usec, (long long)swap.msc));
+ present_event_notify(info->event_id, ust64(swap.tv_sec, swap.tv_usec), swap.msc);
free(info);
}
@@ -343,10 +339,7 @@ page_flip(ScreenPtr screen,
event->event_id = event_id;
event->crtc = crtc ? crtc->devPrivate : NULL;
- event->count = sna_page_flip(sna, bo,
- MARK_PRESENT(event),
- crtc ? sna_crtc_to_pipe(event->crtc) : -1);
- if (event->count == 0) {
+ if (!sna_page_flip(sna, bo, present_flip_handler, event)) {
DBG(("%s: pageflip failed\n", __FUNCTION__));
free(event);
return FALSE;
diff --git a/src/sna/sna_render.c b/src/sna/sna_render.c
index bf170690..b03134d6 100644
--- a/src/sna/sna_render.c
+++ b/src/sna/sna_render.c
@@ -777,7 +777,7 @@ static int sna_render_picture_downsample(struct sna *sna,
goto fixup;
}
- if (!sna_pixmap_force_to_gpu(pixmap, MOVE_SOURCE_HINT | MOVE_READ)) {
+ if (!sna_pixmap_move_to_gpu(pixmap, MOVE_SOURCE_HINT | MOVE_READ)) {
fixup:
DBG(("%s: unable to create GPU bo for target or temporary pixmaps\n",
__FUNCTION__));