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>
This commit is contained in:
Thomas Hellstrom
2015-02-25 01:51:11 -08:00
parent 8f0cf7c035
commit 1e443c4717
7 changed files with 61 additions and 13 deletions

View File

@@ -120,6 +120,26 @@ vmwgfx_disable_scanout(ScrnInfoPtr pScrn)
xf86RotateFreeShadow(pScrn); xf86RotateFreeShadow(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 static Bool
crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y) Rotation rotation, int x, int y)
@@ -191,7 +211,8 @@ crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
vmwgfx_scanout_unref(&crtcp->entry); vmwgfx_scanout_unref(&crtcp->entry);
crtcp->entry.pixmap = pixmap; 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) { if (crtcp->scanout_id == -1) {
crtcp->entry.pixmap = NULL; crtcp->entry.pixmap = NULL;
LogMessage(X_ERROR, "Failed to convert pixmap to scanout.\n"); LogMessage(X_ERROR, "Failed to convert pixmap to scanout.\n");

View File

@@ -541,6 +541,14 @@ drv_pre_init(ScrnInfoPtr pScrn, int flags)
ms->drm_major, ms->drm_minor, ms->drm_patch); 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); 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) { 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->fb_id != -1) {
if (vpix->pending_update) { if (vpix->pending_update) {
if (ms->only_hw_presents && if (vpix->scanout_hw &&
REGION_NOTEMPTY(pscreen, vpix->pending_update)) { REGION_NOTEMPTY(pscreen, vpix->pending_update)) {
(void) vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT, (void) vmwgfx_hw_accel_validate(pixmap, 0, XA_FLAG_SCANOUT,
0, NULL); 0, NULL);
@@ -756,7 +764,7 @@ void xorg_flush(ScreenPtr pScreen)
REGION_EMPTY(pScreen, vpix->pending_update); REGION_EMPTY(pScreen, vpix->pending_update);
} }
if (vpix->pending_present) { if (vpix->pending_present) {
if (ms->only_hw_presents) if (vpix->scanout_hw)
(void) vmwgfx_scanout_update(ms->fd, vpix->fb_id, (void) vmwgfx_scanout_update(ms->fd, vpix->fb_id,
vpix->pending_present); vpix->pending_present);
else else
@@ -1071,7 +1079,8 @@ drv_screen_init(SCREEN_INIT_ARGS_DECL)
if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush, if (!vmwgfx_saa_init(pScreen, ms->fd, ms->xat, &xorg_flush,
ms->direct_presents, ms->direct_presents,
ms->only_hw_presents, ms->only_hw_presents,
ms->rendercheck)) { ms->rendercheck,
ms->has_screen_targets)) {
FatalError("Failed to initialize SAA.\n"); FatalError("Failed to initialize SAA.\n");
} }
@@ -1102,9 +1111,14 @@ drv_screen_init(SCREEN_INIT_ARGS_DECL)
if (ms->xat != NULL) { if (ms->xat != NULL) {
xf86DrvMsg(pScrn->scrnIndex, ms->from_dp, "Direct presents are %s.\n", xf86DrvMsg(pScrn->scrnIndex, ms->from_dp, "Direct presents are %s.\n",
(ms->direct_presents) ? "enabled" : "disabled"); (ms->direct_presents) ? "enabled" : "disabled");
xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents " if (ms->only_hw_presents)
"are %s.\n", xf86DrvMsg(pScrn->scrnIndex, ms->from_hwp, "Hardware only presents "
(ms->only_hw_presents) ? "enabled" : "disabled"); "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); xf86SetBackingStore(pScreen);

View File

@@ -115,6 +115,7 @@ typedef struct _modesettingRec
Bool only_hw_presents; Bool only_hw_presents;
MessageType from_hwp; MessageType from_hwp;
Bool isMaster; Bool isMaster;
Bool has_screen_targets;
/* Broken-out options. */ /* Broken-out options. */

View File

@@ -76,6 +76,7 @@
#define DRM_VMW_PARAM_FIFO_CAPS 4 #define DRM_VMW_PARAM_FIFO_CAPS 4
#define DRM_VMW_PARAM_MAX_FB_SIZE 5 #define DRM_VMW_PARAM_MAX_FB_SIZE 5
#define DRM_VMW_PARAM_FIFO_HW_VERSION 6 #define DRM_VMW_PARAM_FIFO_HW_VERSION 6
#define DRM_VMW_PARAM_SCREEN_TARGET 11
/** /**
* struct drm_vmw_getparam_arg * struct drm_vmw_getparam_arg

View File

@@ -1318,7 +1318,7 @@ vmwgfx_dirty(struct saa_driver *driver, PixmapPtr pixmap,
* just before we call the kms update function for the hw * just before we call the kms update function for the hw
* surface. * surface.
*/ */
if (vsaa->only_hw_presents) { if (vpix->scanout_hw) {
if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage)) if (!hw && !vmwgfx_upload_to_hw(&vsaa->driver, pixmap, damage))
return FALSE; return FALSE;
@@ -1408,7 +1408,8 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
void (*present_flush)(ScreenPtr pScreen), void (*present_flush)(ScreenPtr pScreen),
Bool direct_presents, Bool direct_presents,
Bool only_hw_presents, Bool only_hw_presents,
Bool rendercheck) Bool rendercheck,
Bool has_screen_targets)
{ {
struct vmwgfx_saa *vsaa; struct vmwgfx_saa *vsaa;
@@ -1419,6 +1420,7 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
if (xat == NULL) { if (xat == NULL) {
direct_presents = FALSE; direct_presents = FALSE;
only_hw_presents = FALSE; only_hw_presents = FALSE;
has_screen_targets = FALSE;
} }
vsaa->pScreen = pScreen; vsaa->pScreen = pScreen;
@@ -1433,6 +1435,7 @@ vmwgfx_saa_init(ScreenPtr pScreen, int drm_fd, struct xa_tracker *xat,
vsaa->rendercheck = rendercheck; vsaa->rendercheck = rendercheck;
vsaa->is_master = TRUE; vsaa->is_master = TRUE;
vsaa->known_prime_format = FALSE; vsaa->known_prime_format = FALSE;
vsaa->has_screen_targets = has_screen_targets;
WSBMINITLISTHEAD(&vsaa->sync_x_list); WSBMINITLISTHEAD(&vsaa->sync_x_list);
WSBMINITLISTHEAD(&vsaa->pixmaps); WSBMINITLISTHEAD(&vsaa->pixmaps);
@@ -1492,7 +1495,8 @@ vmwgfx_scanout_refresh(PixmapPtr pixmap)
*/ */
uint32_t 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; PixmapPtr pixmap = entry->pixmap;
struct vmwgfx_saa *vsaa = struct vmwgfx_saa *vsaa =
@@ -1503,7 +1507,10 @@ vmwgfx_scanout_ref(struct vmwgfx_screen_entry *entry)
uint32_t handle, dummy; uint32_t handle, dummy;
unsigned int depth; 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 * The KMS fb will be a HW surface. Create it, add damage
* and get the handle. * and get the handle.

View File

@@ -56,6 +56,7 @@ struct vmwgfx_saa_pixmap {
struct _WsbmListHead sync_x_head; struct _WsbmListHead sync_x_head;
struct _WsbmListHead scanout_list; struct _WsbmListHead scanout_list;
struct _WsbmListHead pixmap_list; struct _WsbmListHead pixmap_list;
Bool scanout_hw;
uint32_t xa_flags; uint32_t xa_flags;
uint32_t staging_add_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), void (*present_flush)(ScreenPtr pScreen),
Bool direct_presents, Bool direct_presents,
Bool only_hw_presents, Bool only_hw_presents,
Bool rendercheck); Bool rendercheck,
Bool has_screen_targets);
extern uint32_t 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 extern void
vmwgfx_scanout_unref(struct vmwgfx_screen_entry *box); vmwgfx_scanout_unref(struct vmwgfx_screen_entry *box);

View File

@@ -56,6 +56,7 @@ struct vmwgfx_saa {
Bool rendercheck; Bool rendercheck;
Bool is_master; Bool is_master;
Bool known_prime_format; Bool known_prime_format;
Bool has_screen_targets;
void (*present_flush) (ScreenPtr pScreen); void (*present_flush) (ScreenPtr pScreen);
struct _WsbmListHead sync_x_list; struct _WsbmListHead sync_x_list;
struct _WsbmListHead pixmaps; struct _WsbmListHead pixmaps;