summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2016-09-08 17:04:05 +0900
committerMichel Dänzer <michel@daenzer.net>2016-09-09 19:02:40 +0900
commit6d31fb124d4418e64c949bde9ed1facf95967762 (patch)
tree8ae14e3e4bc198bba94d42b24e8cb43e66af6a5d /src
parentb10ecdbd89b0a60a990c78c3e53bab6c4c96fe9f (diff)
Handle RandR 1.4 slave dirty updates via amdgpu_drm_queue
This reduces PCIe bandwidth usage and tearing. (Ported from radeon commit ad0a0656dd0e74683e6d7789decba827aa29c221) Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'src')
-rw-r--r--src/amdgpu_kms.c96
1 files changed, 93 insertions, 3 deletions
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index 9670c3f..aaaee1a 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -304,8 +304,10 @@ static Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
}
#ifdef AMDGPU_PIXMAP_SHARING
-static void redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty)
+static void
+redisplay_dirty(PixmapDirtyUpdatePtr dirty)
{
+ ScrnInfoPtr scrn = xf86ScreenToScrn(dirty->src->drawable.pScreen);
RegionRec pixregion;
PixmapRegionInit(&pixregion, dirty->slave_dst);
@@ -316,8 +318,94 @@ static void redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty)
PixmapSyncDirtyHelper(dirty, &pixregion);
#endif
+ amdgpu_glamor_flush(scrn);
DamageRegionProcessPending(&dirty->slave_dst->drawable);
RegionUninit(&pixregion);
+
+ DamageEmpty(dirty->damage);
+}
+
+static void
+amdgpu_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
+{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+ drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+void
+amdgpu_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
+ void *event_data)
+{
+ ScrnInfoPtr scrn = crtc->scrn;
+ ScreenPtr screen = scrn->pScreen;
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+ PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap;
+ PixmapDirtyUpdatePtr dirty;
+
+ xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
+ if (dirty->src == scanoutpix &&
+ dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) {
+ redisplay_dirty(dirty);
+ break;
+ }
+ }
+
+ drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+amdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
+{
+ ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
+ ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+ xf86CrtcPtr xf86_crtc = NULL;
+ drmmode_crtc_private_ptr drmmode_crtc = NULL;
+ uintptr_t drm_queue_seq;
+ drmVBlank vbl;
+ int c;
+
+ /* Find the CRTC which is scanning out from this slave pixmap */
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ xf86_crtc = xf86_config->crtc[c];
+ drmmode_crtc = xf86_crtc->driver_private;
+ if (drmmode_crtc->scanout[0].pixmap == dirty->slave_dst)
+ break;
+ }
+
+ if (c == xf86_config->num_crtc ||
+ !xf86_crtc->enabled ||
+ drmmode_crtc->scanout_update_pending ||
+ !drmmode_crtc->scanout[0].pixmap ||
+ drmmode_crtc->pending_dpms_mode != DPMSModeOn)
+ return;
+
+ drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
+ AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
+ AMDGPU_DRM_QUEUE_ID_DEFAULT, NULL,
+ amdgpu_prime_scanout_update_handler,
+ amdgpu_prime_scanout_update_abort);
+ if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "amdgpu_drm_queue_alloc failed for PRIME 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 = drm_queue_seq;
+ if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl)) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "drmWaitVBlank failed for PRIME update: %s\n",
+ strerror(errno));
+ amdgpu_drm_abort_entry(drm_queue_seq);
+ return;
+ }
+
+ drmmode_crtc->scanout_update_pending = TRUE;
}
static void amdgpu_dirty_update(ScreenPtr screen)
@@ -331,8 +419,10 @@ static void amdgpu_dirty_update(ScreenPtr screen)
xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
region = DamageRegion(ent->damage);
if (RegionNotEmpty(region)) {
- redisplay_dirty(screen, ent);
- DamageEmpty(ent->damage);
+ if (screen->isGPU)
+ amdgpu_prime_scanout_update(ent);
+ else
+ redisplay_dirty(ent);
}
}
}