summaryrefslogtreecommitdiff
path: root/src/amdgpu_kms.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/amdgpu_kms.c')
-rw-r--r--src/amdgpu_kms.c167
1 files changed, 163 insertions, 4 deletions
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index cfdf716..5a672c9 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -67,6 +67,7 @@ const OptionInfoRec AMDGPUOptions_KMS[] = {
{OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
{ OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE },
+ {OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
{-1, NULL, OPTV_NONE, {0}, FALSE}
};
@@ -210,6 +211,134 @@ static void amdgpu_dirty_update(ScreenPtr screen)
}
#endif
+static Bool
+amdgpu_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
+{
+ extents->x1 = max(extents->x1 - x, 0);
+ extents->y1 = max(extents->y1 - y, 0);
+ extents->x2 = min(extents->x2 - x, w);
+ extents->y2 = min(extents->y2 - y, h);
+
+ return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
+}
+
+static void
+amdgpu_scanout_update_abort(ScrnInfoPtr scrn, void *event_data)
+{
+ xf86CrtcPtr xf86_crtc = event_data;
+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+
+ drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec,
+ void *event_data)
+{
+ xf86CrtcPtr xf86_crtc = event_data;
+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+ DamagePtr pDamage;
+ RegionPtr pRegion;
+ DrawablePtr pDraw;
+ ScreenPtr pScreen;
+ GCPtr gc;
+ BoxRec extents;
+
+ if (!drmmode_crtc->scanout.pixmap ||
+ drmmode_crtc->dpms_mode != DPMSModeOn)
+ goto out;
+
+ pDamage = drmmode_crtc->scanout_damage;
+ if (!pDamage)
+ goto out;
+
+ pRegion = DamageRegion(pDamage);
+ if (!RegionNotEmpty(pRegion))
+ goto out;
+
+ pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+ extents = *RegionExtents(pRegion);
+ if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+ pDraw->width, pDraw->height))
+ goto clear_damage;
+
+ pScreen = pDraw->pScreen;
+ gc = GetScratchGC(pDraw->depth, pScreen);
+
+ ValidateGC(pDraw, gc);
+ (*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
+ pDraw, gc,
+ xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
+ extents.x2 - extents.x1, extents.y2 - extents.y1,
+ extents.x1, extents.y1);
+ FreeScratchGC(gc);
+
+ amdgpu_glamor_flush(scrn);
+
+clear_damage:
+ RegionEmpty(pRegion);
+
+out:
+ drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
+ struct amdgpu_drm_queue_entry *drm_queue_entry;
+ ScrnInfoPtr scrn;
+ drmVBlank vbl;
+ DamagePtr pDamage;
+ RegionPtr pRegion;
+ DrawablePtr pDraw;
+ BoxRec extents;
+
+ if (drmmode_crtc->scanout_update_pending ||
+ !drmmode_crtc->scanout.pixmap ||
+ drmmode_crtc->dpms_mode != DPMSModeOn)
+ return;
+
+ pDamage = drmmode_crtc->scanout_damage;
+ if (!pDamage)
+ return;
+
+ pRegion = DamageRegion(pDamage);
+ if (!RegionNotEmpty(pRegion))
+ return;
+
+ pDraw = &drmmode_crtc->scanout.pixmap->drawable;
+ extents = *RegionExtents(pRegion);
+ if (!amdgpu_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
+ pDraw->width, pDraw->height))
+ return;
+
+ scrn = xf86_crtc->scrn;
+ drm_queue_entry = amdgpu_drm_queue_alloc(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+ AMDGPU_DRM_QUEUE_ID_DEFAULT,
+ xf86_crtc,
+ amdgpu_scanout_update_handler,
+ amdgpu_scanout_update_abort);
+ if (!drm_queue_entry) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "amdgpu_drm_queue_alloc failed for scanout update\n");
+ return;
+ }
+
+ vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+ vbl.request.type |= amdgpu_populate_vbl_request_type(xf86_crtc);
+ vbl.request.sequence = 1;
+ vbl.request.signal = (unsigned long)drm_queue_entry;
+ if (drmWaitVBlank(AMDGPUPTR(scrn)->dri2.drm_fd, &vbl)) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmWaitVBlank failed for scanout update: %s\n",
+ strerror(errno));
+ amdgpu_drm_abort_entry(drm_queue_entry);
+ return;
+ }
+
+ drmmode_crtc->scanout_update_pending = TRUE;
+}
static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
{
SCREEN_PTR(arg);
@@ -220,6 +349,14 @@ static void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
+ if (info->shadow_primary) {
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int c;
+
+ for (c = 0; c < xf86_config->num_crtc; c++)
+ amdgpu_scanout_update(xf86_config->crtc[c]);
+ }
+
if (info->use_glamor)
amdgpu_glamor_flush(pScrn);
@@ -543,12 +680,28 @@ Bool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
amdgpu_get_tile_config(pScrn);
}
+ if (info->use_glamor) {
+ info->shadow_primary =
+ xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
+
+ if (info->shadow_primary)
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n");
+ }
+
info->allowPageFlip = xf86ReturnOptValBool(info->Options,
OPTION_PAGE_FLIP,
TRUE);
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "KMS Pageflipping: %sabled\n",
- info->allowPageFlip ? "en" : "dis");
+ if (info->shadow_primary) {
+ xf86DrvMsg(pScrn->scrnIndex,
+ info->allowPageFlip ? X_WARNING : X_DEFAULT,
+ "KMS Pageflipping: disabled%s\n",
+ info->allowPageFlip ? " because of ShadowPrimary" : "");
+ info->allowPageFlip = FALSE;
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "KMS Pageflipping: %sabled\n",
+ info->allowPageFlip ? "en" : "dis");
+ }
if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) ==
FALSE) {
@@ -993,6 +1146,7 @@ void AMDGPULeaveVT_KMS(VT_FUNC_ARGS_DECL)
drmDropMaster(info->dri2.drm_fd);
xf86RotateFreeShadow(pScrn);
+ drmmode_scanout_free(pScrn);
xf86_hide_cursors(pScrn);
@@ -1074,7 +1228,12 @@ static Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
if (info->front_buffer == NULL) {
int pitch;
- int hint = info->use_glamor ? 0 : AMDGPU_CREATE_PIXMAP_LINEAR;
+ int hint = 0;
+
+ if (info->shadow_primary)
+ hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
+ else if (!info->use_glamor)
+ hint = AMDGPU_CREATE_PIXMAP_LINEAR;
info->front_buffer =
amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,