From 84a4590c793a446e6d4979251295b32467caab7c91a9aded99e415057ae7c1f7 Mon Sep 17 00:00:00 2001 From: Max Staudt Date: Wed, 2 Nov 2016 10:39:34 +0000 Subject: [PATCH] Accepting request 438260 from home:mstaudt:branches:X11:XOrg - U_01-* ... U_20-* : Include patches that haven't made it into the 7.7.1 release. This means almost all commits between xf86-video-ati-7.7.0 and 12d30eeb9711bd2b1609d6bbb74c4a1760596f72. Fixes (bsc#990066). OBS-URL: https://build.opensuse.org/request/show/438260 OBS-URL: https://build.opensuse.org/package/show/X11:XOrg/xf86-video-ati?expand=0&rev=51 --- ..._dri3_pixmap_from_fd-if-calloc-fails.patch | 27 + ...or-async-flips-to-radeon_do_pageflip.patch | 123 +++ U_03-present-Support-async-flips.patch | 42 + ...efault-when-building-for-Xorg-1.18.3.patch | 46 + ...XA-6xx-7xx-fast-solid-pixmap-support.patch | 944 ++++++++++++++++++ ...rate-PictOpOver-with-component-alpha.patch | 130 +++ U_07-Adapt-to-XF86_CRTC_VERSION-7.patch | 80 ++ ...plicit-RADEON_DRM_QUEUE_ERROR-define.patch | 124 +++ ...on-t-enable-DRI3-by-default-with-EXA.patch | 48 + ...hing-every-time-in-the-FlushCallback.patch | 170 ++++ ...-event-related-flushes-per-client-v2.patch | 142 +++ ...elpers-for-RandR-1.4-scanout-pixmaps.patch | 170 ++++ ...e-dirty-updates-via-radeon_drm_queue.patch | 136 +++ ...curately-for-RandR-1.4-slave-scanout.patch | 144 +++ U_15-Fix-build-against-xserver-1.13.patch | 50 + ...d-pixmap-on-demand-for-slave-scanout.patch | 163 +++ U_17-Factor-out-transform_region-helper.patch | 107 ++ ...-up-radeon_scanout_extents_intersect.patch | 76 ++ ...hronize-scanout-pixmaps-for-TearFree.patch | 327 ++++++ ...e-effective-with-PRIME-slave-scanout.patch | 265 +++++ xf86-video-ati.changes | 11 + xf86-video-ati.spec | 40 + 22 files changed, 3365 insertions(+) create mode 100644 U_01-dri3-Return-NULL-from-radeon_dri3_pixmap_from_fd-if-calloc-fails.patch create mode 100644 U_02-Add-support-for-async-flips-to-radeon_do_pageflip.patch create mode 100644 U_03-present-Support-async-flips.patch create mode 100644 U_04-Enable-DRI3-by-default-when-building-for-Xorg-1.18.3.patch create mode 100644 U_05-EXA-6xx-7xx-fast-solid-pixmap-support.patch create mode 100644 U_06-EXA-6xx-7xx-accelerate-PictOpOver-with-component-alpha.patch create mode 100644 U_07-Adapt-to-XF86_CRTC_VERSION-7.patch create mode 100644 U_08-Add-explicit-RADEON_DRM_QUEUE_ERROR-define.patch create mode 100644 U_09-Don-t-enable-DRI3-by-default-with-EXA.patch create mode 100644 U_10-Use-EventCallback-to-avoid-flushing-every-time-in-the-FlushCallback.patch create mode 100644 U_11-Keep-track-of-damage-event-related-flushes-per-client-v2.patch create mode 100644 U_12-Use-drmmode_crtc_scanout_-helpers-for-RandR-1.4-scanout-pixmaps.patch create mode 100644 U_13-Handle-RandR-1.4-slave-dirty-updates-via-radeon_drm_queue.patch create mode 100644 U_14-Track-damage-accurately-for-RandR-1.4-slave-scanout.patch create mode 100644 U_15-Fix-build-against-xserver-1.13.patch create mode 100644 U_16-Only-copy-from-screen-pixmap-to-shared-pixmap-on-demand-for-slave-scanout.patch create mode 100644 U_17-Factor-out-transform_region-helper.patch create mode 100644 U_18-Move-up-radeon_scanout_extents_intersect.patch create mode 100644 U_19-Synchronize-scanout-pixmaps-for-TearFree.patch create mode 100644 U_20-Make-TearFree-effective-with-PRIME-slave-scanout.patch diff --git a/U_01-dri3-Return-NULL-from-radeon_dri3_pixmap_from_fd-if-calloc-fails.patch b/U_01-dri3-Return-NULL-from-radeon_dri3_pixmap_from_fd-if-calloc-fails.patch new file mode 100644 index 0000000..4d23527 --- /dev/null +++ b/U_01-dri3-Return-NULL-from-radeon_dri3_pixmap_from_fd-if-calloc-fails.patch @@ -0,0 +1,27 @@ +From: Tom St Denis +Date: Fri Apr 8 10:22:11 2016 -0400 +Subject: [PATCH 1/20]dri3: Return NULL from radeon_dri3_pixmap_from_fd if calloc fails. +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: bd4c72c8625996d842824ce4963f2d759fe2954a +References: bsc#990066 +Signed-off-by: Max Staudt + +Signed-off-by: Tom St Denis +Reviewed-by: Michel Dänzer +--- + src/radeon_dri3.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/radeon_dri3.c b/src/radeon_dri3.c +index 43a073b..c567024 100644 +--- a/src/radeon_dri3.c ++++ b/src/radeon_dri3.c +@@ -144,6 +144,7 @@ static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen, + } + + screen->DestroyPixmap(pixmap); ++ return NULL; + } + } + #endif diff --git a/U_02-Add-support-for-async-flips-to-radeon_do_pageflip.patch b/U_02-Add-support-for-async-flips-to-radeon_do_pageflip.patch new file mode 100644 index 0000000..6318b8d --- /dev/null +++ b/U_02-Add-support-for-async-flips-to-radeon_do_pageflip.patch @@ -0,0 +1,123 @@ +From: Michel Dänzer +Date: Tue Mar 15 16:42:16 2016 +0900 +Subject: [PATCH 2/20]Add support for async flips to radeon_do_pageflip +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 90a915c62d012e99193833aecc93974e68880c60 +References: bsc#990066 +Signed-off-by: Max Staudt + +Will be used by the next change. No functional change here. + +Reviewed-by: Alex Deucher +--- + src/drmmode_display.c | 9 +++++++-- + src/drmmode_display.h | 9 ++++++++- + src/radeon_dri2.c | 2 +- + src/radeon_present.c | 5 +++-- + 4 files changed, 19 insertions(+), 6 deletions(-) + +diff --git a/src/drmmode_display.c b/src/drmmode_display.c +index 0f57292..34b76e9 100644 +--- a/src/drmmode_display.c ++++ b/src/drmmode_display.c +@@ -2741,7 +2741,8 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) + Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, + uint32_t new_front_handle, uint64_t id, void *data, + int ref_crtc_hw_id, radeon_drm_handler_proc handler, +- radeon_drm_abort_proc abort) ++ radeon_drm_abort_proc abort, ++ enum drmmode_flip_sync flip_sync) + { + RADEONInfoPtr info = RADEONPTR(scrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); +@@ -2751,6 +2752,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, + unsigned int pitch; + int i; + uint32_t tiling_flags = 0; ++ uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT; + drmmode_flipdata_ptr flipdata; + uintptr_t drm_queue_seq = 0; + +@@ -2797,6 +2799,9 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, + flipdata->handler = handler; + flipdata->abort = abort; + ++ if (flip_sync == FLIP_ASYNC) ++ flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC; ++ + for (i = 0; i < config->num_crtc; i++) { + crtc = config->crtc[i]; + +@@ -2823,7 +2828,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, + } + + if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, +- drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, ++ drmmode->fb_id, flip_flags, + (void*)drm_queue_seq)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "flip queue failed: %s\n", strerror(errno)); +diff --git a/src/drmmode_display.h b/src/drmmode_display.h +index bbb827c..63b96ac 100644 +--- a/src/drmmode_display.h ++++ b/src/drmmode_display.h +@@ -127,6 +127,12 @@ typedef struct { + } drmmode_output_private_rec, *drmmode_output_private_ptr; + + ++enum drmmode_flip_sync { ++ FLIP_VSYNC, ++ FLIP_ASYNC, ++}; ++ ++ + extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp); + extern void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode); + extern void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode); +@@ -154,7 +160,8 @@ extern void drmmode_clear_pending_flip(xf86CrtcPtr crtc); + Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, + uint32_t new_front_handle, uint64_t id, void *data, + int ref_crtc_hw_id, radeon_drm_handler_proc handler, +- radeon_drm_abort_proc abort); ++ radeon_drm_abort_proc abort, ++ enum drmmode_flip_sync flip_sync); + int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc); + int drmmode_get_current_ust(int drm_fd, CARD64 *ust); + +diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c +index 0cd6b24..5ebc9b7 100644 +--- a/src/radeon_dri2.c ++++ b/src/radeon_dri2.c +@@ -678,7 +678,7 @@ radeon_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, + RADEON_DRM_QUEUE_ID_DEFAULT, flip_info, + ref_crtc_hw_id, + radeon_dri2_flip_event_handler, +- radeon_dri2_flip_event_abort)) { ++ radeon_dri2_flip_event_abort, FLIP_VSYNC)) { + info->drmmode.dri2_flipping = TRUE; + return TRUE; + } +diff --git a/src/radeon_present.c b/src/radeon_present.c +index 2389c7f..1a0e06a 100644 +--- a/src/radeon_present.c ++++ b/src/radeon_present.c +@@ -338,7 +338,8 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, + ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle, + event_id, event, crtc_id, + radeon_present_flip_event, +- radeon_present_flip_abort); ++ radeon_present_flip_abort, ++ FLIP_VSYNC); + if (!ret) + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); + else +@@ -381,7 +382,7 @@ radeon_present_unflip(ScreenPtr screen, uint64_t event_id) + + if (radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle, + event_id, event, -1, radeon_present_flip_event, +- radeon_present_flip_abort)) ++ radeon_present_flip_abort, FLIP_VSYNC)) + return; + + modeset: diff --git a/U_03-present-Support-async-flips.patch b/U_03-present-Support-async-flips.patch new file mode 100644 index 0000000..1d1c24a --- /dev/null +++ b/U_03-present-Support-async-flips.patch @@ -0,0 +1,42 @@ +From: Michel Dänzer +Date: Tue Mar 15 16:47:35 2016 +0900 +Subject: [PATCH 3/20]present: Support async flips +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 1ca677309720e2f6c953c9e76f5b34c22a4416c6 +References: bsc#990066 +Signed-off-by: Max Staudt + +The xserver Present code only calls radeon_present_flip with +sync_flip=FALSE if radeon_present_screen_init sets +PresentCapabilityAsync, and the latter only sets it if the kernel driver +advertises support for async flips. + +Reviewed-by: Alex Deucher +--- + src/radeon_present.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/src/radeon_present.c b/src/radeon_present.c +index 1a0e06a..69a0532 100644 +--- a/src/radeon_present.c ++++ b/src/radeon_present.c +@@ -248,9 +248,6 @@ radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, + if (info->hwcursor_disabled) + return FALSE; + +- if (!sync_flip) +- return FALSE; +- + if (info->drmmode.dri2_flipping) + return FALSE; + +@@ -339,7 +336,7 @@ radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, + event_id, event, crtc_id, + radeon_present_flip_event, + radeon_present_flip_abort, +- FLIP_VSYNC); ++ sync_flip ? FLIP_VSYNC : FLIP_ASYNC); + if (!ret) + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); + else diff --git a/U_04-Enable-DRI3-by-default-when-building-for-Xorg-1.18.3.patch b/U_04-Enable-DRI3-by-default-when-building-for-Xorg-1.18.3.patch new file mode 100644 index 0000000..1c0cf7d --- /dev/null +++ b/U_04-Enable-DRI3-by-default-when-building-for-Xorg-1.18.3.patch @@ -0,0 +1,46 @@ +From: Michel Dänzer +Date: Tue May 10 19:02:20 2016 +0900 +Subject: [PATCH 4/20]Enable DRI3 by default when building for Xorg >= 1.18.3 +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 1181b9c582f10b6c523e4b2988e2ce87ecf3d367 +References: bsc#990066 +Signed-off-by: Max Staudt + +Seems to work well enough in general now. + +Reviewed-by: Alex Deucher +--- + man/radeon.man | 2 ++ + src/radeon_kms.c | 4 ++++ + 2 files changed, 6 insertions(+) + +diff --git a/man/radeon.man b/man/radeon.man +index 1acdc63..cacafb5 100644 +--- a/man/radeon.man ++++ b/man/radeon.man +@@ -270,6 +270,8 @@ Sea Islands. + .BI "Option \*qDRI\*q \*q" integer \*q + Define the maximum level of DRI to enable. Valid values are 2 for DRI2 or 3 for DRI3. + The default is ++.B 3 for DRI3 ++if the driver was compiled for Xorg >= 1.18.3, otherwise + .B 2 for DRI2. + .TP + .BI "Option \*qEnablePageFlip\*q \*q" boolean \*q +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index f9abc09..0ced370 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -1725,7 +1725,11 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL) + } + #endif + ++#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,18,3,0,0) ++ value = TRUE; ++#else + value = FALSE; ++#endif + from = X_DEFAULT; + + if (!info->r600_shadow_fb) { diff --git a/U_05-EXA-6xx-7xx-fast-solid-pixmap-support.patch b/U_05-EXA-6xx-7xx-fast-solid-pixmap-support.patch new file mode 100644 index 0000000..667d992 --- /dev/null +++ b/U_05-EXA-6xx-7xx-fast-solid-pixmap-support.patch @@ -0,0 +1,944 @@ +From: Tan Hu +Date: Fri May 27 17:05:14 2016 +0800 +Subject: [PATCH 5/20]EXA/6xx/7xx: fast solid pixmap support +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 9b9ad669c748f53247e53fa3f3b03a77da5e5cb3 +References: bsc#990066 +Signed-off-by: Max Staudt + +Solid pixmaps are currently implemented with scratch pixmaps, which +is slow. This replaces the hack with a proper implementation. The +Composite shader can now either sample a src/mask or use a constant +value. + +r6xx still be used on some machine, +Ported from commit 94d0d14914a025525a0766669b556eaa6681def7. + +Signed-off-by: Tan Hu +Reviewed-by: Grigori Goronzy +--- + src/r600_exa.c | 257 ++++++++++++++++++++++++--------- + src/r600_shader.c | 418 +++++++++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 526 insertions(+), 149 deletions(-) + +diff --git a/src/r600_exa.c b/src/r600_exa.c +index 8d11ce7..10df4ec 100644 +--- a/src/r600_exa.c ++++ b/src/r600_exa.c +@@ -1165,6 +1165,134 @@ static Bool R600CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskP + + } + ++static void R600SetSolidConsts(ScrnInfoPtr pScrn, float *buf, int format, uint32_t fg, int unit) ++{ ++ RADEONInfoPtr info = RADEONPTR(pScrn); ++ struct radeon_accel_state *accel_state = info->accel_state; ++ float pix_r = 0, pix_g = 0, pix_b = 0, pix_a = 0; ++ ++ uint32_t w = (fg >> 24) & 0xff; ++ uint32_t z = (fg >> 16) & 0xff; ++ uint32_t y = (fg >> 8) & 0xff; ++ uint32_t x = (fg >> 0) & 0xff; ++ float xf = (float)x / 255; /* R */ ++ float yf = (float)y / 255; /* G */ ++ float zf = (float)z / 255; /* B */ ++ float wf = (float)w / 255; /* A */ ++ ++ /* component swizzles */ ++ switch (format) { ++ case PICT_a1r5g5b5: ++ case PICT_a8r8g8b8: ++ pix_r = zf; /* R */ ++ pix_g = yf; /* G */ ++ pix_b = xf; /* B */ ++ pix_a = wf; /* A */ ++ break; ++ case PICT_a8b8g8r8: ++ pix_r = xf; /* R */ ++ pix_g = yf; /* G */ ++ pix_b = zf; /* B */ ++ pix_a = wf; /* A */ ++ break; ++ case PICT_x8b8g8r8: ++ pix_r = xf; /* R */ ++ pix_g = yf; /* G */ ++ pix_b = zf; /* B */ ++ pix_a = 1.0; /* A */ ++ break; ++ case PICT_b8g8r8a8: ++ pix_r = yf; /* R */ ++ pix_g = zf; /* G */ ++ pix_b = wf; /* B */ ++ pix_a = xf; /* A */ ++ break; ++ case PICT_b8g8r8x8: ++ pix_r = yf; /* R */ ++ pix_g = zf; /* G */ ++ pix_b = wf; /* B */ ++ pix_a = 1.0; /* A */ ++ break; ++ case PICT_x1r5g5b5: ++ case PICT_x8r8g8b8: ++ case PICT_r5g6b5: ++ pix_r = zf; /* R */ ++ pix_g = yf; /* G */ ++ pix_b = xf; /* B */ ++ pix_a = 1.0; /* A */ ++ break; ++ case PICT_a8: ++ pix_r = 0.0; /* R */ ++ pix_g = 0.0; /* G */ ++ pix_b = 0.0; /* B */ ++ pix_a = xf; /* A */ ++ break; ++ default: ++ ErrorF("Bad format 0x%x\n", format); ++ } ++ ++ if (unit == 0) { ++ if (!accel_state->msk_pic) { ++ if (PICT_FORMAT_RGB(format) == 0) { ++ pix_r = 0.0; ++ pix_g = 0.0; ++ pix_b = 0.0; ++ } ++ ++ if (PICT_FORMAT_A(format) == 0) ++ pix_a = 1.0; ++ } else { ++ if (accel_state->component_alpha) { ++ if (accel_state->src_alpha) { ++ if (PICT_FORMAT_A(format) == 0) { ++ pix_r = 1.0; ++ pix_g = 1.0; ++ pix_b = 1.0; ++ pix_a = 1.0; ++ } else { ++ pix_r = pix_a; ++ pix_g = pix_a; ++ pix_b = pix_a; ++ } ++ } else { ++ if (PICT_FORMAT_A(format) == 0) ++ pix_a = 1.0; ++ } ++ } else { ++ if (PICT_FORMAT_RGB(format) == 0) { ++ pix_r = 0; ++ pix_g = 0; ++ pix_b = 0; ++ } ++ ++ if (PICT_FORMAT_A(format) == 0) ++ pix_a = 1.0; ++ } ++ } ++ } else { ++ if (accel_state->component_alpha) { ++ if (PICT_FORMAT_A(format) == 0) ++ pix_a = 1.0; ++ } else { ++ if (PICT_FORMAT_A(format) == 0) { ++ pix_r = 1.0; ++ pix_g = 1.0; ++ pix_b = 1.0; ++ pix_a = 1.0; ++ } else { ++ pix_r = pix_a; ++ pix_g = pix_a; ++ pix_b = pix_a; ++ } ++ } ++ } ++ ++ buf[0] = pix_r; ++ buf[1] = pix_g; ++ buf[2] = pix_b; ++ buf[3] = pix_a; ++} ++ + static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + PicturePtr pMaskPicture, PicturePtr pDstPicture, + PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst) +@@ -1177,31 +1305,27 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + cb_config_t cb_conf; + shader_config_t vs_conf, ps_conf; + struct r600_accel_object src_obj, mask_obj, dst_obj; ++ uint32_t ps_bool_consts = 0; ++ float ps_alu_consts[8]; + + if (pDst->drawable.bitsPerPixel < 8 || (pSrc && pSrc->drawable.bitsPerPixel < 8)) + return FALSE; + +- if (!pSrc) { +- pSrc = RADEONSolidPixmap(pScreen, pSrcPicture->pSourcePict->solidFill.color); +- if (!pSrc) +- RADEON_FALLBACK(("Failed to create solid scratch pixmap\n")); ++ if (pSrc) { ++ src_obj.bo = radeon_get_pixmap_bo(pSrc); ++ src_obj.tiling_flags = radeon_get_pixmap_tiling(pSrc); ++ src_obj.surface = radeon_get_pixmap_surface(pSrc); ++ src_obj.pitch = exaGetPixmapPitch(pSrc) / (pSrc->drawable.bitsPerPixel / 8); ++ src_obj.width = pSrc->drawable.width; ++ src_obj.height = pSrc->drawable.height; ++ src_obj.bpp = pSrc->drawable.bitsPerPixel; ++ src_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; + } + + dst_obj.bo = radeon_get_pixmap_bo(pDst); +- src_obj.bo = radeon_get_pixmap_bo(pSrc); + dst_obj.tiling_flags = radeon_get_pixmap_tiling(pDst); +- src_obj.tiling_flags = radeon_get_pixmap_tiling(pSrc); + dst_obj.surface = radeon_get_pixmap_surface(pDst); +- src_obj.surface = radeon_get_pixmap_surface(pSrc); +- +- src_obj.pitch = exaGetPixmapPitch(pSrc) / (pSrc->drawable.bitsPerPixel / 8); + dst_obj.pitch = exaGetPixmapPitch(pDst) / (pDst->drawable.bitsPerPixel / 8); +- +- src_obj.width = pSrc->drawable.width; +- src_obj.height = pSrc->drawable.height; +- src_obj.bpp = pSrc->drawable.bitsPerPixel; +- src_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; +- + dst_obj.width = pDst->drawable.width; + dst_obj.height = pDst->drawable.height; + dst_obj.bpp = pDst->drawable.bitsPerPixel; +@@ -1211,34 +1335,17 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + dst_obj.domain = RADEON_GEM_DOMAIN_VRAM; + + if (pMaskPicture) { +- if (!pMask) { +- pMask = RADEONSolidPixmap(pScreen, pMaskPicture->pSourcePict->solidFill.color); +- if (!pMask) { +- if (!pSrcPicture->pDrawable) +- pScreen->DestroyPixmap(pSrc); +- RADEON_FALLBACK(("Failed to create solid scratch pixmap\n")); +- } ++ if (pMask) { ++ mask_obj.bo = radeon_get_pixmap_bo(pMask); ++ mask_obj.tiling_flags = radeon_get_pixmap_tiling(pMask); ++ mask_obj.surface = radeon_get_pixmap_surface(pMask); ++ mask_obj.pitch = exaGetPixmapPitch(pMask) / (pMask->drawable.bitsPerPixel / 8); ++ mask_obj.width = pMask->drawable.width; ++ mask_obj.height = pMask->drawable.height; ++ mask_obj.bpp = pMask->drawable.bitsPerPixel; ++ mask_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; + } + +- mask_obj.bo = radeon_get_pixmap_bo(pMask); +- mask_obj.tiling_flags = radeon_get_pixmap_tiling(pMask); +- mask_obj.surface = radeon_get_pixmap_surface(pMask); +- +- mask_obj.pitch = exaGetPixmapPitch(pMask) / (pMask->drawable.bitsPerPixel / 8); +- +- mask_obj.width = pMask->drawable.width; +- mask_obj.height = pMask->drawable.height; +- mask_obj.bpp = pMask->drawable.bitsPerPixel; +- mask_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT; +- +- if (!R600SetAccelState(pScrn, +- &src_obj, +- &mask_obj, +- &dst_obj, +- accel_state->comp_vs_offset, accel_state->comp_ps_offset, +- 3, 0xffffffff)) +- return FALSE; +- + accel_state->msk_pic = pMaskPicture; + if (pMaskPicture->componentAlpha) { + accel_state->component_alpha = TRUE; +@@ -1251,19 +1358,19 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + accel_state->src_alpha = FALSE; + } + } else { +- if (!R600SetAccelState(pScrn, +- &src_obj, +- NULL, +- &dst_obj, +- accel_state->comp_vs_offset, accel_state->comp_ps_offset, +- 3, 0xffffffff)) +- return FALSE; +- + accel_state->msk_pic = NULL; + accel_state->component_alpha = FALSE; + accel_state->src_alpha = FALSE; + } + ++ if (!R600SetAccelState(pScrn, ++ pSrc ? &src_obj : NULL, ++ (pMaskPicture && pMask) ? &mask_obj : NULL, ++ &dst_obj, ++ accel_state->comp_vs_offset, accel_state->comp_ps_offset, ++ 3, 0xffffffff)) ++ return FALSE; ++ + if (!R600GetDestFormat(pDstPicture, &dst_format)) + return FALSE; + +@@ -1284,10 +1391,13 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + r600_set_screen_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height); + r600_set_window_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height); + +- if (!R600TextureSetup(pSrcPicture, pSrc, 0)) { +- R600IBDiscard(pScrn); +- return FALSE; +- } ++ if (pSrc) { ++ if (!R600TextureSetup(pSrcPicture, pSrc, 0)) { ++ R600IBDiscard(pScrn); ++ return FALSE; ++ } ++ } else ++ accel_state->is_transform[0] = FALSE; + + if (pMask) { + if (!R600TextureSetup(pMaskPicture, pMask, 1)) { +@@ -1297,12 +1407,16 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + } else + accel_state->is_transform[1] = FALSE; + ++ if (pSrc) ++ ps_bool_consts |= (1 << 0); ++ if (pMask) ++ ps_bool_consts |= (1 << 1); ++ r600_set_bool_consts(pScrn, SQ_BOOL_CONST_ps, ps_bool_consts); ++ + if (pMask) { + r600_set_bool_consts(pScrn, SQ_BOOL_CONST_vs, (1 << 0)); +- r600_set_bool_consts(pScrn, SQ_BOOL_CONST_ps, (1 << 0)); + } else { + r600_set_bool_consts(pScrn, SQ_BOOL_CONST_vs, (0 << 0)); +- r600_set_bool_consts(pScrn, SQ_BOOL_CONST_ps, (0 << 0)); + } + + /* Shader */ +@@ -1315,7 +1429,7 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + + ps_conf.shader_addr = accel_state->ps_mc_addr; + ps_conf.shader_size = accel_state->ps_size; +- ps_conf.num_gprs = 3; ++ ps_conf.num_gprs = 2; + ps_conf.stack_size = 1; + ps_conf.uncached_first_inst = 1; + ps_conf.clamp_consts = 0; +@@ -1381,6 +1495,27 @@ static Bool R600PrepareComposite(int op, PicturePtr pSrcPicture, + else + r600_set_spi(pScrn, (1 - 1), 1); + ++ if (!pSrc) { ++ /* solid src color */ ++ R600SetSolidConsts(pScrn, &ps_alu_consts[0], pSrcPicture->format, ++ pSrcPicture->pSourcePict->solidFill.color, 0); ++ } ++ ++ if (!pMaskPicture) { ++ /* use identity constant if there is no mask */ ++ ps_alu_consts[4] = 1.0; ++ ps_alu_consts[5] = 1.0; ++ ps_alu_consts[6] = 1.0; ++ ps_alu_consts[7] = 1.0; ++ } else if (!pMask) { ++ /* solid mask color */ ++ R600SetSolidConsts(pScrn, &ps_alu_consts[4], pMaskPicture->format, ++ pMaskPicture->pSourcePict->solidFill.color, 1); ++ } ++ ++ r600_set_alu_consts(pScrn, SQ_ALU_CONSTANT_ps, ++ sizeof(ps_alu_consts) / SQ_ALU_CONSTANT_offset, ps_alu_consts); ++ + if (accel_state->vsync) + RADEONVlineHelperClear(pScrn); + +@@ -1405,7 +1540,7 @@ static void R600FinishComposite(ScrnInfoPtr pScrn, PixmapPtr pDst, + accel_state->vline_y1, + accel_state->vline_y2); + +- vtx_size = accel_state->msk_pic ? 24 : 16; ++ vtx_size = accel_state->msk_pix ? 24 : 16; + + r600_finish_op(pScrn, vtx_size); + } +@@ -1418,12 +1553,6 @@ static void R600DoneComposite(PixmapPtr pDst) + struct radeon_accel_state *accel_state = info->accel_state; + + R600FinishComposite(pScrn, pDst, accel_state); +- +- if (!accel_state->src_pic->pDrawable) +- pScreen->DestroyPixmap(accel_state->src_pix); +- +- if (accel_state->msk_pic && !accel_state->msk_pic->pDrawable) +- pScreen->DestroyPixmap(accel_state->msk_pix); + } + + static void R600Composite(PixmapPtr pDst, +@@ -1455,7 +1584,7 @@ static void R600Composite(PixmapPtr pDst, + if (accel_state->vsync) + RADEONVlineHelperSet(pScrn, dstX, dstY, dstX + w, dstY + h); + +- if (accel_state->msk_pic) { ++ if (accel_state->msk_pix) { + + vb = radeon_vbo_space(pScrn, &accel_state->vbo, 24); + +diff --git a/src/r600_shader.c b/src/r600_shader.c +index 4cb2fc8..26a6ab6 100644 +--- a/src/r600_shader.c ++++ b/src/r600_shader.c +@@ -2318,9 +2318,10 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + int i = 0; + + /* 0 */ +- shader[i++] = CF_DWORD0(ADDR(3)); ++ /* call fetch-mask if boolean1 == true */ ++ shader[i++] = CF_DWORD0(ADDR(10)); + shader[i++] = CF_DWORD1(POP_COUNT(0), +- CF_CONST(0), ++ CF_CONST(1), + COND(SQ_CF_COND_BOOL), + I_COUNT(0), + CALL_COUNT(0), +@@ -2330,9 +2331,10 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + WHOLE_QUAD_MODE(0), + BARRIER(0)); + /* 1 */ +- shader[i++] = CF_DWORD0(ADDR(7)); ++ /* call read-constant-mask if boolean1 == false */ ++ shader[i++] = CF_DWORD0(ADDR(12)); + shader[i++] = CF_DWORD1(POP_COUNT(0), +- CF_CONST(0), ++ CF_CONST(1), + COND(SQ_CF_COND_NOT_BOOL), + I_COUNT(0), + CALL_COUNT(0), +@@ -2342,33 +2344,36 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + WHOLE_QUAD_MODE(0), + BARRIER(0)); + /* 2 */ +- shader[i++] = CF_DWORD0(ADDR(0)); ++ /* call fetch-src if boolean0 == true */ ++ shader[i++] = CF_DWORD0(ADDR(6)); + shader[i++] = CF_DWORD1(POP_COUNT(0), + CF_CONST(0), +- COND(SQ_CF_COND_ACTIVE), ++ COND(SQ_CF_COND_BOOL), + I_COUNT(0), + CALL_COUNT(0), +- END_OF_PROGRAM(1), ++ END_OF_PROGRAM(0), + VALID_PIXEL_MODE(0), +- CF_INST(SQ_CF_INST_NOP), ++ CF_INST(SQ_CF_INST_CALL), + WHOLE_QUAD_MODE(0), +- BARRIER(1)); ++ BARRIER(0)); + +- /* 3 - mask sub */ +- shader[i++] = CF_DWORD0(ADDR(14)); ++ /* 3 */ ++ /* call read-constant-src if boolean0 == false */ ++ shader[i++] = CF_DWORD0(ADDR(8)); + shader[i++] = CF_DWORD1(POP_COUNT(0), + CF_CONST(0), +- COND(SQ_CF_COND_ACTIVE), +- I_COUNT(2), ++ COND(SQ_CF_COND_NOT_BOOL), ++ I_COUNT(0), + CALL_COUNT(0), + END_OF_PROGRAM(0), + VALID_PIXEL_MODE(0), +- CF_INST(SQ_CF_INST_TEX), ++ CF_INST(SQ_CF_INST_CALL), + WHOLE_QUAD_MODE(0), +- BARRIER(1)); ++ BARRIER(0)); + + /* 4 */ +- shader[i++] = CF_ALU_DWORD0(ADDR(10), ++ /* src IN mask (GPR0 := GPR1 .* GPR0) */ ++ shader[i++] = CF_ALU_DWORD0(ADDR(14), + KCACHE_BANK0(0), + KCACHE_BANK1(0), + KCACHE_MODE0(SQ_CF_KCACHE_NOP)); +@@ -2382,9 +2387,10 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + BARRIER(1)); + + /* 5 */ ++ /* export pixel data */ + shader[i++] = CF_ALLOC_IMP_EXP_DWORD0(ARRAY_BASE(CF_PIXEL_MRT0), + TYPE(SQ_EXPORT_PIXEL), +- RW_GPR(2), ++ RW_GPR(0), + RW_REL(ABSOLUTE), + INDEX_GPR(0), + ELEM_SIZE(1)); +@@ -2394,55 +2400,57 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + SRC_SEL_W(SQ_SEL_W), + R6xx_ELEM_LOOP(0), + BURST_COUNT(1), +- END_OF_PROGRAM(0), ++ END_OF_PROGRAM(1), + VALID_PIXEL_MODE(0), + CF_INST(SQ_CF_INST_EXPORT_DONE), + WHOLE_QUAD_MODE(0), + BARRIER(1)); ++ /* subroutine fetch src */ + /* 6 */ +- shader[i++] = CF_DWORD0(ADDR(0)); ++ /* fetch src into GPR0*/ ++ shader[i++] = CF_DWORD0(ADDR(26)); + shader[i++] = CF_DWORD1(POP_COUNT(0), + CF_CONST(0), + COND(SQ_CF_COND_ACTIVE), +- I_COUNT(0), ++ I_COUNT(1), + CALL_COUNT(0), + END_OF_PROGRAM(0), + VALID_PIXEL_MODE(0), +- CF_INST(SQ_CF_INST_RETURN), ++ CF_INST(SQ_CF_INST_TEX), + WHOLE_QUAD_MODE(0), + BARRIER(1)); + +- /* 7 non-mask sub */ +- shader[i++] = CF_DWORD0(ADDR(18)); ++ /* 7 */ ++ /* return */ ++ shader[i++] = CF_DWORD0(ADDR(0)); + shader[i++] = CF_DWORD1(POP_COUNT(0), + CF_CONST(0), + COND(SQ_CF_COND_ACTIVE), +- I_COUNT(1), ++ I_COUNT(0), + CALL_COUNT(0), + END_OF_PROGRAM(0), + VALID_PIXEL_MODE(0), +- CF_INST(SQ_CF_INST_TEX), ++ CF_INST(SQ_CF_INST_RETURN), + WHOLE_QUAD_MODE(0), + BARRIER(1)); ++ ++ /* subroutine read-constant-src*/ + /* 8 */ +- shader[i++] = CF_ALLOC_IMP_EXP_DWORD0(ARRAY_BASE(CF_PIXEL_MRT0), +- TYPE(SQ_EXPORT_PIXEL), +- RW_GPR(0), +- RW_REL(ABSOLUTE), +- INDEX_GPR(0), +- ELEM_SIZE(1)); +- shader[i++] = CF_ALLOC_IMP_EXP_DWORD1_SWIZ(SRC_SEL_X(SQ_SEL_X), +- SRC_SEL_Y(SQ_SEL_Y), +- SRC_SEL_Z(SQ_SEL_Z), +- SRC_SEL_W(SQ_SEL_W), +- R6xx_ELEM_LOOP(0), +- BURST_COUNT(1), +- END_OF_PROGRAM(0), +- VALID_PIXEL_MODE(0), +- CF_INST(SQ_CF_INST_EXPORT_DONE), +- WHOLE_QUAD_MODE(0), +- BARRIER(1)); ++ /* read constants into GPR0 */ ++ shader[i++] = CF_ALU_DWORD0(ADDR(18), ++ KCACHE_BANK0(0), ++ KCACHE_BANK1(0), ++ KCACHE_MODE0(SQ_CF_KCACHE_NOP)); ++ shader[i++] = CF_ALU_DWORD1(KCACHE_MODE1(SQ_CF_KCACHE_NOP), ++ KCACHE_ADDR0(0), ++ KCACHE_ADDR1(0), ++ I_COUNT(4), ++ USES_WATERFALL(0), ++ CF_INST(SQ_CF_INST_ALU), ++ WHOLE_QUAD_MODE(0), ++ BARRIER(1)); + /* 9 */ ++ /* return */ + shader[i++] = CF_DWORD0(ADDR(0)); + shader[i++] = CF_DWORD1(POP_COUNT(0), + CF_CONST(0), +@@ -2455,8 +2463,67 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + WHOLE_QUAD_MODE(0), + BARRIER(1)); + +- /* 10 - alu 0 */ +- /* MUL gpr[2].x gpr[1].x gpr[0].x */ ++ /* subroutine fetch mask */ ++ /* 10 */ ++ /* fetch mask into GPR1*/ ++ shader[i++] = CF_DWORD0(ADDR(28)); ++ shader[i++] = CF_DWORD1(POP_COUNT(0), ++ CF_CONST(0), ++ COND(SQ_CF_COND_ACTIVE), ++ I_COUNT(1), ++ CALL_COUNT(0), ++ END_OF_PROGRAM(0), ++ VALID_PIXEL_MODE(0), ++ CF_INST(SQ_CF_INST_TEX), ++ WHOLE_QUAD_MODE(0), ++ BARRIER(1)); ++ ++ /* 11 */ ++ /* return */ ++ shader[i++] = CF_DWORD0(ADDR(0)); ++ shader[i++] = CF_DWORD1(POP_COUNT(0), ++ CF_CONST(0), ++ COND(SQ_CF_COND_ACTIVE), ++ I_COUNT(0), ++ CALL_COUNT(0), ++ END_OF_PROGRAM(0), ++ VALID_PIXEL_MODE(0), ++ CF_INST(SQ_CF_INST_RETURN), ++ WHOLE_QUAD_MODE(0), ++ BARRIER(1)); ++ ++ /* subroutine read-constant-mask*/ ++ /* 12 */ ++ /* read constants into GPR1 */ ++ shader[i++] = CF_ALU_DWORD0(ADDR(22), ++ KCACHE_BANK0(0), ++ KCACHE_BANK1(0), ++ KCACHE_MODE0(SQ_CF_KCACHE_NOP)); ++ shader[i++] = CF_ALU_DWORD1(KCACHE_MODE1(SQ_CF_KCACHE_NOP), ++ KCACHE_ADDR0(0), ++ KCACHE_ADDR1(0), ++ I_COUNT(4), ++ USES_WATERFALL(0), ++ CF_INST(SQ_CF_INST_ALU), ++ WHOLE_QUAD_MODE(0), ++ BARRIER(1)); ++ /* 13 */ ++ /* return */ ++ shader[i++] = CF_DWORD0(ADDR(0)); ++ shader[i++] = CF_DWORD1(POP_COUNT(0), ++ CF_CONST(0), ++ COND(SQ_CF_COND_ACTIVE), ++ I_COUNT(0), ++ CALL_COUNT(0), ++ END_OF_PROGRAM(0), ++ VALID_PIXEL_MODE(0), ++ CF_INST(SQ_CF_INST_RETURN), ++ WHOLE_QUAD_MODE(0), ++ BARRIER(1)); ++ /* ALU clauses */ ++ ++ /* 14 - alu 0 */ ++ /* MUL gpr[0].x gpr[1].x gpr[0].x */ + shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_GPR_BASE + 1), + SRC0_REL(ABSOLUTE), + SRC0_ELEM(ELEM_X), +@@ -2478,12 +2545,12 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + OMOD(SQ_ALU_OMOD_OFF), + ALU_INST(SQ_OP2_INST_MUL), + BANK_SWIZZLE(SQ_ALU_VEC_012), +- DST_GPR(2), ++ DST_GPR(0), + DST_REL(ABSOLUTE), + DST_ELEM(ELEM_X), + CLAMP(1)); +- /* 11 - alu 1 */ +- /* MUL gpr[2].y gpr[1].y gpr[0].y */ ++ /* 15 - alu 1 */ ++ /* MUL gpr[0].y gpr[1].y gpr[0].y */ + shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_GPR_BASE + 1), + SRC0_REL(ABSOLUTE), + SRC0_ELEM(ELEM_Y), +@@ -2505,12 +2572,12 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + OMOD(SQ_ALU_OMOD_OFF), + ALU_INST(SQ_OP2_INST_MUL), + BANK_SWIZZLE(SQ_ALU_VEC_012), +- DST_GPR(2), ++ DST_GPR(0), + DST_REL(ABSOLUTE), + DST_ELEM(ELEM_Y), + CLAMP(1)); +- /* 12 - alu 2 */ +- /* MUL gpr[2].z gpr[1].z gpr[0].z */ ++ /* 16 - alu 2 */ ++ /* MUL gpr[0].z gpr[1].z gpr[0].z */ + shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_GPR_BASE + 1), + SRC0_REL(ABSOLUTE), + SRC0_ELEM(ELEM_Z), +@@ -2532,12 +2599,12 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + OMOD(SQ_ALU_OMOD_OFF), + ALU_INST(SQ_OP2_INST_MUL), + BANK_SWIZZLE(SQ_ALU_VEC_012), +- DST_GPR(2), ++ DST_GPR(0), + DST_REL(ABSOLUTE), + DST_ELEM(ELEM_Z), + CLAMP(1)); +- /* 13 - alu 3 */ +- /* MUL gpr[2].w gpr[1].w gpr[0].w */ ++ /* 17 - alu 3 */ ++ /* MUL gpr[0].w gpr[1].w gpr[0].w */ + shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_GPR_BASE + 1), + SRC0_REL(ABSOLUTE), + SRC0_ELEM(ELEM_W), +@@ -2559,12 +2626,222 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + OMOD(SQ_ALU_OMOD_OFF), + ALU_INST(SQ_OP2_INST_MUL), + BANK_SWIZZLE(SQ_ALU_VEC_012), +- DST_GPR(2), ++ DST_GPR(0), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_W), ++ CLAMP(1)); ++ ++ /* 18 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 0), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_X), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_X), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(0)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(0), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_X), ++ CLAMP(1)); ++ /* 19 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 0), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_Y), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_Y), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(0)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(0), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_Y), ++ CLAMP(1)); ++ /* 20 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 0), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_Z), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_Z), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(0)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(0), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_Z), ++ CLAMP(1)); ++ /* 21 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 0), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_W), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_W), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(1)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(0), + DST_REL(ABSOLUTE), + DST_ELEM(ELEM_W), + CLAMP(1)); + +- /* 14/15 - src - mask */ ++ /* 22 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 1), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_X), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_X), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(0)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(1), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_X), ++ CLAMP(1)); ++ /* 23 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 1), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_Y), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_Y), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(0)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(1), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_Y), ++ CLAMP(1)); ++ /* 24 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 1), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_Z), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_Z), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(0)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(1), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_Z), ++ CLAMP(1)); ++ /* 25 */ ++ shader[i++] = ALU_DWORD0(SRC0_SEL(ALU_SRC_CFILE_BASE + 1), ++ SRC0_REL(ABSOLUTE), ++ SRC0_ELEM(ELEM_W), ++ SRC0_NEG(0), ++ SRC1_SEL(ALU_SRC_GPR_BASE + 0), ++ SRC1_REL(ABSOLUTE), ++ SRC1_ELEM(ELEM_W), ++ SRC1_NEG(0), ++ INDEX_MODE(SQ_INDEX_AR_X), ++ PRED_SEL(SQ_PRED_SEL_OFF), ++ LAST(1)); ++ shader[i++] = ALU_DWORD1_OP2(ChipSet, ++ SRC0_ABS(0), ++ SRC1_ABS(0), ++ UPDATE_EXECUTE_MASK(0), ++ UPDATE_PRED(0), ++ WRITE_MASK(1), ++ FOG_MERGE(0), ++ OMOD(SQ_ALU_OMOD_OFF), ++ ALU_INST(SQ_OP2_INST_MOV), ++ BANK_SWIZZLE(SQ_ALU_VEC_012), ++ DST_GPR(1), ++ DST_REL(ABSOLUTE), ++ DST_ELEM(ELEM_W), ++ CLAMP(1)); ++ ++ /* 26/27 - src */ + shader[i++] = TEX_DWORD0(TEX_INST(SQ_TEX_INST_SAMPLE), + BC_FRAC_MODE(0), + FETCH_WHOLE_QUAD(0), +@@ -2592,7 +2869,7 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + SRC_SEL_Z(SQ_SEL_0), + SRC_SEL_W(SQ_SEL_1)); + shader[i++] = TEX_DWORD_PAD; +- /* 16/17 - mask */ ++ /* 28/29 - mask */ + shader[i++] = TEX_DWORD0(TEX_INST(SQ_TEX_INST_SAMPLE), + BC_FRAC_MODE(0), + FETCH_WHOLE_QUAD(0), +@@ -2621,34 +2898,5 @@ int R600_comp_ps(RADEONChipFamily ChipSet, uint32_t* shader) + SRC_SEL_W(SQ_SEL_1)); + shader[i++] = TEX_DWORD_PAD; + +- /* 18/19 - src - non-mask */ +- shader[i++] = TEX_DWORD0(TEX_INST(SQ_TEX_INST_SAMPLE), +- BC_FRAC_MODE(0), +- FETCH_WHOLE_QUAD(0), +- RESOURCE_ID(0), +- SRC_GPR(0), +- SRC_REL(ABSOLUTE), +- R7xx_ALT_CONST(0)); +- shader[i++] = TEX_DWORD1(DST_GPR(0), +- DST_REL(ABSOLUTE), +- DST_SEL_X(SQ_SEL_X), +- DST_SEL_Y(SQ_SEL_Y), +- DST_SEL_Z(SQ_SEL_Z), +- DST_SEL_W(SQ_SEL_W), +- LOD_BIAS(0), +- COORD_TYPE_X(TEX_NORMALIZED), +- COORD_TYPE_Y(TEX_NORMALIZED), +- COORD_TYPE_Z(TEX_NORMALIZED), +- COORD_TYPE_W(TEX_NORMALIZED)); +- shader[i++] = TEX_DWORD2(OFFSET_X(0), +- OFFSET_Y(0), +- OFFSET_Z(0), +- SAMPLER_ID(0), +- SRC_SEL_X(SQ_SEL_X), +- SRC_SEL_Y(SQ_SEL_Y), +- SRC_SEL_Z(SQ_SEL_0), +- SRC_SEL_W(SQ_SEL_1)); +- shader[i++] = TEX_DWORD_PAD; +- + return i; + } diff --git a/U_06-EXA-6xx-7xx-accelerate-PictOpOver-with-component-alpha.patch b/U_06-EXA-6xx-7xx-accelerate-PictOpOver-with-component-alpha.patch new file mode 100644 index 0000000..66a41b9 --- /dev/null +++ b/U_06-EXA-6xx-7xx-accelerate-PictOpOver-with-component-alpha.patch @@ -0,0 +1,130 @@ +From: Tan Hu +Date: Fri May 27 17:05:15 2016 +0800 +Subject: [PATCH 6/20]EXA/6xx/7xx: accelerate PictOpOver with component alpha +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 0945db4d902056bda3d9ad4a4de2dfa685d10a70 +References: bsc#990066 +Signed-off-by: Max Staudt + +Subpixel text rendering is typically done with a solid src and +a pixmap mask. Traditionally, this cannot be accelerated in a single +pass and requires two passes [1]. However, we can cheat a little +with a constant blend color. + +We can use: +const.A = src.A / src.A +const.R = src.R / src.A +const.G = src.G / src.A +const.B = src.B / src.A + +dst.A = const.A * (src.A * mask.A) + (1 - (src.A * mask.A)) * dst.A +dst.R = const.R * (src.A * mask.R) + (1 - (src.A * mask.R)) * dst.R +dst.G = const.G * (src.A * mask.G) + (1 - (src.A * mask.G)) * dst.G +dst.B = const.B * (src.A * mask.B) + (1 - (src.A * mask.B)) * dst.B + +This only needs a single source value. src.A is cancelled down in +the right places. + +[1] http://anholt.livejournal.com/32058.html + +r6xx still be used on some machine, +Ported from commit 4375a6e75e5d41139be7031a0dee58c057ecbd07. + +Signed-off-by: Tan Hu +Reviewed-by: Grigori Goronzy +--- + src/r600_exa.c | 22 ++++++++++++++++++++-- + src/r600_state.h | 2 ++ + src/r6xx_accel.c | 14 ++++++++++++++ + 3 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/src/r600_exa.c b/src/r600_exa.c +index 10df4ec..e9ac721 100644 +--- a/src/r600_exa.c ++++ b/src/r600_exa.c +@@ -766,6 +766,14 @@ static uint32_t R600GetBlendCntl(int op, PicturePtr pMask, uint32_t dst_format) + } else if (dblend == (BLEND_ONE_MINUS_SRC_ALPHA << COLOR_DESTBLEND_shift)) { + dblend = (BLEND_ONE_MINUS_SRC_COLOR << COLOR_DESTBLEND_shift); + } ++ ++ /* With some tricks, we can still accelerate PictOpOver with solid src. ++ * This is commonly used for text rendering, so it's worth the extra ++ * effort. ++ */ ++ if (sblend == (BLEND_ONE << COLOR_SRCBLEND_shift)) { ++ sblend = (BLEND_CONSTANT_COLOR << COLOR_SRCBLEND_shift); ++ } + } + + return sblend | dblend; +@@ -1143,12 +1151,17 @@ static Bool R600CheckComposite(int op, PicturePtr pSrcPicture, PicturePtr pMaskP + /* Check if it's component alpha that relies on a source alpha and + * on the source value. We can only get one of those into the + * single source value that we get to blend with. ++ * ++ * We can cheat a bit if the src is solid, though. PictOpOver ++ * can use the constant blend color to sneak a second blend ++ * source in. + */ + if (R600BlendOp[op].src_alpha && + (R600BlendOp[op].blend_cntl & COLOR_SRCBLEND_mask) != + (BLEND_ZERO << COLOR_SRCBLEND_shift)) { +- RADEON_FALLBACK(("Component alpha not supported with source " +- "alpha and source value blending.\n")); ++ if (pSrcPicture->pDrawable || op != PictOpOver) ++ RADEON_FALLBACK(("Component alpha not supported with source " ++ "alpha and source value blending.\n")); + } + } + +@@ -1244,6 +1257,11 @@ static void R600SetSolidConsts(ScrnInfoPtr pScrn, float *buf, int format, uint32 + } else { + if (accel_state->component_alpha) { + if (accel_state->src_alpha) { ++ /* required for PictOpOver */ ++ float cblend[4] = { pix_r / pix_a, pix_g / pix_a, ++ pix_b / pix_a, pix_a / pix_a }; ++ r600_set_blend_color(pScrn, cblend); ++ + if (PICT_FORMAT_A(format) == 0) { + pix_r = 1.0; + pix_g = 1.0; +diff --git a/src/r600_state.h b/src/r600_state.h +index fa777e8..fda297d 100644 +--- a/src/r600_state.h ++++ b/src/r600_state.h +@@ -266,6 +266,8 @@ r600_wait_3d_idle(ScrnInfoPtr pScrn); + void + r600_start_3d(ScrnInfoPtr pScrn); + void ++r600_set_blend_color(ScrnInfoPtr pScrn, float *color); ++void + r600_set_render_target(ScrnInfoPtr pScrn, cb_config_t *cb_conf, uint32_t domain); + void + r600_cp_wait_vline_sync(ScrnInfoPtr pScrn, PixmapPtr pPix, xf86CrtcPtr crtc, int start, int stop); +diff --git a/src/r6xx_accel.c b/src/r6xx_accel.c +index a97c84b..1f5c052 100644 +--- a/src/r6xx_accel.c ++++ b/src/r6xx_accel.c +@@ -174,6 +174,20 @@ r600_sq_setup(ScrnInfoPtr pScrn, sq_config_t *sq_conf) + END_BATCH(); + } + ++void r600_set_blend_color(ScrnInfoPtr pScrn, float *color) ++{ ++ RADEONInfoPtr info = RADEONPTR(pScrn); ++ ++ BEGIN_BATCH(2 + 4); ++ PACK0(CB_BLEND_RED, 4); ++ EFLOAT(color[0]); /* R */ ++ EFLOAT(color[1]); /* G */ ++ EFLOAT(color[2]); /* B */ ++ EFLOAT(color[3]); /* A */ ++ END_BATCH(); ++} ++ ++ + void + r600_set_render_target(ScrnInfoPtr pScrn, cb_config_t *cb_conf, uint32_t domain) + { diff --git a/U_07-Adapt-to-XF86_CRTC_VERSION-7.patch b/U_07-Adapt-to-XF86_CRTC_VERSION-7.patch new file mode 100644 index 0000000..c5159d2 --- /dev/null +++ b/U_07-Adapt-to-XF86_CRTC_VERSION-7.patch @@ -0,0 +1,80 @@ +From: Michel Dänzer +Date: Mon Mar 28 18:49:15 2016 +0900 +Subject: [PATCH 7/20]Adapt to XF86_CRTC_VERSION 7 +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 7835558acdce318130ba4a09ef936fd675e3197d +References: bsc#990066 +Signed-off-by: Max Staudt + +Now the HW cursor can be used with TearFree rotation. + +This also allows always using the separate scanout pixmap mechanism for +rotation, so that should be much smoother even without TearFree enabled. + +Reviewed-by: Alex Deucher +--- + src/drmmode_display.c | 18 +++++++++++++----- + 1 file changed, 13 insertions(+), 5 deletions(-) + +diff --git a/src/drmmode_display.c b/src/drmmode_display.c +index 34b76e9..e32791d 100644 +--- a/src/drmmode_display.c ++++ b/src/drmmode_display.c +@@ -643,7 +643,7 @@ drmmode_can_use_hw_cursor(xf86CrtcPtr crtc) + if (crtc->transformPresent) + return FALSE; + +-#if XF86_CRTC_VERSION >= 4 ++#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 + /* Xorg doesn't correctly handle cursor position transform in the + * rotation case + */ +@@ -666,11 +666,19 @@ drmmode_can_use_hw_cursor(xf86CrtcPtr crtc) + static Bool + drmmode_handle_transform(xf86CrtcPtr crtc) + { +- RADEONInfoPtr info = RADEONPTR(crtc->scrn); + Bool ret; + ++#if XF86_CRTC_VERSION >= 7 ++ if (!crtc->transformPresent && crtc->rotation != RR_Rotate_0) ++ crtc->driverIsPerformingTransform = XF86DriverTransformOutput; ++ else ++ crtc->driverIsPerformingTransform = XF86DriverTransformNone; ++#else ++ RADEONInfoPtr info = RADEONPTR(crtc->scrn); ++ + crtc->driverIsPerformingTransform = info->tear_free && + !crtc->transformPresent && crtc->rotation != RR_Rotate_0; ++#endif + + ret = xf86CrtcRotate(crtc); + +@@ -921,7 +929,7 @@ drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + +-#if XF86_CRTC_VERSION >= 4 ++#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 + if (crtc->driverIsPerformingTransform) { + x += crtc->x; + y += crtc->y; +@@ -932,7 +940,7 @@ drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) + drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); + } + +-#if XF86_CRTC_VERSION >= 4 ++#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 + + static int + drmmode_cursor_src_offset(Rotation rotation, int width, int height, +@@ -978,7 +986,7 @@ drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) + /* cursor should be mapped already */ + ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr); + +-#if XF86_CRTC_VERSION >= 4 ++#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 + if (crtc->driverIsPerformingTransform) { + uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; + int dstx, dsty; diff --git a/U_08-Add-explicit-RADEON_DRM_QUEUE_ERROR-define.patch b/U_08-Add-explicit-RADEON_DRM_QUEUE_ERROR-define.patch new file mode 100644 index 0000000..29cad01 --- /dev/null +++ b/U_08-Add-explicit-RADEON_DRM_QUEUE_ERROR-define.patch @@ -0,0 +1,124 @@ +From: Michel Dänzer +Date: Wed Jul 6 12:46:01 2016 +0900 +Subject: [PATCH 8/20]Add explicit RADEON_DRM_QUEUE_ERROR define +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: a37af701768b12d86868a831a79f1e02ee4968cf +References: bsc#990066 +Signed-off-by: Max Staudt + +Should make the radeon_drm_queue_alloc error handling clearer, and gets +rid of a compile warning about it returning NULL. + +Reviewed-by: Alexandre Demers +--- + src/drmmode_display.c | 2 +- + src/radeon_dri2.c | 4 ++-- + src/radeon_drm_queue.c | 7 ++++--- + src/radeon_drm_queue.h | 2 ++ + src/radeon_kms.c | 4 ++-- + src/radeon_present.c | 2 +- + 6 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/src/drmmode_display.c b/src/drmmode_display.c +index e32791d..b9c8097 100644 +--- a/src/drmmode_display.c ++++ b/src/drmmode_display.c +@@ -2829,7 +2829,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, + flipdata, + drmmode_flip_handler, + drmmode_flip_abort); +- if (!drm_queue_seq) { ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Allocating DRM queue event entry failed.\n"); + goto error; +diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c +index 5ebc9b7..69fd0ea 100644 +--- a/src/radeon_dri2.c ++++ b/src/radeon_dri2.c +@@ -1143,7 +1143,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, + drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, + wait_info, radeon_dri2_frame_event_handler, + radeon_dri2_frame_event_abort); +- if (!drm_queue_seq) { ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Allocating DRM queue event entry failed.\n"); + goto out_complete; +@@ -1290,7 +1290,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, + drm_queue_seq = radeon_drm_queue_alloc(crtc, client, RADEON_DRM_QUEUE_ID_DEFAULT, + swap_info, radeon_dri2_frame_event_handler, + radeon_dri2_frame_event_abort); +- if (!drm_queue_seq) { ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Allocating DRM queue entry failed.\n"); + goto blit_fallback; +diff --git a/src/radeon_drm_queue.c b/src/radeon_drm_queue.c +index 0d999dd..31f2435 100644 +--- a/src/radeon_drm_queue.c ++++ b/src/radeon_drm_queue.c +@@ -92,10 +92,11 @@ radeon_drm_queue_alloc(xf86CrtcPtr crtc, ClientPtr client, + + e = calloc(1, sizeof(struct radeon_drm_queue_entry)); + if (!e) +- return NULL; ++ return RADEON_DRM_QUEUE_ERROR; ++ ++ if (_X_UNLIKELY(radeon_drm_queue_seq == RADEON_DRM_QUEUE_ERROR)) ++ radeon_drm_queue_seq++; + +- if (!radeon_drm_queue_seq) +- radeon_drm_queue_seq = 1; + e->seq = radeon_drm_queue_seq++; + e->client = client; + e->crtc = crtc; +diff --git a/src/radeon_drm_queue.h b/src/radeon_drm_queue.h +index 0d9d278..c3e2076 100644 +--- a/src/radeon_drm_queue.h ++++ b/src/radeon_drm_queue.h +@@ -29,6 +29,8 @@ + #ifndef _RADEON_DRM_QUEUE_H_ + #define _RADEON_DRM_QUEUE_H_ + ++#define RADEON_DRM_QUEUE_ERROR 0 ++ + #define RADEON_DRM_QUEUE_CLIENT_DEFAULT serverClient + #define RADEON_DRM_QUEUE_ID_DEFAULT ~0ULL + +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 0ced370..3ba9945 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -529,7 +529,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc) + drmmode_crtc, + radeon_scanout_update_handler, + radeon_scanout_update_abort); +- if (!drm_queue_seq) { ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "radeon_drm_queue_alloc failed for scanout update\n"); + return; +@@ -581,7 +581,7 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info, + RADEON_DRM_QUEUE_ID_DEFAULT, + drmmode_crtc, NULL, + radeon_scanout_flip_abort); +- if (!drm_queue_seq) { ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Allocating DRM event queue entry failed.\n"); + return; +diff --git a/src/radeon_present.c b/src/radeon_present.c +index 69a0532..93c18a8 100644 +--- a/src/radeon_present.c ++++ b/src/radeon_present.c +@@ -169,7 +169,7 @@ radeon_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) + event_id, event, + radeon_present_vblank_handler, + radeon_present_vblank_abort); +- if (!drm_queue_seq) { ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { + free(event); + return BadAlloc; + } diff --git a/U_09-Don-t-enable-DRI3-by-default-with-EXA.patch b/U_09-Don-t-enable-DRI3-by-default-with-EXA.patch new file mode 100644 index 0000000..b30cf94 --- /dev/null +++ b/U_09-Don-t-enable-DRI3-by-default-with-EXA.patch @@ -0,0 +1,48 @@ +From: Michel Dänzer +Date: Tue Jul 12 17:36:27 2016 +0900 +Subject: [PATCH 9/20]Don't enable DRI3 by default with EXA +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 94fe42f29e0b00a26e810581d6c438ac6d8ecd8a +References: bsc#990066 +Signed-off-by: Max Staudt + +It doesn't work correctly in all cases, see e.g. +https://bugs.freedesktop.org/show_bug.cgi?id=95475 . I'm not sure this +is fixable, given EXA's architecture. + +Reviewed-by: Alex Deucher +--- + man/radeon.man | 5 +++-- + src/radeon_kms.c | 2 +- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/man/radeon.man b/man/radeon.man +index cacafb5..44603a5 100644 +--- a/man/radeon.man ++++ b/man/radeon.man +@@ -271,8 +271,9 @@ Sea Islands. + Define the maximum level of DRI to enable. Valid values are 2 for DRI2 or 3 for DRI3. + The default is + .B 3 for DRI3 +-if the driver was compiled for Xorg >= 1.18.3, otherwise +-.B 2 for DRI2. ++if the driver was compiled for Xorg >= 1.18.3 and glamor is enabled, otherwise ++.B 2 for DRI2. Note: ++DRI3 may not work correctly in all cases with EXA, enable at your own risk. + .TP + .BI "Option \*qEnablePageFlip\*q \*q" boolean \*q + Enable DRI2 page flipping. The default is +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 3ba9945..a618513 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -1726,7 +1726,7 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL) + #endif + + #if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,18,3,0,0) +- value = TRUE; ++ value = info->use_glamor; + #else + value = FALSE; + #endif diff --git a/U_10-Use-EventCallback-to-avoid-flushing-every-time-in-the-FlushCallback.patch b/U_10-Use-EventCallback-to-avoid-flushing-every-time-in-the-FlushCallback.patch new file mode 100644 index 0000000..fcdd442 --- /dev/null +++ b/U_10-Use-EventCallback-to-avoid-flushing-every-time-in-the-FlushCallback.patch @@ -0,0 +1,170 @@ +From: Michel Dänzer +Date: Mon Jul 11 12:22:09 2016 +0900 +Subject: [PATCH 10/20]Use EventCallback to avoid flushing every time in the FlushCallback +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 9a1afbf61fbb2827c86bd86d295fa0848980d60b +References: bsc#990066 +Signed-off-by: Max Staudt + +We only need to flush for XDamageNotify events. + +Significantly reduces compositing slowdown due to flushing overhead, in +particular with glamor. + +Reviewed-by: Alex Deucher +--- + src/radeon.h | 2 ++ + src/radeon_kms.c | 79 +++++++++++++++++++++++++++++++++++++++++++++----------- + 2 files changed, 66 insertions(+), 15 deletions(-) + +diff --git a/src/radeon.h b/src/radeon.h +index 37d5fb6..25ff61c 100644 +--- a/src/radeon.h ++++ b/src/radeon.h +@@ -473,6 +473,8 @@ typedef struct { + Bool RenderAccel; /* Render */ + Bool allowColorTiling; + Bool allowColorTiling2D; ++ int callback_event_type; ++ uint_fast32_t callback_needs_flush; + uint_fast32_t gpu_flushed; + uint_fast32_t gpu_synced; + struct radeon_accel_state *accel_state; +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index a618513..f778d30 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -51,6 +51,8 @@ + #include + #endif + ++#include ++ + #include "radeon_chipinfo_gen.h" + + #include "radeon_bo_gem.h" +@@ -91,10 +93,11 @@ void radeon_cs_flush_indirect(ScrnInfoPtr pScrn) + struct radeon_accel_state *accel_state; + int ret; + ++ info->gpu_flushed++; ++ + #ifdef USE_GLAMOR + if (info->use_glamor) { + glamor_block_handler(pScrn->pScreen); +- info->gpu_flushed++; + return; + } + #endif +@@ -237,8 +240,51 @@ radeonUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf) + shadowUpdatePacked(pScreen, pBuf); + } + ++static Bool ++callback_needs_flush(RADEONInfoPtr info) ++{ ++ return (int)(info->callback_needs_flush - info->gpu_flushed) > 0; ++} ++ ++static void ++radeon_event_callback(CallbackListPtr *list, ++ pointer user_data, pointer call_data) ++{ ++ EventInfoRec *eventinfo = call_data; ++ ScrnInfoPtr pScrn = user_data; ++ RADEONInfoPtr info = RADEONPTR(pScrn); ++ int i; ++ ++ if (callback_needs_flush(info)) ++ return; ++ ++ /* Don't let gpu_flushed get too far ahead of callback_needs_flush, ++ * in order to prevent false positives in callback_needs_flush() ++ */ ++ info->callback_needs_flush = info->gpu_flushed; ++ ++ for (i = 0; i < eventinfo->count; i++) { ++ if (eventinfo->events[i].u.u.type == info->callback_event_type) { ++ info->callback_needs_flush++; ++ return; ++ } ++ } ++} ++ ++static void ++radeon_flush_callback(CallbackListPtr *list, ++ pointer user_data, pointer call_data) ++{ ++ ScrnInfoPtr pScrn = user_data; ++ RADEONInfoPtr info = RADEONPTR(pScrn); ++ ++ if (pScrn->vtSema && callback_needs_flush(info)) ++ radeon_cs_flush_indirect(pScrn); ++} ++ + static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) + { ++ ExtensionEntry *damage_ext = CheckExtension("DAMAGE"); + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + RADEONInfoPtr info = RADEONPTR(pScrn); + PixmapPtr pixmap; +@@ -294,6 +340,19 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) + if (info->use_glamor) + radeon_glamor_create_screen_resources(pScreen); + ++ info->callback_event_type = -1; ++ if (damage_ext) { ++ info->callback_event_type = damage_ext->eventBase + XDamageNotify; ++ ++ if (!AddCallback(&FlushCallback, radeon_flush_callback, pScrn)) ++ return FALSE; ++ ++ if (!AddCallback(&EventCallback, radeon_event_callback, pScrn)) { ++ DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn); ++ return FALSE; ++ } ++ } ++ + return TRUE; + } + +@@ -641,16 +700,6 @@ static void RADEONBlockHandler_oneshot(BLOCKHANDLER_ARGS_DECL) + drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE); + } + +-static void +-radeon_flush_callback(CallbackListPtr *list, +- pointer user_data, pointer call_data) +-{ +- ScrnInfoPtr pScrn = user_data; +- +- if (pScrn->vtSema) +- radeon_cs_flush_indirect(pScrn); +-} +- + static Bool RADEONIsFastFBWorking(ScrnInfoPtr pScrn) + { + RADEONInfoPtr info = RADEONPTR(pScrn); +@@ -1564,7 +1613,10 @@ static Bool RADEONCloseScreen_KMS(CLOSE_SCREEN_ARGS_DECL) + radeon_drm_queue_close(pScrn); + radeon_cs_flush_indirect(pScrn); + +- DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn); ++ if (info->callback_event_type != -1) { ++ DeleteCallback(&EventCallback, radeon_event_callback, pScrn); ++ DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn); ++ } + + if (info->accel_state->exa) { + exaDriverFini(pScreen); +@@ -1838,9 +1890,6 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL) + info->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = RADEONBlockHandler_oneshot; + +- if (!AddCallback(&FlushCallback, radeon_flush_callback, pScrn)) +- return FALSE; +- + info->CreateScreenResources = pScreen->CreateScreenResources; + pScreen->CreateScreenResources = RADEONCreateScreenResources_KMS; + diff --git a/U_11-Keep-track-of-damage-event-related-flushes-per-client-v2.patch b/U_11-Keep-track-of-damage-event-related-flushes-per-client-v2.patch new file mode 100644 index 0000000..1175d74 --- /dev/null +++ b/U_11-Keep-track-of-damage-event-related-flushes-per-client-v2.patch @@ -0,0 +1,142 @@ +From: Michel Dänzer +Date: Mon Jul 11 12:51:46 2016 +0900 +Subject: [PATCH 11/20]Keep track of damage event related flushes per-client v2 +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 121a6de72da5fcf9a32408eff36b2235f3dfbcfe +References: bsc#990066 +Signed-off-by: Max Staudt + +This further reduces the compositing slowdown due to flushing overhead, +by only flushing when the X server actually sends XDamageNotify events +to a client, and there hasn't been a flush yet in the meantime. + +v2: Use ScreenPrivateKey, fixes invalid memory access with GPU screens +Reviewed-by: Alex Deucher +--- + src/radeon.h | 5 ++++- + src/radeon_kms.c | 41 +++++++++++++++++++++++++++++++++-------- + 2 files changed, 37 insertions(+), 9 deletions(-) + +diff --git a/src/radeon.h b/src/radeon.h +index 25ff61c..f3a3e1c 100644 +--- a/src/radeon.h ++++ b/src/radeon.h +@@ -448,6 +448,10 @@ struct radeon_accel_state { + Bool force; + }; + ++struct radeon_client_priv { ++ uint_fast32_t needs_flush; ++}; ++ + typedef struct { + EntityInfoPtr pEnt; + pciVideoPtr PciInfo; +@@ -474,7 +478,6 @@ typedef struct { + Bool allowColorTiling; + Bool allowColorTiling2D; + int callback_event_type; +- uint_fast32_t callback_needs_flush; + uint_fast32_t gpu_flushed; + uint_fast32_t gpu_synced; + struct radeon_accel_state *accel_state; +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index f778d30..136c46c 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -40,6 +40,7 @@ + + #include "radeon_version.h" + #include "shadow.h" ++#include + + #include "atipciids.h" + +@@ -59,6 +60,8 @@ + #include "radeon_cs_gem.h" + #include "radeon_vbo.h" + ++static DevScreenPrivateKeyRec radeon_client_private_key; ++ + extern SymTabRec RADEONChipsets[]; + static Bool radeon_setup_kernel_mem(ScreenPtr pScreen); + +@@ -241,9 +244,9 @@ radeonUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf) + } + + static Bool +-callback_needs_flush(RADEONInfoPtr info) ++callback_needs_flush(RADEONInfoPtr info, struct radeon_client_priv *client_priv) + { +- return (int)(info->callback_needs_flush - info->gpu_flushed) > 0; ++ return (int)(client_priv->needs_flush - info->gpu_flushed) > 0; + } + + static void +@@ -252,20 +255,30 @@ radeon_event_callback(CallbackListPtr *list, + { + EventInfoRec *eventinfo = call_data; + ScrnInfoPtr pScrn = user_data; ++ ScreenPtr pScreen = pScrn->pScreen; ++ struct radeon_client_priv *client_priv = ++ dixLookupScreenPrivate(&eventinfo->client->devPrivates, ++ &radeon_client_private_key, pScreen); ++ struct radeon_client_priv *server_priv = ++ dixLookupScreenPrivate(&serverClient->devPrivates, ++ &radeon_client_private_key, pScreen); + RADEONInfoPtr info = RADEONPTR(pScrn); + int i; + +- if (callback_needs_flush(info)) ++ if (callback_needs_flush(info, client_priv) || ++ callback_needs_flush(info, server_priv)) + return; + +- /* Don't let gpu_flushed get too far ahead of callback_needs_flush, +- * in order to prevent false positives in callback_needs_flush() ++ /* Don't let gpu_flushed get too far ahead of needs_flush, in order ++ * to prevent false positives in callback_needs_flush() + */ +- info->callback_needs_flush = info->gpu_flushed; ++ client_priv->needs_flush = info->gpu_flushed; ++ server_priv->needs_flush = info->gpu_flushed; + + for (i = 0; i < eventinfo->count; i++) { + if (eventinfo->events[i].u.u.type == info->callback_event_type) { +- info->callback_needs_flush++; ++ client_priv->needs_flush++; ++ server_priv->needs_flush++; + return; + } + } +@@ -276,9 +289,14 @@ radeon_flush_callback(CallbackListPtr *list, + pointer user_data, pointer call_data) + { + ScrnInfoPtr pScrn = user_data; ++ ScreenPtr pScreen = pScrn->pScreen; ++ ClientPtr client = call_data ? call_data : serverClient; ++ struct radeon_client_priv *client_priv = ++ dixLookupScreenPrivate(&client->devPrivates, ++ &radeon_client_private_key, pScreen); + RADEONInfoPtr info = RADEONPTR(pScrn); + +- if (pScrn->vtSema && callback_needs_flush(info)) ++ if (pScrn->vtSema && callback_needs_flush(info, client_priv)) + radeon_cs_flush_indirect(pScrn); + } + +@@ -351,6 +369,13 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) + DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn); + return FALSE; + } ++ ++ if (!dixRegisterScreenPrivateKey(&radeon_client_private_key, pScreen, ++ PRIVATE_CLIENT, sizeof(struct radeon_client_priv))) { ++ DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn); ++ DeleteCallback(&EventCallback, radeon_event_callback, pScrn); ++ return FALSE; ++ } + } + + return TRUE; diff --git a/U_12-Use-drmmode_crtc_scanout_-helpers-for-RandR-1.4-scanout-pixmaps.patch b/U_12-Use-drmmode_crtc_scanout_-helpers-for-RandR-1.4-scanout-pixmaps.patch new file mode 100644 index 0000000..b027f8e --- /dev/null +++ b/U_12-Use-drmmode_crtc_scanout_-helpers-for-RandR-1.4-scanout-pixmaps.patch @@ -0,0 +1,170 @@ +From: Michel Dänzer +Date: Fri Nov 27 16:53:30 2015 +0900 +Subject: [PATCH 12/20]Use drmmode_crtc_scanout_* helpers for RandR 1.4 scanout pixmaps +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 4cfa4615f79f64062e5e771cd45dd7048f48b4f6 +References: bsc#990066 +Signed-off-by: Max Staudt + +This should allow using multiple CRTCs via RandR 1.4 even with xserver +< 1.17. It also simplifies the code a little, and paves the way for +following changes. + +Reviewed-by: Alex Deucher +--- + src/drmmode_display.c | 71 ++++++++++++++------------------------------------- + src/drmmode_display.h | 1 - + src/radeon_kms.c | 16 +++++++----- + 3 files changed, 28 insertions(+), 60 deletions(-) + +diff --git a/src/drmmode_display.c b/src/drmmode_display.c +index b9c8097..383c8a0 100644 +--- a/src/drmmode_display.c ++++ b/src/drmmode_display.c +@@ -785,11 +785,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + fb_id = drmmode->fb_id; + #ifdef RADEON_PIXMAP_SHARING + if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) { +- x = drmmode_crtc->prime_pixmap_x; +- y = 0; +- +- drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]); +- drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]); ++ fb_id = drmmode_crtc->scanout[0].fb_id; ++ x = y = 0; + } else + #endif + if (drmmode_crtc->rotate.fb_id) { +@@ -798,11 +795,12 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]); + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]); +- } else if (info->tear_free || ++ } else if (!pScreen->isGPU && ++ (info->tear_free || + #if XF86_CRTC_VERSION >= 4 +- crtc->driverIsPerformingTransform || ++ crtc->driverIsPerformingTransform || + #endif +- info->shadow_primary) { ++ info->shadow_primary)) { + for (i = 0; i < (info->tear_free ? 2 : 1); i++) { + drmmode_crtc_scanout_create(crtc, + &drmmode_crtc->scanout[i], +@@ -1114,61 +1112,30 @@ drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, + static Bool + drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) + { +- ScreenPtr screen = xf86ScrnToScreen(crtc->scrn); +- PixmapPtr screenpix = screen->GetScreenPixmap(screen); +- xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; +- int c, total_width = 0, max_height = 0, this_x = 0; + + if (!ppix) { + if (crtc->randr_crtc->scanout_pixmap) +- PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix); +- drmmode_crtc->prime_pixmap_x = 0; ++ PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, ++ drmmode_crtc->scanout[0].pixmap); ++ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, ++ &drmmode_crtc->scanout[0]); + return TRUE; + } + +- /* iterate over all the attached crtcs - +- work out bounding box */ +- for (c = 0; c < xf86_config->num_crtc; c++) { +- xf86CrtcPtr iter = xf86_config->crtc[c]; +- if (!iter->enabled && iter != crtc) +- continue; +- if (iter == crtc) { +- this_x = total_width; +- total_width += ppix->drawable.width; +- if (max_height < ppix->drawable.height) +- max_height = ppix->drawable.height; +- } else { +- total_width += iter->mode.HDisplay; +- if (max_height < iter->mode.VDisplay) +- max_height = iter->mode.VDisplay; +- } +-#if !defined(HAS_DIRTYTRACKING_ROTATION) && !defined(HAS_DIRTYTRACKING2) +- if (iter != crtc) { +- ErrorF("Cannot do multiple crtcs without X server dirty tracking 2 interface\n"); +- return FALSE; +- } +-#endif +- } +- +- if (total_width != screenpix->drawable.width || +- max_height != screenpix->drawable.height) { +- Bool ret; +- ret = drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height); +- if (ret == FALSE) +- return FALSE; ++ if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], ++ ppix->drawable.width, ++ ppix->drawable.height)) ++ return FALSE; + +- screenpix = screen->GetScreenPixmap(screen); +- screen->width = screenpix->drawable.width = total_width; +- screen->height = screenpix->drawable.height = max_height; +- } +- drmmode_crtc->prime_pixmap_x = this_x; + #ifdef HAS_DIRTYTRACKING_ROTATION +- PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0); ++ PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap, ++ 0, 0, 0, 0, RR_Rotate_0); + #elif defined(HAS_DIRTYTRACKING2) +- PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0); ++ PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[0].pixmap, ++ 0, 0, 0, 0); + #else +- PixmapStartDirtyTracking(ppix, screenpix, 0, 0); ++ PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap, 0, 0); + #endif + return TRUE; + } +diff --git a/src/drmmode_display.h b/src/drmmode_display.h +index 63b96ac..53c7926 100644 +--- a/src/drmmode_display.h ++++ b/src/drmmode_display.h +@@ -95,7 +95,6 @@ typedef struct { + int dpms_last_fps; + uint32_t interpolated_vblanks; + uint16_t lut_r[256], lut_g[256], lut_b[256]; +- int prime_pixmap_x; + + /* Modeset needed (for DPMS on or after a page flip crossing with a + * modeset) +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 136c46c..53994c9 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -696,15 +696,17 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) + (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); + pScreen->BlockHandler = RADEONBlockHandler_KMS; + +- for (c = 0; c < xf86_config->num_crtc; c++) { +- if (info->tear_free) +- radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]); +- else if (info->shadow_primary ++ if (!pScreen->isGPU) { ++ for (c = 0; c < xf86_config->num_crtc; c++) { ++ if (info->tear_free) ++ radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]); ++ else if (info->shadow_primary + #if XF86_CRTC_VERSION >= 4 +- || xf86_config->crtc[c]->driverIsPerformingTransform ++ || xf86_config->crtc[c]->driverIsPerformingTransform + #endif +- ) +- radeon_scanout_update(xf86_config->crtc[c]); ++ ) ++ radeon_scanout_update(xf86_config->crtc[c]); ++ } + } + + radeon_cs_flush_indirect(pScrn); diff --git a/U_13-Handle-RandR-1.4-slave-dirty-updates-via-radeon_drm_queue.patch b/U_13-Handle-RandR-1.4-slave-dirty-updates-via-radeon_drm_queue.patch new file mode 100644 index 0000000..30f1909 --- /dev/null +++ b/U_13-Handle-RandR-1.4-slave-dirty-updates-via-radeon_drm_queue.patch @@ -0,0 +1,136 @@ +From: Michel Dänzer +Date: Fri Nov 27 16:31:21 2015 +0900 +Subject: [PATCH 13/20]Handle RandR 1.4 slave dirty updates via radeon_drm_queue +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: ad0a0656dd0e74683e6d7789decba827aa29c221 +References: bsc#990066 +Signed-off-by: Max Staudt + +This reduces PCIe bandwidth usage and tearing. + +Reviewed-by: Alex Deucher +--- + src/radeon_kms.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 90 insertions(+), 4 deletions(-) + +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 53994c9..07ba362 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -383,9 +383,9 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) + + #ifdef RADEON_PIXMAP_SHARING + static void +-redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty) ++redisplay_dirty(PixmapDirtyUpdatePtr dirty) + { +- ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); ++ ScrnInfoPtr pScrn = xf86ScreenToScrn(dirty->src->drawable.pScreen); + RegionRec pixregion; + + PixmapRegionInit(&pixregion, dirty->slave_dst); +@@ -399,6 +399,90 @@ redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty) + radeon_cs_flush_indirect(pScrn); + DamageRegionProcessPending(&dirty->slave_dst->drawable); + RegionUninit(&pixregion); ++ ++ DamageEmpty(dirty->damage); ++} ++ ++static void ++radeon_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 ++radeon_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 ++radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty) ++{ ++ ScreenPtr screen = dirty->slave_dst->drawable.pScreen; ++ ScrnInfoPtr scrn = xf86ScreenToScrn(screen); ++ 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 = radeon_drm_queue_alloc(xf86_crtc, ++ RADEON_DRM_QUEUE_CLIENT_DEFAULT, ++ RADEON_DRM_QUEUE_ID_DEFAULT, NULL, ++ radeon_prime_scanout_update_handler, ++ radeon_prime_scanout_update_abort); ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { ++ xf86DrvMsg(scrn->scrnIndex, X_WARNING, ++ "radeon_drm_queue_alloc failed for PRIME update\n"); ++ return; ++ } ++ ++ vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT; ++ vbl.request.type |= radeon_populate_vbl_request_type(xf86_crtc); ++ vbl.request.sequence = 1; ++ vbl.request.signal = drm_queue_seq; ++ if (drmWaitVBlank(RADEONPTR(scrn)->dri2.drm_fd, &vbl)) { ++ xf86DrvMsg(scrn->scrnIndex, X_WARNING, ++ "drmWaitVBlank failed for PRIME update: %s\n", ++ strerror(errno)); ++ radeon_drm_abort_entry(drm_queue_seq); ++ return; ++ } ++ ++ drmmode_crtc->scanout_update_pending = TRUE; + } + + static void +@@ -413,8 +497,10 @@ radeon_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) ++ radeon_prime_scanout_update(ent); ++ else ++ redisplay_dirty(ent); + } + } + } diff --git a/U_14-Track-damage-accurately-for-RandR-1.4-slave-scanout.patch b/U_14-Track-damage-accurately-for-RandR-1.4-slave-scanout.patch new file mode 100644 index 0000000..e54e1b1 --- /dev/null +++ b/U_14-Track-damage-accurately-for-RandR-1.4-slave-scanout.patch @@ -0,0 +1,144 @@ +From: Michel Dänzer +Date: Mon Nov 30 18:54:12 2015 +0900 +Subject: [PATCH 14/20]Track damage accurately for RandR 1.4 slave scanout +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: b0867063abb197b9134166706d99fcbe5f204bb5 +References: bsc#990066 +Signed-off-by: Max Staudt + +This further reduces the PCIe bandwidth usage. + +Reviewed-by: Alex Deucher +--- + src/radeon_kms.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 71 insertions(+), 11 deletions(-) + +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 07ba362..c10fb42 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -382,23 +382,76 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) + } + + #ifdef RADEON_PIXMAP_SHARING ++static RegionPtr ++dirty_region(PixmapDirtyUpdatePtr dirty) ++{ ++ RegionPtr damageregion = DamageRegion(dirty->damage); ++ RegionPtr dstregion; ++ ++#ifdef HAS_DIRTYTRACKING_ROTATION ++ if (dirty->rotation != RR_Rotate_0) { ++ BoxPtr boxes = RegionRects(damageregion); ++ int nboxes = RegionNumRects(damageregion); ++ xRectanglePtr rects = malloc(nboxes * sizeof(*rects)); ++ int dst_w = dirty->slave_dst->drawable.width; ++ int dst_h = dirty->slave_dst->drawable.height; ++ int nrects = 0; ++ BoxRec box; ++ int i; ++ ++ for (i = 0; i < nboxes; i++) { ++ box.x1 = boxes[i].x1; ++ box.x2 = boxes[i].x2; ++ box.y1 = boxes[i].y1; ++ box.y2 = boxes[i].y2; ++ pixman_f_transform_bounds(&dirty->f_inverse, &box); ++ ++ box.x1 = max(box.x1, 0); ++ box.y1 = max(box.y1, 0); ++ box.x2 = min(box.x2, dst_w); ++ box.y2 = min(box.y2, dst_h); ++ if (box.x1 >= box.x2 || box.y1 >= box.y2) ++ continue; ++ ++ rects[nrects].x = box.x1; ++ rects[nrects].y = box.y1; ++ rects[nrects].width = box.x2 - box.x1; ++ rects[nrects].height = box.y2 - box.y1; ++ nrects++; ++ } ++ dstregion = RegionFromRects(nrects, rects, CT_UNSORTED); ++ } else ++#endif ++ { ++ RegionRec pixregion; ++ ++ dstregion = RegionDuplicate(damageregion); ++ RegionTranslate(dstregion, -dirty->x, -dirty->y); ++ PixmapRegionInit(&pixregion, dirty->slave_dst); ++ RegionIntersect(dstregion, dstregion, &pixregion); ++ RegionUninit(&pixregion); ++ } ++ ++ return dstregion; ++} ++ + static void +-redisplay_dirty(PixmapDirtyUpdatePtr dirty) ++redisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region) + { + ScrnInfoPtr pScrn = xf86ScreenToScrn(dirty->src->drawable.pScreen); +- RegionRec pixregion; + +- PixmapRegionInit(&pixregion, dirty->slave_dst); +- DamageRegionAppend(&dirty->slave_dst->drawable, &pixregion); ++ if (dirty->slave_dst->master_pixmap) ++ DamageRegionAppend(&dirty->slave_dst->drawable, region); ++ + #ifdef HAS_DIRTYTRACKING_ROTATION + PixmapSyncDirtyHelper(dirty); + #else +- PixmapSyncDirtyHelper(dirty, &pixregion); ++ PixmapSyncDirtyHelper(dirty, region); + #endif + + radeon_cs_flush_indirect(pScrn); +- DamageRegionProcessPending(&dirty->slave_dst->drawable); +- RegionUninit(&pixregion); ++ if (dirty->slave_dst->master_pixmap) ++ DamageRegionProcessPending(&dirty->slave_dst->drawable); + + DamageEmpty(dirty->damage); + } +@@ -424,7 +477,10 @@ radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t u + 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); ++ RegionPtr region = dirty_region(dirty); ++ ++ redisplay_dirty(dirty, region); ++ RegionDestroy(region); + break; + } + } +@@ -488,20 +544,24 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty) + static void + radeon_dirty_update(ScreenPtr screen) + { +- RegionPtr region; + PixmapDirtyUpdatePtr ent; + + if (xorg_list_is_empty(&screen->pixmap_dirty_list)) + return; + + xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) { +- region = DamageRegion(ent->damage); ++ RegionPtr region = dirty_region(ent); ++ + if (RegionNotEmpty(region)) { + if (screen->isGPU) + radeon_prime_scanout_update(ent); + else +- redisplay_dirty(ent); ++ redisplay_dirty(ent, region); ++ } else { ++ DamageEmpty(ent->damage); + } ++ ++ RegionDestroy(region); + } + } + #endif diff --git a/U_15-Fix-build-against-xserver-1.13.patch b/U_15-Fix-build-against-xserver-1.13.patch new file mode 100644 index 0000000..2f320f7 --- /dev/null +++ b/U_15-Fix-build-against-xserver-1.13.patch @@ -0,0 +1,50 @@ +From: Michel Dänzer +Date: Fri Aug 26 18:09:03 2016 +0900 +Subject: [PATCH 15/20]Fix build against xserver < 1.13 +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: a92c27484703abc7c410b6ae0e4b8d1efbbb8e6f +References: bsc#990066 +Signed-off-by: Max Staudt + +pScreen->isGPU was only introduced in 1.13. + +Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97490 +Reviewed-by: Alex Deucher +--- + src/drmmode_display.c | 5 ++++- + src/radeon_kms.c | 5 ++++- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/drmmode_display.c b/src/drmmode_display.c +index 383c8a0..1fcd7c3 100644 +--- a/src/drmmode_display.c ++++ b/src/drmmode_display.c +@@ -795,7 +795,10 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]); + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]); +- } else if (!pScreen->isGPU && ++ } else if ( ++#ifdef RADEON_PIXMAP_SHARING ++ !pScreen->isGPU && ++#endif + (info->tear_free || + #if XF86_CRTC_VERSION >= 4 + crtc->driverIsPerformingTransform || +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index c10fb42..51f320c 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -842,7 +842,10 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) + (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); + pScreen->BlockHandler = RADEONBlockHandler_KMS; + +- if (!pScreen->isGPU) { ++#ifdef RADEON_PIXMAP_SHARING ++ if (!pScreen->isGPU) ++#endif ++ { + for (c = 0; c < xf86_config->num_crtc; c++) { + if (info->tear_free) + radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]); diff --git a/U_16-Only-copy-from-screen-pixmap-to-shared-pixmap-on-demand-for-slave-scanout.patch b/U_16-Only-copy-from-screen-pixmap-to-shared-pixmap-on-demand-for-slave-scanout.patch new file mode 100644 index 0000000..f64222c --- /dev/null +++ b/U_16-Only-copy-from-screen-pixmap-to-shared-pixmap-on-demand-for-slave-scanout.patch @@ -0,0 +1,163 @@ +From: Michel Dänzer +Date: Tue Dec 1 17:58:13 2015 +0900 +Subject: [PATCH 16/20]Only copy from screen pixmap to shared pixmap on demand for slave scanout +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 99232f64db52812a843cd616d263d3a6b90eef3d +References: bsc#990066 +Signed-off-by: Max Staudt + +Only copy once for each time we update the corresponding scanout pixmap. +This can significantly reduce the bandwidth usage when there are +frequent updates to the screen pixmap. + +This initial implementation only works when both the master and slave +screens use this driver. + +v2: +* Reduce churn in radeon_prime_scanout_update_handler +* Clear the correct damage in radeon_dirty_update + +Reviewed-by: Alex Deucher +--- + src/radeon_kms.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 69 insertions(+), 13 deletions(-) + +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 51f320c..711e84a 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -440,6 +440,9 @@ redisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region) + { + ScrnInfoPtr pScrn = xf86ScreenToScrn(dirty->src->drawable.pScreen); + ++ if (RegionNil(region)) ++ goto out; ++ + if (dirty->slave_dst->master_pixmap) + DamageRegionAppend(&dirty->slave_dst->drawable, region); + +@@ -453,6 +456,7 @@ redisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region) + if (dirty->slave_dst->master_pixmap) + DamageRegionProcessPending(&dirty->slave_dst->drawable); + ++out: + DamageEmpty(dirty->damage); + } + +@@ -465,6 +469,39 @@ radeon_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data) + } + + void ++radeon_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty) ++{ ++ ScreenPtr master_screen = dirty->src->master_pixmap->drawable.pScreen; ++ PixmapDirtyUpdatePtr ent; ++ RegionPtr region; ++ ++ xorg_list_for_each_entry(ent, &master_screen->pixmap_dirty_list, ent) { ++ if (ent->slave_dst != dirty->src) ++ continue; ++ ++ region = dirty_region(ent); ++ redisplay_dirty(ent, region); ++ RegionDestroy(region); ++ } ++} ++ ++static Bool ++master_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty) ++{ ++ ScrnInfoPtr master_scrn = xf86ScreenToScrn(dirty->src->master_pixmap->drawable.pScreen); ++ ++ return master_scrn->driverName == scrn->driverName; ++} ++ ++static Bool ++slave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty) ++{ ++ ScrnInfoPtr slave_scrn = xf86ScreenToScrn(dirty->slave_dst->drawable.pScreen); ++ ++ return slave_scrn->driverName == scrn->driverName; ++} ++ ++void + radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, + void *event_data) + { +@@ -477,8 +514,12 @@ radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t u + xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { + if (dirty->src == scanoutpix && + dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) { +- RegionPtr region = dirty_region(dirty); ++ RegionPtr region; + ++ if (master_has_sync_shared_pixmap(scrn, dirty)) ++ radeon_sync_shared_pixmap(dirty); ++ ++ region = dirty_region(dirty); + redisplay_dirty(dirty, region); + RegionDestroy(region); + break; +@@ -542,26 +583,41 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty) + } + + static void +-radeon_dirty_update(ScreenPtr screen) ++radeon_dirty_update(ScrnInfoPtr scrn) + { ++ ScreenPtr screen = scrn->pScreen; + PixmapDirtyUpdatePtr ent; +- +- if (xorg_list_is_empty(&screen->pixmap_dirty_list)) +- return; ++ RegionPtr region; + + xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) { +- RegionPtr region = dirty_region(ent); ++ if (screen->isGPU) { ++ PixmapDirtyUpdatePtr region_ent = ent; ++ ++ if (master_has_sync_shared_pixmap(scrn, ent)) { ++ ScreenPtr master_screen = ent->src->master_pixmap->drawable.pScreen; + +- if (RegionNotEmpty(region)) { +- if (screen->isGPU) ++ xorg_list_for_each_entry(region_ent, &master_screen->pixmap_dirty_list, ent) { ++ if (region_ent->slave_dst == ent->src) ++ break; ++ } ++ } ++ ++ region = dirty_region(region_ent); ++ ++ if (RegionNotEmpty(region)) + radeon_prime_scanout_update(ent); + else +- redisplay_dirty(ent, region); ++ DamageEmpty(region_ent->damage); ++ ++ RegionDestroy(region); + } else { +- DamageEmpty(ent->damage); +- } ++ if (slave_has_sync_shared_pixmap(scrn, ent)) ++ continue; + +- RegionDestroy(region); ++ region = dirty_region(ent); ++ redisplay_dirty(ent, region); ++ RegionDestroy(region); ++ } + } + } + #endif +@@ -861,7 +917,7 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) + radeon_cs_flush_indirect(pScrn); + + #ifdef RADEON_PIXMAP_SHARING +- radeon_dirty_update(pScreen); ++ radeon_dirty_update(pScrn); + #endif + } + diff --git a/U_17-Factor-out-transform_region-helper.patch b/U_17-Factor-out-transform_region-helper.patch new file mode 100644 index 0000000..aa34125 --- /dev/null +++ b/U_17-Factor-out-transform_region-helper.patch @@ -0,0 +1,107 @@ +From: Michel Dänzer +Date: Thu Sep 1 17:19:27 2016 +0900 +Subject: [PATCH 17/20]Factor out transform_region helper +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 5a57005178fc13b6f7e513458ca6dae72a3e5783 +References: bsc#990066 +Signed-off-by: Max Staudt + +While we're at it, fix leaking the memory allocated for xRectangles. + +Reviewed-by: Alex Deucher +--- + src/radeon_kms.c | 73 +++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 43 insertions(+), 30 deletions(-) + +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 711e84a..7173b77 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -382,6 +382,45 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) + } + + #ifdef RADEON_PIXMAP_SHARING ++ ++static RegionPtr ++transform_region(RegionPtr region, struct pict_f_transform *transform, ++ int w, int h) ++{ ++ BoxPtr boxes = RegionRects(region); ++ int nboxes = RegionNumRects(region); ++ xRectanglePtr rects = malloc(nboxes * sizeof(*rects)); ++ RegionPtr transformed; ++ int nrects = 0; ++ BoxRec box; ++ int i; ++ ++ for (i = 0; i < nboxes; i++) { ++ box.x1 = boxes[i].x1; ++ box.x2 = boxes[i].x2; ++ box.y1 = boxes[i].y1; ++ box.y2 = boxes[i].y2; ++ pixman_f_transform_bounds(transform, &box); ++ ++ box.x1 = max(box.x1, 0); ++ box.y1 = max(box.y1, 0); ++ box.x2 = min(box.x2, w); ++ box.y2 = min(box.y2, h); ++ if (box.x1 >= box.x2 || box.y1 >= box.y2) ++ continue; ++ ++ rects[nrects].x = box.x1; ++ rects[nrects].y = box.y1; ++ rects[nrects].width = box.x2 - box.x1; ++ rects[nrects].height = box.y2 - box.y1; ++ nrects++; ++ } ++ ++ transformed = RegionFromRects(nrects, rects, CT_UNSORTED); ++ free(rects); ++ return transformed; ++} ++ + static RegionPtr + dirty_region(PixmapDirtyUpdatePtr dirty) + { +@@ -390,36 +429,10 @@ dirty_region(PixmapDirtyUpdatePtr dirty) + + #ifdef HAS_DIRTYTRACKING_ROTATION + if (dirty->rotation != RR_Rotate_0) { +- BoxPtr boxes = RegionRects(damageregion); +- int nboxes = RegionNumRects(damageregion); +- xRectanglePtr rects = malloc(nboxes * sizeof(*rects)); +- int dst_w = dirty->slave_dst->drawable.width; +- int dst_h = dirty->slave_dst->drawable.height; +- int nrects = 0; +- BoxRec box; +- int i; +- +- for (i = 0; i < nboxes; i++) { +- box.x1 = boxes[i].x1; +- box.x2 = boxes[i].x2; +- box.y1 = boxes[i].y1; +- box.y2 = boxes[i].y2; +- pixman_f_transform_bounds(&dirty->f_inverse, &box); +- +- box.x1 = max(box.x1, 0); +- box.y1 = max(box.y1, 0); +- box.x2 = min(box.x2, dst_w); +- box.y2 = min(box.y2, dst_h); +- if (box.x1 >= box.x2 || box.y1 >= box.y2) +- continue; +- +- rects[nrects].x = box.x1; +- rects[nrects].y = box.y1; +- rects[nrects].width = box.x2 - box.x1; +- rects[nrects].height = box.y2 - box.y1; +- nrects++; +- } +- dstregion = RegionFromRects(nrects, rects, CT_UNSORTED); ++ dstregion = transform_region(damageregion, ++ &dirty->f_inverse, ++ dirty->slave_dst->drawable.width, ++ dirty->slave_dst->drawable.height); + } else + #endif + { diff --git a/U_18-Move-up-radeon_scanout_extents_intersect.patch b/U_18-Move-up-radeon_scanout_extents_intersect.patch new file mode 100644 index 0000000..6e45919 --- /dev/null +++ b/U_18-Move-up-radeon_scanout_extents_intersect.patch @@ -0,0 +1,76 @@ +From: Michel Dänzer +Date: Fri Sep 2 17:23:16 2016 +0900 +Subject: [PATCH 18/20]Move up radeon_scanout_extents_intersect +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 2f6e5fb15f1a9ce523c85550e493f8bda9d0c00f +References: bsc#990066 +Signed-off-by: Max Staudt + +Will be needed higher up by the following changes. No functional change. + +Reviewed-by: Alex Deucher +--- + src/radeon_kms.c | 42 +++++++++++++++++++++--------------------- + 1 file changed, 21 insertions(+), 21 deletions(-) + +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 7173b77..568c49e 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -381,6 +381,27 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) + return TRUE; + } + ++static Bool ++radeon_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w, ++ int h) ++{ ++ extents->x1 = max(extents->x1 - xf86_crtc->x, 0); ++ extents->y1 = max(extents->y1 - xf86_crtc->y, 0); ++ ++ switch (xf86_crtc->rotation & 0xf) { ++ case RR_Rotate_90: ++ case RR_Rotate_270: ++ extents->x2 = min(extents->x2 - xf86_crtc->x, h); ++ extents->y2 = min(extents->y2 - xf86_crtc->y, w); ++ break; ++ default: ++ extents->x2 = min(extents->x2 - xf86_crtc->x, w); ++ extents->y2 = min(extents->y2 - xf86_crtc->y, h); ++ } ++ ++ return (extents->x1 < extents->x2 && extents->y1 < extents->y2); ++} ++ + #ifdef RADEON_PIXMAP_SHARING + + static RegionPtr +@@ -636,27 +657,6 @@ radeon_dirty_update(ScrnInfoPtr scrn) + #endif + + static Bool +-radeon_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w, +- int h) +-{ +- extents->x1 = max(extents->x1 - xf86_crtc->x, 0); +- extents->y1 = max(extents->y1 - xf86_crtc->y, 0); +- +- switch (xf86_crtc->rotation & 0xf) { +- case RR_Rotate_90: +- case RR_Rotate_270: +- extents->x2 = min(extents->x2 - xf86_crtc->x, h); +- extents->y2 = min(extents->y2 - xf86_crtc->y, w); +- break; +- default: +- extents->x2 = min(extents->x2 - xf86_crtc->x, w); +- extents->y2 = min(extents->y2 - xf86_crtc->y, h); +- } +- +- return (extents->x1 < extents->x2 && extents->y1 < extents->y2); +-} +- +-static Bool + radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) + { + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; diff --git a/U_19-Synchronize-scanout-pixmaps-for-TearFree.patch b/U_19-Synchronize-scanout-pixmaps-for-TearFree.patch new file mode 100644 index 0000000..09d58d6 --- /dev/null +++ b/U_19-Synchronize-scanout-pixmaps-for-TearFree.patch @@ -0,0 +1,327 @@ +From: Michel Dänzer +Date: Thu Sep 1 12:54:13 2016 +0900 +Subject: [PATCH 19/20]Synchronize scanout pixmaps for TearFree +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: eda1f3df6aaed683036369fe8820da4dac3c2ae2 +References: bsc#990066 +Signed-off-by: Max Staudt + +Copy the damaged areas which are still valid in the other scanout pixmap +from there, then only copy the remaining damaged area from the screen +pixmap. + +This is slightly more efficient (only needs one Damage record instead of +two, and only needs to copy each screen update across PCIe once with +ShadowPrimary and a discrete GPU), and will be significantly more +efficient for PRIME with the following change. + +Reviewed-by: Alex Deucher +--- + src/drmmode_display.c | 95 +++++++++++++++++++++++++-------------------------- + src/drmmode_display.h | 3 +- + src/radeon_kms.c | 92 ++++++++++++++++++++++++++++++++++++++++--------- + 3 files changed, 124 insertions(+), 66 deletions(-) + +diff --git a/src/drmmode_display.c b/src/drmmode_display.c +index 1fcd7c3..44a4032 100644 +--- a/src/drmmode_display.c ++++ b/src/drmmode_display.c +@@ -519,10 +519,20 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode, + radeon_bo_unref(scanout->bo); + scanout->bo = NULL; + } ++} + +- if (scanout->damage) { +- DamageDestroy(scanout->damage); +- scanout->damage = NULL; ++static void ++drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) ++{ ++ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, ++ &drmmode_crtc->scanout[0]); ++ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, ++ &drmmode_crtc->scanout[1]); ++ ++ if (drmmode_crtc->scanout_damage) { ++ DamageDestroy(drmmode_crtc->scanout_damage); ++ drmmode_crtc->scanout_damage = NULL; ++ RegionUninit(&drmmode_crtc->scanout_last_region); + } + } + +@@ -532,15 +542,8 @@ drmmode_scanout_free(ScrnInfoPtr scrn) + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + int c; + +- for (c = 0; c < xf86_config->num_crtc; c++) { +- drmmode_crtc_private_ptr drmmode_crtc = +- xf86_config->crtc[c]->driver_private; +- +- drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, +- &drmmode_crtc->scanout[0]); +- drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, +- &drmmode_crtc->scanout[1]); +- } ++ for (c = 0; c < xf86_config->num_crtc; c++) ++ drmmode_crtc_scanout_free(xf86_config->crtc[c]->driver_private); + } + + static void * +@@ -793,8 +796,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + fb_id = drmmode_crtc->rotate.fb_id; + x = y = 0; + +- drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]); +- drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]); ++ drmmode_crtc_scanout_free(drmmode_crtc); + } else if ( + #ifdef RADEON_PIXMAP_SHARING + !pScreen->isGPU && +@@ -809,42 +811,40 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, + &drmmode_crtc->scanout[i], + mode->HDisplay, + mode->VDisplay); +- +- if (drmmode_crtc->scanout[i].pixmap) { +- RegionPtr pRegion; +- BoxPtr pBox; +- +- if (!drmmode_crtc->scanout[i].damage) { +- drmmode_crtc->scanout[i].damage = +- DamageCreate(radeon_screen_damage_report, +- NULL, DamageReportRawRegion, +- TRUE, pScreen, NULL); +- DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable, +- drmmode_crtc->scanout[i].damage); +- } +- +- pRegion = DamageRegion(drmmode_crtc->scanout[i].damage); +- RegionUninit(pRegion); +- pRegion->data = NULL; +- pBox = RegionExtents(pRegion); +- pBox->x1 = min(pBox->x1, x); +- pBox->y1 = min(pBox->y1, y); +- +- switch (crtc->rotation & 0xf) { +- case RR_Rotate_90: +- case RR_Rotate_270: +- pBox->x2 = max(pBox->x2, x + mode->VDisplay); +- pBox->y2 = max(pBox->y2, y + mode->HDisplay); +- break; +- default: +- pBox->x2 = max(pBox->x2, x + mode->HDisplay); +- pBox->y2 = max(pBox->y2, y + mode->VDisplay); +- } +- } + } + + if (drmmode_crtc->scanout[0].pixmap && + (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) { ++ RegionPtr pRegion; ++ BoxPtr pBox; ++ ++ if (!drmmode_crtc->scanout_damage) { ++ drmmode_crtc->scanout_damage = ++ DamageCreate(radeon_screen_damage_report, ++ NULL, DamageReportRawRegion, ++ TRUE, pScreen, NULL); ++ DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable, ++ drmmode_crtc->scanout_damage); ++ } ++ ++ pRegion = DamageRegion(drmmode_crtc->scanout_damage); ++ RegionUninit(pRegion); ++ pRegion->data = NULL; ++ pBox = RegionExtents(pRegion); ++ pBox->x1 = min(pBox->x1, x); ++ pBox->y1 = min(pBox->y1, y); ++ ++ switch (crtc->rotation & 0xf) { ++ case RR_Rotate_90: ++ case RR_Rotate_270: ++ pBox->x2 = max(pBox->x2, x + mode->VDisplay); ++ pBox->y2 = max(pBox->y2, y + mode->HDisplay); ++ break; ++ default: ++ pBox->x2 = max(pBox->x2, x + mode->HDisplay); ++ pBox->y2 = max(pBox->y2, y + mode->VDisplay); ++ } ++ + drmmode_crtc->scanout_id = 0; + fb_id = drmmode_crtc->scanout[0].fb_id; + x = y = 0; +@@ -1121,8 +1121,7 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) + if (crtc->randr_crtc->scanout_pixmap) + PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, + drmmode_crtc->scanout[0].pixmap); +- drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, +- &drmmode_crtc->scanout[0]); ++ drmmode_crtc_scanout_free(drmmode_crtc); + return TRUE; + } + +diff --git a/src/drmmode_display.h b/src/drmmode_display.h +index 53c7926..5df9773 100644 +--- a/src/drmmode_display.h ++++ b/src/drmmode_display.h +@@ -73,7 +73,6 @@ typedef struct { + struct drmmode_scanout { + struct radeon_bo *bo; + PixmapPtr pixmap; +- DamagePtr damage; + unsigned fb_id; + int width, height; + }; +@@ -85,6 +84,8 @@ typedef struct { + struct radeon_bo *cursor_bo; + struct drmmode_scanout rotate; + struct drmmode_scanout scanout[2]; ++ DamagePtr scanout_damage; ++ RegionRec scanout_last_region; + unsigned scanout_id; + Bool scanout_update_pending; + int dpms_mode; +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index 568c49e..bcaa024 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -402,8 +402,6 @@ radeon_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w, + return (extents->x1 < extents->x2 && extents->y1 < extents->y2); + } + +-#ifdef RADEON_PIXMAP_SHARING +- + static RegionPtr + transform_region(RegionPtr region, struct pict_f_transform *transform, + int w, int h) +@@ -442,6 +440,70 @@ transform_region(RegionPtr region, struct pict_f_transform *transform, + return transformed; + } + ++static void ++radeon_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region, ++ int scanout_id) ++{ ++ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; ++ DrawablePtr dst = &drmmode_crtc->scanout[scanout_id].pixmap->drawable; ++ DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1].pixmap->drawable; ++ RegionPtr last_region = &drmmode_crtc->scanout_last_region; ++ ScrnInfoPtr scrn = xf86_crtc->scrn; ++ ScreenPtr pScreen = scrn->pScreen; ++ RADEONInfoPtr info = RADEONPTR(scrn); ++ RegionRec remaining; ++ RegionPtr sync_region = NULL; ++ BoxRec extents; ++ Bool force; ++ GCPtr gc; ++ ++ if (RegionNil(last_region)) ++ return; ++ ++ RegionNull(&remaining); ++ RegionSubtract(&remaining, last_region, new_region); ++ if (RegionNil(&remaining)) ++ goto uninit; ++ ++ extents = *RegionExtents(&remaining); ++ if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, dst->width, ++ dst->height)) ++ goto uninit; ++ ++#if XF86_CRTC_VERSION >= 4 ++ if (xf86_crtc->driverIsPerformingTransform) { ++ sync_region = transform_region(&remaining, ++ &xf86_crtc->f_framebuffer_to_crtc, ++ dst->width, dst->height); ++ } else ++#endif /* XF86_CRTC_VERSION >= 4 */ ++ { ++ sync_region = RegionDuplicate(&remaining); ++ RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y); ++ } ++ ++ force = info->accel_state->force; ++ info->accel_state->force = TRUE; ++ ++ gc = GetScratchGC(dst->depth, pScreen); ++ if (gc) { ++ ValidateGC(dst, gc); ++ gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0); ++ sync_region = NULL; ++ gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0); ++ FreeScratchGC(gc); ++ } ++ ++ info->accel_state->force = force; ++ ++ uninit: ++ if (sync_region) ++ RegionDestroy(sync_region); ++ RegionUninit(&remaining); ++} ++ ++#ifdef RADEON_PIXMAP_SHARING ++ + static RegionPtr + dirty_region(PixmapDirtyUpdatePtr dirty) + { +@@ -660,13 +722,12 @@ static Bool + radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) + { + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; +- ScrnInfoPtr scrn; +- DamagePtr pDamage; +- RegionPtr pRegion; ++ RegionPtr pRegion = DamageRegion(drmmode_crtc->scanout_damage); ++ ScrnInfoPtr scrn = xf86_crtc->scrn; ++ ScreenPtr pScreen = scrn->pScreen; ++ RADEONInfoPtr info = RADEONPTR(scrn); + DrawablePtr pDraw; +- ScreenPtr pScreen; + BoxRec extents; +- RADEONInfoPtr info; + Bool force; + + if (!xf86_crtc->enabled || +@@ -674,24 +735,21 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id) + !drmmode_crtc->scanout[scanout_id].pixmap) + return FALSE; + +- pDamage = drmmode_crtc->scanout[scanout_id].damage; +- if (!pDamage) +- return FALSE; +- +- pRegion = DamageRegion(pDamage); + if (!RegionNotEmpty(pRegion)) + return FALSE; + + pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable; +- pScreen = pDraw->pScreen; + extents = *RegionExtents(pRegion); +- RegionEmpty(pRegion); + if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width, + pDraw->height)) + return FALSE; + +- scrn = xf86_crtc->scrn; +- info = RADEONPTR(scrn); ++ if (info->tear_free) { ++ radeon_sync_scanout_pixmaps(xf86_crtc, pRegion, scanout_id); ++ RegionCopy(&drmmode_crtc->scanout_last_region, pRegion); ++ } ++ RegionEmpty(pRegion); ++ + force = info->accel_state->force; + info->accel_state->force = TRUE; + +@@ -807,7 +865,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc) + drmmode_crtc->pending_dpms_mode != DPMSModeOn) + return; + +- pDamage = drmmode_crtc->scanout[0].damage; ++ pDamage = drmmode_crtc->scanout_damage; + if (!pDamage) + return; + diff --git a/U_20-Make-TearFree-effective-with-PRIME-slave-scanout.patch b/U_20-Make-TearFree-effective-with-PRIME-slave-scanout.patch new file mode 100644 index 0000000..2539070 --- /dev/null +++ b/U_20-Make-TearFree-effective-with-PRIME-slave-scanout.patch @@ -0,0 +1,265 @@ +From: Michel Dänzer +Date: Fri Sep 2 11:08:28 2016 +0900 +Subject: [PATCH 20/20]Make TearFree effective with PRIME slave scanout +Patch-mainline: Upstream +Git-repo: git://anongit.freedesktop.org/xorg/driver/xf86-video-ati +Git-commit: 38797a33117222dadbc89e5f21ed8cd5deef9bea +References: bsc#990066 +Signed-off-by: Max Staudt + +TearFree can now prevent tearing with any possible display +configuration. + +Note that there may still be inter-GPU tearing if the primary GPU uses +a different driver. + +v2: +* Also test dirty->slave_dst in radeon_prime_scanout_do_update + +Reviewed-by: Alex Deucher [v1] +--- + src/drmmode_display.c | 33 ++++++++++++--- + src/drmmode_display.h | 1 + + src/radeon_kms.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++---- + 3 files changed, 132 insertions(+), 13 deletions(-) + +diff --git a/src/drmmode_display.c b/src/drmmode_display.c +index 44a4032..44615d3 100644 +--- a/src/drmmode_display.c ++++ b/src/drmmode_display.c +@@ -524,10 +524,19 @@ drmmode_crtc_scanout_destroy(drmmode_ptr drmmode, + static void + drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) + { +- drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, +- &drmmode_crtc->scanout[0]); +- drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, +- &drmmode_crtc->scanout[1]); ++ if (drmmode_crtc->flip_pending) { ++ drmmode_crtc->scanout_destroy[0] = drmmode_crtc->scanout[0]; ++ drmmode_crtc->scanout[0].pixmap = NULL; ++ drmmode_crtc->scanout[0].bo = NULL; ++ drmmode_crtc->scanout_destroy[1] = drmmode_crtc->scanout[1]; ++ drmmode_crtc->scanout[1].pixmap = NULL; ++ drmmode_crtc->scanout[1].bo = NULL; ++ } else { ++ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, ++ &drmmode_crtc->scanout[0]); ++ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, ++ &drmmode_crtc->scanout[1]); ++ } + + if (drmmode_crtc->scanout_damage) { + DamageDestroy(drmmode_crtc->scanout_damage); +@@ -1116,11 +1125,12 @@ static Bool + drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) + { + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; ++ RADEONInfoPtr info = RADEONPTR(crtc->scrn); + + if (!ppix) { + if (crtc->randr_crtc->scanout_pixmap) + PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, +- drmmode_crtc->scanout[0].pixmap); ++ drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap); + drmmode_crtc_scanout_free(drmmode_crtc); + return TRUE; + } +@@ -1130,6 +1140,14 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) + ppix->drawable.height)) + return FALSE; + ++ if (info->tear_free && ++ !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], ++ ppix->drawable.width, ++ ppix->drawable.height)) { ++ drmmode_crtc_scanout_free(drmmode_crtc); ++ return FALSE; ++ } ++ + #ifdef HAS_DIRTYTRACKING_ROTATION + PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap, + 0, 0, 0, 0, RR_Rotate_0); +@@ -2196,6 +2214,11 @@ drmmode_clear_pending_flip(xf86CrtcPtr crtc) + + drmmode_crtc_dpms(crtc, drmmode_crtc->pending_dpms_mode); + } ++ ++ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, ++ &drmmode_crtc->scanout_destroy[0]); ++ drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, ++ &drmmode_crtc->scanout_destroy[1]); + } + + static void +diff --git a/src/drmmode_display.h b/src/drmmode_display.h +index 5df9773..7602eb8 100644 +--- a/src/drmmode_display.h ++++ b/src/drmmode_display.h +@@ -84,6 +84,7 @@ typedef struct { + struct radeon_bo *cursor_bo; + struct drmmode_scanout rotate; + struct drmmode_scanout scanout[2]; ++ struct drmmode_scanout scanout_destroy[2]; + DamagePtr scanout_damage; + RegionRec scanout_last_region; + unsigned scanout_id; +diff --git a/src/radeon_kms.c b/src/radeon_kms.c +index bcaa024..9bcf657 100644 +--- a/src/radeon_kms.c ++++ b/src/radeon_kms.c +@@ -597,31 +597,56 @@ slave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty) + return slave_scrn->driverName == scrn->driverName; + } + +-void +-radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, +- void *event_data) ++static Bool ++radeon_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id) + { + ScrnInfoPtr scrn = crtc->scrn; + ScreenPtr screen = scrn->pScreen; ++ RADEONInfoPtr info = RADEONPTR(scrn); + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap; + PixmapDirtyUpdatePtr dirty; ++ Bool ret = FALSE; + + xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { +- if (dirty->src == scanoutpix && +- dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) { ++ if (dirty->src == scanoutpix && dirty->slave_dst == ++ drmmode_crtc->scanout[scanout_id ^ info->tear_free].pixmap) { + RegionPtr region; + + if (master_has_sync_shared_pixmap(scrn, dirty)) + radeon_sync_shared_pixmap(dirty); + + region = dirty_region(dirty); ++ if (RegionNil(region)) ++ goto destroy; ++ ++ if (info->tear_free) { ++ RegionTranslate(region, crtc->x, crtc->y); ++ radeon_sync_scanout_pixmaps(crtc, region, scanout_id); ++ radeon_cs_flush_indirect(scrn); ++ RegionCopy(&drmmode_crtc->scanout_last_region, region); ++ RegionTranslate(region, -crtc->x, -crtc->y); ++ dirty->slave_dst = drmmode_crtc->scanout[scanout_id].pixmap; ++ } ++ + redisplay_dirty(dirty, region); ++ ret = TRUE; ++ destroy: + RegionDestroy(region); + break; + } + } + ++ return ret; ++} ++ ++void ++radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, ++ void *event_data) ++{ ++ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; ++ ++ radeon_prime_scanout_do_update(crtc, 0); + drmmode_crtc->scanout_update_pending = FALSE; + } + +@@ -679,8 +704,74 @@ radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty) + } + + static void ++radeon_prime_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data) ++{ ++ drmmode_crtc_private_ptr drmmode_crtc = event_data; ++ ++ drmmode_crtc->scanout_update_pending = FALSE; ++ drmmode_clear_pending_flip(crtc); ++} ++ ++static void ++radeon_prime_scanout_flip(PixmapDirtyUpdatePtr ent) ++{ ++ ScreenPtr screen = ent->slave_dst->drawable.pScreen; ++ ScrnInfoPtr scrn = xf86ScreenToScrn(screen); ++ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); ++ xf86CrtcPtr crtc = NULL; ++ drmmode_crtc_private_ptr drmmode_crtc = NULL; ++ uintptr_t drm_queue_seq; ++ unsigned scanout_id; ++ int c; ++ ++ /* Find the CRTC which is scanning out from this slave pixmap */ ++ for (c = 0; c < xf86_config->num_crtc; c++) { ++ crtc = xf86_config->crtc[c]; ++ drmmode_crtc = crtc->driver_private; ++ scanout_id = drmmode_crtc->scanout_id; ++ if (drmmode_crtc->scanout[scanout_id].pixmap == ent->slave_dst) ++ break; ++ } ++ ++ if (c == xf86_config->num_crtc || ++ !crtc->enabled || ++ drmmode_crtc->scanout_update_pending || ++ !drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap || ++ drmmode_crtc->pending_dpms_mode != DPMSModeOn) ++ return; ++ ++ scanout_id = drmmode_crtc->scanout_id ^ 1; ++ if (!radeon_prime_scanout_do_update(crtc, scanout_id)) ++ return; ++ ++ drm_queue_seq = radeon_drm_queue_alloc(crtc, ++ RADEON_DRM_QUEUE_CLIENT_DEFAULT, ++ RADEON_DRM_QUEUE_ID_DEFAULT, ++ drmmode_crtc, NULL, ++ radeon_prime_scanout_flip_abort); ++ if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) { ++ xf86DrvMsg(scrn->scrnIndex, X_WARNING, ++ "Allocating DRM event queue entry failed for PRIME flip.\n"); ++ return; ++ } ++ ++ if (drmModePageFlip(drmmode_crtc->drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, ++ drmmode_crtc->scanout[scanout_id].fb_id, ++ DRM_MODE_PAGE_FLIP_EVENT, (void*)drm_queue_seq)) { ++ xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n", ++ __func__, strerror(errno)); ++ return; ++ } ++ ++ drmmode_crtc->scanout_id = scanout_id; ++ drmmode_crtc->scanout_update_pending = TRUE; ++ drmmode_crtc->flip_pending = TRUE; ++} ++ ++static void + radeon_dirty_update(ScrnInfoPtr scrn) + { ++ RADEONInfoPtr info = RADEONPTR(scrn); + ScreenPtr screen = scrn->pScreen; + PixmapDirtyUpdatePtr ent; + RegionPtr region; +@@ -700,10 +791,14 @@ radeon_dirty_update(ScrnInfoPtr scrn) + + region = dirty_region(region_ent); + +- if (RegionNotEmpty(region)) +- radeon_prime_scanout_update(ent); +- else ++ if (RegionNotEmpty(region)) { ++ if (info->tear_free) ++ radeon_prime_scanout_flip(ent); ++ else ++ radeon_prime_scanout_update(ent); ++ } else { + DamageEmpty(region_ent->damage); ++ } + + RegionDestroy(region); + } else { diff --git a/xf86-video-ati.changes b/xf86-video-ati.changes index a6d1745..0e872a6 100644 --- a/xf86-video-ati.changes +++ b/xf86-video-ati.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Fri Oct 14 15:12:36 UTC 2016 - mstaudt@suse.com + +- U_01-* ... U_20-* : + Include patches that haven't made it into the 7.7.1 release. + + This means almost all commits between xf86-video-ati-7.7.0 + and 12d30eeb9711bd2b1609d6bbb74c4a1760596f72. + + Fixes (bsc#990066). + ------------------------------------------------------------------- Mon Sep 19 13:32:04 UTC 2016 - tobias.johannes.klausmann@mni.thm.de diff --git a/xf86-video-ati.spec b/xf86-video-ati.spec index 9381d50..f110536 100644 --- a/xf86-video-ati.spec +++ b/xf86-video-ati.spec @@ -28,6 +28,26 @@ Url: http://xorg.freedesktop.org/ Source0: http://xorg.freedesktop.org/releases/individual/driver/%{name}-%{version}.tar.bz2 Source1: http://xorg.freedesktop.org/releases/individual/driver/%{name}-%{version}.tar.bz2.sig Source2: %{name}.keyring +Patch1: U_01-dri3-Return-NULL-from-radeon_dri3_pixmap_from_fd-if-calloc-fails.patch +Patch2: U_02-Add-support-for-async-flips-to-radeon_do_pageflip.patch +Patch3: U_03-present-Support-async-flips.patch +Patch4: U_04-Enable-DRI3-by-default-when-building-for-Xorg-1.18.3.patch +Patch5: U_05-EXA-6xx-7xx-fast-solid-pixmap-support.patch +Patch6: U_06-EXA-6xx-7xx-accelerate-PictOpOver-with-component-alpha.patch +Patch7: U_07-Adapt-to-XF86_CRTC_VERSION-7.patch +Patch8: U_08-Add-explicit-RADEON_DRM_QUEUE_ERROR-define.patch +Patch9: U_09-Don-t-enable-DRI3-by-default-with-EXA.patch +Patch10: U_10-Use-EventCallback-to-avoid-flushing-every-time-in-the-FlushCallback.patch +Patch11: U_11-Keep-track-of-damage-event-related-flushes-per-client-v2.patch +Patch12: U_12-Use-drmmode_crtc_scanout_-helpers-for-RandR-1.4-scanout-pixmaps.patch +Patch13: U_13-Handle-RandR-1.4-slave-dirty-updates-via-radeon_drm_queue.patch +Patch14: U_14-Track-damage-accurately-for-RandR-1.4-slave-scanout.patch +Patch15: U_15-Fix-build-against-xserver-1.13.patch +Patch16: U_16-Only-copy-from-screen-pixmap-to-shared-pixmap-on-demand-for-slave-scanout.patch +Patch17: U_17-Factor-out-transform_region-helper.patch +Patch18: U_18-Move-up-radeon_scanout_extents_intersect.patch +Patch19: U_19-Synchronize-scanout-pixmaps-for-TearFree.patch +Patch20: U_20-Make-TearFree-effective-with-PRIME-slave-scanout.patch BuildRequires: Mesa-devel BuildRequires: autoconf >= 2.60 @@ -69,6 +89,26 @@ driver as appropriate. %prep %setup -q +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 %build autoreconf -fiv