summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2011-06-11 10:15:14 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2011-06-12 10:44:18 +0100
commitff262aca9c46b7616c59d8e8f04d33a5bbc6e324 (patch)
tree0f77136a1b116aa20971383940994b5c56c5c665
parentb199bc2b415fd0f06e456e0b1f44dd25ba8dbe02 (diff)
sna/dri: Fix tripple-buffering for vblank_mode=0
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/kgem.c23
-rw-r--r--src/sna/kgem.h6
-rw-r--r--src/sna/sna.h16
-rw-r--r--src/sna/sna_accel.c2
-rw-r--r--src/sna/sna_display.c203
-rw-r--r--src/sna/sna_dri.c517
-rw-r--r--src/sna/sna_driver.c33
-rw-r--r--src/sna/sna_video_textured.c7
8 files changed, 400 insertions, 407 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index d6009368..8a8bca2a 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -515,6 +515,7 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
bo->deleted = 1;
}
+ kgem->need_expire = true;
list_move(&bo->list, (bo->rq || bo->needs_flush) ? &kgem->active : inactive(kgem, bo->size));
if (bo->rq == NULL && bo->needs_flush) {
assert(list_is_empty(&bo->request));
@@ -943,21 +944,6 @@ void kgem_throttle(struct kgem *kgem)
}
}
-bool kgem_needs_expire(struct kgem *kgem)
-{
- int i;
-
- if (!list_is_empty(&kgem->active))
- return true;
-
- for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) {
- if (!list_is_empty(&kgem->inactive[i]))
- return true;
- }
-
- return false;
-}
-
bool kgem_expire_cache(struct kgem *kgem)
{
time_t now, expire;
@@ -1018,6 +1004,7 @@ bool kgem_expire_cache(struct kgem *kgem)
DBG(("%s: purge? %d -- expired %d objects, %d bytes\n", __FUNCTION__, kgem->need_purge, count, size));
+ kgem->need_expire = !idle;
kgem->need_purge = false;
return idle;
(void)count;
@@ -1539,7 +1526,11 @@ uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo)
if (ret)
return 0;
- bo->reusable = false;
+ /* Ordinarily giving the name aware makes the buffer non-reusable.
+ * However, we track the lifetime of all clients and their hold
+ * on the buffer, and *presuming* they do not pass it on to a third
+ * party, we track the lifetime accurately.
+ */
return flink.name;
}
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index fc1c38cc..eb16ceb8 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -97,8 +97,9 @@ struct kgem {
uint16_t nreloc;
uint16_t nfence;
- uint32_t flush;
- uint32_t need_purge;
+ uint32_t flush:1;
+ uint32_t need_expire:1;
+ uint32_t need_purge:1;
uint32_t has_vmap :1;
uint32_t has_relaxed_fencing :1;
@@ -312,7 +313,6 @@ struct kgem_bo *kgem_create_buffer(struct kgem *kgem,
void kgem_buffer_sync(struct kgem *kgem, struct kgem_bo *bo);
void kgem_throttle(struct kgem *kgem);
-bool kgem_needs_expire(struct kgem *kgem);
bool kgem_expire_cache(struct kgem *kgem);
#if HAS_EXTRA_DEBUG
diff --git a/src/sna/sna.h b/src/sna/sna.h
index 844705d7..1173b7b2 100644
--- a/src/sna/sna.h
+++ b/src/sna/sna.h
@@ -120,13 +120,6 @@ static inline void list_add_tail(struct list *new, struct list *head)
__list_add(new, head->prev, head);
}
-enum DRI2FrameEventType {
- DRI2_SWAP,
- DRI2_ASYNC_SWAP,
- DRI2_FLIP,
- DRI2_WAITMSC,
-};
-
#ifndef CREATE_PIXMAP_USAGE_SCRATCH_HEADER
#define CREATE_PIXMAP_USAGE_SCRATCH_HEADER -1
#endif
@@ -182,7 +175,6 @@ enum {
OPTION_PREFER_OVERLAY,
OPTION_COLOR_KEY,
OPTION_VIDEO_KEY,
- OPTION_SWAPBUFFERS_WAIT,
OPTION_HOTPLUG,
OPTION_THROTTLE,
OPTION_RELAXED_FENCING,
@@ -201,7 +193,6 @@ struct sna {
unsigned flags;
#define SNA_NO_THROTTLE 0x1
-#define SNA_SWAP_WAIT 0x2
int timer[NUM_TIMERS];
int timer_active;
@@ -222,9 +213,6 @@ struct sna {
struct sna_dri {
int flip_pending[2];
- unsigned int fe_frame;
- unsigned int fe_tv_sec;
- unsigned int fe_tv_usec;
} dri;
unsigned int tiling;
@@ -239,7 +227,9 @@ struct sna {
struct intel_chipset chipset;
ScreenBlockHandlerProcPtr BlockHandler;
+ void *BlockData;
ScreenWakeupHandlerProcPtr WakeupHandler;
+ void *WakeupData;
CloseScreenProcPtr CloseScreen;
union {
@@ -315,7 +305,7 @@ extern xf86CrtcPtr sna_covering_crtc(ScrnInfoPtr scrn,
BoxPtr crtc_box_ret);
extern bool sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
- xf86CrtcPtr crtc, RegionPtr clip);
+ xf86CrtcPtr crtc, const BoxRec *clip);
Bool sna_dri_open(struct sna *sna, ScreenPtr pScreen);
void sna_dri_wakeup(struct sna *sna);
diff --git a/src/sna/sna_accel.c b/src/sna/sna_accel.c
index d84d7031..8a8165e8 100644
--- a/src/sna/sna_accel.c
+++ b/src/sna/sna_accel.c
@@ -3131,7 +3131,7 @@ static Bool sna_accel_do_expire(struct sna *sna)
return_if_timer_active(EXPIRE_TIMER);
- if (!kgem_needs_expire(&sna->kgem))
+ if (!sna->kgem.need_expire)
return FALSE;
if (sna->timer[EXPIRE_TIMER] == -1)
diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c
index 6131be19..bf0b98ff 100644
--- a/src/sna/sna_display.c
+++ b/src/sna/sna_display.c
@@ -1310,11 +1310,8 @@ sna_output_init(ScrnInfoPtr scrn, struct sna_mode *mode, int num)
if (xf86IsEntityShared(scrn->entityList[0])) {
s = xf86GetOptValString(sna->Options, OPTION_ZAPHOD);
- if (s && !sna_zaphod_match(scrn, s, name)) {
- ErrorF("output '%s' not matched for zaphod '%s'\n",
- name, s);
+ if (s && !sna_zaphod_match(scrn, s, name))
goto cleanup_encoder;
- }
}
output = xf86OutputCreate(scrn, &sna_output_funcs, name);
@@ -1492,7 +1489,8 @@ static int do_page_flip(struct sna *sna, void *data, int ref_crtc_hw_id)
struct sna_crtc *crtc = config->crtc[i]->driver_private;
uintptr_t evdata;
- if (!config->crtc[i]->enabled)
+ DBG(("%s: crtc %d active? %d\n",__FUNCTION__, i,crtc->active));
+ if (!crtc->active)
continue;
/* Only the reference crtc will finally deliver its page flip
@@ -1510,8 +1508,12 @@ static int do_page_flip(struct sna *sna, void *data, int ref_crtc_hw_id)
sna->mode.fb_id,
DRM_MODE_PAGE_FLIP_EVENT,
(void*)evdata)) {
+ int err = errno;
+ DBG(("%s: flip [fb=%d] on crtc %d [%d] failed - %d\n",
+ __FUNCTION__, sna->mode.fb_id,
+ i, crtc_id(crtc), err));
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
- "flip queue failed: %s\n", strerror(errno));
+ "flip queue failed: %s\n", strerror(err));
continue;
}
@@ -1531,11 +1533,12 @@ sna_do_pageflip(struct sna *sna,
{
ScrnInfoPtr scrn = sna->scrn;
struct sna_mode *mode = &sna->mode;
- struct kgem_bo *bo = sna_pixmap_pin(pixmap);
+ struct kgem_bo *bo;
int count;
assert(pixmap != sna->front);
+ bo = sna_pixmap_pin(pixmap);
if (!bo)
return 0;
@@ -1574,20 +1577,13 @@ sna_do_pageflip(struct sna *sna,
* may never complete; this is a configuration error.
*/
count = do_page_flip(sna, data, ref_crtc_hw_id);
+ DBG(("%s: page flipped %d crtcs\n", __FUNCTION__, count));
if (count > 0) {
- int id = sna->front->drawable.serialNumber;
-
sna->front = pixmap;
pixmap->refcnt++;
sna_redirect_screen_pixmap(scrn, *old_front, sna->front);
scrn->displayWidth = bo->pitch / sna->mode.cpp;
-
- /* DRI2 uses the serialNumber as a means for detecting
- * when to revoke its buffers after a reconfigureatin event.
- * For the ScreenPixmap this means set_size.
- */
- pixmap->drawable.serialNumber = id;
} else {
drmModeRmFB(sna->kgem.fd, mode->fb_id);
mode->fb_id = *old_fb;
@@ -1683,11 +1679,23 @@ static void sna_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box)
{
if (crtc->enabled) {
crtc_box->x1 = crtc->x;
- crtc_box->x2 =
- crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation);
crtc_box->y1 = crtc->y;
- crtc_box->y2 =
- crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation);
+
+ switch (crtc->rotation & 0xf) {
+ default:
+ assert(0);
+ case RR_Rotate_0:
+ case RR_Rotate_180:
+ crtc_box->x2 = crtc->x + crtc->mode.HDisplay;
+ crtc_box->y2 = crtc->y + crtc->mode.VDisplay;
+ break;
+
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ crtc_box->x2 = crtc->x + crtc->mode.VDisplay;
+ crtc_box->y2 = crtc->y + crtc->mode.HDisplay;
+ break;
+ }
} else
crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0;
}
@@ -1781,74 +1789,51 @@ sna_covering_crtc(ScrnInfoPtr scrn,
return best_crtc;
}
-bool
-sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
- xf86CrtcPtr crtc, RegionPtr clip)
-{
- pixman_box16_t box, crtc_box;
- int pipe, event;
- Bool full_height;
- int y1, y2;
- uint32_t *b;
+/* Gen6 wait for scan line support */
+#define MI_LOAD_REGISTER_IMM (0x22<<23)
- /* XXX no wait for scanline support on SNB? */
- if (sna->kgem.gen >= 60)
- return false;
+/* gen6: Scan lines register */
+#define GEN6_PIPEA_SLC (0x7004)
+#define GEN6_PIPEB_SLC (0x7104)
- if (!pixmap_is_scanout(pixmap))
- return false;
+static void sna_emit_wait_for_scanline_gen6(struct sna *sna,
+ int pipe, int y1, int y2,
+ bool full_height)
+{
+ uint32_t event;
+ uint32_t *b;
- if (crtc == NULL) {
- if (clip) {
- crtc_box = *REGION_EXTENTS(NULL, clip);
- } else {
- crtc_box.x1 = 0; /* XXX drawable offsets? */
- crtc_box.y1 = 0;
- crtc_box.x2 = pixmap->drawable.width;
- crtc_box.y2 = pixmap->drawable.height;
- }
- crtc = sna_covering_crtc(sna->scrn, &crtc_box, NULL, &crtc_box);
+ /* We just wait until the trace passes the roi */
+ if (pipe == 0) {
+ pipe = GEN6_PIPEA_SLC;
+ event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
+ } else {
+ pipe = GEN6_PIPEB_SLC;
+ event = MI_WAIT_FOR_PIPEB_SCAN_LINE_WINDOW;
}
- if (crtc == NULL)
- return false;
-
- if (clip) {
- box = *REGION_EXTENTS(unused, clip);
-
- if (crtc->transform_in_use)
- pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
-
- /* We could presume the clip was correctly computed... */
- sna_crtc_box(crtc, &crtc_box);
- sna_box_intersect(&box, &crtc_box, &box);
+ kgem_set_mode(&sna->kgem, KGEM_RENDER);
+ b = kgem_get_batch(&sna->kgem, 4);
+ b[0] = MI_LOAD_REGISTER_IMM | 1;
+ b[1] = pipe;
+ b[2] = y2 - 1;
+ b[3] = MI_WAIT_FOR_EVENT | event;
+ kgem_advance_batch(&sna->kgem, 4);
+}
- /*
- * Make sure we don't wait for a scanline that will
- * never occur
- */
- y1 = (crtc_box.y1 <= box.y1) ? box.y1 - crtc_box.y1 : 0;
- y2 = (box.y2 <= crtc_box.y2) ?
- box.y2 - crtc_box.y1 : crtc_box.y2 - crtc_box.y1;
- if (y2 <= y1)
- return false;
-
- full_height = FALSE;
- if (y1 == 0 && y2 == (crtc_box.y2 - crtc_box.y1))
- full_height = TRUE;
- } else {
- sna_crtc_box(crtc, &crtc_box);
- y1 = crtc_box.y1;
- y2 = crtc_box.y2;
- full_height = TRUE;
- }
+static void sna_emit_wait_for_scanline_gen2(struct sna *sna,
+ int pipe, int y1, int y2,
+ bool full_height)
+{
+ uint32_t event;
+ uint32_t *b;
/*
* Pre-965 doesn't have SVBLANK, so we need a bit
* of extra time for the blitter to start up and
* do its job for a full height blit
*/
- if (sna_crtc_to_pipe(crtc) == 0) {
+ if (pipe == 0) {
pipe = MI_LOAD_SCAN_LINES_DISPLAY_PIPEA;
event = MI_WAIT_FOR_PIPEA_SCAN_LINE_WINDOW;
if (full_height)
@@ -1860,11 +1845,8 @@ sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
event = MI_WAIT_FOR_PIPEB_SVBLANK;
}
- if (crtc->mode.Flags & V_INTERLACE) {
- /* DSL count field lines */
- y1 /= 2;
- y2 /= 2;
- }
+ if (sna->kgem.mode == KGEM_NONE)
+ kgem_set_mode(&sna->kgem, KGEM_BLT);
b = kgem_get_batch(&sna->kgem, 5);
/* The documentation says that the LOAD_SCAN_LINES command
@@ -1875,5 +1857,66 @@ sna_wait_for_scanline(struct sna *sna, PixmapPtr pixmap,
b[3] = (y1 << 16) | (y2-1);
b[4] = MI_WAIT_FOR_EVENT | event;
kgem_advance_batch(&sna->kgem, 5);
+}
+
+bool
+sna_wait_for_scanline(struct sna *sna,
+ PixmapPtr pixmap,
+ xf86CrtcPtr crtc,
+ const BoxRec *clip)
+{
+ pixman_box16_t box, crtc_box;
+ Bool full_height;
+ int y1, y2, pipe;
+
+ if (sna->kgem.gen >= 60)
+ return false;
+
+ if (!pixmap_is_scanout(pixmap))
+ return false;
+
+ if (crtc == NULL) {
+ crtc = sna_covering_crtc(sna->scrn, clip, NULL, &crtc_box);
+ assert(crtc);
+ } else
+ sna_crtc_box(crtc, &crtc_box);
+
+ if (crtc->transform_in_use) {
+ box = *clip;
+ pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
+ clip = &box;
+ }
+
+ /*
+ * Make sure we don't wait for a scanline that will
+ * never occur
+ */
+ y1 = clip->y1 - crtc_box.y1;
+ if (y1 < 0)
+ y1 = 0;
+ y2 = clip->y2 - crtc_box.y1;
+ if (y2 > crtc_box.y2 - crtc_box.y1)
+ y2 = crtc_box.y2 - crtc_box.y1;
+ DBG(("%s: clipped range = %d, %d\n", __FUNCTION__, y1, y2));
+ if (y2 <= y1)
+ return false;
+
+ full_height = y1 == 0 && y2 == crtc_box.y2 - crtc_box.y1;
+
+ if (crtc->mode.Flags & V_INTERLACE) {
+ /* DSL count field lines */
+ y1 /= 2;
+ y2 /= 2;
+ }
+
+ pipe = sna_crtc_to_pipe(crtc);
+ DBG(("%s: pipe=%d, y1=%d, y2=%d, full_height?=%d\n",
+ __FUNCTION__, pipe, y1, y2, full_height));
+
+ if (sna->kgem.gen >= 60)
+ sna_emit_wait_for_scanline_gen6(sna, pipe, y1, y2, full_height);
+ else
+ sna_emit_wait_for_scanline_gen2(sna, pipe, y1, y2, full_height);
+
return true;
}
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index 94cd2059..14a2f3d1 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -77,6 +77,14 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#define NDEBUG 1
#endif
+enum frame_event_type {
+ DRI2_SWAP,
+ DRI2_SWAP_THROTTLE,
+ DRI2_ASYNC_FLIP,
+ DRI2_FLIP,
+ DRI2_WAITMSC,
+};
+
struct sna_dri_private {
int refcnt;
PixmapPtr pixmap;
@@ -88,7 +96,7 @@ struct sna_dri_frame_event {
XID drawable_id;
XID client_id; /* fake client ID to track client destruction */
ClientPtr client;
- enum DRI2FrameEventType type;
+ enum frame_event_type type;
int frame;
int pipe;
int count;
@@ -99,6 +107,10 @@ struct sna_dri_frame_event {
DRI2BufferPtr front;
DRI2BufferPtr back;
+ unsigned int fe_frame;
+ unsigned int fe_tv_sec;
+ unsigned int fe_tv_usec;
+
PixmapPtr old_front;
uint32_t old_fb;
};
@@ -291,13 +303,11 @@ static void sna_dri_reference_buffer(DRI2Buffer2Ptr buffer)
}
}
-static void damage(DrawablePtr drawable, RegionPtr region)
+static void damage(DrawablePtr drawable, PixmapPtr pixmap, RegionPtr region)
{
- PixmapPtr pixmap;
struct sna_pixmap *priv;
int16_t dx, dy;
- pixmap = get_drawable_pixmap(drawable);
get_drawable_deltas(drawable, pixmap, &dx, &dy);
priv = sna_pixmap(pixmap);
@@ -350,51 +360,65 @@ static void damage(DrawablePtr drawable, RegionPtr region)
}
static void
-sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
- DRI2BufferPtr dst_buffer, DRI2BufferPtr src_buffer)
+sna_dri_copy_region(DrawablePtr draw,
+ RegionPtr region,
+ DRI2BufferPtr dst_buffer,
+ DRI2BufferPtr src_buffer)
{
- struct sna *sna = to_sna_from_drawable(drawable);
- struct sna_dri_private *srcPrivate = src_buffer->driverPrivate;
- struct sna_dri_private *dstPrivate = dst_buffer->driverPrivate;
- ScreenPtr screen = drawable->pScreen;
- DrawablePtr src = (src_buffer->attachment == DRI2BufferFrontLeft)
- ? drawable : &srcPrivate->pixmap->drawable;
- DrawablePtr dst = (dst_buffer->attachment == DRI2BufferFrontLeft)
- ? drawable : &dstPrivate->pixmap->drawable;
- GCPtr gc;
- bool flush = false;
+ struct sna *sna = to_sna_from_drawable(draw);
+ struct sna_dri_private *src_priv = src_buffer->driverPrivate;
+ struct sna_dri_private *dst_priv = dst_buffer->driverPrivate;
+ PixmapPtr src = src_priv->pixmap;
+ PixmapPtr dst = dst_priv->pixmap;
+ pixman_region16_t clip;
DBG(("%s(region=(%d, %d), (%d, %d)))\n", __FUNCTION__,
region ? REGION_EXTENTS(NULL, region)->x1 : 0,
region ? REGION_EXTENTS(NULL, region)->y1 : 0,
- region ? REGION_EXTENTS(NULL, region)->x2 : dst->width,
- region ? REGION_EXTENTS(NULL, region)->y2 : dst->height));
+ region ? REGION_EXTENTS(NULL, region)->x2 : draw->width,
+ region ? REGION_EXTENTS(NULL, region)->y2 : draw->height));
DBG(("%s: dst -- attachment=%d, name=%d, handle=%d\n",
__FUNCTION__,
dst_buffer->attachment,
dst_buffer->name,
- dstPrivate->bo->handle));
+ dst_priv->bo->handle));
DBG(("%s: src -- attachment=%d, name=%d, handle=%d\n",
__FUNCTION__,
src_buffer->attachment,
src_buffer->name,
- srcPrivate->bo->handle));
+ src_priv->bo->handle));
- gc = GetScratchGC(dst->depth, screen);
- if (!gc)
- return;
-
- if (region) {
- RegionPtr clip;
+ if (draw->type == DRAWABLE_WINDOW) {
+ WindowPtr win = (WindowPtr)draw;
- clip = REGION_CREATE(screen, NULL, 0);
- pixman_region_intersect_rect(clip, region,
- 0, 0, dst->width, dst->height);
- (*gc->funcs->ChangeClip)(gc, CT_REGION, clip, 0);
- region = clip;
+ pixman_region_init(&clip);
+ pixman_region_intersect(&clip, &win->clipList, region);
+ if (!pixman_region_not_empty(&clip)) {
+ DBG(("%s: all clipped\n", __FUNCTION__));
+ return;
+ }
+ region = &clip;
}
- ValidateGC(dst, gc);
+
+ assert(sna_pixmap(src)->cpu_damage == NULL);
+ assert(sna_pixmap(dst)->cpu_damage == NULL);
+
+ /* 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
+ * client will wait for the DRI2CopyRegion reply or the swap
+ * buffer event before rendering, and we'll hit the flush
+ * callback chain before those messages are sent. We submit
+ * our batch buffers from the flush callback chain so we know
+ * that will happen before the client tries to render
+ * again.
+ */
+ sna->render.copy_boxes(sna, GXcopy,
+ src, src_priv->bo, draw->x, draw->y,
+ dst, dst_priv->bo, draw->x, draw->y,
+ REGION_RECTS(region),
+ REGION_NUM_RECTS(region));
/* Invalidate src to reflect unknown modifications made by the client
*
@@ -402,12 +426,46 @@ sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
* between the last flush and this request? Hopefully nobody will
* hit that race window to find out...
*/
- damage(src, region);
+ damage(draw, src, region);
+ damage(draw, dst, region);
+ if (region == &clip)
+ pixman_region_fini(&clip);
+}
+
+static void
+sna_dri_swap_blit(struct sna *sna, DrawablePtr draw, DRI2BufferPtr back)
+{
+ struct sna_dri_private *src_priv = back->driverPrivate;
+ PixmapPtr src = src_priv->pixmap;
+ PixmapPtr dst = sna->front;
+ bool flush = false;
+ BoxRec box, *boxes;
+ int n;
+
+ DBG(("%s: back -- attachment=%d, name=%d, handle=%d\n",
+ __FUNCTION__,
+ back->attachment,
+ back->name,
+ src_priv->bo->handle));
+
+ if (draw->type == DRAWABLE_PIXMAP) {
+ box.x1 = box.y1 = 0;
+ box.x2 = draw->width;
+ box.y2 = draw->height;
+
+ boxes = &box;
+ n = 1;
+ } else {
+ WindowPtr win = (WindowPtr)draw;
+
+ boxes = REGION_RECTS(&win->clipList);
+ n = REGION_NUM_RECTS(&win->clipList);
+ if (n == 0)
+ return;
- /* Wait for the scanline to be outside the region to be copied */
- if (sna->flags & SNA_SWAP_WAIT)
- flush = sna_wait_for_scanline(sna, get_drawable_pixmap(dst),
- NULL, region);
+ flush = sna_wait_for_scanline(sna, sna->front,
+ NULL, &win->clipList.extents);
+ }
/* It's important that this copy gets submitted before the
* direct rendering client submits rendering for the next
@@ -419,11 +477,19 @@ sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
* that will happen before the client tries to render
* again.
*/
- gc->ops->CopyArea(src, dst, gc,
- 0, 0,
- drawable->width, drawable->height,
- 0, 0);
- FreeScratchGC(gc);
+ sna->render.copy_boxes(sna, GXcopy,
+ src, src_priv->bo, draw->x, draw->y,
+ dst, sna_pixmap_get_bo(dst), draw->x, draw->y,
+ boxes, n);
+
+ /* Invalidate src to reflect unknown modifications made by the client
+ *
+ * XXX But what about any conflicting shadow writes made by others
+ * between the last flush and this request? Hopefully nobody will
+ * hit that race window to find out...
+ */
+ damage(draw, src, NULL);
+ damage(draw, dst, NULL);
DBG(("%s: flushing? %d\n", __FUNCTION__, flush));
if (flush) /* STAT! */
@@ -432,12 +498,10 @@ sna_dri_copy_region(DrawablePtr drawable, RegionPtr region,
#if DRI2INFOREC_VERSION >= 4
-
static int
sna_dri_get_pipe(DrawablePtr pDraw)
{
- ScreenPtr pScreen = pDraw->pScreen;
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ ScrnInfoPtr pScrn = xf86Screens[pDraw->pScreen->myNum];
BoxRec box, crtcbox;
xf86CrtcPtr crtc;
int pipe;
@@ -533,7 +597,7 @@ sna_dri_add_frame_event(struct sna_dri_frame_event *frame_event)
}
static void
-sna_dri_frame_event_info(struct sna_dri_frame_event *info)
+sna_dri_frame_event_info_free(struct sna_dri_frame_event *info)
{
if (info->client_id)
FreeResourceByType(info->client_id,
@@ -559,7 +623,8 @@ sna_dri_exchange_buffers(DrawablePtr draw,
{
int tmp;
- DBG(("%s()\n", __FUNCTION__));
+ DBG(("%s(%d <--> %d)\n",
+ __FUNCTION__, front->attachment, back->attachment));
assert(front->format == back->format);
@@ -577,83 +642,21 @@ sna_dri_schedule_flip(struct sna *sna,
DrawablePtr draw,
struct sna_dri_frame_event *info)
{
- struct sna_dri *dri = &sna->dri;
struct sna_dri_private *back_priv;
- /* Main crtc for this drawable shall finally deliver pageflip event. */
- int ref_crtc_hw_id = sna_dri_get_pipe(draw);
-
DBG(("%s()\n", __FUNCTION__));
- dri->fe_frame = 0;
- dri->fe_tv_sec = 0;
- dri->fe_tv_usec = 0;
-
/* Page flip the full screen buffer */
back_priv = info->back->driverPrivate;
info->count = sna_do_pageflip(sna,
back_priv->pixmap,
- info, ref_crtc_hw_id,
+ info, info->pipe,
&info->old_front,
&info->old_fb);
return info->count != 0;
}
static Bool
-can_exchange(DRI2BufferPtr front,
- DRI2BufferPtr back)
-{
- struct sna_dri_private *front_priv = front->driverPrivate;
- struct sna_dri_private *back_priv = back->driverPrivate;
- PixmapPtr front_pixmap = front_priv->pixmap;
- PixmapPtr back_pixmap = back_priv->pixmap;
- struct sna_pixmap *front_sna, *back_sna;
-
- if (front_pixmap->drawable.width != back_pixmap->drawable.width) {
- DBG(("%s -- no, size mismatch: front width=%d, back=%d\n",
- __FUNCTION__,
- front_pixmap->drawable.width,
- back_pixmap->drawable.width));
- return FALSE;
- }
-
- if (front_pixmap->drawable.height != back_pixmap->drawable.height) {
- DBG(("%s -- no, size mismatch: front height=%d, back=%d\n",
- __FUNCTION__,
- front_pixmap->drawable.height,
- back_pixmap->drawable.height));
- return FALSE;
- }
-
- if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel) {
- DBG(("%s -- no, depth mismatch: front bpp=%d, back=%d\n",
- __FUNCTION__,
- front_pixmap->drawable.bitsPerPixel,
- back_pixmap->drawable.bitsPerPixel));
- return FALSE;
- }
-
- /* prevent an implicit tiling mode change */
- front_sna = sna_pixmap(front_pixmap);
- back_sna = sna_pixmap(back_pixmap);
- if (front_sna->gpu_bo->tiling != back_sna->gpu_bo->tiling) {
- DBG(("%s -- no, tiling mismatch: front %d, back=%d\n",
- __FUNCTION__,
- front_sna->gpu_bo->tiling,
- back_sna->gpu_bo->tiling));
- return FALSE;
- }
-
- if (front_sna->gpu_only != back_sna->gpu_only) {
- DBG(("%s -- no, mismatch in gpu_only: front %d, back=%d\n",
- __FUNCTION__, front_sna->gpu_only, back_sna->gpu_only));
- return FALSE;
- }
-
- return TRUE;
-}
-
-static Bool
can_flip(struct sna * sna,
DrawablePtr draw,
DRI2BufferPtr front,
@@ -773,78 +776,59 @@ static void sna_dri_vblank_handle(int fd,
unsigned int tv_usec,
void *data)
{
- struct sna_dri_frame_event *swap_info = data;
+ struct sna_dri_frame_event *info = data;
DrawablePtr draw;
- ScreenPtr screen;
- ScrnInfoPtr scrn;
struct sna *sna;
int status;
DBG(("%s(id=%d, type=%d)\n", __FUNCTION__,
- (int)swap_info->drawable_id, swap_info->type));
+ (int)info->drawable_id, info->type));
status = BadDrawable;
- if (swap_info->drawable_id)
+ if (info->drawable_id)
status = dixLookupDrawable(&draw,
- swap_info->drawable_id,
+ info->drawable_id,
serverClient,
M_ANY, DixWriteAccess);
if (status != Success)
goto done;
- screen = draw->pScreen;
- scrn = xf86Screens[screen->myNum];
- sna = to_sna(scrn);
+ sna = to_sna_from_drawable(draw);
- switch (swap_info->type) {
+ switch (info->type) {
case DRI2_FLIP:
/* If we can still flip... */
- if (can_flip(sna, draw,
- swap_info->front, swap_info->back) &&
- sna_dri_schedule_flip(sna, draw, swap_info)) {
- sna_dri_exchange_buffers(draw,
- swap_info->front,
- swap_info->back);
+ if (can_flip(sna, draw, info->front, info->back) &&
+ sna_dri_schedule_flip(sna, draw, info)) {
+ sna_dri_exchange_buffers(draw, info->front, info->back);
return;
}
/* else fall through to exchange/blit */
- case DRI2_SWAP: {
- int swap_type;
-
- if (DRI2CanExchange(draw) &&
- can_exchange(swap_info->front, swap_info->back)) {
- sna_dri_exchange_buffers(draw,
- swap_info->front,
- swap_info->back);
- swap_type = DRI2_EXCHANGE_COMPLETE;
- } else {
- sna_dri_copy_region(draw, NULL,
- swap_info->front,
- swap_info->back);
- swap_type = DRI2_BLIT_COMPLETE;
- }
- DRI2SwapComplete(swap_info->client,
+ case DRI2_SWAP:
+ sna_dri_swap_blit(sna, draw, info->back);
+ case DRI2_SWAP_THROTTLE:
+ DRI2SwapComplete(info->client,
draw, frame,
tv_sec, tv_usec,
- swap_type,
- swap_info->client ? swap_info->event_complete : NULL,
- swap_info->event_data);
+ DRI2_BLIT_COMPLETE,
+ info->client ? info->event_complete : NULL,
+ info->event_data);
break;
- }
+
case DRI2_WAITMSC:
- if (swap_info->client)
- DRI2WaitMSCComplete(swap_info->client, draw,
+ if (info->client)
+ DRI2WaitMSCComplete(info->client, draw,
frame, tv_sec, tv_usec);
break;
default:
- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
/* Unknown type */
break;
}
done:
- sna_dri_frame_event_info(swap_info);
+ sna_dri_frame_event_info_free(info);
}
static void sna_dri_flip_event(struct sna *sna,
@@ -855,9 +839,9 @@ static void sna_dri_flip_event(struct sna *sna,
DBG(("%s(frame=%d, tv=%d.%06d, type=%d)\n",
__FUNCTION__,
- sna->dri.fe_frame,
- sna->dri.fe_tv_sec,
- sna->dri.fe_tv_usec,
+ flip->fe_frame,
+ flip->fe_tv_sec,
+ flip->fe_tv_usec,
flip->type));
if (!flip->drawable_id)
@@ -878,8 +862,8 @@ static void sna_dri_flip_event(struct sna *sna,
* into account. This usually means some defective kms pageflip completion,
* causing wrong (msc, ust) return values and possible visual corruption.
*/
- if ((sna->dri.fe_frame < flip->frame) &&
- (flip->frame - sna->dri.fe_frame < 5)) {
+ if ((flip->fe_frame < flip->frame) &&
+ (flip->frame - flip->fe_frame < 5)) {
static int limit = 5;
/* XXX we are currently hitting this path with older
@@ -888,25 +872,25 @@ static void sna_dri_flip_event(struct sna *sna,
if (limit) {
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"%s: Pageflip completion has impossible msc %d < target_msc %d\n",
- __func__, sna->dri.fe_frame, flip->frame);
+ __func__, flip->fe_frame, flip->frame);
limit--;
}
/* All-0 values signal timestamping failure. */
- sna->dri.fe_frame = sna->dri.fe_tv_sec = sna->dri.fe_tv_usec = 0;
+ flip->fe_frame = flip->fe_tv_sec = flip->fe_tv_usec = 0;
}
DBG(("%s: flip complete\n", __FUNCTION__));
DRI2SwapComplete(flip->client, drawable,
- sna->dri.fe_frame,
- sna->dri.fe_tv_sec,
- sna->dri.fe_tv_usec,
+ flip->fe_frame,
+ flip->fe_tv_sec,
+ flip->fe_tv_usec,
DRI2_FLIP_COMPLETE,
flip->client ? flip->event_complete : NULL,
flip->event_data);
break;
- case DRI2_ASYNC_SWAP:
+ case DRI2_ASYNC_FLIP:
DBG(("%s: async swap flip completed on pipe %d, pending %d\n",
__FUNCTION__, flip->pipe, sna->dri.flip_pending[flip->pipe]));
sna->dri.flip_pending[flip->pipe]--;
@@ -925,16 +909,15 @@ sna_dri_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *data)
{
struct sna_dri_frame_event *info = to_frame_event(data);
- struct sna_dri *dri = &info->sna->dri;
DBG(("%s: pending flip_count=%d\n", __FUNCTION__, info->count));
/* Is this the event whose info shall be delivered to higher level? */
if ((uintptr_t)data & 1) {
/* Yes: Cache msc, ust for later delivery. */
- dri->fe_frame = frame;
- dri->fe_tv_sec = tv_sec;
- dri->fe_tv_usec = tv_usec;
+ info->fe_frame = frame;
+ info->fe_tv_sec = tv_sec;
+ info->fe_tv_usec = tv_usec;
}
if (--info->count)
@@ -943,7 +926,7 @@ sna_dri_page_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
sna_dri_flip_event(info->sna, info);
sna_mode_delete_fb(info->sna, info->old_front, info->old_fb);
- sna_dri_frame_event_info(info);
+ sna_dri_frame_event_info_free(info);
}
/*
@@ -976,16 +959,20 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
struct sna *sna = to_sna(scrn);
drmVBlank vbl;
int pipe, flip;
- struct sna_dri_frame_event *info;
- enum DRI2FrameEventType swap_type = DRI2_SWAP;
+ struct sna_dri_frame_event *info = NULL;
+ enum frame_event_type swap_type = DRI2_SWAP;
CARD64 current_msc;
- DBG(("%s(target_msc=%llu)\n", __FUNCTION__, (long long)*target_msc));
+ DBG(("%s(target_msc=%llu, divisor=%llu, remainder=%llu)\n",
+ __FUNCTION__,
+ (long long)*target_msc,
+ (long long)divisor,
+ (long long)remainder));
/* Drawable not displayed... just complete the swap */
pipe = sna_dri_get_pipe(draw);
if (pipe == -1)
- goto xchg_fallback;
+ goto blit_fallback;
/* Truncate to match kernel interfaces; means occasional overflow
* misses, but that's generally not a big deal */
@@ -995,7 +982,7 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
info = calloc(1, sizeof(struct sna_dri_frame_event));
if (!info)
- goto xchg_fallback;
+ goto blit_fallback;
info->sna = sna;
info->drawable_id = draw->id;
@@ -1004,10 +991,12 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
info->event_data = data;
info->front = front;
info->back = back;
+ info->pipe = pipe;
if (!sna_dri_add_frame_event(info)) {
free(info);
- goto xchg_fallback;
+ info = NULL;
+ goto blit_fallback;
}
sna_dri_reference_buffer(front);
@@ -1064,8 +1053,23 @@ immediate:
return TRUE;
}
- /* Similarly, the CopyRegion blit is coupled to vsync. */
- goto blit_fallback;
+ DBG(("%s: emitting immediate vsync'ed blit, throttling client\n"));
+
+ info->type = DRI2_SWAP_THROTTLE;
+
+ vbl.request.type =
+ DRM_VBLANK_RELATIVE |
+ DRM_VBLANK_EVENT |
+ DRM_VBLANK_NEXTONMISS;
+ if (pipe > 0)
+ vbl.request.type |= DRM_VBLANK_SECONDARY;
+ vbl.request.sequence = 0;
+ vbl.request.signal = (unsigned long)info;
+ if (drmWaitVBlank(sna->kgem.fd, &vbl))
+ sna_dri_frame_event_info_free(info);
+
+ sna_dri_swap_blit(sna, draw, back);
+ return TRUE;
}
/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
@@ -1126,15 +1130,10 @@ immediate:
blit_fallback:
DBG(("%s -- blit\n", __FUNCTION__));
- sna_dri_copy_region(draw, NULL, front, back);
- sna_dri_frame_event_info(info);
- swap_type = DRI2_BLIT_COMPLETE;
- goto fallback;
-xchg_fallback:
- swap_type = DRI2_EXCHANGE_COMPLETE;
- sna_dri_exchange_buffers(draw, front, back);
-fallback:
- DRI2SwapComplete(client, draw, 0, 0, 0, swap_type, func, data);
+ sna_dri_swap_blit(sna, draw, back);
+ if (info)
+ sna_dri_frame_event_info_free(info);
+ DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data);
*target_msc = 0; /* offscreen, so zero out target vblank count */
return TRUE;
}
@@ -1142,53 +1141,53 @@ fallback:
#if DRI2INFOREC_VERSION >= 6
static void
sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
- DRI2BufferPtr front, DRI2BufferPtr back,
- DRI2SwapEventPtr func, void *data)
+ DRI2BufferPtr front, DRI2BufferPtr back,
+ DRI2SwapEventPtr func, void *data)
{
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
- int pipe = sna_dri_get_pipe(draw);
int type = DRI2_EXCHANGE_COMPLETE;
+ struct sna_dri_private *back_priv = back->driverPrivate;
+ struct sna_dri_private *front_priv = front->driverPrivate;
+ PixmapPtr pixmap;
+ int pipe;
DBG(("%s()\n", __FUNCTION__));
/* Drawable not displayed... just complete the swap */
- if (pipe == -1)
- goto exchange;
-
- if (!can_flip(sna, draw, front, back)) {
- /* Do an synchronous copy instead */
- struct sna_dri_private *front_priv = front->driverPrivate;
- struct sna_dri_private *back_priv = back->driverPrivate;
+ pipe = sna_dri_get_pipe(draw);
+ if (pipe == -1 || !can_flip(sna, draw, front, back)) {
BoxRec box, *boxes;
- PixmapPtr dst;
int n;
- DBG(("%s: fallback blit: %dx%d\n",
- __FUNCTION__, draw->width, draw->height));
-
- /* XXX clipping */
if (draw->type == DRAWABLE_PIXMAP) {
box.x1 = box.y1 = 0;
box.x2 = draw->width;
box.y2 = draw->height;
- dst = front_priv->pixmap;
boxes = &box;
n = 1;
} else {
WindowPtr win = (WindowPtr)draw;
- dst = sna->front;
boxes = REGION_RECTS(&win->clipList);
n = REGION_NUM_RECTS(&win->clipList);
}
- sna->render.copy_boxes(sna, GXcopy,
- back_priv->pixmap, back_priv->bo, 0, 0,
- dst, sna_pixmap_get_bo(dst), 0, 0,
- boxes, n);
+ DBG(("%s: fallback blit: %dx%d\n",
+ __FUNCTION__, draw->width, draw->height));
+
+ if (n) {
+ sna->render.copy_boxes(sna, GXcopy,
+ back_priv->pixmap,
+ back_priv->bo,
+ 0, 0,
+ front_priv->pixmap,
+ front_priv->bo,
+ 0, 0,
+ boxes, n);
+ }
DRI2SwapComplete(client, draw, 0, 0, 0,
DRI2_BLIT_COMPLETE, func, data);
@@ -1197,72 +1196,60 @@ sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
if (!sna->dri.flip_pending[pipe]) {
struct sna_dri_frame_event *info;
- struct sna_dri_private *back_priv = back->driverPrivate;
- struct sna_pixmap *priv;
- PixmapPtr src = back_priv->pixmap;
- PixmapPtr copy;
- BoxRec box;
+ DRI2BufferPtr t;
DBG(("%s: no pending flip on pipe %d, so updating scanout\n",
__FUNCTION__, pipe));
- copy = screen->CreatePixmap(screen,
- src->drawable.width,
- src->drawable.height,
- src->drawable.depth,
- SNA_CREATE_FB);
- if (copy == NullPixmap)
- goto exchange;
-
- priv = sna_pixmap_force_to_gpu(copy);
- if (priv == NULL) {
- screen->DestroyPixmap(copy);
- goto exchange;
- }
-
- box.x1 = box.y1 = 0;
- box.x2 = src->drawable.width;
- box.y2 = src->drawable.height;
- if (!sna->render.copy_boxes(sna, GXcopy,
- src, back_priv->bo, 0, 0,
- copy, priv->gpu_bo, 0, 0,
- &box, 1)) {
- screen->DestroyPixmap(copy);
- goto exchange;
- }
- sna_damage_all(&priv->gpu_damage,
- src->drawable.width, src->drawable.height);
- assert(priv->cpu_damage == NULL);
-
info = calloc(1, sizeof(struct sna_dri_frame_event));
if (!info) {
- screen->DestroyPixmap(copy);
goto exchange;
}
info->sna = sna;
info->drawable_id = draw->id;
info->client = client;
- info->type = DRI2_ASYNC_SWAP;
+ info->type = DRI2_ASYNC_FLIP;
info->pipe = pipe;
if (!sna_dri_add_frame_event(info)) {
free(info);
- screen->DestroyPixmap(copy);
goto exchange;
}
- info->count = sna_do_pageflip(sna, copy, info, pipe,
+ info->count = sna_do_pageflip(sna, back_priv->pixmap,
+ info, pipe,
&info->old_front, &info->old_fb);
- screen->DestroyPixmap(copy);
if (info->count == 0) {
+ DBG(("%s: pageflip failed\n", __FUNCTION__));
free(info);
goto exchange;
}
type = DRI2_FLIP_COMPLETE;
sna->dri.flip_pending[pipe]++;
+
+ /* and flip the pointers */
+ t = front;
+ front = back;
+ back = t;
+
+ front_priv = front->driverPrivate;
+ back_priv = back->driverPrivate;
+ }
+
+ if (front_priv->pixmap == sna->front &&
+ (pixmap = screen->CreatePixmap(screen,
+ draw->width,
+ draw->height,
+ draw->depth,
+ SNA_CREATE_FB))) {
+ screen->DestroyPixmap(front_priv->pixmap);
+ front_priv->pixmap = pixmap;
+ front_priv->bo = sna_pixmap_set_dri(sna, pixmap);
+ front->name = kgem_bo_flink(&sna->kgem, front_priv->bo);
+ front->pitch = front_priv->bo->pitch;
}
exchange:
@@ -1278,11 +1265,9 @@ exchange:
static int
sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
{
- ScreenPtr screen = draw->pScreen;
- ScrnInfoPtr scrn = xf86Screens[screen->myNum];
- struct sna *sna = to_sna(scrn);
+ struct sna *sna = to_sna_from_drawable(draw);
drmVBlank vbl;
- int ret, pipe = sna_dri_get_pipe(draw);
+ int pipe = sna_dri_get_pipe(draw);
DBG(("%s()\n", __FUNCTION__));
@@ -1298,22 +1283,21 @@ sna_dri_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = 0;
- ret = drmWaitVBlank(sna->kgem.fd, &vbl);
- if (ret) {
+ if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
static int limit = 5;
if (limit) {
- xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"%s:%d get vblank counter failed: %s\n",
__FUNCTION__, __LINE__,
strerror(errno));
limit--;
}
+ DBG(("%s: failed on pipe %d\n", __FUNCTION__, pipe));
return FALSE;
}
*ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
*msc = vbl.reply.sequence;
-
return TRUE;
}
@@ -1330,9 +1314,9 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
ScreenPtr screen = draw->pScreen;
ScrnInfoPtr scrn = xf86Screens[screen->myNum];
struct sna *sna = to_sna(scrn);
- struct sna_dri_frame_event *wait_info;
+ struct sna_dri_frame_event *info;
drmVBlank vbl;
- int ret, pipe = sna_dri_get_pipe(draw);
+ int pipe = sna_dri_get_pipe(draw);
CARD64 current_msc;
DBG(("%s(target_msc=%llu, divisor=%llu, rem=%llu)\n",
@@ -1351,22 +1335,21 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
if (pipe == -1)
goto out_complete;
- wait_info = calloc(1, sizeof(struct sna_dri_frame_event));
- if (!wait_info)
+ info = calloc(1, sizeof(struct sna_dri_frame_event));
+ if (!info)
goto out_complete;
- wait_info->sna = sna;
- wait_info->drawable_id = draw->id;
- wait_info->client = client;
- wait_info->type = DRI2_WAITMSC;
+ info->sna = sna;
+ info->drawable_id = draw->id;
+ info->client = client;
+ info->type = DRI2_WAITMSC;
/* Get current count */
vbl.request.type = DRM_VBLANK_RELATIVE;
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = 0;
- ret = drmWaitVBlank(sna->kgem.fd, &vbl);
- if (ret) {
+ if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
static int limit = 5;
if (limit) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -1398,9 +1381,8 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
if (pipe > 0)
vbl.request.type |= DRM_VBLANK_SECONDARY;
vbl.request.sequence = target_msc;
- vbl.request.signal = (unsigned long)wait_info;
- ret = drmWaitVBlank(sna->kgem.fd, &vbl);
- if (ret) {
+ vbl.request.signal = (unsigned long)info;
+ if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
static int limit = 5;
if (limit) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -1412,7 +1394,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
goto out_complete;
}
- wait_info->frame = vbl.reply.sequence;
+ info->frame = vbl.reply.sequence;
DRI2BlockClient(client, draw);
return TRUE;
}
@@ -1437,9 +1419,8 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
if ((current_msc % divisor) >= remainder)
vbl.request.sequence += divisor;
- vbl.request.signal = (unsigned long)wait_info;
- ret = drmWaitVBlank(sna->kgem.fd, &vbl);
- if (ret) {
+ vbl.request.signal = (unsigned long)info;
+ if (drmWaitVBlank(sna->kgem.fd, &vbl)) {
static int limit = 5;
if (limit) {
xf86DrvMsg(scrn->scrnIndex, X_WARNING,
@@ -1451,7 +1432,7 @@ sna_dri_schedule_wait_msc(ClientPtr client, DrawablePtr draw, CARD64 target_msc,
goto out_complete;
}
- wait_info->frame = vbl.reply.sequence;
+ info->frame = vbl.reply.sequence;
DRI2BlockClient(client, draw);
return TRUE;
diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c
index b9402e75..99701771 100644
--- a/src/sna/sna_driver.c
+++ b/src/sna/sna_driver.c
@@ -84,7 +84,6 @@ static OptionInfoRec sna_options[] = {
{OPTION_PREFER_OVERLAY, "XvPreferOverlay", OPTV_BOOLEAN, {0}, FALSE},
{OPTION_COLOR_KEY, "ColorKey", OPTV_INTEGER, {0}, FALSE},
{OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE},
- {OPTION_SWAPBUFFERS_WAIT, "SwapbuffersWait", OPTV_BOOLEAN, {0}, TRUE},
{OPTION_HOTPLUG, "HotPlug", OPTV_BOOLEAN, {0}, TRUE},
{OPTION_THROTTLE, "Throttle", OPTV_BOOLEAN, {0}, TRUE},
{OPTION_RELAXED_FENCING, "UseRelaxedFencing", OPTV_BOOLEAN, {0}, TRUE},
@@ -502,8 +501,6 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
sna->flags = 0;
if (!xf86ReturnOptValBool(sna->Options, OPTION_THROTTLE, TRUE))
sna->flags |= SNA_NO_THROTTLE;
- if (xf86ReturnOptValBool(sna->Options, OPTION_SWAPBUFFERS_WAIT, TRUE))
- sna->flags |= SNA_SWAP_WAIT;
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Framebuffer %s\n",
sna->tiling & SNA_TILING_FB ? "tiled" : "linear");
@@ -511,8 +508,6 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
sna->tiling & SNA_TILING_2D ? "tiled" : "linear");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "3D buffers %s\n",
sna->tiling & SNA_TILING_3D ? "tiled" : "linear");
- xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "SwapBuffers wait %sabled\n",
- sna->flags & SNA_SWAP_WAIT ? "en" : "dis");
xf86DrvMsg(scrn->scrnIndex, X_CONFIG, "Throttling %sabled\n",
sna->flags & SNA_NO_THROTTLE ? "dis" : "en");
@@ -558,18 +553,11 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int flags)
static void
sna_block_handler(int i, pointer data, pointer timeout, pointer read_mask)
{
- ScreenPtr screen = screenInfo.screens[i];
- ScrnInfoPtr scrn = xf86Screens[i];
- struct sna *sna = to_sna(scrn);
+ struct sna *sna = data;
DBG(("%s\n", __FUNCTION__));
- screen->BlockHandler = sna->BlockHandler;
-
- (*screen->BlockHandler) (i, data, timeout, read_mask);
-
- sna->BlockHandler = screen->BlockHandler;
- screen->BlockHandler = sna_block_handler;
+ sna->BlockHandler(i, sna->BlockData, timeout, read_mask);
sna_accel_block_handler(sna);
}
@@ -577,19 +565,10 @@ sna_block_handler(int i, pointer data, pointer timeout, pointer read_mask)
static void
sna_wakeup_handler(int i, pointer data, unsigned long result, pointer read_mask)
{
- ScreenPtr screen = screenInfo.screens[i];
- ScrnInfoPtr scrn = xf86Screens[i];
- struct sna *sna = to_sna(scrn);
+ struct sna *sna = data;
DBG(("%s\n", __FUNCTION__));
- screen->WakeupHandler = sna->WakeupHandler;
-
- (*screen->WakeupHandler) (i, data, result, read_mask);
-
- sna->WakeupHandler = screen->WakeupHandler;
- screen->WakeupHandler = sna_wakeup_handler;
-
/* despite all appearances, result is just a signed int */
if ((int)result < 0)
return;
@@ -597,6 +576,8 @@ sna_wakeup_handler(int i, pointer data, unsigned long result, pointer read_mask)
if (FD_ISSET(sna->kgem.fd, (fd_set*)read_mask))
sna_dri_wakeup(sna);
+ sna->WakeupHandler(i, sna->WakeupData, result, read_mask);
+
sna_accel_wakeup_handler(sna);
}
@@ -852,10 +833,14 @@ sna_screen_init(int scrnIndex, ScreenPtr screen, int argc, char **argv)
scrn->vtSema = TRUE;
sna->BlockHandler = screen->BlockHandler;
+ sna->BlockData = screen->blockData;
screen->BlockHandler = sna_block_handler;
+ screen->blockData = sna;
sna->WakeupHandler = screen->WakeupHandler;
+ sna->WakeupData = screen->wakeupData;
screen->WakeupHandler = sna_wakeup_handler;
+ screen->wakeupData = sna;
screen->SaveScreen = xf86SaveScreen;
sna->CloseScreen = screen->CloseScreen;
diff --git a/src/sna/sna_video_textured.c b/src/sna/sna_video_textured.c
index 66c70d4a..a10c6769 100644
--- a/src/sna/sna_video_textured.c
+++ b/src/sna/sna_video_textured.c
@@ -238,6 +238,7 @@ sna_video_textured_put_image(ScrnInfoPtr scrn,
BoxRec dstBox;
xf86CrtcPtr crtc;
int top, left, npixels, nlines;
+ Bool flush = false;
if (!sna_video_clip_helper(scrn, video, &crtc, &dstBox,
src_x, src_y, drw_x, drw_y,
@@ -267,7 +268,8 @@ sna_video_textured_put_image(ScrnInfoPtr scrn,
}
if (crtc && video->SyncToVblank != 0)
- sna_wait_for_scanline(sna, pixmap, crtc, clip);
+ flush = sna_wait_for_scanline(sna, pixmap, crtc,
+ &clip->extents);
sna->render.video(sna, video, &frame, clip,
src_w, src_h,
@@ -281,7 +283,8 @@ sna_video_textured_put_image(ScrnInfoPtr scrn,
/* Push the frame to the GPU as soon as possible so
* we can hit the next vsync.
*/
- kgem_submit(&sna->kgem);
+ if (flush)
+ kgem_submit(&sna->kgem);
return Success;
}