diff options
Diffstat (limited to 'src/sna/sna_dri2.c')
-rw-r--r-- | src/sna/sna_dri2.c | 280 |
1 files changed, 256 insertions, 24 deletions
diff --git a/src/sna/sna_dri2.c b/src/sna/sna_dri2.c index 8553169b..5e1e7eaa 100644 --- a/src/sna/sna_dri2.c +++ b/src/sna/sna_dri2.c @@ -72,7 +72,7 @@ static inline void unref(struct kgem_bo *bo) struct sna_dri2_private { PixmapPtr pixmap; struct kgem_bo *bo; - bool scanout; + DRI2Buffer2Ptr proxy; bool stale; uint32_t size; int refcnt; @@ -129,6 +129,7 @@ static void sna_dri2_flip_event(struct sna *sna, static void sna_dri2_get_back(struct sna *sna, + DrawablePtr draw, DRI2BufferPtr back, struct sna_dri2_event *info) { @@ -160,12 +161,11 @@ sna_dri2_get_back(struct sna *sna, } } if (bo == NULL) { - DrawablePtr draw = &sna->front->drawable; DBG(("%s: allocating new backbuffer\n", __FUNCTION__)); bo = kgem_create_2d(&sna->kgem, draw->width, draw->height, draw->bitsPerPixel, get_private(back)->bo->tiling, - CREATE_SCANOUT); + get_private(back)->bo->scanout ? CREATE_SCANOUT : 0); if (bo == NULL) return; @@ -203,6 +203,7 @@ sna_dri2_get_back(struct sna *sna, } struct dri2_window { + DRI2BufferPtr front; struct sna_dri2_event *chain; xf86CrtcPtr crtc; int64_t msc_delta; @@ -248,7 +249,7 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer) if (buffer->attachment == DRI2BufferBackLeft && draw->type != DRAWABLE_PIXMAP) { DBG(("%s: replacing back buffer\n", __FUNCTION__)); - sna_dri2_get_back(to_sna_from_drawable(draw), buffer, dri2_chain(draw)); + sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw)); assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name); assert(get_private(buffer)->bo->active_scanout == 0); @@ -409,22 +410,30 @@ sna_dri2_create_buffer(DrawablePtr draw, switch (attachment) { case DRI2BufferFrontLeft: pixmap = get_drawable_pixmap(draw); - buffer = sna_pixmap_get_buffer(pixmap); + buffer = NULL; + if (draw->type != DRAWABLE_PIXMAP) + buffer = dri2_window((WindowPtr)draw)->front; + if (buffer == NULL) + buffer = sna_pixmap_get_buffer(pixmap); if (buffer) { private = get_private(buffer); - DBG(("%s: reusing front buffer attachment, pixmap=%ld, handle=%d, name=%d\n", - __FUNCTION__, pixmap->drawable.serialNumber, + DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld %dx%d, handle=%d, name=%d\n", + __FUNCTION__, + draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0, + draw->width, draw->height, + pixmap->drawable.serialNumber, + pixmap->drawable.width, + pixmap->drawable.height, private->bo->handle, buffer->name)); assert(private->pixmap == pixmap); - assert(private->bo->flush); assert(sna_pixmap(pixmap)->flush); - assert(sna_pixmap(pixmap)->gpu_bo == private->bo); assert(sna_pixmap(pixmap)->pinned & PIN_DRI2); + assert(private->proxy != NULL || sna_pixmap(pixmap)->gpu_bo == private->bo); assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name); - assert(8*private->bo->pitch >= pixmap->drawable.width * pixmap->drawable.bitsPerPixel); - assert(private->bo->pitch * pixmap->drawable.height <= kgem_bo_size(private->bo)); + + buffer->attachment = DRI2BufferFrontLeft; private->refcnt++; return buffer; @@ -448,10 +457,14 @@ sna_dri2_create_buffer(DrawablePtr draw, break; case DRI2BufferBackLeft: - if (draw->width == sna->front->drawable.width && - draw->height == sna->front->drawable.height && - (sna->flags & (SNA_NO_WAIT | SNA_NO_FLIP)) == 0) - flags |= CREATE_SCANOUT; + if (draw->type != DRAWABLE_PIXMAP) { + if (dri2_window((WindowPtr)draw)->front) + flags |= CREATE_SCANOUT; + if (draw->width == sna->front->drawable.width && + draw->height == sna->front->drawable.height && + (sna->flags & (SNA_NO_WAIT | SNA_NO_FLIP)) == 0) + flags |= CREATE_SCANOUT; + } case DRI2BufferBackRight: case DRI2BufferFrontRight: case DRI2BufferFakeFrontLeft: @@ -533,7 +546,6 @@ sna_dri2_create_buffer(DrawablePtr draw, private->refcnt = 1; private->bo = bo; private->pixmap = pixmap; - private->scanout = !!(flags & CREATE_SCANOUT); private->size = size; if (buffer->name == 0) @@ -593,6 +605,12 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer) return; assert(private->bo); + + if (private->proxy) { + _sna_dri2_destroy_buffer(sna, private->proxy); + private->pixmap = NULL; + } + if (private->pixmap) { PixmapPtr pixmap = private->pixmap; struct sna_pixmap *priv = sna_pixmap(pixmap); @@ -1078,6 +1096,7 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc) if (priv == NULL) { priv = malloc(sizeof(*priv)); if (priv != NULL) { + priv->front = NULL; priv->crtc = crtc; priv->msc_delta = 0; priv->chain = NULL; @@ -1226,6 +1245,7 @@ sna_dri2_event_free(struct sna *sna, void sna_dri2_destroy_window(WindowPtr win) { + struct sna *sna; struct dri2_window *priv; priv = dri2_window(win); @@ -1233,9 +1253,15 @@ void sna_dri2_destroy_window(WindowPtr win) return; DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.serialNumber)); + sna = to_sna_from_drawable(&win->drawable); + + if (priv->front) { + assert(priv->crtc); + sna_shadow_unset_crtc(sna, priv->crtc); + _sna_dri2_destroy_buffer(sna, priv->front); + } if (priv->chain) { - struct sna *sna = to_sna_from_drawable(&win->drawable); struct sna_dri2_event *info, *chain; DBG(("%s: freeing chain\n", __FUNCTION__)); @@ -1377,7 +1403,7 @@ can_flip(struct sna * sna, assert(get_private(front)->pixmap == sna->front); assert(sna_pixmap(sna->front)->gpu_bo == get_private(front)->bo); - if (!get_private(back)->scanout) { + if (!get_private(back)->bo->scanout) { DBG(("%s: no, DRI2 drawable was too small at time of creation)\n", __FUNCTION__)); return false; @@ -1513,6 +1539,107 @@ can_xchg(struct sna * sna, return true; } +static bool +overlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn); + int c; + + for (c = 0; c < sna->mode.num_real_crtc; c++) { + xf86CrtcPtr crtc = config->crtc[c]; + + if (crtc == desired) + continue; + + if (!crtc->enabled) + continue; + + if (desired->bounds.x1 < crtc->bounds.x2 && + desired->bounds.x2 > crtc->bounds.x1 && + desired->bounds.y1 < crtc->bounds.y2 && + desired->bounds.y2 > crtc->bounds.y1) + return true; + } + + return false; +} + +static bool +can_xchg_one(struct sna *sna, + DrawablePtr draw, + DRI2BufferPtr front, + DRI2BufferPtr back, + xf86CrtcPtr crtc) +{ + WindowPtr win = (WindowPtr)draw; + PixmapPtr pixmap; + + if ((sna->flags & SNA_TEAR_FREE) == 0) { + DBG(("%s: no, requires TearFree\n", + __FUNCTION__)); + return false; + } + + 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; + } + + if (sna_crtc_is_transformed(crtc)) { + DBG(("%s: no, CRTC is rotated\n", __FUNCTION__)); + return false; + } + + pixmap = get_window_pixmap(win); + if (pixmap != sna->front) { + DBG(("%s: no, not attached to front buffer\n", __FUNCTION__)); + 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, &win->drawable)) { + 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 (overlaps_other_crtc(sna, crtc)) { + DBG(("%s: no, overlaps other CRTC\n", __FUNCTION__)); + return false; + } + + if (get_private(back)->size != (draw->height << 16 | draw->width)) { + DBG(("%s: no, DRI2 buffers does not fit window\n", + __FUNCTION__)); + return false; + } + + DBG(("%s: yes\n", __FUNCTION__)); + return true; +} + static void sna_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, @@ -1900,7 +2027,7 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_event *info) return false; if (!XORG_CAN_TRIPLE_BUFFER) { - sna_dri2_get_back(sna, info->back, info); + sna_dri2_get_back(sna, info->draw, info->back, info); DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); frame_swap_complete(sna, info, DRI2_FLIP_COMPLETE); } @@ -2180,7 +2307,7 @@ 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, back, info); + sna_dri2_get_back(sna, draw, back, info); DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__)); frame_swap_complete(sna, info, DRI2_EXCHANGE_COMPLETE); if (info->type == FLIP_ASYNC) @@ -2314,6 +2441,94 @@ complete: return true; } +static bool +sna_dri2_schedule_xchg_one(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, ¤t_msc)) + return false; + + sync = current_msc < *target_msc; + event = dri2_chain(draw) == NULL; + if (!sync || event) { + WindowPtr win = (WindowPtr)draw; + PixmapPtr pixmap = get_window_pixmap(win); + + DBG(("%s: performing immediate xchg only on pipe %d\n", + __FUNCTION__, sna_crtc_to_pipe(crtc))); + DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n", + __FUNCTION__, + get_private(front)->bo->handle, front->name, + get_private(back)->bo->handle, back->name, + win->drawable.id, + pixmap->drawable.serialNumber, + pixmap->drawable.width, + pixmap->drawable.height)); + + sna_shadow_set_crtc(sna, crtc, get_private(back)->bo); + DamageRegionProcessPending(&win->drawable); + + if (get_private(front)->size == (draw->height << 16 | draw->width)) { + front->attachment = DRI2BufferBackLeft; + get_private(front)->stale = true; + } else + front->attachment = -1; + back->attachment = DRI2BufferFrontLeft; + if (get_private(back)->proxy == NULL) { + get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(pixmap)); + get_private(back)->pixmap = pixmap; + } + + assert(dri2_window(win)->front == NULL); + dri2_window(win)->front = sna_dri2_reference_buffer(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; + + info->queued = true; + if (sna_wait_vblank(sna, &vbl, info->pipe)) { + sna_dri2_event_free(sna, draw, info); + goto complete; + } + + 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; +} + static bool has_pending_events(struct sna *sna) { struct pollfd pfd; @@ -2353,9 +2568,12 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, 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", + DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d) , front=%u (refs=%d/%d, flush=%d)\n", __FUNCTION__, - (long)draw->id, get_drawable_pixmap(draw)->drawable.serialNumber, + (long)draw->id, draw->width, draw->height, + get_drawable_pixmap(draw)->drawable.serialNumber, + get_drawable_pixmap(draw)->drawable.width, + get_drawable_pixmap(draw)->drawable.height, get_private(back)->bo->handle, get_private(back)->refcnt, get_private(back)->bo->refcnt, @@ -2375,10 +2593,18 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, assert(get_private(back)->refcnt); assert(get_private(front)->bo->refcnt); - assert(get_private(front)->bo->flush); - assert(get_private(back)->bo->refcnt); + if (draw->type != DRAWABLE_PIXMAP) { + struct dri2_window *priv = dri2_window((WindowPtr)draw); + if (priv->front) { + assert(front == priv->front); + assert(get_private(priv->front)->refcnt > 1); + get_private(priv->front)->refcnt--; + priv->front = NULL; + } + } + if (get_private(front)->pixmap != get_drawable_pixmap(draw)) goto skip; @@ -2408,6 +2634,12 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front, func, data)) return TRUE; + if (can_xchg_one(sna, draw, front, back, crtc) && + sna_dri2_schedule_xchg_one(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, |