diff --git a/hw/xfree86/drivers/modesetting/driver.c b/hw/xfree86/drivers/modesetting/driver.c index 43783c4b1..dfbe5bb94 100644 --- a/hw/xfree86/drivers/modesetting/driver.c +++ b/hw/xfree86/drivers/modesetting/driver.c @@ -913,6 +913,51 @@ msSetWindowVRRMode(WindowPtr window, WindowVRRMode mode) ms_present_set_screen_vrr(scrn, variable_refresh); } + +Bool +ms_window_has_async_flip(WindowPtr win) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + return priv->async_flip; +} + +void +ms_window_update_async_flip(WindowPtr win, Bool async_flip) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + priv->async_flip = async_flip; +} + +Bool +ms_window_has_async_flip_modifiers(WindowPtr win) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + return priv->async_flip_modifiers; +} + +void +ms_window_update_async_flip_modifiers(WindowPtr win, Bool async_flip) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(win->drawable.pScreen); + modesettingPtr ms = modesettingPTR(scrn); + struct ms_async_flip_priv *priv = dixLookupPrivate(&win->devPrivates, + &ms->drmmode.asyncFlipPrivateKeyRec); + + priv->async_flip_modifiers = async_flip; +} + static void FreeScreen(ScrnInfoPtr pScrn) { @@ -1711,6 +1756,11 @@ modsetCreateScreenResources(ScreenPtr pScreen) sizeof(struct ms_vrr_priv))) return FALSE; + if (!dixRegisterPrivateKey(&ms->drmmode.asyncFlipPrivateKeyRec, + PRIVATE_WINDOW, + sizeof(struct ms_async_flip_priv))) + return FALSE; + return ret; } diff --git a/hw/xfree86/drivers/modesetting/driver.h b/hw/xfree86/drivers/modesetting/driver.h index 62b0db0cc..8b465e6e1 100644 --- a/hw/xfree86/drivers/modesetting/driver.h +++ b/hw/xfree86/drivers/modesetting/driver.h @@ -49,6 +49,11 @@ struct ms_vrr_priv { Bool variable_refresh; }; +struct ms_async_flip_priv { + Bool async_flip; + Bool async_flip_modifiers; +}; + typedef enum { OPTION_SW_CURSOR, OPTION_DEVICE_PATH, @@ -261,3 +266,7 @@ void ms_drain_drm_events(ScreenPtr screen); Bool ms_window_has_variable_refresh(modesettingPtr ms, WindowPtr win); void ms_present_set_screen_vrr(ScrnInfoPtr scrn, Bool vrr_enabled); Bool ms_tearfree_is_active_on_crtc(xf86CrtcPtr crtc); +Bool ms_window_has_async_flip(WindowPtr win); +void ms_window_update_async_flip(WindowPtr win, Bool async_flip); +Bool ms_window_has_async_flip_modifiers(WindowPtr win); +void ms_window_update_async_flip_modifiers(WindowPtr win, Bool async_flip); diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index f28c3596b..8ebdd4a1f 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -114,8 +114,18 @@ get_opaque_format(uint32_t format) } } +static drmmode_format_ptr get_format(drmmode_crtc_private_ptr drmmode_crtc, + Bool async_flip, int i) +{ + if (async_flip && drmmode_crtc->formats_async) + return &drmmode_crtc->formats_async[i]; + else + return &drmmode_crtc->formats[i]; +} + Bool -drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier) +drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, + uint64_t modifier, Bool async_flip) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); int c, i, j; @@ -135,7 +145,7 @@ drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier continue; for (i = 0; i < drmmode_crtc->num_formats; i++) { - drmmode_format_ptr iter = &drmmode_crtc->formats[i]; + drmmode_format_ptr iter = get_format(drmmode_crtc, async_flip, i); if (iter->format != format) continue; @@ -166,7 +176,7 @@ drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier #ifdef GBM_BO_WITH_MODIFIERS static uint32_t get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers, - Bool enabled_crtc_only, Bool exclude_multiplane) + Bool enabled_crtc_only, Bool exclude_multiplane, Bool async_flip) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); modesettingPtr ms = modesettingPTR(scrn); @@ -186,7 +196,7 @@ get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers, continue; for (i = 0; i < drmmode_crtc->num_formats; i++) { - drmmode_format_ptr iter = &drmmode_crtc->formats[i]; + drmmode_format_ptr iter = get_format(drmmode_crtc, async_flip, i); if (iter->format != format) continue; @@ -233,6 +243,7 @@ get_drawable_modifiers(DrawablePtr draw, uint32_t format, { ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen); modesettingPtr ms = modesettingPTR(scrn); + Bool async_flip; if (!present_can_window_flip((WindowPtr) draw) || !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) { @@ -241,7 +252,11 @@ get_drawable_modifiers(DrawablePtr draw, uint32_t format, return TRUE; } - *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE); + async_flip = ms_window_has_async_flip((WindowPtr)draw); + ms_window_update_async_flip_modifiers((WindowPtr)draw, async_flip); + + *num_modifiers = get_modifiers_set(scrn, format, modifiers, + TRUE, FALSE, async_flip); return TRUE; } #endif @@ -1114,10 +1129,6 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, #ifdef GLAMOR_HAS_GBM if (drmmode->glamor) { -#ifdef GBM_BO_WITH_MODIFIERS - uint32_t num_modifiers; - uint64_t *modifiers = NULL; -#endif uint32_t format; switch (drmmode->scrn->depth) { @@ -1135,22 +1146,6 @@ drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo, break; } -#ifdef GBM_BO_WITH_MODIFIERS - num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers, - FALSE, TRUE); - if (num_modifiers > 0 && - !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) { - bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height, - format, modifiers, - num_modifiers); - free(modifiers); - if (bo->gbm) { - bo->used_modifiers = TRUE; - return TRUE; - } - } -#endif - bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format, GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT); bo->used_modifiers = FALSE; @@ -2315,7 +2310,7 @@ is_plane_assigned(ScrnInfoPtr scrn, int plane_id) */ static Bool populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane, - uint32_t blob_id) + drmmode_format_rec *formats, uint32_t blob_id) { drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; @@ -2361,9 +2356,9 @@ populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane, modifiers[num_modifiers - 1] = mod->modifier; } - drmmode_crtc->formats[i].format = blob_formats[i]; - drmmode_crtc->formats[i].modifiers = modifiers; - drmmode_crtc->formats[i].num_modifiers = num_modifiers; + formats[i].format = blob_formats[i]; + formats[i].modifiers = modifiers; + formats[i].num_modifiers = num_modifiers; } drmModeFreePropertyBlob(blob); @@ -2379,7 +2374,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) drmModePlaneRes *kplane_res; drmModePlane *kplane, *best_kplane = NULL; drmModeObjectProperties *props; - uint32_t i, type, blob_id; + uint32_t i, type, blob_id, async_blob_id; int current_crtc, best_plane = 0; static drmmode_prop_enum_info_rec plane_type_enums[] = { @@ -2402,6 +2397,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", }, [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", }, [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", }, + [DRMMODE_PLANE_IN_FORMATS_ASYNC] = { .name = "IN_FORMATS_ASYNC", }, [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", }, [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", }, [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", }, @@ -2420,6 +2416,7 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) return; } + drmSetClientCap(drmmode->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); kplane_res = drmModeGetPlaneResources(drmmode->fd); if (!kplane_res) { xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR, @@ -2475,6 +2472,8 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) best_kplane = kplane; blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS], props, 0); + async_blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], + props, 0); drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, DRMMODE_PLANE__COUNT, 1); drmModeFreeObjectProperties(props); @@ -2486,6 +2485,8 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) best_kplane = kplane; blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS], props, 0); + async_blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS_ASYNC], + props, 0); drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props, DRMMODE_PLANE__COUNT, 1); } else { @@ -2500,9 +2501,18 @@ drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num) drmmode_crtc->num_formats = best_kplane->count_formats; drmmode_crtc->formats = calloc(best_kplane->count_formats, sizeof(drmmode_format_rec)); - if (!populate_format_modifiers(crtc, best_kplane, blob_id)) { + if (!populate_format_modifiers(crtc, best_kplane, + drmmode_crtc->formats, blob_id)) { for (i = 0; i < best_kplane->count_formats; i++) drmmode_crtc->formats[i].format = best_kplane->formats[i]; + } else { + drmmode_crtc->formats_async = calloc(best_kplane->count_formats, + sizeof(drmmode_format_rec)); + if (!populate_format_modifiers(crtc, best_kplane, + drmmode_crtc->formats_async, async_blob_id)) { + free(drmmode_crtc->formats_async); + drmmode_crtc->formats_async = NULL; + } } drmModeFreePlane(best_kplane); } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index a82ae2609..5e7ba9df1 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -42,6 +42,7 @@ enum drmmode_plane_property { DRMMODE_PLANE_TYPE = 0, DRMMODE_PLANE_FB_ID, DRMMODE_PLANE_IN_FORMATS, + DRMMODE_PLANE_IN_FORMATS_ASYNC, DRMMODE_PLANE_CRTC_ID, DRMMODE_PLANE_SRC_X, DRMMODE_PLANE_SRC_Y, @@ -118,6 +119,7 @@ typedef struct { DevPrivateKeyRec pixmapPrivateKeyRec; DevScreenPrivateKeyRec spritePrivateKeyRec; DevPrivateKeyRec vrrPrivateKeyRec; + DevPrivateKeyRec asyncFlipPrivateKeyRec; /* Number of SW cursors currently visible on this screen */ int sprites_visible; @@ -198,6 +200,7 @@ typedef struct { drmmode_mode_ptr current_mode; uint32_t num_formats; drmmode_format_rec *formats; + drmmode_format_rec *formats_async; drmmode_bo rotate_bo; unsigned rotate_fb_id; @@ -293,7 +296,7 @@ typedef struct _msSpritePriv { extern miPointerSpriteFuncRec drmmode_sprite_funcs; Bool drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, - uint64_t modifier); + uint64_t modifier, Bool async_flip); int drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo, uint32_t *fb_id); int drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo); diff --git a/hw/xfree86/drivers/modesetting/present.c b/hw/xfree86/drivers/modesetting/present.c index 421d70016..80ac5c9d3 100644 --- a/hw/xfree86/drivers/modesetting/present.c +++ b/hw/xfree86/drivers/modesetting/present.c @@ -294,7 +294,7 @@ ms_present_check_unflip(RRCrtcPtr crtc, modifier = gbm_bo_get_modifier(gbm); gbm_bo_destroy(gbm); - if (!drmmode_is_format_supported(scrn, format, modifier)) { + if (!drmmode_is_format_supported(scrn, format, modifier, !sync_flip)) { if (reason) *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT; return FALSE; @@ -321,6 +321,7 @@ ms_present_check_flip(RRCrtcPtr crtc, ScreenPtr screen = window->drawable.pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); modesettingPtr ms = modesettingPTR(scrn); + Bool async_flip = !sync_flip; if (ms->drmmode.sprites_visible > 0) goto no_flip; @@ -328,8 +329,22 @@ ms_present_check_flip(RRCrtcPtr crtc, if (ms->drmmode.pending_modeset) goto no_flip; - if(!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason)) + if (!ms_present_check_unflip(crtc, window, pixmap, sync_flip, reason)) { + if (reason && *reason == PRESENT_FLIP_REASON_BUFFER_FORMAT) + ms_window_update_async_flip(window, async_flip); goto no_flip; + } + + ms_window_update_async_flip(window, async_flip); + + /* + * Force a format renegotiation when switching between sync and async, + * otherwise we may end up with a working but suboptimal modifier. + */ + if (reason && async_flip != ms_window_has_async_flip_modifiers(window)) { + *reason = PRESENT_FLIP_REASON_BUFFER_FORMAT; + goto no_flip; + } ms->flip_window = window; diff --git a/present/present.c b/present/present.c index aa265aabf..6386a90a8 100644 --- a/present/present.c +++ b/present/present.c @@ -120,9 +120,14 @@ present_set_tree_pixmap_visit(WindowPtr window, void *data) struct pixmap_visit *visit = data; ScreenPtr screen = window->drawable.pScreen; - if ((*screen->GetWindowPixmap)(window) != visit->old) - return WT_DONTWALKCHILDREN; - (*screen->SetWindowPixmap)(window, visit->new); + if ((*screen->GetWindowPixmap)(window) == visit->old) + (*screen->SetWindowPixmap)(window, visit->new); + + /* + * Walk the entire tree in case windows using the + * the old pixmap have been reparented to newly + * created windows using the screen pixmap instead. + */ return WT_WALKCHILDREN; } diff --git a/present/present_vblank.c b/present/present_vblank.c index 72a8b2e3e..7b83bc630 100644 --- a/present/present_vblank.c +++ b/present/present_vblank.c @@ -40,6 +40,20 @@ present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_ } } +static Bool +present_want_async_flip(uint32_t options, uint32_t capabilities) +{ + if (options & PresentOptionAsync && + capabilities & PresentCapabilityAsync) + return TRUE; + + if (options & PresentOptionAsyncMayTear && + capabilities & PresentCapabilityAsyncMayTear) + return TRUE; + + return FALSE; +} + /* The memory vblank points to must be 0-initialized before calling this function. * * If this function returns FALSE, present_vblank_destroy must be called to clean @@ -118,15 +132,14 @@ present_vblank_init(present_vblank_ptr vblank, if (pixmap != NULL && !(options & PresentOptionCopy) && screen_priv->check_flip) { - if (msc_is_after(target_msc, crtc_msc) && - screen_priv->check_flip (target_crtc, window, pixmap, TRUE, valid, x_off, y_off, &reason)) - { - vblank->flip = TRUE; - vblank->sync_flip = TRUE; - } else if ((capabilities & PresentAllAsyncCapabilities) && - screen_priv->check_flip (target_crtc, window, pixmap, FALSE, valid, x_off, y_off, &reason)) + + Bool sync_flip = !present_want_async_flip(options, capabilities); + + if (screen_priv->check_flip (target_crtc, window, pixmap, + sync_flip, valid, x_off, y_off, &reason)) { vblank->flip = TRUE; + vblank->sync_flip = sync_flip; } } vblank->reason = reason;