diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2015-02-25 01:51:11 -0800 |
---|---|---|
committer | Thomas Hellstrom <thellstrom@vmware.com> | 2015-05-04 23:26:34 -0700 |
commit | 1e443c4717a8b107c0c9283e222482703ac0f358 (patch) | |
tree | 1ea708f3e0929d325e1e0263c72126996dfddb33 | |
parent | 8f0cf7c03597532feb1a8ccf3bb1cafcd6170f89 (diff) |
vmware/vmwgfx: Try to use only_hw_present semantics if screen targets are enabled
If screen targets are enabled and there is a reasonable chance that the vmwgfx
drm driver can use the surface backing a pixmap as a screen target surface,
then make that surface a modesetting framebuffer rather than the corresponding
DMA buffer. In practice this applies when we start scanning out from the
origin (0,0) of the pixmap. However, we would also like to apply the constraint
that the scanout area is the entire pixmap, since that is the constraint used
by the drm driver, but that would currently require drm framebuffer
reallocations and possible flicker, so disable that for now. The drm driver
will correctly handle the possibly oversized surface handed to it anyway, and
the cost we pay for this is an extra hardware copy of the dirtied area when
doing a software update of the scanout.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Sinclair Yeh <syeh@vmware.com>
-rw-r--r-- | vmwgfx/vmwgfx_crtc.c | 23 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_driver.c | 26 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_driver.h | 1 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_drm.h | 1 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_saa.c | 15 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_saa.h | 7 | ||||
-rw-r--r-- | vmwgfx/vmwgfx_saa_priv.h | 1 |
7 files changed, 61 insertions, 13 deletions
diff --git a/vmwgfx/vmwgfx_crtc.c b/vmwgfx/vmwgfx_crtc.c index dad8815..1e85b08 100644 --- a/vmwgfx/vmwgfx_crtc.c +++ b/vmwgfx/vmwgfx_crtc.c @@ -121,6 +121,26 @@ vmwgfx_disable_scanout(ScrnInfoPtr pScrn) } static Bool +vmwgfx_scanout_equals_pixmap(DisplayModePtr mode, PixmapPtr pixmap, + int x, int y) +{ + return x == 0 && y == 0; +/* + * Mode test is disabled for now, since the X server has a tendency to first + * change the pixmap dimensions, then change the mode, keeping the pixmap. + * This would lead to a lot of false non-equals, or flickering if we were to + * kill the drm fb in between. + * However, currently we prefer false equals as long as x == 0 and y == 0. + * The false equals will then typically correspond to the primary screen in a + * multimon setup. Let's live with that for now. + */ +#if 0 + && mode->HDisplay == pixmap->drawable.width && + mode->VDisplay == pixmap->drawable.height; +#endif +} + +static Bool crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, Rotation rotation, int x, int y) { @@ -191,7 +211,8 @@ crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, vmwgfx_scanout_unref(&crtcp->entry); crtcp->entry.pixmap = pixmap; - crtcp->scanout_id = vmwgfx_scanout_ref(&crtcp->entry); + crtcp->scanout_id = vmwgfx_scanout_ref + (&crtcp->entry, vmwgfx_scanout_equals_pixmap(mode, pixmap, x, y)); if (crtcp->scanout_id == -1) { crtcp->entry.pixmap = NULL; LogMessage(X_ERROR, "Failed to convert pixmap to scanout.\n"); diff --git a/vmwgfx/vmwgfx_driver.c b/vmwgfx/vmwgfx_driver.c index 2925227..48f8a63 100644 --- a/vmwgfx/vmwgfx_driver.c +++ b/vmwgfx/vmwgfx_driver.c @@ -541,6 +541,14 @@ drv_pre_init(ScrnInfoPtr pScrn, int flags) ms->drm_major, ms->drm_minor, ms->drm_patch); } + ms->has_screen_targets = ms->drm_major > 2 || + (ms->drm_major == 2 && ms->drm_minor >= 7); + ms->has_screen_targets = (ms->has_screen_targets && + !vmwgfx_get_param(ms->fd, + DRM_VMW_PARAM_SCREEN_TARGET, + &cap) && + cap != 0); + ms->check_fb_size = (vmwgfx_max_fb_size(ms->fd, &ms->max_fb_size) == 0); if (vmwgfx_get_param(ms->fd, DRM_VMW_PARAM_HW_CAPS, &cap) != 0) { @@ -744,7 +752,7 @@ void xorg_flush(ScreenPtr pScreen) if (vpix->fb_id != -1) { if (vpix->pending_update) { - if (ms->only_hw_presents && + if (vpix->scanout_hw && REGION_NOTEMPTY(pscreen, vpix->pending_update)) { (void) vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, 0, NULL); @@ -756,7 +764,7 @@ void xorg_flush(ScreenPtr pScreen) REGION_EMPTY(pScreen, vpix->pending_update); } if (vpix->pending_present) { - if (ms->only_hw_presents) + if (vpix->scanout_hw) (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, vpix->pending_present); else @@ -1071,7 +1079,8 @@ drv_screen_init(SCREEN_INIT_ARGS_DECL) if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush, ms->direct_presents, ms->only_hw_presents, - ms->rendercheck)) { + ms->rendercheck, + ms->has_screen_targets)) { FatalError("Failed to initialize SAA.\n"); } @@ -1102,9 +1111,14 @@ drv_screen_init(SCREEN_INIT_ARGS_DECL) if (ms->xat != NULL) { xf86DrvMsg(pScrn->scrnIndex, ms->from_dp, "Direct presents are %s.\n", (ms->direct_presents) ? "enabled" : "disabled"); - xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " - "are %s.\n", - (ms->only_hw_presents) ? "enabled" : "disabled"); + if (ms->only_hw_presents) + xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " + "are enabled.\n"); + else + xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " + "are %s.\n", + (ms->has_screen_targets) ? "automatic per scanout" : + "disabled"); } xf86SetBackingStore(pScreen); diff --git a/vmwgfx/vmwgfx_driver.h b/vmwgfx/vmwgfx_driver.h index 31dfc0f..b57d523 100644 --- a/vmwgfx/vmwgfx_driver.h +++ b/vmwgfx/vmwgfx_driver.h @@ -115,6 +115,7 @@ typedef struct _modesettingRec Bool only_hw_presents; MessageType from_hwp; Bool isMaster; + Bool has_screen_targets; /* Broken-out options. */ diff --git a/vmwgfx/vmwgfx_drm.h b/vmwgfx/vmwgfx_drm.h index 906a41c..d5234e6 100644 --- a/vmwgfx/vmwgfx_drm.h +++ b/vmwgfx/vmwgfx_drm.h @@ -76,6 +76,7 @@ #define DRM_VMW_PARAM_FIFO_CAPS 4 #define DRM_VMW_PARAM_MAX_FB_SIZE 5 #define DRM_VMW_PARAM_FIFO_HW_VERSION 6 +#define DRM_VMW_PARAM_SCREEN_TARGET 11 /** * struct drm_vmw_getparam_arg diff --git a/vmwgfx/vmwgfx_saa.c b/vmwgfx/vmwgfx_saa.c index bca3d93..b8ad2a7 100644 --- a/vmwgfx/vmwgfx_saa.c +++ b/vmwgfx/vmwgfx_saa.c @@ -1318,7 +1318,7 @@ vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap, * just before we call the kms update function for the hw * surface. */ - if (vsaa->only_hw_presents) { + if (vpix->scanout_hw) { if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) return FALSE; @@ -1408,7 +1408,8 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, void (*present_flush)(ScreenPtr pScreen), Bool direct_presents, Bool only_hw_presents, - Bool rendercheck) + Bool rendercheck, + Bool has_screen_targets) { struct vmwgfx_saa *vsaa; @@ -1419,6 +1420,7 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, if (xat == NULL) { direct_presents = FALSE; only_hw_presents = FALSE; + has_screen_targets = FALSE; } vsaa->pScreen = pScreen; @@ -1433,6 +1435,7 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, vsaa->rendercheck = rendercheck; vsaa->is_master = TRUE; vsaa->known_prime_format = FALSE; + vsaa->has_screen_targets = has_screen_targets; WSBMINITLISTHEAD(&vsaa->sync_x_list); WSBMINITLISTHEAD(&vsaa->pixmaps); @@ -1492,7 +1495,8 @@ vmwgfx_scanout_refresh(PixmapPtr pixmap) */ uint32_t -vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry) +vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry, + Bool scanout_equals_pixmap) { PixmapPtr pixmap = entry->pixmap; struct vmwgfx_saa *vsaa = @@ -1503,7 +1507,10 @@ vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry) uint32_t handle, dummy; unsigned int depth; - if (vsaa->only_hw_presents) { + vpix->scanout_hw = vsaa->only_hw_presents || + (vsaa->has_screen_targets && scanout_equals_pixmap); + + if (vpix->scanout_hw) { /* * The KMS fb will be a HW surface. Create it, add damage * and get the handle. diff --git a/vmwgfx/vmwgfx_saa.h b/vmwgfx/vmwgfx_saa.h index 921fabd..15ae770 100644 --- a/vmwgfx/vmwgfx_saa.h +++ b/vmwgfx/vmwgfx_saa.h @@ -56,6 +56,7 @@ struct vmwgfx_saa_pixmap { struct _WsbmListHead sync_x_head; struct _WsbmListHead scanout_list; struct _WsbmListHead pixmap_list; + Bool scanout_hw; uint32_t xa_flags; uint32_t staging_add_flags; @@ -85,10 +86,12 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat, void (*present_flush)(ScreenPtr pScreen), Bool direct_presents, Bool only_hw_presents, - Bool rendercheck); + Bool rendercheck, + Bool has_screen_targets); extern uint32_t -vmwgfx_scanout_ref(struct vmwgfx_screen_entry *box); +vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry, + Bool scanout_equals_pixmap); extern void vmwgfx_scanout_unref(struct vmwgfx_screen_entry *box); diff --git a/vmwgfx/vmwgfx_saa_priv.h b/vmwgfx/vmwgfx_saa_priv.h index 4a0c302..507833a 100644 --- a/vmwgfx/vmwgfx_saa_priv.h +++ b/vmwgfx/vmwgfx_saa_priv.h @@ -56,6 +56,7 @@ struct vmwgfx_saa { Bool rendercheck; Bool is_master; Bool known_prime_format; + Bool has_screen_targets; void (*present_flush) (ScreenPtr pScreen); struct _WsbmListHead sync_x_list; struct _WsbmListHead pixmaps; |