summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2012-12-30 14:50:49 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2012-12-31 15:55:28 +0000
commita7988bf77f5a106a48b6e39b6eaf60ef2f8bec11 (patch)
tree0d348cad9c9341f7980a7b407ce7aa6738fb22ac /src
parent736b89504a32239a0c7dfb5961c1b8292dd744bd (diff)
sna/dri: Fix triple buffering to not penalise missed frames
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'src')
-rw-r--r--src/sna/kgem.c45
-rw-r--r--src/sna/kgem.h1
-rw-r--r--src/sna/sna_dri.c792
-rw-r--r--src/sna/sna_video.c3
4 files changed, 392 insertions, 449 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c
index 21d5d1cb..f4c2b1c9 100644
--- a/src/sna/kgem.c
+++ b/src/sna/kgem.c
@@ -942,6 +942,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen)
list_init(&kgem->large);
list_init(&kgem->large_inactive);
list_init(&kgem->snoop);
+ list_init(&kgem->scanout);
for (i = 0; i < ARRAY_SIZE(kgem->pinned_batches); i++)
list_init(&kgem->pinned_batches[i]);
for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++)
@@ -1666,7 +1667,6 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
assert(bo->proxy == NULL);
bo->binding.offset = 0;
- kgem_bo_clear_scanout(kgem, bo);
if (DBG_NO_CACHE)
goto destroy;
@@ -1708,6 +1708,12 @@ static void __kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo)
bo->reusable = false;
}
+ if (bo->scanout) {
+ DBG(("%s: handle=%d -> scanout\n", __FUNCTION__, bo->handle));
+ list_add(&bo->list, &kgem->scanout);
+ return;
+ }
+
if (!bo->reusable) {
DBG(("%s: handle=%d, not reusable\n",
__FUNCTION__, bo->handle));
@@ -2705,6 +2711,13 @@ bool kgem_expire_cache(struct kgem *kgem)
}
+ while (!list_is_empty(&kgem->scanout)) {
+ bo = list_first_entry(&kgem->scanout, struct kgem_bo, list);
+ list_del(&bo->list);
+ kgem_bo_clear_scanout(kgem, bo);
+ __kgem_bo_destroy(kgem, bo);
+ }
+
expire = 0;
list_for_each_entry(bo, &kgem->snoop, list) {
if (bo->delta) {
@@ -3393,6 +3406,36 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
size /= PAGE_SIZE;
bucket = cache_bucket(size);
+ if (flags & CREATE_SCANOUT) {
+ list_for_each_entry(bo, &kgem->scanout, list) {
+ assert(bo->scanout);
+ assert(bo->delta);
+ assert(!bo->purged);
+
+ if (size > num_pages(bo) || num_pages(bo) > 2*size)
+ continue;
+
+ if (bo->tiling != tiling ||
+ (tiling != I915_TILING_NONE && bo->pitch != pitch)) {
+ if (!gem_set_tiling(kgem->fd, bo->handle,
+ tiling, pitch))
+ continue;
+
+ bo->tiling = tiling;
+ bo->pitch = pitch;
+ }
+
+ list_del(&bo->list);
+
+ bo->unique_id = kgem_get_unique_id(kgem);
+ DBG((" 1:from scanout: pitch=%d, tiling=%d, handle=%d, id=%d\n",
+ bo->pitch, bo->tiling, bo->handle, bo->unique_id));
+ assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo));
+ bo->refcnt = 1;
+ return bo;
+ }
+ }
+
if (bucket >= NUM_CACHE_BUCKETS) {
DBG(("%s: large bo num pages=%d, bucket=%d\n",
__FUNCTION__, size, bucket));
diff --git a/src/sna/kgem.h b/src/sna/kgem.h
index bf457930..eed4132c 100644
--- a/src/sna/kgem.h
+++ b/src/sna/kgem.h
@@ -133,6 +133,7 @@ struct kgem {
struct list inactive[NUM_CACHE_BUCKETS];
struct list pinned_batches[2];
struct list snoop;
+ struct list scanout;
struct list batch_buffers, active_buffers;
struct list requests[2];
diff --git a/src/sna/sna_dri.c b/src/sna/sna_dri.c
index af75a553..9886f371 100644
--- a/src/sna/sna_dri.c
+++ b/src/sna/sna_dri.c
@@ -52,18 +52,17 @@ USE OR OTHER DEALINGS IN THE SOFTWARE.
#endif
#if DRI2INFOREC_VERSION < 10
+#undef USE_ASYNC_SWAP
#define USE_ASYNC_SWAP 0
#endif
#define COLOR_PREFER_TILING_Y 0
-#define FLIP_OFF_DELAY 5
enum frame_event_type {
DRI2_SWAP,
DRI2_SWAP_WAIT,
DRI2_SWAP_THROTTLE,
DRI2_XCHG_THROTTLE,
- DRI2_ASYNC_FLIP,
DRI2_FLIP,
DRI2_FLIP_THROTTLE,
DRI2_WAITMSC,
@@ -92,9 +91,9 @@ struct sna_dri_frame_event {
struct dri_bo {
struct kgem_bo *bo;
uint32_t name;
- } old_front, next_front, cache;
+ } scanout[2], cache;
- int off_delay;
+ int mode;
};
struct sna_dri_private {
@@ -1019,8 +1018,10 @@ sna_dri_frame_event_info_free(struct sna *sna,
_sna_dri_destroy_buffer(sna, info->front);
_sna_dri_destroy_buffer(sna, info->back);
- if (info->old_front.bo)
- kgem_bo_destroy(&sna->kgem, info->old_front.bo);
+ assert(info->scanout[1].bo == NULL);
+
+ if (info->scanout[0].bo)
+ kgem_bo_destroy(&sna->kgem, info->scanout[0].bo);
if (info->cache.bo)
kgem_bo_destroy(&sna->kgem, info->cache.bo);
@@ -1035,23 +1036,34 @@ static bool
sna_dri_page_flip(struct sna *sna, struct sna_dri_frame_event *info)
{
struct kgem_bo *bo = get_private(info->back)->bo;
+ struct dri_bo tmp;
DBG(("%s()\n", __FUNCTION__));
assert(sna_pixmap_get_buffer(sna->front) == info->front);
assert(get_drawable_pixmap(info->draw)->drawable.height * bo->pitch <= kgem_bo_size(bo));
+ assert(info->scanout[0].bo);
info->count = sna_page_flip(sna, bo, info, info->pipe);
if (!info->count)
return false;
- info->old_front.name = info->front->name;
- info->old_front.bo = get_private(info->front)->bo;
+ info->scanout[1] = info->scanout[0];
+ info->scanout[0].bo = ref(bo);
+ info->scanout[0].name = info->back->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;
+
+ sna->dri.flip_pending = info;
return true;
}
@@ -1117,6 +1129,7 @@ can_flip(struct sna * sna,
return false;
}
assert(get_private(front)->pixmap == sna->front);
+ assert(sna_pixmap(sna->front)->gpu_bo == get_private(front)->bo);
if (!get_private(back)->scanout) {
DBG(("%s: no, DRI2 drawable was too small at time of creation)\n",
@@ -1274,10 +1287,12 @@ sna_dri_exchange_buffers(DrawablePtr draw,
pixmap->drawable.width,
pixmap->drawable.height));
- DBG(("%s: back_bo pitch=%d, size=%d\n",
- __FUNCTION__, back_bo->pitch, kgem_bo_size(back_bo)));
- DBG(("%s: front_bo pitch=%d, size=%d\n",
- __FUNCTION__, front_bo->pitch, kgem_bo_size(front_bo)));
+ 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));
+ 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));
@@ -1387,12 +1402,9 @@ void sna_dri_vblank_handler(struct sna *sna, struct drm_event_vblank *event)
case DRI2_FLIP:
/* If we can still flip... */
if (can_flip(sna, draw, info->front, info->back) &&
- sna_dri_page_flip(sna, info)) {
- info->back->name = info->old_front.name;
- get_private(info->back)->bo = info->old_front.bo;
- info->old_front.bo = NULL;
+ sna_dri_page_flip(sna, info))
return;
- }
+
/* else fall through to blit */
case DRI2_SWAP:
if (can_blit(sna, draw, info->front, info->back))
@@ -1449,24 +1461,91 @@ done:
sna_dri_frame_event_info_free(sna, draw, info);
}
+static void
+sna_dri_flip_get_back(struct sna *sna, struct sna_dri_frame_event *info)
+{
+ struct kgem_bo *bo;
+ uint32_t name;
+
+ DBG(("%s: scanout=(%d, %d), back=%d, cache=%d\n",
+ __FUNCTION__,
+ info->scanout[0].bo ? info->scanout[0].bo->handle : 0,
+ info->scanout[1].bo ? info->scanout[1].bo->handle : 0,
+ get_private(info->back)->bo->handle,
+ info->cache.bo ? info->cache.bo->handle : 0));
+
+ bo = get_private(info->back)->bo;
+ if (!(bo == info->scanout[0].bo || bo == info->scanout[1].bo))
+ return;
+
+ bo = info->cache.bo;
+ name = info->cache.name;
+ if (bo == NULL ||
+ bo == info->scanout[0].bo ||
+ bo == info->scanout[1].bo) {
+ if (bo) {
+ DBG(("%s: discarding old backbuffer\n", __FUNCTION__));
+ kgem_bo_destroy(&sna->kgem, bo);
+ }
+ 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,
+ CREATE_SCANOUT | CREATE_EXACT);
+ name = kgem_bo_flink(&sna->kgem, bo);
+ }
+
+ info->cache.bo = get_private(info->back)->bo;
+ info->cache.name = info->back->name;
+
+ get_private(info->back)->bo = bo;
+ info->back->name = name;
+
+ assert(get_private(info->back)->bo != info->scanout[0].bo);
+ assert(get_private(info->back)->bo != info->scanout[1].bo);
+}
+
static bool
sna_dri_flip_continue(struct sna *sna, struct sna_dri_frame_event *info)
{
- struct dri_bo tmp;
+ DBG(("%s(mode=%d)\n", __FUNCTION__, info->mode));
- DBG(("%s()\n", __FUNCTION__));
+ if (info->mode > 1){
+ if (get_private(info->front)->bo != sna_pixmap(sna->front)->gpu_bo)
+ return false;
- assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
+ info->count = sna_page_flip(sna,
+ get_private(info->front)->bo,
+ info, info->pipe);
+ if (!info->count)
+ return false;
- tmp = info->old_front;
+ info->scanout[1] = info->scanout[0];
+ info->scanout[0].bo = ref(get_private(info->front)->bo);
+ info->scanout[0].name = info->front->name;
+ sna->dri.flip_pending = info;
+ } else {
+ if (!info->draw)
+ return false;
- if (!sna_dri_page_flip(sna, info))
- return false;
+ assert(sna_pixmap_get_buffer(get_drawable_pixmap(info->draw)) == info->front);
+ if (!can_flip(sna, info->draw, info->front, info->back))
+ return false;
- get_private(info->back)->bo = tmp.bo;
- info->back->name = tmp.name;
+ if (!sna_dri_page_flip(sna, info))
+ return false;
- info->next_front.name = 0;
+ sna_dri_flip_get_back(sna, info);
+ DRI2SwapComplete(info->client, info->draw,
+ 0, 0, 0,
+ DRI2_FLIP_COMPLETE,
+ info->client ? info->event_complete : NULL,
+ info->event_data);
+ }
+
+ info->mode = 0;
return true;
}
@@ -1488,23 +1567,9 @@ static void chain_flip(struct sna *sna)
can_flip(sna, chain->draw, chain->front, chain->back) &&
sna_dri_page_flip(sna, chain)) {
DBG(("%s: performing chained flip\n", __FUNCTION__));
-
- chain->back->name = chain->old_front.name;
- get_private(chain->back)->bo = chain->old_front.bo;
- chain->old_front.bo = NULL;
-
- if (chain->count == 0) {
- DRI2SwapComplete(chain->client, chain->draw, 0, 0, 0,
- DRI2_EXCHANGE_COMPLETE,
- chain->event_complete,
- chain->event_data);
- sna_dri_frame_event_info_free(sna, chain->draw, chain);
- } else
- sna->dri.flip_pending = chain;
} else {
if (can_blit(sna, chain->draw, chain->front, chain->back)) {
DBG(("%s: emitting chained vsync'ed blit\n", __FUNCTION__));
-
chain->bo = sna_dri_copy_to_front(sna, chain->draw, NULL,
get_private(chain->front)->bo,
get_private(chain->back)->bo,
@@ -1526,6 +1591,14 @@ static void sna_dri_flip_event(struct sna *sna,
flip->fe_tv_usec,
flip->type));
+ if (flip->cache.bo == NULL) {
+ flip->cache = flip->scanout[1];
+ flip->scanout[1].bo = NULL;
+ }
+ if (flip->scanout[1].bo) {
+ kgem_bo_destroy(&sna->kgem, flip->scanout[1].bo);
+ flip->scanout[1].bo = NULL;
+ }
if (sna->dri.flip_pending == flip)
sna->dri.flip_pending = NULL;
@@ -1553,12 +1626,9 @@ static void sna_dri_flip_event(struct sna *sna,
if (sna->dri.flip_pending) {
sna_dri_frame_event_info_free(sna, flip->draw, flip);
chain_flip(sna);
- } else if (!flip->next_front.name) {
- /* Keep the pageflipping running for a couple of frames
- * so we keep the uncached scanouts alive.
- */
- DBG(("%s: flip chain complete, off-delay=%d\n",
- __FUNCTION__, flip->off_delay));
+ } else if (!flip->mode) {
+ DBG(("%s: flip chain complete\n", __FUNCTION__));
+
if (flip->chain) {
sna_dri_remove_frame_event((WindowPtr)flip->draw,
flip);
@@ -1570,31 +1640,8 @@ static void sna_dri_flip_event(struct sna *sna,
flip->draw = NULL;
}
- if (flip->off_delay-- && flip->draw &&
- can_flip(sna, flip->draw, flip->front, flip->front) &&
- (flip->count = sna_page_flip(sna,
- get_private(flip->front)->bo,
- flip, flip->pipe))) {
- assert(flip == sna_dri_window_get_chain((WindowPtr)flip->draw));
- sna->dri.flip_pending = flip;
- } else {
- DBG(("%s: flip chain complete, off\n", __FUNCTION__));
- sna_dri_frame_event_info_free(sna, flip->draw, flip);
- }
- } else if (flip->draw &&
- can_flip(sna, flip->draw, flip->front, flip->back) &&
- sna_dri_flip_continue(sna, flip)) {
- DRI2SwapComplete(flip->client, flip->draw,
- 0, 0, 0,
- DRI2_FLIP_COMPLETE,
- flip->client ? flip->event_complete : NULL,
- flip->event_data);
- if (flip->count) {
- flip->off_delay = FLIP_OFF_DELAY;
- sna->dri.flip_pending = flip;
- } else
- sna_dri_frame_event_info_free(sna, flip->draw, flip);
- } else {
+ sna_dri_frame_event_info_free(sna, flip->draw, flip);
+ } else if (!sna_dri_flip_continue(sna, flip)) {
DBG(("%s: no longer able to flip\n", __FUNCTION__));
if (flip->draw) {
@@ -1615,77 +1662,6 @@ static void sna_dri_flip_event(struct sna *sna,
}
break;
-#if USE_ASYNC_SWAP
- case DRI2_ASYNC_FLIP:
- DBG(("%s: async swap flip completed on pipe %d, pending? %d, new? %d\n",
- __FUNCTION__, flip->pipe,
- sna->dri.flip_pending != NULL,
- flip->front->name != flip->next_front.name));
-
- if (sna->dri.flip_pending) {
- chain_flip(sna);
- goto finish_async_flip;
- } else if (flip->front->name != flip->next_front.name) {
- DBG(("%s: async flip continuing\n", __FUNCTION__));
-
- flip->cache = flip->old_front;
- flip->old_front = flip->next_front;
-
- flip->count = sna_page_flip(sna,
- get_private(flip->front)->bo,
- flip, flip->pipe);
- if (flip->count == 0) {
- if (flip->chain)
- goto chain_async_flip;
- else
- goto finish_async_flip;
- }
-
- flip->next_front.bo = get_private(flip->front)->bo;
- flip->next_front.name = flip->front->name;
- flip->off_delay = FLIP_OFF_DELAY;
-
- sna->dri.flip_pending = flip;
- } else {
- if (flip->chain) {
-chain_async_flip:
- sna_dri_remove_frame_event((WindowPtr)flip->draw,
- flip);
- chain_swap(sna, flip->draw,
- flip->fe_frame,
- flip->fe_tv_sec,
- flip->fe_tv_usec,
- flip->chain);
- flip->draw = NULL;
- }
-
- if (flip->draw &&
- can_flip(sna, flip->draw, flip->front, flip->back) &&
- flip->off_delay--) {
- assert(flip == sna_dri_window_get_chain((WindowPtr)flip->draw));
- DBG(("%s: queuing no-flip [delay=%d]\n",
- __FUNCTION__, flip->off_delay));
- /* Just queue a no-op flip to trigger another event */
- flip->count = sna_page_flip(sna,
- get_private(flip->front)->bo,
- flip, flip->pipe);
- if (flip->count == 0)
- goto finish_async_flip;
-
- assert(flip->next_front.bo == get_private(flip->front)->bo);
- assert(flip->next_front.name == flip->front->name);
-
- sna->dri.flip_pending = flip;
- } else {
-finish_async_flip:
- DBG(("%s: async flip completed (drawable gone? %d)\n",
- __FUNCTION__, flip->draw == NULL));
- sna_dri_frame_event_info_free(sna, flip->draw, flip);
- }
- }
- break;
-#endif
-
default:
xf86DrvMsg(sna->scrn->scrnIndex, X_WARNING,
"%s: unknown vblank event received\n", __func__);
@@ -1715,6 +1691,105 @@ sna_dri_page_flip_handler(struct sna *sna,
sna_dri_flip_event(sna, info);
}
+static void
+sna_dri_immediate_xchg(struct sna *sna,
+ DrawablePtr draw,
+ struct sna_dri_frame_event *info,
+ bool sync)
+{
+ drmVBlank vbl;
+
+ if (sna->flags & SNA_NO_WAIT)
+ sync = false;
+
+ DBG(("%s: emitting immediate exchange, throttling client, synced? %d\n",
+ __FUNCTION__, sync));
+ VG_CLEAR(vbl);
+
+ if (sync) {
+ info->type = DRI2_XCHG_THROTTLE;
+ if (sna_dri_window_get_chain((WindowPtr)draw) == info) {
+ DBG(("%s: no pending xchg, starting chain\n",
+ __FUNCTION__));
+
+ sna_dri_exchange_buffers(draw, info->front, info->back);
+ DRI2SwapComplete(info->client, draw, 0, 0, 0,
+ DRI2_EXCHANGE_COMPLETE,
+ info->event_complete,
+ info->event_data);
+ vbl.request.type =
+ DRM_VBLANK_RELATIVE |
+ DRM_VBLANK_NEXTONMISS |
+ DRM_VBLANK_EVENT |
+ pipe_select(info->pipe);
+ vbl.request.sequence = 0;
+ vbl.request.signal = (unsigned long)info;
+ if (sna_wait_vblank(sna, &vbl))
+ sna_dri_frame_event_info_free(sna, draw, info);
+ }
+ } else {
+ sna_dri_exchange_buffers(draw, info->front, info->back);
+ DRI2SwapComplete(info->client, draw, 0, 0, 0,
+ DRI2_EXCHANGE_COMPLETE,
+ info->event_complete,
+ info->event_data);
+ sna_dri_frame_event_info_free(sna, draw, info);
+ }
+}
+
+static void
+sna_dri_immediate_blit(struct sna *sna,
+ DrawablePtr draw,
+ struct sna_dri_frame_event *info,
+ bool sync)
+{
+ if (sna->flags & SNA_NO_WAIT)
+ sync = false;
+
+ DBG(("%s: emitting immediate blit, throttling client, synced? %d\n",
+ __FUNCTION__, sync));
+
+ if (sync) {
+ info->type = DRI2_SWAP_THROTTLE;
+ if (sna_dri_window_get_chain((WindowPtr)draw) == info) {
+ drmVBlank vbl;
+
+ DBG(("%s: no pending blit, starting chain\n",
+ __FUNCTION__));
+
+ info->bo = sna_dri_copy_to_front(sna, draw, NULL,
+ get_private(info->front)->bo,
+ get_private(info->back)->bo,
+ true);
+ DRI2SwapComplete(info->client, draw, 0, 0, 0,
+ DRI2_BLIT_COMPLETE,
+ info->event_complete,
+ info->event_data);
+
+ VG_CLEAR(vbl);
+ vbl.request.type =
+ DRM_VBLANK_RELATIVE |
+ DRM_VBLANK_NEXTONMISS |
+ DRM_VBLANK_EVENT |
+ pipe_select(info->pipe);
+ vbl.request.sequence = 0;
+ vbl.request.signal = (unsigned long)info;
+ if (sna_wait_vblank(sna, &vbl))
+ sna_dri_frame_event_info_free(sna, draw, info);
+ }
+ } else {
+ info->bo = sna_dri_copy_to_front(sna, draw, NULL,
+ get_private(info->front)->bo,
+ get_private(info->back)->bo,
+ false);
+ DRI2SwapComplete(info->client, draw, 0, 0, 0,
+ DRI2_BLIT_COMPLETE,
+ info->event_complete,
+ info->event_data);
+ sna_dri_frame_event_info_free(sna, draw, info);
+ }
+}
+
static CARD64
get_current_msc_for_target(struct sna *sna, CARD64 target_msc, int pipe)
{
@@ -1734,50 +1809,43 @@ get_current_msc_for_target(struct sna *sna, CARD64 target_msc, int pipe)
}
static bool
-sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
- DRI2BufferPtr back, CARD64 *target_msc, CARD64 divisor,
- CARD64 remainder, DRI2SwapEventPtr func, void *data)
+sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw,
+ DRI2BufferPtr front, DRI2BufferPtr back, int pipe,
+ CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
+ DRI2SwapEventPtr func, void *data)
{
struct sna *sna = to_sna_from_drawable(draw);
struct sna_dri_frame_event *info;
drmVBlank vbl;
- int pipe;
CARD64 current_msc;
- DBG(("%s(target_msc=%llu, divisor=%llu, remainder=%llu)\n",
- __FUNCTION__,
- (long long)*target_msc,
- (long long)divisor,
- (long long)remainder));
-
- VG_CLEAR(vbl);
-
- pipe = sna_dri_get_pipe(draw);
- if (pipe == -1) {
- /* XXX WARN_ON(sna->dri.flip_pending) ? */
- if (sna->dri.flip_pending == NULL) {
- sna_dri_exchange_buffers(draw, front, back);
- DRI2SwapComplete(client, draw, 0, 0, 0,
- DRI2_EXCHANGE_COMPLETE, func, data);
- return true;
- } else
- return false;
- }
-
current_msc = get_current_msc_for_target(sna, *target_msc, pipe);
DBG(("%s: target_msc=%u, current_msc=%u, divisor=%u\n", __FUNCTION__,
(uint32_t)*target_msc, (uint32_t)current_msc, (uint32_t)divisor));
- if (divisor == 0 && current_msc >= *target_msc) {
- DBG(("%s: performing immediate swap on pipe %d, pending? %d\n",
- __FUNCTION__, pipe, sna->dri.flip_pending != NULL));
-
+ if (divisor == 0 && current_msc >= *target_msc - 1) {
info = sna->dri.flip_pending;
- if (info && info->draw == draw && info->type == DRI2_FLIP_THROTTLE) {
- DBG(("%s: chaining flip\n", __FUNCTION__));
- info->next_front.name = 1;
- return true;
+
+ DBG(("%s: performing immediate swap on pipe %d, pending? %d, mode: %d\n",
+ __FUNCTION__, pipe, info != NULL, info ? info->mode : 0));
+
+ if (info && info->draw == draw) {
+ assert(info->type == DRI2_FLIP_THROTTLE);
+ assert(info->front == front);
+ assert(info->back == back);
+ if (current_msc >= *target_msc) {
+ DBG(("%s: executing xchg of pending flip\n",
+ __FUNCTION__));
+ sna_dri_exchange_buffers(draw, front, back);
+ info->mode = 2;
+ goto new_back;
+ } else {
+ DBG(("%s: chaining flip\n", __FUNCTION__));
+ info->mode = 1;
+ current_msc++;
+ goto out;
+ }
}
info = calloc(1, sizeof(struct sna_dri_frame_event));
@@ -1794,6 +1862,9 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
info->back = back;
info->pipe = pipe;
+ info->scanout[0].bo = ref(get_private(front)->bo);
+ info->scanout[0].name = info->front->name;
+
sna_dri_add_frame_event(draw, info);
sna_dri_reference_buffer(front);
sna_dri_reference_buffer(back);
@@ -1807,202 +1878,109 @@ sna_dri_schedule_flip(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
__FUNCTION__));
info->type = DRI2_FLIP;
sna->dri.flip_pending = info;
+ *target_msc = current_msc + 1;
return true;
}
if (!sna_dri_page_flip(sna, info)) {
sna_dri_frame_event_info_free(sna, draw, info);
return false;
- } else if (info->type != DRI2_FLIP) {
- get_private(info->back)->bo =
- kgem_create_2d(&sna->kgem,
- draw->width,
- draw->height,
- draw->bitsPerPixel,
- get_private(info->front)->bo->tiling,
- CREATE_SCANOUT | CREATE_EXACT);
- info->back->name = kgem_bo_flink(&sna->kgem,
- get_private(info->back)->bo);
- info->off_delay = FLIP_OFF_DELAY;
- sna->dri.flip_pending = info;
+ }
- DRI2SwapComplete(info->client, draw, 0, 0, 0,
+ if (info->type != DRI2_FLIP) {
+ current_msc++;
+new_back:
+ sna_dri_flip_get_back(sna, info);
+ DRI2SwapComplete(client, draw, 0, 0, 0,
DRI2_EXCHANGE_COMPLETE,
- info->event_complete,
- info->event_data);
- } else {
- info->back->name = info->old_front.name;
- get_private(info->back)->bo = info->old_front.bo;
- info->old_front.bo = NULL;
+ func, data);
}
- } else {
- info = calloc(1, sizeof(struct sna_dri_frame_event));
- if (info == NULL)
- return false;
-
- info->draw = draw;
- info->client = client;
- info->event_complete = func;
- info->event_data = data;
- info->front = front;
- info->back = back;
- info->pipe = pipe;
- info->type = DRI2_FLIP;
-
- sna_dri_add_frame_event(draw, info);
- sna_dri_reference_buffer(front);
- sna_dri_reference_buffer(back);
-
- *target_msc &= 0xffffffff;
- remainder &= 0xffffffff;
-
- vbl.request.type =
- DRM_VBLANK_ABSOLUTE |
- DRM_VBLANK_EVENT |
- pipe_select(pipe);
+out:
+ *target_msc = current_msc;
+ return true;
+ }
- /*
- * If divisor is zero, or current_msc is smaller than target_msc
- * we just need to make sure target_msc passes before initiating
- * the swap.
- */
- if (current_msc < *target_msc) {
- DBG(("%s: waiting for swap: current=%d, target=%d, divisor=%d\n",
- __FUNCTION__,
- (int)current_msc,
- (int)*target_msc,
- (int)divisor));
- vbl.request.sequence = *target_msc;
- } else {
- DBG(("%s: missed target, queueing event for next: current=%d, target=%d, divisor=%d\n",
- __FUNCTION__,
- (int)current_msc,
- (int)*target_msc,
- (int)divisor));
-
- if (divisor == 0)
- divisor = 1;
-
- vbl.request.sequence = current_msc - current_msc % divisor + remainder;
-
- /*
- * If the calculated deadline vbl.request.sequence is
- * smaller than or equal to current_msc, it means
- * we've passed the last point when effective onset
- * frame seq could satisfy *seq % divisor == remainder,
- * so we need to wait for the next time this will
- * happen.
- *
- * This comparison takes the 1 frame swap delay
- * in pageflipping mode into account.
- */
- if (vbl.request.sequence <= current_msc)
- vbl.request.sequence += divisor;
+ info = calloc(1, sizeof(struct sna_dri_frame_event));
+ if (info == NULL)
+ return false;
- /* Adjust returned value for 1 frame pageflip offset */
- *target_msc = vbl.reply.sequence + 1;
- }
+ info->draw = draw;
+ info->client = client;
+ info->event_complete = func;
+ info->event_data = data;
+ info->front = front;
+ info->back = back;
+ info->pipe = pipe;
+ info->type = DRI2_FLIP;
- /* Account for 1 frame extra pageflip delay */
- vbl.request.sequence -= 1;
- vbl.request.signal = (unsigned long)info;
- if (sna_wait_vblank(sna, &vbl)) {
- sna_dri_frame_event_info_free(sna, draw, info);
- return false;
- }
- }
+ info->scanout[0].bo = ref(get_private(front)->bo);
+ info->scanout[0].name = info->front->name;
- return true;
-}
+ sna_dri_add_frame_event(draw, info);
+ sna_dri_reference_buffer(front);
+ sna_dri_reference_buffer(back);
-static void
-sna_dri_immediate_xchg(struct sna *sna,
- DrawablePtr draw,
- struct sna_dri_frame_event *info)
-{
- drmVBlank vbl;
+ *target_msc &= 0xffffffff;
+ remainder &= 0xffffffff;
- DBG(("%s: emitting immediate exchange, throttling client\n",
- __FUNCTION__));
VG_CLEAR(vbl);
- if ((sna->flags & SNA_NO_WAIT) == 0) {
- info->type = DRI2_XCHG_THROTTLE;
- if (sna_dri_window_get_chain((WindowPtr)draw) == info) {
- DBG(("%s: no pending xchg, starting chain\n",
- __FUNCTION__));
+ vbl.request.type =
+ DRM_VBLANK_ABSOLUTE |
+ DRM_VBLANK_EVENT |
+ pipe_select(pipe);
- sna_dri_exchange_buffers(draw, info->front, info->back);
- DRI2SwapComplete(info->client, draw, 0, 0, 0,
- DRI2_EXCHANGE_COMPLETE,
- info->event_complete,
- info->event_data);
- vbl.request.type =
- DRM_VBLANK_RELATIVE |
- DRM_VBLANK_NEXTONMISS |
- DRM_VBLANK_EVENT |
- pipe_select(info->pipe);
- vbl.request.sequence = 0;
- vbl.request.signal = (unsigned long)info;
- if (sna_wait_vblank(sna, &vbl))
- sna_dri_frame_event_info_free(sna, draw, info);
- }
+ /*
+ * If divisor is zero, or current_msc is smaller than target_msc
+ * we just need to make sure target_msc passes before initiating
+ * the swap.
+ */
+ if (current_msc <= *target_msc - 1) {
+ DBG(("%s: waiting for swap: current=%d, target=%d, divisor=%d\n",
+ __FUNCTION__,
+ (int)current_msc,
+ (int)*target_msc,
+ (int)divisor));
+ vbl.request.sequence = *target_msc;
} else {
- sna_dri_exchange_buffers(draw, info->front, info->back);
- DRI2SwapComplete(info->client, draw, 0, 0, 0,
- DRI2_EXCHANGE_COMPLETE,
- info->event_complete,
- info->event_data);
- sna_dri_frame_event_info_free(sna, draw, info);
- }
-}
+ DBG(("%s: missed target, queueing event for next: current=%d, target=%d, divisor=%d\n",
+ __FUNCTION__,
+ (int)current_msc,
+ (int)*target_msc,
+ (int)divisor));
-static void
-sna_dri_immediate_blit(struct sna *sna,
- DrawablePtr draw,
- struct sna_dri_frame_event *info)
-{
- DBG(("%s: emitting immediate blit, throttling client\n", __FUNCTION__));
+ if (divisor == 0)
+ divisor = 1;
- if ((sna->flags & SNA_NO_WAIT) == 0) {
- info->type = DRI2_SWAP_THROTTLE;
- if (sna_dri_window_get_chain((WindowPtr)draw) == info) {
- drmVBlank vbl;
+ vbl.request.sequence = current_msc - current_msc % divisor + remainder;
- DBG(("%s: no pending blit, starting chain\n",
- __FUNCTION__));
+ /*
+ * If the calculated deadline vbl.request.sequence is
+ * smaller than or equal to current_msc, it means
+ * we've passed the last point when effective onset
+ * frame seq could satisfy *seq % divisor == remainder,
+ * so we need to wait for the next time this will
+ * happen.
+ *
+ * This comparison takes the 1 frame swap delay
+ * in pageflipping mode into account.
+ */
+ if (vbl.request.sequence <= current_msc)
+ vbl.request.sequence += divisor;
- info->bo = sna_dri_copy_to_front(sna, draw, NULL,
- get_private(info->front)->bo,
- get_private(info->back)->bo,
- true);
- DRI2SwapComplete(info->client, draw, 0, 0, 0,
- DRI2_BLIT_COMPLETE,
- info->event_complete,
- info->event_data);
+ /* Adjust returned value for 1 frame pageflip offset */
+ *target_msc = vbl.reply.sequence;
+ }
- VG_CLEAR(vbl);
- vbl.request.type =
- DRM_VBLANK_RELATIVE |
- DRM_VBLANK_NEXTONMISS |
- DRM_VBLANK_EVENT |
- pipe_select(info->pipe);
- vbl.request.sequence = 0;
- vbl.request.signal = (unsigned long)info;
- if (sna_wait_vblank(sna, &vbl))
- sna_dri_frame_event_info_free(sna, draw, info);
- }
- } else {
- info->bo = sna_dri_copy_to_front(sna, draw, NULL,
- get_private(info->front)->bo,
- get_private(info->back)->bo,
- false);
- DRI2SwapComplete(info->client, draw, 0, 0, 0,
- DRI2_BLIT_COMPLETE,
- info->event_complete,
- info->event_data);
+ /* Account for 1 frame extra pageflip delay */
+ vbl.request.sequence -= 1;
+ vbl.request.signal = (unsigned long)info;
+ if (sna_wait_vblank(sna, &vbl)) {
sna_dri_frame_event_info_free(sna, draw, info);
+ return false;
}
+
+ return true;
}
/*
@@ -2051,30 +2029,19 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
divisor &= 0xffffffff;
remainder &= 0xffffffff;
- if (can_flip(sna, draw, front, back)) {
- DBG(("%s: try flip\n", __FUNCTION__));
- if (sna_dri_schedule_flip(client, draw, front, back,
- target_msc, divisor, remainder,
- func, data))
- return TRUE;
- }
-
/* Drawable not displayed... just complete the swap */
pipe = sna_dri_get_pipe(draw);
if (pipe == -1) {
- if (can_exchange(sna, draw, front, back)) {
- DBG(("%s: unattached, exchange pixmaps\n", __FUNCTION__));
- sna_dri_exchange_buffers(draw, front, back);
-
- DRI2SwapComplete(client, draw, 0, 0, 0,
- DRI2_EXCHANGE_COMPLETE, func, data);
- return TRUE;
- }
-
DBG(("%s: off-screen, immediate update\n", __FUNCTION__));
goto blit_fallback;
}
+ if (can_flip(sna, draw, front, back) &&
+ sna_dri_schedule_flip(client, draw, front, back, pipe,
+ target_msc, divisor, remainder,
+ func, data))
+ return TRUE;
+
VG_CLEAR(vbl);
info = calloc(1, sizeof(struct sna_dri_frame_event));
@@ -2099,16 +2066,19 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
DBG(("%s: target_msc=%u, current_msc=%u, divisor=%u\n", __FUNCTION__,
(uint32_t)*target_msc, (uint32_t)current_msc, (uint32_t)divisor));
- if (divisor == 0 && current_msc >= *target_msc) {
+ if (divisor == 0 && current_msc >= *target_msc - 1) {
if (can_exchange(sna, draw, front, back)) {
- sna_dri_immediate_xchg(sna, draw, info);
+ sna_dri_immediate_xchg(sna, draw, info,
+ current_msc < *target_msc);
} else if (can_blit(sna, draw, front, back)) {
- sna_dri_immediate_blit(sna, draw, info);
+ sna_dri_immediate_blit(sna, draw, info,
+ current_msc < *target_msc);
} else {
DRI2SwapComplete(client, draw, 0, 0, 0,
DRI2_BLIT_COMPLETE, func, data);
sna_dri_frame_event_info_free(sna, draw, info);
}
+ *target_msc = current_msc + 1;
return TRUE;
}
@@ -2168,13 +2138,13 @@ sna_dri_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
*/
if (vbl.request.sequence < current_msc)
vbl.request.sequence += divisor;
- vbl.request.sequence -= 1;
+ *target_msc = vbl.reply.sequence;
+ vbl.request.sequence -= 1;
vbl.request.signal = (unsigned long)info;
if (sna_wait_vblank(sna, &vbl))
goto blit_fallback;
- *target_msc = vbl.reply.sequence;
return TRUE;
blit_fallback:
@@ -2204,19 +2174,20 @@ sna_dri_async_swap(ClientPtr client, DrawablePtr draw,
DRI2SwapEventPtr func, void *data)
{
struct sna *sna = to_sna_from_drawable(draw);
- struct sna_dri_frame_event *info;
- struct kgem_bo *bo;
- int name;
+ CARD64 target_msc = 0;
+ int pipe;
DBG(("%s()\n", __FUNCTION__));
- if (!can_flip(sna, draw, front, back)) {
-blit:
- name = DRI2_BLIT_COMPLETE;
+ if (!can_flip(sna, draw, front, back) ||
+ (pipe = sna_dri_get_pipe(draw)) < 0 ||
+ !sna_dri_schedule_flip(client, draw, front, back, pipe,
+ &target_msc, 0, 0, func, data)) {
+ pipe = DRI2_BLIT_COMPLETE;
if (can_exchange(sna, draw, front, back)) {
DBG(("%s: unable to flip, so xchg\n", __FUNCTION__));
sna_dri_exchange_buffers(draw, front, back);
- name = DRI2_EXCHANGE_COMPLETE;
+ pipe = DRI2_EXCHANGE_COMPLETE;
} else if (can_blit(sna, draw, front, back)) {
DBG(("%s: unable to flip, so blit\n", __FUNCTION__));
sna_dri_copy_to_front(sna, draw, NULL,
@@ -2225,80 +2196,9 @@ blit:
false);
}
- DRI2SwapComplete(client, draw, 0, 0, 0, name, func, data);
- return name == DRI2_EXCHANGE_COMPLETE;
+ DRI2SwapComplete(client, draw, 0, 0, 0, pipe, func, data);
+ return pipe == DRI2_EXCHANGE_COMPLETE;
}
-
- bo = NULL;
- name = 0;
-
- info = sna->dri.flip_pending;
- if (info == NULL) {
- int pipe = sna_dri_get_pipe(draw);
- if (pipe == -1)
- goto blit;
-
- DBG(("%s: no pending flip, so updating scanout\n",
- __FUNCTION__));
-
- info = calloc(1, sizeof(struct sna_dri_frame_event));
- if (!info)
- goto blit;
-
- info->client = client;
- info->draw = draw;
- info->type = DRI2_ASYNC_FLIP;
- info->pipe = pipe;
- info->front = front;
- info->back = back;
-
- sna_dri_add_frame_event(draw, info);
- sna_dri_reference_buffer(front);
- sna_dri_reference_buffer(back);
-
- if (!sna_dri_page_flip(sna, info))
- goto blit;
-
- info->next_front.name = info->front->name;
- info->next_front.bo = get_private(info->front)->bo;
- info->off_delay = FLIP_OFF_DELAY;
- } else if (info->type != DRI2_ASYNC_FLIP) {
- /* A normal vsync'ed client is finishing, wait for it
- * to unpin the old framebuffer before taking over.
- */
- goto blit;
- } else {
- DBG(("%s: pending flip, chaining next\n", __FUNCTION__));
- if (info->next_front.name == info->front->name) {
- name = info->cache.name;
- bo = info->cache.bo;
- } else {
- name = info->front->name;
- bo = get_private(info->front)->bo;
- }
- info->front->name = info->back->name;
- get_private(info->front)->bo = get_private(info->back)->bo;
- }
-
- if (bo == NULL) {
- DBG(("%s: creating new back buffer\n", __FUNCTION__));
- bo = kgem_create_2d(&sna->kgem,
- draw->width,
- draw->height,
- draw->bitsPerPixel,
- get_private(info->front)->bo->tiling,
- CREATE_SCANOUT | CREATE_EXACT);
- name = kgem_bo_flink(&sna->kgem, bo);
- }
- assert(bo->refcnt);
- get_private(info->back)->bo = bo;
- info->back->name = name;
-
- set_bo(sna->front, get_private(info->front)->bo);
- sna->dri.flip_pending = info;
-
- DRI2SwapComplete(client, draw, 0, 0, 0,
- DRI2_EXCHANGE_COMPLETE, func, data);
return TRUE;
}
#endif
diff --git a/src/sna/sna_video.c b/src/sna/sna_video.c
index 8d111d54..05d76dda 100644
--- a/src/sna/sna_video.c
+++ b/src/sna/sna_video.c
@@ -104,8 +104,7 @@ sna_video_buffer(struct sna *sna,
if (video->tiled) {
video->buf = kgem_create_2d(&sna->kgem,
frame->width, frame->height, 32,
- I915_TILING_X,
- CREATE_EXACT | CREATE_SCANOUT);
+ I915_TILING_X, CREATE_EXACT);
} else {
video->buf = kgem_create_linear(&sna->kgem, frame->size,
CREATE_GTT_MAP);