diff options
-rw-r--r-- | src/sna/kgem.c | 8 | ||||
-rw-r--r-- | src/sna/kgem.h | 1 | ||||
-rw-r--r-- | src/sna/sna.h | 36 | ||||
-rw-r--r-- | src/sna/sna_accel.c | 61 | ||||
-rw-r--r-- | src/sna/sna_display.c | 480 | ||||
-rw-r--r-- | src/sna/sna_dri2.c | 648 | ||||
-rw-r--r-- | src/sna/sna_driver.c | 21 | ||||
-rw-r--r-- | src/sna/sna_present.c | 41 | ||||
-rw-r--r-- | src/sna/sna_render.c | 2 |
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(®ion, 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, ®ion); + } + } 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, ¤t_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, ¤t_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, ¤t_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__)); |