sna/dri2: Allow TearFree flipping to individual CRTC
Baby step. We first take advantage of TearFree to allow us to redirect a single CRTC to the DRI2 frontbuffer and so allow a fullscreen game covering a single monitor to avoid expensive blits when running in a multi-monitor setup. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
parent
af3130cbba
commit
3932e97057
|
|
@ -4400,7 +4400,7 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
|
|||
bucket = cache_bucket(size);
|
||||
|
||||
if (flags & CREATE_SCANOUT) {
|
||||
struct kgem_bo *last = NULL, *first = NULL;
|
||||
struct kgem_bo *last = NULL;
|
||||
|
||||
list_for_each_entry_reverse(bo, &kgem->scanout, list) {
|
||||
assert(bo->scanout);
|
||||
|
|
@ -4414,11 +4414,8 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
|
|||
/* No tiling/pitch without recreating fb */
|
||||
continue;
|
||||
|
||||
if (bo->delta && !check_scanout_size(kgem, bo, width, height)) {
|
||||
if (first == NULL)
|
||||
first = bo;
|
||||
if (bo->delta && !check_scanout_size(kgem, bo, width, height))
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags & CREATE_INACTIVE && bo->rq) {
|
||||
last = bo;
|
||||
|
|
@ -4448,44 +4445,60 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem,
|
|||
return last;
|
||||
}
|
||||
|
||||
if (first) {
|
||||
ScrnInfoPtr scrn =
|
||||
container_of(kgem, struct sna, kgem)->scrn;
|
||||
if (container_of(kgem, struct sna, kgem)->scrn->vtSema) {
|
||||
ScrnInfoPtr scrn = container_of(kgem, struct sna, kgem)->scrn;
|
||||
|
||||
if (scrn->vtSema) {
|
||||
DBG(("%s: recreate fb %dx%d@%d/%d\n",
|
||||
__FUNCTION__, width, height, scrn->depth, scrn->bitsPerPixel));
|
||||
list_for_each_entry_reverse(bo, &kgem->scanout, list) {
|
||||
struct drm_mode_fb_cmd arg;
|
||||
|
||||
if (first->tiling != tiling ||
|
||||
(tiling != I915_TILING_NONE && first->pitch != pitch)) {
|
||||
if (gem_set_tiling(kgem->fd, first->handle,
|
||||
assert(bo->scanout);
|
||||
|
||||
if (size > num_pages(bo) || num_pages(bo) > 2*size)
|
||||
continue;
|
||||
|
||||
if (flags & CREATE_INACTIVE && bo->rq)
|
||||
continue;
|
||||
|
||||
list_del(&bo->list);
|
||||
|
||||
if (bo->tiling != tiling || bo->pitch != pitch) {
|
||||
if (bo->delta) {
|
||||
kgem_bo_rmfb(kgem, bo);
|
||||
bo->delta = 0;
|
||||
}
|
||||
|
||||
if (gem_set_tiling(kgem->fd, bo->handle,
|
||||
tiling, pitch)) {
|
||||
first->tiling = tiling;
|
||||
first->pitch = pitch;
|
||||
}
|
||||
}
|
||||
|
||||
if (first->tiling == tiling && first->pitch == pitch) {
|
||||
struct drm_mode_fb_cmd arg;
|
||||
|
||||
VG_CLEAR(arg);
|
||||
arg.width = width;
|
||||
arg.height = height;
|
||||
arg.pitch = first->pitch;
|
||||
arg.bpp = scrn->bitsPerPixel;
|
||||
arg.depth = scrn->depth;
|
||||
arg.handle = first->handle;
|
||||
|
||||
kgem_bo_rmfb(kgem, first);
|
||||
if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg)) {
|
||||
kgem_bo_free(kgem, first);
|
||||
bo->tiling = tiling;
|
||||
bo->pitch = pitch;
|
||||
} else {
|
||||
DBG(("%s: attached fb=%d to handle=%d\n",
|
||||
__FUNCTION__, arg.fb_id, arg.handle));
|
||||
first->delta = arg.fb_id;
|
||||
return first;
|
||||
kgem_bo_free(kgem, bo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VG_CLEAR(arg);
|
||||
arg.width = width;
|
||||
arg.height = height;
|
||||
arg.pitch = bo->pitch;
|
||||
arg.bpp = scrn->bitsPerPixel;
|
||||
arg.depth = scrn->depth;
|
||||
arg.handle = bo->handle;
|
||||
|
||||
if (do_ioctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &arg)) {
|
||||
kgem_bo_free(kgem, bo);
|
||||
break;
|
||||
}
|
||||
|
||||
bo->delta = arg.fb_id;
|
||||
bo->unique_id = kgem_get_unique_id(kgem);
|
||||
|
||||
DBG((" 2: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));
|
||||
assert_tiling(kgem, bo);
|
||||
bo->refcnt = 1;
|
||||
return bo;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -291,6 +291,8 @@ struct sna {
|
|||
|
||||
int max_crtc_width, max_crtc_height;
|
||||
RegionRec shadow_region;
|
||||
struct list shadow_crtc;
|
||||
bool shadow_dirty;
|
||||
|
||||
unsigned num_real_crtc;
|
||||
unsigned num_real_output;
|
||||
|
|
@ -424,6 +426,8 @@ 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);
|
||||
extern void sna_shadow_set_crtc(struct sna *sna, xf86CrtcPtr crtc, struct kgem_bo *bo);
|
||||
extern void sna_shadow_unset_crtc(struct sna *sna, xf86CrtcPtr crtc);
|
||||
extern void sna_pixmap_discard_shadow_damage(struct sna_pixmap *priv,
|
||||
RegionPtr region);
|
||||
extern void sna_mode_close(struct sna *sna);
|
||||
|
|
@ -570,7 +574,8 @@ extern bool sna_crtc_set_sprite_rotation(xf86CrtcPtr crtc, uint32_t rotation);
|
|||
extern int sna_crtc_to_pipe(xf86CrtcPtr crtc);
|
||||
extern uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc);
|
||||
extern uint32_t sna_crtc_id(xf86CrtcPtr crtc);
|
||||
extern int sna_crtc_is_on(xf86CrtcPtr crtc);
|
||||
extern bool sna_crtc_is_on(xf86CrtcPtr crtc);
|
||||
extern bool sna_crtc_is_transformed(xf86CrtcPtr crtc);
|
||||
|
||||
CARD32 sna_format_for_depth(int depth);
|
||||
CARD32 sna_render_format_for_depth(int depth);
|
||||
|
|
@ -688,6 +693,7 @@ sna_pixmap_undo_cow(struct sna *sna, struct sna_pixmap *priv, unsigned flags);
|
|||
#define MOVE_WHOLE_HINT 0x20
|
||||
#define __MOVE_FORCE 0x40
|
||||
#define __MOVE_DRI 0x80
|
||||
#define __MOVE_SCANOUT 0x100
|
||||
|
||||
struct sna_pixmap *
|
||||
sna_pixmap_move_area_to_gpu(PixmapPtr pixmap, const BoxRec *box, unsigned int flags);
|
||||
|
|
|
|||
|
|
@ -16868,7 +16868,7 @@ static void sna_scanout_flush(struct sna *sna)
|
|||
|
||||
if (priv &&
|
||||
sna_pixmap_force_to_gpu(priv->pixmap,
|
||||
MOVE_READ | MOVE_ASYNC_HINT))
|
||||
MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT))
|
||||
kgem_scanout_flush(&sna->kgem, priv->gpu_bo);
|
||||
|
||||
sna_mode_redisplay(sna);
|
||||
|
|
|
|||
|
|
@ -99,12 +99,14 @@ union compat_mode_get_connector{
|
|||
extern XF86ConfigPtr xf86configptr;
|
||||
|
||||
struct sna_crtc {
|
||||
xf86CrtcPtr base;
|
||||
struct drm_mode_modeinfo kmode;
|
||||
int dpms_mode;
|
||||
PixmapPtr scanout_pixmap;
|
||||
struct kgem_bo *bo, *shadow_bo;
|
||||
struct sna_cursor *cursor;
|
||||
uint32_t sprite;
|
||||
uint32_t offset;
|
||||
bool shadow;
|
||||
bool fallback_shadow;
|
||||
bool transform;
|
||||
|
|
@ -125,6 +127,8 @@ struct sna_crtc {
|
|||
sna_flip_handler_t flip_handler;
|
||||
struct kgem_bo *flip_bo;
|
||||
void *flip_data;
|
||||
|
||||
struct list shadow_link;
|
||||
};
|
||||
|
||||
struct sna_property {
|
||||
|
|
@ -234,12 +238,18 @@ uint32_t sna_crtc_to_sprite(xf86CrtcPtr crtc)
|
|||
return to_sna_crtc(crtc)->sprite;
|
||||
}
|
||||
|
||||
int sna_crtc_is_on(xf86CrtcPtr crtc)
|
||||
bool sna_crtc_is_on(xf86CrtcPtr crtc)
|
||||
{
|
||||
assert(to_sna_crtc(crtc));
|
||||
return to_sna_crtc(crtc)->bo != NULL;
|
||||
}
|
||||
|
||||
bool sna_crtc_is_transformed(xf86CrtcPtr crtc)
|
||||
{
|
||||
assert(to_sna_crtc(crtc));
|
||||
return to_sna_crtc(crtc)->transform;
|
||||
}
|
||||
|
||||
static inline uint64_t msc64(struct sna_crtc *sna_crtc, uint32_t seq)
|
||||
{
|
||||
if (seq < sna_crtc->last_seq) {
|
||||
|
|
@ -988,9 +998,11 @@ sna_crtc_apply(xf86CrtcPtr crtc)
|
|||
if (sna_crtc->transform) {
|
||||
arg.x = 0;
|
||||
arg.y = 0;
|
||||
sna_crtc->offset = 0;
|
||||
} else {
|
||||
arg.x = crtc->x;
|
||||
arg.y = crtc->y;
|
||||
sna_crtc->offset = arg.y << 16 | arg.x;
|
||||
}
|
||||
arg.set_connectors_ptr = (uintptr_t)output_ids;
|
||||
arg.count_connectors = output_count;
|
||||
|
|
@ -1032,6 +1044,34 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
|
|||
if (flags == 0 || pixmap != sna->front || !sna->mode.shadow_damage)
|
||||
goto done;
|
||||
|
||||
if ((flags & __MOVE_SCANOUT) == 0) {
|
||||
while (!list_is_empty(&sna->mode.shadow_crtc)) {
|
||||
struct sna_crtc *crtc =
|
||||
list_first_entry(&sna->mode.shadow_crtc, struct sna_crtc, shadow_link);
|
||||
RegionRec region;
|
||||
|
||||
DBG(("%s: copying replaced CRTC: (%d, %d), (%d, %d)\n",
|
||||
__FUNCTION__,
|
||||
crtc->base->bounds.x1,
|
||||
crtc->base->bounds.y1,
|
||||
crtc->base->bounds.x2,
|
||||
crtc->base->bounds.y2));
|
||||
ret = sna->render.copy_boxes(sna, GXcopy,
|
||||
pixmap, crtc->shadow_bo, -crtc->base->bounds.x1, -crtc->base->bounds.y1,
|
||||
pixmap, priv->gpu_bo, 0, 0,
|
||||
&crtc->base->bounds, 1,
|
||||
0);
|
||||
|
||||
kgem_bo_destroy(&sna->kgem, crtc->shadow_bo);
|
||||
crtc->shadow_bo = NULL;
|
||||
list_del(&crtc->shadow_link);
|
||||
|
||||
region.extents = crtc->base->bounds;
|
||||
region.data = NULL;
|
||||
RegionSubtract(&sna->mode.shadow_region, &sna->mode.shadow_region, ®ion);
|
||||
}
|
||||
}
|
||||
|
||||
if ((flags & MOVE_WRITE) == 0)
|
||||
return true;
|
||||
|
||||
|
|
@ -1123,7 +1163,8 @@ static bool wait_for_shadow(struct sna *sna, struct sna_pixmap *priv, unsigned f
|
|||
sna_dri2_pixmap_update_bo(sna, pixmap, bo);
|
||||
|
||||
done:
|
||||
RegionUninit(&sna->mode.shadow_region);
|
||||
RegionEmpty(&sna->mode.shadow_region);
|
||||
sna->mode.shadow_dirty = false;
|
||||
|
||||
priv->move_to_gpu_data = NULL;
|
||||
priv->move_to_gpu = NULL;
|
||||
|
|
@ -1199,6 +1240,7 @@ static void sna_mode_disable_shadow(struct sna *sna)
|
|||
}
|
||||
|
||||
assert(sna->mode.shadow_active == 0);
|
||||
sna->mode.shadow_dirty = false;
|
||||
}
|
||||
|
||||
static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
|
||||
|
|
@ -1235,6 +1277,13 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc)
|
|||
sna_mode_disable_shadow(sna);
|
||||
|
||||
if (crtc->shadow_bo) {
|
||||
if (!crtc->transform) {
|
||||
sna->render.copy_boxes(sna, GXcopy,
|
||||
sna->front, crtc->shadow_bo, -crtc->base->bounds.x1, -crtc->base->bounds.y1,
|
||||
sna->front, __sna_pixmap_get_bo(sna->front), 0, 0,
|
||||
&crtc->base->bounds, 1, 0);
|
||||
list_del(&crtc->shadow_link);
|
||||
}
|
||||
kgem_bo_destroy(&sna->kgem, crtc->shadow_bo);
|
||||
crtc->shadow_bo = NULL;
|
||||
}
|
||||
|
|
@ -1556,9 +1605,6 @@ static void set_shadow(struct sna *sna, RegionPtr region)
|
|||
assert((priv->pinned & PIN_PRIME) == 0);
|
||||
assert(sna->mode.shadow != priv->gpu_bo);
|
||||
|
||||
assert(priv->move_to_gpu == NULL);
|
||||
|
||||
RegionNull(&sna->mode.shadow_region);
|
||||
RegionCopy(&sna->mode.shadow_region, region);
|
||||
|
||||
priv->move_to_gpu = wait_for_shadow;
|
||||
|
|
@ -1635,7 +1681,7 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
|
|||
return NULL;
|
||||
|
||||
if (sna->flags & SNA_TEAR_FREE) {
|
||||
DBG(("%s: creating TearFree shadow\n", __FUNCTION__));
|
||||
DBG(("%s: enabling TearFree shadow\n", __FUNCTION__));
|
||||
if (!sna_crtc_enable_shadow(sna, sna_crtc))
|
||||
return NULL;
|
||||
|
||||
|
|
@ -1643,6 +1689,8 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
|
|||
RegionRec region;
|
||||
struct kgem_bo *shadow;
|
||||
|
||||
DBG(("%s: creating TearFree shadow bo\n", __FUNCTION__));
|
||||
|
||||
region.extents.x1 = 0;
|
||||
region.extents.y1 = 0;
|
||||
region.extents.x2 = sna->scrn->virtualX;
|
||||
|
|
@ -1778,6 +1826,12 @@ sna_crtc_damage(xf86CrtcPtr crtc)
|
|||
assert(sna->mode.shadow_damage && sna->mode.shadow_active);
|
||||
damage = DamageRegion(sna->mode.shadow_damage);
|
||||
RegionUnion(damage, damage, ®ion);
|
||||
|
||||
DBG(("%s: damage now %ldx[(%d, %d), (%d, %d)]\n",
|
||||
__FUNCTION__,
|
||||
(long)RegionNumRects(damage),
|
||||
damage->extents.x1, damage->extents.y1,
|
||||
damage->extents.x2, damage->extents.y2));
|
||||
}
|
||||
|
||||
static char *outputs_for_crtc(xf86CrtcPtr crtc, char *outputs, int max)
|
||||
|
|
@ -1831,6 +1885,7 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
|
|||
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
|
||||
struct kgem_bo *saved_bo, *bo;
|
||||
struct drm_mode_modeinfo saved_kmode;
|
||||
uint32_t saved_offset;
|
||||
bool saved_transform;
|
||||
char outputs[256];
|
||||
|
||||
|
|
@ -1859,6 +1914,7 @@ sna_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
|
|||
saved_kmode = sna_crtc->kmode;
|
||||
saved_bo = sna_crtc->bo;
|
||||
saved_transform = sna_crtc->transform;
|
||||
saved_offset = sna_crtc->offset;
|
||||
|
||||
sna_crtc->fallback_shadow = false;
|
||||
retry: /* Attach per-crtc pixmap or direct */
|
||||
|
|
@ -1881,6 +1937,7 @@ retry: /* Attach per-crtc pixmap or direct */
|
|||
xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
|
||||
"failed to set mode: %s\n", strerror(errno));
|
||||
|
||||
sna_crtc->offset = saved_offset;
|
||||
sna_crtc->transform = saved_transform;
|
||||
sna_crtc->bo = saved_bo;
|
||||
sna_crtc->kmode = saved_kmode;
|
||||
|
|
@ -2112,6 +2169,8 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
|
|||
sna_crtc->pipe = get_pipe.pipe;
|
||||
sna_crtc->sprite = sna_crtc_find_sprite(sna, sna_crtc->pipe);
|
||||
|
||||
list_init(&sna_crtc->shadow_link);
|
||||
|
||||
if (xf86IsEntityShared(scrn->entityList[0]) &&
|
||||
scrn->confScreen->device->screen != sna_crtc->pipe) {
|
||||
free(sna_crtc);
|
||||
|
|
@ -2128,6 +2187,7 @@ sna_crtc_add(ScrnInfoPtr scrn, int id)
|
|||
sna_crtc_init__cursor(sna, sna_crtc);
|
||||
|
||||
crtc->driver_private = sna_crtc;
|
||||
sna_crtc->base = crtc;
|
||||
DBG(("%s: attached crtc[%d] pipe=%d\n",
|
||||
__FUNCTION__, id, sna_crtc->pipe));
|
||||
|
||||
|
|
@ -4873,6 +4933,9 @@ bool sna_mode_pre_init(ScrnInfoPtr scrn, struct sna *sna)
|
|||
sna->mode.max_crtc_width = res->max_width;
|
||||
sna->mode.max_crtc_height = res->max_height;
|
||||
|
||||
RegionEmpty(&sna->mode.shadow_region);
|
||||
list_init(&sna->mode.shadow_crtc);
|
||||
|
||||
drmModeFreeResources(res);
|
||||
|
||||
sna_cursor_pre_init(sna);
|
||||
|
|
@ -5689,6 +5752,121 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region)
|
|||
|
||||
#define shadow_flip_handler (sna_flip_handler_t)sna_mode_redisplay
|
||||
|
||||
void sna_shadow_set_crtc(struct sna *sna,
|
||||
xf86CrtcPtr crtc,
|
||||
struct kgem_bo *bo)
|
||||
{
|
||||
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
|
||||
struct sna_pixmap *priv;
|
||||
|
||||
DBG(("%s: setting shadow override for CRTC:%d to handle=%d\n",
|
||||
__FUNCTION__, sna_crtc->id, bo->handle));
|
||||
|
||||
assert(sna->flags & SNA_TEAR_FREE);
|
||||
assert(sna_crtc);
|
||||
assert(!sna_crtc->transform);
|
||||
|
||||
if (sna_crtc->shadow_bo != bo) {
|
||||
if (sna_crtc->shadow_bo)
|
||||
kgem_bo_destroy(&sna->kgem, sna_crtc->shadow_bo);
|
||||
|
||||
sna_crtc->shadow_bo = kgem_bo_reference(bo);
|
||||
sna_crtc_damage(crtc);
|
||||
}
|
||||
|
||||
list_move(&sna_crtc->shadow_link, &sna->mode.shadow_crtc);
|
||||
sna->mode.shadow_dirty = true;
|
||||
|
||||
priv = sna_pixmap(sna->front);
|
||||
assert(priv->gpu_bo);
|
||||
priv->move_to_gpu = wait_for_shadow;
|
||||
priv->move_to_gpu_data = sna;
|
||||
}
|
||||
|
||||
void sna_shadow_unset_crtc(struct sna *sna,
|
||||
xf86CrtcPtr crtc)
|
||||
{
|
||||
struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
|
||||
|
||||
DBG(("%s: clearin shadow override for CRTC:%d\n",
|
||||
__FUNCTION__, sna_crtc->id));
|
||||
|
||||
if (sna_crtc->shadow_bo == NULL)
|
||||
return;
|
||||
|
||||
kgem_bo_destroy(&sna->kgem, sna_crtc->shadow_bo);
|
||||
sna_crtc->shadow_bo = NULL;
|
||||
list_del(&sna_crtc->shadow_link);
|
||||
sna->mode.shadow_dirty = true;
|
||||
|
||||
sna_crtc_damage(crtc);
|
||||
}
|
||||
|
||||
static bool
|
||||
sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc)
|
||||
{
|
||||
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
|
||||
struct kgem_bo *bo = crtc->shadow_bo ? crtc->shadow_bo : crtc->bo;
|
||||
struct drm_mode_crtc arg;
|
||||
uint32_t output_ids[32];
|
||||
int output_count = 0;
|
||||
int i;
|
||||
|
||||
DBG(("%s CRTC:%d [pipe=%d], handle=%d\n", __FUNCTION__, crtc->id, crtc->pipe, bo->handle));
|
||||
|
||||
assert(config->num_output < ARRAY_SIZE(output_ids));
|
||||
|
||||
for (i = 0; i < config->num_output; i++) {
|
||||
xf86OutputPtr output = config->output[i];
|
||||
|
||||
if (output->crtc != crtc->base)
|
||||
continue;
|
||||
|
||||
DBG(("%s: attaching output '%s' %d [%d] to crtc:%d (pipe %d) (possible crtc:%x, possible clones:%x)\n",
|
||||
__FUNCTION__, output->name, i, to_connector_id(output),
|
||||
crtc->id, crtc->pipe,
|
||||
(uint32_t)output->possible_crtcs,
|
||||
(uint32_t)output->possible_clones));
|
||||
|
||||
assert(output->possible_crtcs & (1 << crtc->pipe) ||
|
||||
xf86IsEntityShared(sna->scrn->entityList[0]));
|
||||
|
||||
output_ids[output_count] = to_connector_id(output);
|
||||
if (++output_count == ARRAY_SIZE(output_ids))
|
||||
return false;
|
||||
}
|
||||
|
||||
VG_CLEAR(arg);
|
||||
arg.crtc_id = crtc->id;
|
||||
arg.fb_id = fb_id(bo);
|
||||
assert(arg.fb_id);
|
||||
if (bo != crtc->bo) {
|
||||
arg.x = 0;
|
||||
arg.y = 0;
|
||||
crtc->offset = 0;
|
||||
} else {
|
||||
arg.x = crtc->base->x;
|
||||
arg.y = crtc->base->y;
|
||||
crtc->offset = arg.y << 16 | arg.x;
|
||||
}
|
||||
arg.set_connectors_ptr = (uintptr_t)output_ids;
|
||||
arg.count_connectors = output_count;
|
||||
arg.mode = crtc->kmode;
|
||||
arg.mode_valid = 1;
|
||||
|
||||
DBG(("%s: applying crtc [%d, pipe=%d] mode=%dx%d+%d+%d@%d, fb=%d%s update to %d outputs [%d...]\n",
|
||||
__FUNCTION__, crtc->id, crtc->pipe,
|
||||
arg.mode.hdisplay,
|
||||
arg.mode.vdisplay,
|
||||
arg.x, arg.y,
|
||||
arg.mode.clock,
|
||||
arg.fb_id,
|
||||
bo != crtc->bo ? " [shadow]" : "",
|
||||
output_count, output_count ? output_ids[0] : 0));
|
||||
|
||||
return drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_SETCRTC, &arg) == 0;
|
||||
}
|
||||
|
||||
void sna_mode_redisplay(struct sna *sna)
|
||||
{
|
||||
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
|
||||
|
|
@ -5729,7 +5907,8 @@ void sna_mode_redisplay(struct sna *sna)
|
|||
if (sna->mode.flip_active)
|
||||
return;
|
||||
|
||||
if (wedged(sna) || !sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT)) {
|
||||
if (wedged(sna) || !sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT | __MOVE_SCANOUT)) {
|
||||
DBG(("%s: forcing scanout update using the CPU\n", __FUNCTION__));
|
||||
if (!sna_pixmap_move_to_cpu(sna->front, MOVE_READ))
|
||||
return;
|
||||
|
||||
|
|
@ -5764,12 +5943,14 @@ void sna_mode_redisplay(struct sna *sna)
|
|||
assert(priv != NULL);
|
||||
|
||||
if (priv->move_to_gpu) {
|
||||
if (priv->move_to_gpu == wait_for_shadow) {
|
||||
if (priv->move_to_gpu == wait_for_shadow &&
|
||||
!sna->mode.shadow_dirty) {
|
||||
/* No damage written to new scanout
|
||||
* (backbuffer), ignore redisplay request
|
||||
* and continue with the current intact
|
||||
* scanout (frontbuffer).
|
||||
*/
|
||||
DBG(("%s: shadow idle, skipping update\n", __FUNCTION__));
|
||||
RegionEmpty(region);
|
||||
return;
|
||||
}
|
||||
|
|
@ -5875,31 +6056,33 @@ disable1:
|
|||
struct kgem_bo *new = __sna_pixmap_get_bo(sna->front);
|
||||
struct kgem_bo *old = sna->mode.shadow;
|
||||
struct drm_mode_crtc_page_flip arg;
|
||||
uint32_t fb_id;
|
||||
|
||||
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;
|
||||
|
||||
fb_id = get_fb(sna, new,
|
||||
sna->scrn->virtualX,
|
||||
sna->scrn->virtualY);
|
||||
if (fb_id == 0) {
|
||||
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);
|
||||
if (sna_pixmap_move_to_gpu(sna->front, MOVE_READ | MOVE_ASYNC_HINT)) {
|
||||
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, __sna_pixmap_get_bo(sna->front), 0, 0,
|
||||
sna->front, old, 0, 0,
|
||||
&box, 1, COPY_LAST)) {
|
||||
kgem_submit(&sna->kgem);
|
||||
RegionEmpty(region);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -5912,6 +6095,8 @@ fixup_shadow:
|
|||
|
||||
for (i = 0; i < sna->mode.num_real_crtc; i++) {
|
||||
struct sna_crtc *crtc = config->crtc[i]->driver_private;
|
||||
struct kgem_bo *flip_bo;
|
||||
uint32_t crtc_offset = 0;
|
||||
|
||||
assert(crtc != NULL);
|
||||
DBG(("%s: crtc %d [%d, pipe=%d] active? %d, transformed? %d\n",
|
||||
|
|
@ -5925,23 +6110,64 @@ fixup_shadow:
|
|||
arg.crtc_id = crtc->id;
|
||||
arg.user_data = (uintptr_t)crtc;
|
||||
|
||||
if (crtc->shadow_bo) {
|
||||
DBG(("%s: apply shadow override bo for CRTC:%d on pipe=%d, handle=%d\n",
|
||||
__FUNCTION__, crtc->id, crtc->pipe, crtc->shadow_bo->handle));
|
||||
arg.fb_id = get_fb(sna, crtc->shadow_bo,
|
||||
crtc->base->mode.HDisplay,
|
||||
crtc->base->mode.VDisplay);
|
||||
flip_bo = crtc->shadow_bo;
|
||||
crtc_offset = 0;
|
||||
} else {
|
||||
arg.fb_id = fb_id;
|
||||
flip_bo = new;
|
||||
crtc_offset = crtc->base->y << 16 | crtc->base->x;
|
||||
}
|
||||
|
||||
if (crtc->bo == flip_bo)
|
||||
continue;
|
||||
|
||||
if (flip_bo->pitch != crtc->bo->pitch || crtc_offset != crtc->offset) {
|
||||
DBG(("%s: changing pitch (%d == %d) or offset (%x == %x)\n",
|
||||
__FUNCTION__,
|
||||
flip_bo->pitch, crtc->bo->pitch,
|
||||
crtc_offset, crtc->offset));
|
||||
fixup_flip:
|
||||
if (sna_crtc_flip(sna, crtc)) {
|
||||
assert(crtc->bo->active_scanout);
|
||||
assert(crtc->bo->refcnt >= crtc->bo->active_scanout);
|
||||
crtc->bo->active_scanout--;
|
||||
kgem_bo_destroy(&sna->kgem, crtc->bo);
|
||||
|
||||
crtc->bo = kgem_bo_reference(flip_bo);
|
||||
crtc->bo->active_scanout++;
|
||||
|
||||
if (crtc->shadow_bo)
|
||||
sna_shadow_set_crtc(sna, crtc->base, flip_bo);
|
||||
} else {
|
||||
if (sna->mode.flip_active == 0) {
|
||||
DBG(("%s: abandoning flip attempt\n", __FUNCTION__));
|
||||
goto fixup_shadow;
|
||||
}
|
||||
|
||||
xf86DrvMsg(sna->scrn->scrnIndex, X_ERROR,
|
||||
"%s: page flipping failed, disabling CRTC:%d (pipe=%d)\n",
|
||||
__FUNCTION__, crtc->id, crtc->pipe);
|
||||
sna_crtc_disable(crtc->base);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (drmIoctl(sna->kgem.fd, DRM_IOCTL_MODE_PAGE_FLIP, &arg)) {
|
||||
ERR(("%s: flip [fb=%d] on crtc %d [%d, pipe=%d] failed - %d\n",
|
||||
__FUNCTION__, arg.fb_id, i, crtc->id, crtc->pipe, errno));
|
||||
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",
|
||||
__FUNCTION__, crtc->id, crtc->pipe);
|
||||
sna_crtc_disable(config->crtc[i]);
|
||||
continue;
|
||||
goto fixup_flip;
|
||||
}
|
||||
sna->mode.flip_active++;
|
||||
|
||||
assert(crtc->flip_bo == NULL);
|
||||
crtc->flip_handler = shadow_flip_handler;
|
||||
crtc->flip_bo = kgem_bo_reference(new);
|
||||
crtc->flip_bo = kgem_bo_reference(flip_bo);
|
||||
crtc->flip_bo->active_scanout++;
|
||||
}
|
||||
|
||||
|
|
@ -6012,6 +6238,7 @@ void sna_mode_wakeup(struct sna *sna)
|
|||
crtc->flip_bo = NULL;
|
||||
}
|
||||
|
||||
DBG(("%s: flip complete, pending? %d\n", __FUNCTION__, sna->mode.flip_active));
|
||||
assert(sna->mode.flip_active);
|
||||
if (--sna->mode.flip_active == 0)
|
||||
crtc->flip_handler(sna, vbl, crtc->flip_data);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ static inline void unref(struct kgem_bo *bo)
|
|||
struct sna_dri2_private {
|
||||
PixmapPtr pixmap;
|
||||
struct kgem_bo *bo;
|
||||
bool scanout;
|
||||
DRI2Buffer2Ptr proxy;
|
||||
bool stale;
|
||||
uint32_t size;
|
||||
int refcnt;
|
||||
|
|
@ -129,6 +129,7 @@ static void sna_dri2_flip_event(struct sna *sna,
|
|||
|
||||
static void
|
||||
sna_dri2_get_back(struct sna *sna,
|
||||
DrawablePtr draw,
|
||||
DRI2BufferPtr back,
|
||||
struct sna_dri2_event *info)
|
||||
{
|
||||
|
|
@ -160,12 +161,11 @@ sna_dri2_get_back(struct sna *sna,
|
|||
}
|
||||
}
|
||||
if (bo == NULL) {
|
||||
DrawablePtr draw = &sna->front->drawable;
|
||||
DBG(("%s: allocating new backbuffer\n", __FUNCTION__));
|
||||
bo = kgem_create_2d(&sna->kgem,
|
||||
draw->width, draw->height, draw->bitsPerPixel,
|
||||
get_private(back)->bo->tiling,
|
||||
CREATE_SCANOUT);
|
||||
get_private(back)->bo->scanout ? CREATE_SCANOUT : 0);
|
||||
if (bo == NULL)
|
||||
return;
|
||||
|
||||
|
|
@ -203,6 +203,7 @@ sna_dri2_get_back(struct sna *sna,
|
|||
}
|
||||
|
||||
struct dri2_window {
|
||||
DRI2BufferPtr front;
|
||||
struct sna_dri2_event *chain;
|
||||
xf86CrtcPtr crtc;
|
||||
int64_t msc_delta;
|
||||
|
|
@ -248,7 +249,7 @@ sna_dri2_reuse_buffer(DrawablePtr draw, DRI2BufferPtr buffer)
|
|||
if (buffer->attachment == DRI2BufferBackLeft &&
|
||||
draw->type != DRAWABLE_PIXMAP) {
|
||||
DBG(("%s: replacing back buffer\n", __FUNCTION__));
|
||||
sna_dri2_get_back(to_sna_from_drawable(draw), buffer, dri2_chain(draw));
|
||||
sna_dri2_get_back(to_sna_from_drawable(draw), draw, buffer, dri2_chain(draw));
|
||||
|
||||
assert(kgem_bo_flink(&to_sna_from_drawable(draw)->kgem, get_private(buffer)->bo) == buffer->name);
|
||||
assert(get_private(buffer)->bo->active_scanout == 0);
|
||||
|
|
@ -409,22 +410,30 @@ sna_dri2_create_buffer(DrawablePtr draw,
|
|||
switch (attachment) {
|
||||
case DRI2BufferFrontLeft:
|
||||
pixmap = get_drawable_pixmap(draw);
|
||||
buffer = sna_pixmap_get_buffer(pixmap);
|
||||
buffer = NULL;
|
||||
if (draw->type != DRAWABLE_PIXMAP)
|
||||
buffer = dri2_window((WindowPtr)draw)->front;
|
||||
if (buffer == NULL)
|
||||
buffer = sna_pixmap_get_buffer(pixmap);
|
||||
if (buffer) {
|
||||
private = get_private(buffer);
|
||||
|
||||
DBG(("%s: reusing front buffer attachment, pixmap=%ld, handle=%d, name=%d\n",
|
||||
__FUNCTION__, pixmap->drawable.serialNumber,
|
||||
DBG(("%s: reusing front buffer attachment, win=%lu %dx%d, pixmap=%ld %dx%d, handle=%d, name=%d\n",
|
||||
__FUNCTION__,
|
||||
draw->type != DRAWABLE_PIXMAP ? (long)draw->id : (long)0,
|
||||
draw->width, draw->height,
|
||||
pixmap->drawable.serialNumber,
|
||||
pixmap->drawable.width,
|
||||
pixmap->drawable.height,
|
||||
private->bo->handle, buffer->name));
|
||||
|
||||
assert(private->pixmap == pixmap);
|
||||
assert(private->bo->flush);
|
||||
assert(sna_pixmap(pixmap)->flush);
|
||||
assert(sna_pixmap(pixmap)->gpu_bo == private->bo);
|
||||
assert(sna_pixmap(pixmap)->pinned & PIN_DRI2);
|
||||
assert(private->proxy != NULL || sna_pixmap(pixmap)->gpu_bo == private->bo);
|
||||
assert(kgem_bo_flink(&sna->kgem, private->bo) == buffer->name);
|
||||
assert(8*private->bo->pitch >= pixmap->drawable.width * pixmap->drawable.bitsPerPixel);
|
||||
assert(private->bo->pitch * pixmap->drawable.height <= kgem_bo_size(private->bo));
|
||||
|
||||
buffer->attachment = DRI2BufferFrontLeft;
|
||||
|
||||
private->refcnt++;
|
||||
return buffer;
|
||||
|
|
@ -448,10 +457,14 @@ sna_dri2_create_buffer(DrawablePtr draw,
|
|||
break;
|
||||
|
||||
case DRI2BufferBackLeft:
|
||||
if (draw->width == sna->front->drawable.width &&
|
||||
draw->height == sna->front->drawable.height &&
|
||||
(sna->flags & (SNA_NO_WAIT | SNA_NO_FLIP)) == 0)
|
||||
flags |= CREATE_SCANOUT;
|
||||
if (draw->type != DRAWABLE_PIXMAP) {
|
||||
if (dri2_window((WindowPtr)draw)->front)
|
||||
flags |= CREATE_SCANOUT;
|
||||
if (draw->width == sna->front->drawable.width &&
|
||||
draw->height == sna->front->drawable.height &&
|
||||
(sna->flags & (SNA_NO_WAIT | SNA_NO_FLIP)) == 0)
|
||||
flags |= CREATE_SCANOUT;
|
||||
}
|
||||
case DRI2BufferBackRight:
|
||||
case DRI2BufferFrontRight:
|
||||
case DRI2BufferFakeFrontLeft:
|
||||
|
|
@ -533,7 +546,6 @@ sna_dri2_create_buffer(DrawablePtr draw,
|
|||
private->refcnt = 1;
|
||||
private->bo = bo;
|
||||
private->pixmap = pixmap;
|
||||
private->scanout = !!(flags & CREATE_SCANOUT);
|
||||
private->size = size;
|
||||
|
||||
if (buffer->name == 0)
|
||||
|
|
@ -593,6 +605,12 @@ static void _sna_dri2_destroy_buffer(struct sna *sna, DRI2Buffer2Ptr buffer)
|
|||
return;
|
||||
|
||||
assert(private->bo);
|
||||
|
||||
if (private->proxy) {
|
||||
_sna_dri2_destroy_buffer(sna, private->proxy);
|
||||
private->pixmap = NULL;
|
||||
}
|
||||
|
||||
if (private->pixmap) {
|
||||
PixmapPtr pixmap = private->pixmap;
|
||||
struct sna_pixmap *priv = sna_pixmap(pixmap);
|
||||
|
|
@ -1078,6 +1096,7 @@ draw_current_msc(DrawablePtr draw, xf86CrtcPtr crtc, uint64_t msc)
|
|||
if (priv == NULL) {
|
||||
priv = malloc(sizeof(*priv));
|
||||
if (priv != NULL) {
|
||||
priv->front = NULL;
|
||||
priv->crtc = crtc;
|
||||
priv->msc_delta = 0;
|
||||
priv->chain = NULL;
|
||||
|
|
@ -1226,6 +1245,7 @@ sna_dri2_event_free(struct sna *sna,
|
|||
|
||||
void sna_dri2_destroy_window(WindowPtr win)
|
||||
{
|
||||
struct sna *sna;
|
||||
struct dri2_window *priv;
|
||||
|
||||
priv = dri2_window(win);
|
||||
|
|
@ -1233,9 +1253,15 @@ void sna_dri2_destroy_window(WindowPtr win)
|
|||
return;
|
||||
|
||||
DBG(("%s: window=%ld\n", __FUNCTION__, win->drawable.serialNumber));
|
||||
sna = to_sna_from_drawable(&win->drawable);
|
||||
|
||||
if (priv->front) {
|
||||
assert(priv->crtc);
|
||||
sna_shadow_unset_crtc(sna, priv->crtc);
|
||||
_sna_dri2_destroy_buffer(sna, priv->front);
|
||||
}
|
||||
|
||||
if (priv->chain) {
|
||||
struct sna *sna = to_sna_from_drawable(&win->drawable);
|
||||
struct sna_dri2_event *info, *chain;
|
||||
|
||||
DBG(("%s: freeing chain\n", __FUNCTION__));
|
||||
|
|
@ -1377,7 +1403,7 @@ can_flip(struct sna * sna,
|
|||
assert(get_private(front)->pixmap == sna->front);
|
||||
assert(sna_pixmap(sna->front)->gpu_bo == get_private(front)->bo);
|
||||
|
||||
if (!get_private(back)->scanout) {
|
||||
if (!get_private(back)->bo->scanout) {
|
||||
DBG(("%s: no, DRI2 drawable was too small at time of creation)\n",
|
||||
__FUNCTION__));
|
||||
return false;
|
||||
|
|
@ -1513,6 +1539,107 @@ can_xchg(struct sna * sna,
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
overlaps_other_crtc(struct sna *sna, xf86CrtcPtr desired)
|
||||
{
|
||||
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(sna->scrn);
|
||||
int c;
|
||||
|
||||
for (c = 0; c < sna->mode.num_real_crtc; c++) {
|
||||
xf86CrtcPtr crtc = config->crtc[c];
|
||||
|
||||
if (crtc == desired)
|
||||
continue;
|
||||
|
||||
if (!crtc->enabled)
|
||||
continue;
|
||||
|
||||
if (desired->bounds.x1 < crtc->bounds.x2 &&
|
||||
desired->bounds.x2 > crtc->bounds.x1 &&
|
||||
desired->bounds.y1 < crtc->bounds.y2 &&
|
||||
desired->bounds.y2 > crtc->bounds.y1)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
can_xchg_one(struct sna *sna,
|
||||
DrawablePtr draw,
|
||||
DRI2BufferPtr front,
|
||||
DRI2BufferPtr back,
|
||||
xf86CrtcPtr crtc)
|
||||
{
|
||||
WindowPtr win = (WindowPtr)draw;
|
||||
PixmapPtr pixmap;
|
||||
|
||||
if ((sna->flags & SNA_TEAR_FREE) == 0) {
|
||||
DBG(("%s: no, requires TearFree\n",
|
||||
__FUNCTION__));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (draw->type == DRAWABLE_PIXMAP)
|
||||
return false;
|
||||
|
||||
if (front->format != back->format) {
|
||||
DBG(("%s: no, format mismatch, front = %d, back = %d\n",
|
||||
__FUNCTION__, front->format, back->format));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (front->attachment != DRI2BufferFrontLeft) {
|
||||
DBG(("%s: no, front attachment [%d] is not FrontLeft [%d]\n",
|
||||
__FUNCTION__,
|
||||
front->attachment,
|
||||
DRI2BufferFrontLeft));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sna_crtc_is_transformed(crtc)) {
|
||||
DBG(("%s: no, CRTC is rotated\n", __FUNCTION__));
|
||||
return false;
|
||||
}
|
||||
|
||||
pixmap = get_window_pixmap(win);
|
||||
if (pixmap != sna->front) {
|
||||
DBG(("%s: no, not attached to front buffer\n", __FUNCTION__));
|
||||
return false;
|
||||
}
|
||||
|
||||
DBG(("%s: window size: %dx%d, clip=(%d, %d), (%d, %d) x %d\n",
|
||||
__FUNCTION__,
|
||||
win->drawable.width, win->drawable.height,
|
||||
win->clipList.extents.x1, win->clipList.extents.y1,
|
||||
win->clipList.extents.x2, win->clipList.extents.y2,
|
||||
RegionNumRects(&win->clipList)));
|
||||
if (is_clipped(&win->clipList, &win->drawable)) {
|
||||
DBG(("%s: no, %dx%d window is clipped: clip region=(%d, %d), (%d, %d)\n",
|
||||
__FUNCTION__,
|
||||
draw->width, draw->height,
|
||||
win->clipList.extents.x1,
|
||||
win->clipList.extents.y1,
|
||||
win->clipList.extents.x2,
|
||||
win->clipList.extents.y2));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (overlaps_other_crtc(sna, crtc)) {
|
||||
DBG(("%s: no, overlaps other CRTC\n", __FUNCTION__));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (get_private(back)->size != (draw->height << 16 | draw->width)) {
|
||||
DBG(("%s: no, DRI2 buffers does not fit window\n",
|
||||
__FUNCTION__));
|
||||
return false;
|
||||
}
|
||||
|
||||
DBG(("%s: yes\n", __FUNCTION__));
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
sna_dri2_exchange_buffers(DrawablePtr draw,
|
||||
DRI2BufferPtr front,
|
||||
|
|
@ -1900,7 +2027,7 @@ sna_dri2_flip_continue(struct sna *sna, struct sna_dri2_event *info)
|
|||
return false;
|
||||
|
||||
if (!XORG_CAN_TRIPLE_BUFFER) {
|
||||
sna_dri2_get_back(sna, info->back, info);
|
||||
sna_dri2_get_back(sna, info->draw, info->back, info);
|
||||
DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
|
||||
frame_swap_complete(sna, info, DRI2_FLIP_COMPLETE);
|
||||
}
|
||||
|
|
@ -2180,7 +2307,7 @@ sna_dri2_schedule_flip(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
|
|||
if (type >= FLIP_COMPLETE) {
|
||||
new_back:
|
||||
if (!XORG_CAN_TRIPLE_BUFFER)
|
||||
sna_dri2_get_back(sna, back, info);
|
||||
sna_dri2_get_back(sna, draw, back, info);
|
||||
DBG(("%s: fake triple buffering, unblocking client\n", __FUNCTION__));
|
||||
frame_swap_complete(sna, info, DRI2_EXCHANGE_COMPLETE);
|
||||
if (info->type == FLIP_ASYNC)
|
||||
|
|
@ -2314,6 +2441,94 @@ complete:
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
sna_dri2_schedule_xchg_one(ClientPtr client, DrawablePtr draw, xf86CrtcPtr crtc,
|
||||
DRI2BufferPtr front, DRI2BufferPtr back,
|
||||
CARD64 *target_msc, CARD64 divisor, CARD64 remainder,
|
||||
DRI2SwapEventPtr func, void *data)
|
||||
{
|
||||
struct sna *sna = to_sna_from_drawable(draw);
|
||||
uint64_t current_msc;
|
||||
bool sync, event;
|
||||
|
||||
if (!immediate_swap(sna, *target_msc, divisor, draw, crtc, ¤t_msc))
|
||||
return false;
|
||||
|
||||
sync = current_msc < *target_msc;
|
||||
event = dri2_chain(draw) == NULL;
|
||||
if (!sync || event) {
|
||||
WindowPtr win = (WindowPtr)draw;
|
||||
PixmapPtr pixmap = get_window_pixmap(win);
|
||||
|
||||
DBG(("%s: performing immediate xchg only on pipe %d\n",
|
||||
__FUNCTION__, sna_crtc_to_pipe(crtc)));
|
||||
DBG(("%s: exchange front=%d/%d and back=%d/%d, win id=%lu, pixmap=%ld %dx%d\n",
|
||||
__FUNCTION__,
|
||||
get_private(front)->bo->handle, front->name,
|
||||
get_private(back)->bo->handle, back->name,
|
||||
win->drawable.id,
|
||||
pixmap->drawable.serialNumber,
|
||||
pixmap->drawable.width,
|
||||
pixmap->drawable.height));
|
||||
|
||||
sna_shadow_set_crtc(sna, crtc, get_private(back)->bo);
|
||||
DamageRegionProcessPending(&win->drawable);
|
||||
|
||||
if (get_private(front)->size == (draw->height << 16 | draw->width)) {
|
||||
front->attachment = DRI2BufferBackLeft;
|
||||
get_private(front)->stale = true;
|
||||
} else
|
||||
front->attachment = -1;
|
||||
back->attachment = DRI2BufferFrontLeft;
|
||||
if (get_private(back)->proxy == NULL) {
|
||||
get_private(back)->proxy = sna_dri2_reference_buffer(sna_pixmap_get_buffer(pixmap));
|
||||
get_private(back)->pixmap = pixmap;
|
||||
}
|
||||
|
||||
assert(dri2_window(win)->front == NULL);
|
||||
dri2_window(win)->front = sna_dri2_reference_buffer(back);
|
||||
}
|
||||
if (sync) {
|
||||
struct sna_dri2_event *info;
|
||||
|
||||
info = sna_dri2_add_event(draw, client);
|
||||
if (!info)
|
||||
goto complete;
|
||||
|
||||
info->event_complete = func;
|
||||
info->event_data = data;
|
||||
|
||||
info->front = sna_dri2_reference_buffer(front);
|
||||
info->back = sna_dri2_reference_buffer(back);
|
||||
info->type = SWAP_THROTTLE;
|
||||
|
||||
if (event) {
|
||||
union drm_wait_vblank vbl;
|
||||
|
||||
VG_CLEAR(vbl);
|
||||
vbl.request.type =
|
||||
DRM_VBLANK_RELATIVE |
|
||||
DRM_VBLANK_EVENT;
|
||||
vbl.request.sequence = 1;
|
||||
vbl.request.signal = (uintptr_t)info;
|
||||
|
||||
info->queued = true;
|
||||
if (sna_wait_vblank(sna, &vbl, info->pipe)) {
|
||||
sna_dri2_event_free(sna, draw, info);
|
||||
goto complete;
|
||||
}
|
||||
|
||||
swap_limit(draw, 2);
|
||||
}
|
||||
} else {
|
||||
complete:
|
||||
fake_swap_complete(sna, client, draw, crtc, DRI2_EXCHANGE_COMPLETE, func, data);
|
||||
}
|
||||
|
||||
*target_msc = current_msc + 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool has_pending_events(struct sna *sna)
|
||||
{
|
||||
struct pollfd pfd;
|
||||
|
|
@ -2353,9 +2568,12 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
|
|||
struct sna_dri2_event *info = NULL;
|
||||
CARD64 current_msc;
|
||||
|
||||
DBG(("%s: draw=%ld, pixmap=%ld, back=%u (refs=%d/%d, flush=%d) , fron=%u (refs=%d/%d, flush=%d)\n",
|
||||
DBG(("%s: draw=%lu %dx%d, pixmap=%ld %dx%d, back=%u (refs=%d/%d, flush=%d) , front=%u (refs=%d/%d, flush=%d)\n",
|
||||
__FUNCTION__,
|
||||
(long)draw->id, get_drawable_pixmap(draw)->drawable.serialNumber,
|
||||
(long)draw->id, draw->width, draw->height,
|
||||
get_drawable_pixmap(draw)->drawable.serialNumber,
|
||||
get_drawable_pixmap(draw)->drawable.width,
|
||||
get_drawable_pixmap(draw)->drawable.height,
|
||||
get_private(back)->bo->handle,
|
||||
get_private(back)->refcnt,
|
||||
get_private(back)->bo->refcnt,
|
||||
|
|
@ -2375,10 +2593,18 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
|
|||
assert(get_private(back)->refcnt);
|
||||
|
||||
assert(get_private(front)->bo->refcnt);
|
||||
assert(get_private(front)->bo->flush);
|
||||
|
||||
assert(get_private(back)->bo->refcnt);
|
||||
|
||||
if (draw->type != DRAWABLE_PIXMAP) {
|
||||
struct dri2_window *priv = dri2_window((WindowPtr)draw);
|
||||
if (priv->front) {
|
||||
assert(front == priv->front);
|
||||
assert(get_private(priv->front)->refcnt > 1);
|
||||
get_private(priv->front)->refcnt--;
|
||||
priv->front = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (get_private(front)->pixmap != get_drawable_pixmap(draw))
|
||||
goto skip;
|
||||
|
||||
|
|
@ -2408,6 +2634,12 @@ sna_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, DRI2BufferPtr front,
|
|||
func, data))
|
||||
return TRUE;
|
||||
|
||||
if (can_xchg_one(sna, draw, front, back, crtc) &&
|
||||
sna_dri2_schedule_xchg_one(client, draw, crtc, front, back,
|
||||
target_msc, divisor, remainder,
|
||||
func, data))
|
||||
return TRUE;
|
||||
|
||||
if (can_flip(sna, draw, front, back, crtc) &&
|
||||
sna_dri2_schedule_flip(client, draw, crtc, front, back,
|
||||
target_msc, divisor, remainder,
|
||||
|
|
|
|||
Loading…
Reference in New Issue