diff --git a/driver/xf86-video-ati/ChangeLog b/driver/xf86-video-ati/ChangeLog index a45a8d809..3aa14d6e1 100644 --- a/driver/xf86-video-ati/ChangeLog +++ b/driver/xf86-video-ati/ChangeLog @@ -1,3 +1,1330 @@ +commit 99cb8c3faf1a4ce368b7500f17a2a7868c15e8e8 +Author: Michel Dänzer +Date: Thu Nov 12 13:38:14 2015 +0900 + + Set version for 7.6.1 release + +commit 4a2114a717ec8d78cacd8fe158e132d62013faac +Author: Michel Dänzer +Date: Thu Nov 12 13:32:25 2015 +0900 + + Remove duplicate free(output_ids) call + + Fixes double-free regression introduced by commit 875ad48e ("Simplify + drmmode_set_mode_major() and avoid leaking memory."). + +commit 960a9f37096b53ec9603a99c7b1f3679f915e03f +Author: Michel Dänzer +Date: Thu Nov 12 13:20:18 2015 +0900 + + Post 7.6.0 release version bump + +commit 9aae4b71fb402841439e3267fcb7f410d8429c3a +Author: Michel Dänzer +Date: Thu Nov 12 11:56:48 2015 +0900 + + Bump version for 7.6.0 release + +commit 98291869ac4a542a0b478920586407ff9d2c8ef0 +Author: Tom St Denis +Date: Wed Nov 11 16:01:41 2015 +0900 + + Clean up radeon_dri2_create_buffer2() + + Remove the depth_pixmap variable from the function and clear + out any dead/odd behaviour that results. + + Signed-off-by: Tom St Denis + (ported from amdgpu commit 6000aef4e2f0a121b94023484406fb6f04688f74) + + Reviewed-by: Alex Deucher + +commit c6fc7e309a8a922f94a1f5f3e8bfb9058cff7ad1 +Author: Michel Dänzer +Date: Wed Nov 11 15:59:06 2015 +0900 + + Properly handle drmModeAddFB failure in drmmode_crtc_scanout_allocate + + We were printing an error message, but not propagating the failure. That + would probably lead to trouble down the road. + + (ported from amdgpu commit 21e72fb2418b5cc7fc849a9cf951186e209036b0) + + Reviewed-by: Alex Deucher + +commit 4e4f4d53da0539ef9feb8766230a6e9927ae005b +Author: Michel Dänzer +Date: Wed Nov 11 15:57:21 2015 +0900 + + Eliminate redundant data parameter from drmmode_crtc_scanout_create + + drmmode_crtc_scanout_create just needs to call + drmmode_crtc_scanout_allocate when scanout->bo is NULL. + + This makes it clearer to the reader / compiler that + drmmode_crtc_scanout_create doesn't dereference scanout->bo when it's + NULL. + + (ported from amdgpu commit 8da1d0c870e1081d77925807d6e3bbc61a23f54f) + + Reviewed-by: Alex Deucher + +commit 421a7e797bdd58d83e81af7a6512cc715a3df514 +Author: Michel Dänzer +Date: Wed Nov 11 15:51:58 2015 +0900 + + Don't advertise rotation support without hardware acceleration v2 + + Rotation currently doesn't work without acceleration (doesn't actually + rotate with Option "NoAccel", crashes with Option "AccelMethod" "none" + or when glamor fails to initialize) and would probably be too slow + anyway. + + v2: Also remove now dead code checking for ShadowFB from + drmmode_crtc_scanout_allocate(). + + (ported from amdgpu commit dc40582d5ff94d812cbc08f95cf14b80cd0f410d) + + Reviewed-by: Alex Deucher + +commit 875ad48e7b5cdb7beefbf18dddcbee3ed22b5446 +Author: Tom St Denis +Date: Wed Nov 11 15:51:19 2015 +0900 + + Simplify drmmode_set_mode_major() and avoid leaking memory. + + The function would leak the memory allocated for output_ids. This + patch addresses that as well as simplifies the logic somewhat. + + Signed-off-by: Tom St Denis + (ported from amdgpu commit 460560502a1bdf26d06f3c30df46fa9f28ffb9e5) + + Reviewed-by: Alex Deucher + +commit 789d7d6a04cca6b36fb088a074027807ccb8dd61 +Author: Tom St Denis +Date: Wed Nov 11 15:48:51 2015 +0900 + + Clean up allocation in RADEONInitVideo() + + The allocation of the adapters should use the correct sizeof (even if + allocating an array of pointers). + + Signed-off-by: Tom St Denis + (ported from amdgpu commit db3bb2061b9ac16b0922d9afae99874820356a04) + + Reviewed-by: Alex Deucher + +commit d88fa0dd5d37604de8efb05853738cfaca6a3166 +Author: Tom St Denis +Date: Wed Nov 11 15:46:50 2015 +0900 + + Simplify pick best crtc to fold two loops into one + + This patch folds the two for loops from radeon_pick_best_crtc() into + one to reduce the LOC and make the routine easier to read. + + Signed-off-by: Tom St Denis + (ported from amdgpu commit 3055724aef76a624718f26d5f0f9e9d567ffbcfb) + + Reviewed-by: Alex Deucher + +commit dbbcd75b3c80aba77673904d46bca97779fd8a8d +Author: Tom St Denis +Date: Wed Nov 11 12:54:54 2015 +0900 + + dri2: Avoid calculation with undefined msc value + + If the get_msc() call fails for any reason we should avoid updating the + vblank counter delta with undefined data. + + Signed-off-by: Tom St Denis + Signed-off-by: Michel Dänzer (minor fixups) + (ported from amdgpu commit 8823c3d4c6db70cff7699b31088f2d92db8faaf4) + + Reviewed-by: Alex Deucher + +commit 7186a8713ba004de4991f21c1a9fc4abc62aeff4 +Author: Stephen Chandler Paul +Date: Fri Oct 23 09:59:36 2015 -0400 + + Handle failures in setting a CRTC to a DRM mode properly + + This fixes a bug where running the card out of PPLL's when hotplugging + another monitor would result in all of the displays going blank and + failing to work properly until X was restarted or the user switched to + another VT. + + [Michel Dänzer: Pass errno instead of -ret to strerror()] + + Signed-off-by: Stephen Chandler Paul + Reviewed-by: Michel Dänzer + +commit 548e97b3b7d1e94075a54ca2bb4eb683025098a7 +Author: Michel Dänzer +Date: Fri Oct 16 16:26:58 2015 +0900 + + Call xf86CrtcRotate from initial drmmode_set_desired_modes call + + Fixes various problems when rotation is specified in xorg.conf. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=92475 + + Reviewed-by: Alex Deucher + +commit ce9914af8d8d5243977023ec7b09c605f9cca8b4 +Author: Michel Dänzer +Date: Fri Oct 2 18:07:18 2015 +0900 + + Only align screen / scanout pixmap height where necessary + + When using glamor acceleration, the pixmap's header has to have a height + that matches exactly what the actual height is minus the GPU memory + alignment. Otherwise CRTCs scanning out from the main scanout buffer + (e.g. every CRTC that isn't rotated or transformed in some way) won't + always work. This results in a bug where rotating one monitor in a + multi-monitor setup won't always work properly. Easiest way to reproduce + this: + + - Have two monitors (I've gotten this working with a 1920x1080 and + 1280x1024, along with two 1920x1080s) + - Rotate one of them from 0° to 90°, then rotate the same monitor from + 90° to 180°. The monitor that hasn't been rotated won't properly + update, and will stay on a blank screen + + This doesn't seem to make any difference when using EXA for + acceleration. + + Compared to Stephen Chandler's patch, this drops the height alignment + in most places and only keeps it where it's really necessary. + + Reported-and-Tested-by: Stephen Chandler Paul + Reviewed-by: Alex Deucher + +commit 0288a4b87b65ba54f37fbeeea3cb32238deee92e +Author: Michel Dänzer +Date: Wed Aug 19 16:54:14 2015 +0900 + + DRI2: Keep MSC monotonic when moving window between CRTCs + + This mirrors the DRI3 implementation in xserver. Fixes VDPAU video + playback hanging when moving the window between CRTCs. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=66384 + + (Ported from amdgpu commit 63948ea091a9b324327ade7ec4fc5d67ca7e6f6f) + + Reviewed-by: Alex Deucher + +commit 1d886b526dc49f32dc6744b7a882894bdac4e846 +Author: Michel Dänzer +Date: Wed Aug 19 18:11:45 2015 +0900 + + DRI2: Don't ignore rotated CRTCs in amdgpu_dri2_drawable_crtc + + Waiting for vblank interrupts works fine with rotated CRTCs. The only + case we can't handle with rotation is page flipping, which is handled + in can_exchange(). + + This fixes gnome-shell hanging on rotation, probably because + amdgpu_dri2_get_msc returned MSC/UST 0 for rotated CRTCs. + + (Ported from amdgpu commit 7b3212e33cd36fb6f122774df27b56ec4e1a22b8) + + Reviewed-by: Alex Deucher + +commit 270da55340766074cabff8af4258e29fe2f0fc81 +Author: Alex Deucher +Date: Mon Aug 10 15:32:34 2015 -0400 + + add new OLAND pci id + + Signed-off-by: Alex Deucher + +commit f123096877f0a0044f3d0315285441f2b5790c29 +Author: Mario Kleiner +Date: Mon Aug 10 23:34:39 2015 +0200 + + Make selection between DRI2 and DRI3 consistent with other drivers. (v2) + + Add Option "DRI" to allow selection of maximum DRI level. + + This allows the user to select the maximum level of DRI + implementation to use, DRI2 or DRI3. It replaces the old + option "DRI3" which had exactly the same purpose, but + differs from the method used in both intel ddx and nouveau ddx. + Make this consistent before a new stable driver is released. + + v2: Retain handling of old Option "DRI3" for backwards + compatibility, but Option "DRI" will take precedence + over "DRI3" if both are provided. + + Signed-off-by: Mario Kleiner + Reviewed-by: Michel Dänzer + +commit 3791fceabf2cb037467dc41c15364e9f9ec1e47e +Author: Michel Dänzer +Date: Thu Aug 6 16:27:01 2015 +0900 + + Wait for scanout BO initialization to finish before setting mode + + This should avoid intermittent artifacts which could sometimes be visible + when setting a new scanout pixmap, e.g. on server startup or when + changing resolutions. + + Reviewed-by: Alex Deucher + +commit 4e3dfa69e4630df2e0ec0f5b81d61159757c4664 +Author: Michel Dänzer +Date: Thu Aug 6 16:16:38 2015 +0900 + + Only call drmmode_copy_fb (at most) once on server startup + + It doesn't make sense to copy the screen contents from console when VT + switching back to Xorg or when Xorg resets. + + Fixes intermittent artifacts when VT switching back from console to the + gdm login screen. + + Reviewed-by: Alex Deucher + +commit 09c7cdb923965f9a1ea11d2f449bc02114408938 +Author: Michel Dänzer +Date: Thu Jul 30 15:58:54 2015 +0900 + + glamor: Move declaration of struct radeon_pixmap out of #if/#else blocks + + Reviewed-by: Dave Airlie + +commit 936582fde0db461c5c3d78ce4f5f4c93a88a489d +Author: Michel Dänzer +Date: Thu Jul 30 15:56:36 2015 +0900 + + Remove unused local variable pRADEONEnt + + ../../src/radeon_probe.c: In function 'radeon_get_scrninfo': + ../../src/radeon_probe.c:157:22: warning: variable 'pRADEONEnt' set but not used [-Wunused-but-set-variable] + RADEONEntPtr pRADEONEnt; + ^ + + Reviewed-by: Dave Airlie + +commit 5510cd6027d2387efdf33575e3bfc424cb11bfd8 +Author: Dave Airlie +Date: Mon Jul 27 09:22:57 2015 +1000 + + radeon: move radeon_pixmap forward declaration into other block + + There is already a radeon_pixmap forward decl here, the #else + block is missing one. + + Reviewed-by: Alex Deucher + Signed-off-by: Dave Airlie + +commit b32a0a3de84a44b9af4f1ca8be19f10d7fa31b12 +Author: Dave Airlie +Date: Wed Jul 22 13:35:07 2015 +1000 + + radeon: cleanup the entity rec + + Some of these were set, some of them were + always opposites, so clean things up. + + Reviewed-by: Alex Deucher + Signed-off-by: Dave Airlie + +commit fcb32231a38f9461d12720cbf72f63502197a711 +Author: Emil Velikov +Date: Tue Jul 21 23:55:20 2015 +0100 + + Do not link radeon_drv.so against libpciaccess + + It's only used/needed by ati_drv.so + + Signed-off-by: Emil Velikov + Reviewed-by: Michel Dänzer + +commit b6d871bf299c7d0f106c07ee4d8bd3b2337f53cc +Author: Dave Airlie +Date: Thu Jul 9 19:25:36 2015 +1000 + + radeon: adopt for new X server dirty tracking APIs. + + Signed-off-by: Dave Airlie + +commit 95f5d09e3667ded027ae648c97eb4737d8bf67c5 +Author: Michel Dänzer +Date: Thu May 28 11:24:42 2015 +0900 + + present: Handle DPMS off in radeon_present_get_ust_msc + + The DRM_IOCTL_WAIT_VBLANK ioctl may return an error during DPMS off, + which would trigger an error message in drmmode_crtc_get_ust_msc. + + Reviewed-by: Alex Deucher + +commit 211862b777d0be251a4662f5dd24f2d400544c09 +Author: Michel Dänzer +Date: Fri May 1 18:20:01 2015 +0900 + + present: Look at all CRTCs to determine if we can flip + + Inspired by modesetting driver change by Kenneth Graunke. + + Reviewed-by: Alex Deucher + +commit 802d33e474a82262d9cdf11b03568b0c4929cd0d +Author: Michel Dänzer +Date: Fri May 1 18:54:16 2015 +0900 + + present: Fall back to modeset for unflip operation + + It's not always possible to use the page flip ioctl for this, e.g. + during DPMS off. We were previously just skipping the unflip in that + case, which could result in hangs when setting DPMS off while a + fullscreen Present app is running, e.g. at the GNOME3 lock screen. + + Reviewed-by: Alex Deucher + +commit a8ed62010d5012dfb27773595c446b217f3c00c5 +Author: Piotr Redlewski +Date: Mon Jul 6 19:57:07 2015 +0200 + + Do not try to enable already enabled CRTCs in DPMS hook + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91227 + + Signed-off-by: Piotr Redlewski + Reviewed-by: Michel Dänzer + +commit fc07c370dac4649511eb7322d05a61605a539f39 +Author: Mario Kleiner +Date: Sun Jun 28 02:45:58 2015 +0200 + + Fix inconsistent default eg_tile_split in evergreen_accel.c + + eg_tile_split() maps the default: switch-case to tile split + flag 6, like for a tile split size of 4096 Bytes. All other + instances of tile split mappings or reverse mappings in both + the ddx and in Mesa's radeon gallium drivers assign the default: + case to tile split flag 4, consistent with a default of 1024 + Bytes. + + Make this one outlier consistent with other instances of + mappings in the code to avoid surprises. + + Signed-off-by: Mario Kleiner + +commit ddaba449e8d6fe9fc0d97085e4045843fd8d7af9 +Author: Piotr Redlewski +Date: Wed Jun 24 18:44:39 2015 +0200 + + Disable CRTCs when disabling the outputs + + When turning the outputs off (DPMSModeOff), CRTCs stayed enabled. This led + to higher gpu temperatures than with fglrx driver. + + v2: when entering DPMS also disable active CRTCs + v3: use drmmode_set_mode_major() for enabling CRTCs when leaving DPMS + + Signed-off-by: Piotr Redlewski + Reviewed-by: Michel Dänzer + +commit acc11877423ecd81a6e0a7f38466f80e43efee20 +Author: Michel Dänzer +Date: Tue Jun 16 17:34:57 2015 +0900 + + Skip disabled CRTCs in radeon_scanout_(do_)update + + The vblank / page flip ioctls don't work as expected for a disabled CRTC. + + Reviewed-by: Alex Deucher + +commit fc9fadaebbc8aead6e030d93a9ccd84561f8f59e +Author: Mario Kleiner +Date: Mon Jun 22 00:09:17 2015 +0200 + + Don't set TILE_SPLIT flags if surface.tile_split == 0. + + On pre-Evergreen hw, libdrm's r6_surface_best() helper + for the surface managers radeon_surface_best() routine + is a no-op and therefore doesn't assign any tile_split + settings to created surfaces, so it leaves + surface.tile_split on its "undefined" value of 0. + + Mesa's DRI3/Present backend creates DRI3 Pixmaps via + the DRIImage extension and the radeon gallium driver + implementation of that extension uses the libdrm + surface manager for backing bo creation and treats + an undefined surface.tile_split==0, as returned by + the surface manager for pre-evergreen, as a signal + to not assign any tile_split flags to the DRI3 Pixmaps + bo. + + The ddx also uses libdrm surface manager to create the + x-screen pixmap, but so far treated the returned undefined + surface.tile_split==0 by mapping it to eg_tile_split()'s + default tile_split flags, which are different from Mesa's + tiling flags for DRI3 pixmaps. Under DRI3/Present this + causes a mismatch of src pixmap and destination root + pixmaps tiling flags and thereby prevents page flipping + for pixmap presents. + + Change the ddx code to treat surface.tile_split==0 the + same way as the radeon gallium driver to avoid mismatched + tiling flags and thereby allow DRI3/Present page-flip to + work on pre-Evergreen hw. + + Tested on RV730 and Evergreen "Juniper". + + Signed-off-by: Mario Kleiner + +commit 49f5b0bc301414df049e00d226034e3d6e56421b +Author: Michel Dänzer +Date: Fri May 1 19:02:36 2015 +0900 + + Don't attempt a DRI2/Present page flip while the other one is flipping + + Fixes corrupted display and hangs when switching between DRI2 and DRI3 + fullscreen apps, e.g. a compositor using DRI3 and a fullscreen app using + DRI2 or vice versa. + + Reviewed-by: Alex Deucher + +commit afab7839fc15722dbaa7203d00fe7f6ce5336b9d +Author: Mario Kleiner +Date: Wed Jun 10 20:55:08 2015 +0200 + + Allow/Fix use of multiple ZaphodHead outputs per x-screen. (v2) + + Defining multiple ZaphodHead outputs per x-screen in a + multiple x-screen's per gpu configuration caused all + outputs except one per x-screen to go dark, because + there was a fixed mapping x-screen number -> crtc number, + limiting the number of crtc's per x-screen to one. + + On a ZaphodHead's setup, be more clever and assign + as many crtc's to a given x-screen as there are + ZaphodHeads defined for that screen, assuming + there are enough unused crtc's available. + + Tested on a triple display setup with different combos + of one, two or three ZaphodHeads per one, two or three + x-screens. + + This is a port of similar code from xf86-video-nouveau. + + v2: Implement suggestions by Michel Dänzer: Less verbose + debug output, more clear warning message on crtc allocation + failure. Move clearing of per gpu assigned_crtc mask to + CloseScreen, indeed testing shows no need for the more + complex new server generation check from v1. + + Signed-off-by: Mario Kleiner + (v1) Reviewed-by: Alex Deucher + Reviewed-by: Michel Dänzer + +commit d7c82731a8bf3d381bc571b94d80d9bb2dd6e40d +Author: Michel Dänzer +Date: Thu May 21 16:01:16 2015 +0900 + + DRI2: Fix handling of drmmode_crtc_get_ust_msc return code + + Fixes regression introduced in commit + 76c2923ac5c7230a8b2f9f8329c308d28b44d9c0 ("DRI2: Split out helper for + getting UST and MSC of a specific CRTC"). + + Reviewed-by: Alex Deucher + +commit e58fc380ccf2a581d28f041fd74b963626ca5404 +Author: Michel Dänzer +Date: Thu May 28 10:59:22 2015 +0900 + + glamor: Only wait for GPU writes in radeon_glamor_prepare_access_cpu_ro + + We don't need to wait for GPU reads to finish before reading with the + CPU. + + Reviewed-by: Alex Deucher + +commit 5f82a720374c9c1caebb42bfbeea1f0cf8847d28 +Author: Michel Dänzer +Date: Thu May 21 15:46:32 2015 +0900 + + present: Remove get_drmmode_crtc helper + + It was getting the drmmode_crtc_private_ptr in a roundabout way. + + Reviewed-by: Alex Deucher + +commit d64a13ebe0ecd241ee3260dbffd8f4a01e254183 +Author: Michel Dänzer +Date: Wed May 20 09:58:38 2015 +0900 + + Replace SyncFence typedef with declaration of struct _SyncFence + + Fixes build failure in some environments: + + CC radeon_sync.lo + In file included from radeon_sync.c:28: + /home/tinderbox/xorg-build/include/xorg/misync.h:31: error: redefinition of typedef 'SyncFence' + radeon.h:93: note: previous declaration of 'SyncFence' was here + make[2]: *** [radeon_sync.lo] Error 1 + + Reported-Tested-and-Acked-by: David Airlie + +commit 818c180c8932233b214a35ba0647af82f7bcec3d +Author: Michel Dänzer +Date: Tue May 12 17:43:57 2015 +0900 + + glamor: Deal with glamor_glyphs_init being removed from xserver + + Reviewed-by: Alex Deucher + +commit 7c4b78ab10b82c6dba9f72034ff7583859cca63d +Author: Alex Deucher +Date: Tue May 12 13:21:24 2015 -0400 + + add new bonaire pci id + + Reviewed-by: Michel Dänzer + Signed-off-by: Alex Deucher + +commit 80eede245d1eda27eaba108b0761a24bfd69aff6 +Author: Mario Kleiner +Date: Sat May 9 07:24:36 2015 +0200 + + present: Fix present notify timestamps and counts. + + Invalid (msc,ust)=(0,0) were returned to the server + because a wrong crtc_id was used to specify which + crtc should deliver pageflip completion data. Fix + it in accordance with the dri2 implementation. + + Signed-off-by: Mario Kleiner + +commit e3be8b0a8cf484ff16597413a6172788178e80c8 +Author: Mario Kleiner +Date: Sat May 9 07:24:35 2015 +0200 + + present: Move check for async flips + + Check for and reject currently unsupported async_flip + inside radeon_present_check_flip() instead of inside + radeon_present_flip(). + + This way the server can detect early that async flips + aren't supported by the ddx and can deal with this + correctly by using its non-vsync'ed CopyRegion fallback. + + Signed-off-by: Mario Kleiner + +commit 1584dc545c78e0bce8d4b4b9f26b568e2c211453 +Author: Michel Dänzer +Date: Tue Apr 28 17:14:11 2015 +0900 + + Skip disabled CRTCs in drmmode_set_desired_modes() even if set_hw == FALSE + + Not skipping a disabled CRTC results in a crash. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90187 + + Reviewed-by: Alex Deucher + +commit 340baf3804b7d9de8082badfc715a9bee7856e8f +Author: Michel Dänzer +Date: Mon Apr 27 15:07:06 2015 +0900 + + Don't call radeon_get_pixmap_private() when using EXA + + It only works when using glamor. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90169 + + Reviewed-by: Alex Deucher + +commit 80f3d727f93cb6efedd2b39338d2301035965fe2 +Author: Michel Dänzer +Date: Wed Apr 22 13:33:15 2015 +0900 + + On screen resize, clear the new buffer before displaying it + + Fixes garbage being intermittently visible during a screen resize. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=27757#c7 + + Reviewed-by: Alex Deucher + +commit 3999bf88cdb192fe2f30b03bd2ed6f6a3f9f9057 +Author: Michel Dänzer +Date: Thu Apr 2 18:29:38 2015 +0900 + + Make drmmode_copy_fb() work with glamor as well + + Needed for Xorg -background none. + + Reviewed-by: Alex Deucher + +commit a4a8cdbcc10c1c5f07485a2af9e9e81e490c3e1d +Author: Michel Dänzer +Date: Thu Apr 2 17:46:34 2015 +0900 + + Update scanout pixmap contents before setting a mode with it + + This ensures the scanout pixmaps used for Option "TearFree" and Option + "ShadowPrimary" have been initialized when their initial mode is set. + + Reviewed-by: Alex Deucher + +commit 673e1c7637687c74fc9bdeeeffb7ace0d04b734f +Author: Michel Dänzer +Date: Thu Apr 2 17:54:33 2015 +0900 + + Defer initial modeset until the first BlockHandler invocation + + This ensures that the screen pixmap contents have been initialized when + the initial modes are set. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=27757 + + Reviewed-by: Alex Deucher + +commit 37874a4eeace5df04b02c8fc28f67b824e3f0f5f +Author: Michel Dänzer +Date: Tue Apr 21 17:19:15 2015 +0900 + + Defer initial drmmode_copy_fb call until root window creation + + That's late enough for acceleration to be fully initialized, but still + early enough to set pScreen->canDoBGNoneRoot. + + Reviewed-by: Alex Deucher + +commit 39c497f3efca5ca08343b884f44c93215dcdef31 +Author: Michel Dänzer +Date: Thu Apr 2 18:10:42 2015 +0900 + + Only copy fbcon BO contents if bgNoneRoot is TRUE + + Otherwise, the X server will initialize the screen pixmap contents + anyway. + + Reviewed-by: Alex Deucher + +commit 1af044d7eee211fd4b248c236280274a68334da5 +Author: Michel Dänzer +Date: Wed Apr 22 18:43:02 2015 +0900 + + DRI2: Clear old->devPrivate.ptr in fixup_glamor + + It doesn't point to the memory of the newly allocated BO. Fixes crash + running piglit with Option "ShadowPrimary" enabled. + + Reviewed-by: Alex Deucher + +commit 43159ef400c3b18b9f4d3e6fa1c4aef2d60d38fe +Author: Michel Dänzer +Date: Mon Apr 20 18:44:36 2015 +0900 + + Add Option "TearFree" v4 + + Avoids tearing by flipping between two scanout BOs per (non-rotated) CRTC + + v2: + * Fix condition for TearFree log message (Richard Wilbur) + * Log warning message about DRI page flipping being enabled because of + TearFree (or ShadowPrimary) also when building without glamor support + + v3: + * Only override fb_id/x/y if all scanout pixmaps have been successfully + allocated + + v4: + * Make log warning clearer if drmModePageFlip returns an error + + Reviewed-by: Alex Deucher (v1) + +commit ed401f5b4f07375db17ff05e294907ec95fc946d +Author: Michel Dänzer +Date: Fri Apr 3 12:11:00 2015 +0900 + + glamor: Remove the stride member of struct radeon_pixmap + + Its value was always the same as that of the PixmapRec devKind member. + + Reviewed-by: Alex Deucher + +commit ae92d1765fa370a8d94c2856ad6c45d273ec3c69 +Author: Michel Dänzer +Date: Wed Mar 18 16:23:24 2015 +0900 + + glamor: Add Option "ShadowPrimary" v2 + + When this option is enabled, most pixmaps (including the screen pixmap) + are allocated in system RAM and mostly accessed by the CPU. Changed areas + of the screen pixmap are copied to dedicated per-CRTC scanout pixmaps + regularly, triggered by the vblank interrupt. + + v2: + * Set region data pointer to NULL for keeping only the extents + * Move pRegion and pBox local variable declarations closer to their uses + in drmmode_set_mode_major() + +commit eea79472a84672ee4dc7adc4487cec6a4037048a +Author: Michel Dänzer +Date: Wed Apr 1 15:51:52 2015 +0900 + + glamor: Add wrappers for the X server rendering hooks + + They can choose between using the GPU or CPU for the operation. + +commit 051d46382656ffc3e6cac1aab3aee7efdf5b623a +Author: Michel Dänzer +Date: Thu Mar 19 17:34:27 2015 +0900 + + glamor: Add radeon_pixmap parameter to radeon_glamor_create_textured_pixmap + +commit 2fa021f77372ca93375a3d13a0c43a9089674899 +Author: Michel Dänzer +Date: Thu Mar 19 17:38:47 2015 +0900 + + glamor: Remove unused function radeon_glamor_pixmap_is_offscreen + +commit e96349ba6281fd18b8bf9c76629128276b065e6c +Author: Michel Dänzer +Date: Wed Apr 1 16:04:13 2015 +0900 + + Add RADEON_CREATE_PIXMAP_SCANOUT flag + + It means that the pixmap is used for scanout exclusively. + +commit 9be7dd382e86d2b804de81d4e2af7431b2e16843 +Author: Michel Dänzer +Date: Wed Apr 1 12:40:16 2015 +0900 + + Split out struct drmmode_scanout for rotation shadow buffer information + + Will be used for other kinds of dedicated scanout buffers as well. + +commit c32b0530302739f6512755bccf281c2300617376 +Author: Michel Dänzer +Date: Thu Mar 19 17:46:48 2015 +0900 + + Rename scanout_pixmap_x field to prime_pixmap_x + + To avoid confusion with upcoming changes. + +commit 5921ba4ca705a0d919515626088f3948cc4848c1 +Author: Michel Dänzer +Date: Tue Mar 31 15:14:52 2015 +0900 + + present: Don't flip between BOs with different tiling parameters + + The kernel driver doesn't handle that correctly yet. + + Fixes or at least avoids issues with OpenGL fullscreen apps with DRI3 + enabled and using PRIME or with (2D) tiling disabled. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89720 + + Reviewed-by: Alex Deucher + +commit 428e416e7cb04a1e0527da39cfebf70218879a77 +Author: Michel Dänzer +Date: Thu Apr 2 10:34:03 2015 +0900 + + Add radeon_get_pixmap_tiling_flags helper + + Reviewed-by: Alex Deucher + +commit 98fb4199e63fedd4607cddee64bf602d6398df81 +Author: Michel Dänzer +Date: Tue Mar 31 12:25:18 2015 +0900 + + Only enable SYNC extension fences and the Present extension along with DRI3 + + This avoids some trouble with the Gallium nine state tracker, which uses + the Present extension even when DRI3 is disabled. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89772 + + Reviewed-by: Alex Deucher + +commit f8b0f23e9f4af9f9097ee5e72d53b45173163c41 +Author: Michel Dänzer +Date: Fri Mar 27 12:34:55 2015 +0900 + + DRI2: Use radeon_get_pixmap_handle + + Now we can share pixmaps with no struct radeon_bo via DRI2. + + Fixes VDPAU video playback freezing when using an OpenGL compositor with + DRI3 enabled. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89755 + + Reviewed-by: Alex Deucher + Tested-by: Nick Sarnie + +commit ccbda955ebae1d457d35293833f12791e0f9fb0b +Author: Michel Dänzer +Date: Fri Mar 27 12:16:44 2015 +0900 + + Move get_pixmap_handle helper to radeon_bo_helper.c + + No functional change. + + Reviewed-by: Alex Deucher + Tested-by: Nick Sarnie + +commit de5ddd09db82141b263338dcf0c28e01f58268ee +Author: Michel Dänzer +Date: Thu Mar 26 16:33:02 2015 +0900 + + Move radeon_drm_handler/abort_proc fields to drmmode_flipdata_rec + + Their values are the same for all DRM flip ioctl calls within a single + radeon_do_pageflip() call. + + Reviewed-by: Alex Deucher + +commit e8c0f6319fbf4c3ea11e22ab1a68837031bdec8c +Author: Michel Dänzer +Date: Thu Mar 26 16:27:35 2015 +0900 + + Simplify radeon_do_pageflip() error handling slightly more + + We don't need the local variable old_fb_id. + + Reviewed-by: Alex Deucher + +commit 8fc22360d5520469c82092ccb0fcf2af330c573f +Author: Michel Dänzer +Date: Thu Mar 26 15:58:01 2015 +0900 + + Increase robustness against DRM page flip ioctl failures v3 + + Centralize cleanup, only clean up things that have been allocated for + the failed ioctl call. + + Fixes double-free after a flip ioctl failure. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89681 + + v2: Only call drmModeRmFB for flipdata->old_fb_id on receipt of last DRM + page flip event. Fixes Black screen on making glxgears fullscreen with + DRI3 enabled. + v3: Avoid double-free of flipdata in the unlikely case that calloc fails + for flipcarrier, but only for the second or later CRTC. + + Reviewed-by: Alex Deucher (v2) + +commit b16609b453bb1a181198cf27778f205dc23fb642 +Author: Michel Dänzer +Date: Thu Mar 26 17:15:21 2015 +0900 + + glamor: Handle GLAMOR_* flags removed from xserver + + The behaviour is the same as when the removed flags were passed in. + + Reviewed-by: Alex Deucher + +commit 391900a670addec39515f924265bfa9f8bfa9ec0 +Author: Michel Dänzer +Date: Wed Mar 18 12:56:07 2015 +0900 + + glamor: Avoid generating GEM flink names for BOs shared via DRI3 v2 + + We can't create our own struct radeon_bo representation in this case + because destroying that would make the GEM handle inaccessible to glamor + as well. So just get the handle directly via dma-buf. + + v2: Close dma-buf file descriptor, pointed out by Axel Davy. + + Reviewed-by: Axel Davy + Reviewed-by: Alex Deucher + +commit dfad91fffb5bd013785223b42d78886df839eacf +Author: Michel Dänzer +Date: Thu Mar 19 12:37:01 2015 +0900 + + Present: Add radeon_present_get_pixmap_handle helper + + Reviewed-by: Axel Davy + Reviewed-by: Alex Deucher + +commit 7b4fc4a677d252d01c2bf80d162bc35814059eaa +Author: Michel Dänzer +Date: Thu Mar 19 12:15:52 2015 +0900 + + Make radeon_do_pageflip take a BO handle directly + + Reviewed-by: Axel Davy + Reviewed-by: Alex Deucher + +commit af6076241c0d322b295a4e898407ae2472bd8eb4 +Author: Michel Dänzer +Date: Tue Mar 24 13:37:01 2015 +0900 + + Adapt radeon_sync.c for misyncshm.h vs misync.h as well + + This should have been part of the previous commit. Without this, SYNC + extension fences (and by extension DRI3) were disabled because it checked + for HAVE_MISYNC_H, but configure now only defines HAVE_MISYNCSHM_H. + +commit aa7825eb29cdf6ac9d7b28ad18186807ff384687 +Author: Michel Dänzer +Date: Mon Mar 23 10:12:17 2015 +0900 + + configure.ac: Check for misyncshm.h again + + We need this header, which was added after the other misync*.h headers, + along with DRI3 support. + +commit 6291baaed261e36a63dc001307427fe00ba82259 +Author: Michel Dänzer +Date: Thu Mar 19 00:12:06 2015 +0900 + + EXA: Return NULL from radeon_get_pixmap_bo if there is no driver private + + This mirrors what the glamor part of the function does. Fixes a crash + running glxgears_pixmap with DRI3 enabled, reported by "marvin24" on IRC. + +commit f68d9b5ba0c91a725b5eec9386c61bea8824c299 +Author: Michel Dänzer +Date: Wed Mar 18 18:29:27 2015 +0900 + + dri3: Use screen->CreatePixmap instead of fbCreatePixmap directly + + Fixes crash with EXA reported by "marvin24" on IRC. + +commit 4b0997e56dec0053cb2cb793e0f4ae35055ff7e6 +Author: Michel Dänzer +Date: Wed Mar 18 12:30:09 2015 +0900 + + glamor: Add glamor_fd_from_pixmap define for standalone glamor tree + +commit af1862a37570fa512a525ab47d72b30400d2e2d6 +Author: Michel Dänzer +Date: Wed Mar 18 11:05:40 2015 +0900 + + Always include misync.h before other misync headers + + Older versions of xserver didn't include misync.h from other misync + headers as needed. + +commit fcd37f65f485291084c174666bd605e215bf1398 +Author: Michel Dänzer +Date: Wed Mar 18 10:39:03 2015 +0900 + + DRI3: Use open hook instead of open_client + + We don't need the client pointer, and this allows it to work with older + versions of xserver as well. + +commit f940fd741b15f03393037c5bb904cd74f012de9d +Author: Michel Dänzer +Date: Wed Mar 18 10:06:47 2015 +0900 + + Initialize boolean variable before calling xf86GetOptValBool + + We were just lucky that it contained 0 in most cases. + +commit 4a98f60117c387a228d5cbaadb6e298fb4e865df +Author: Michel Dänzer +Date: Tue Mar 17 16:47:11 2015 +0900 + + Add xorg_list_for_each_entry_safe fallback in radeon_list.h + + Fixes another build failure against older versions of xserver reported + by "Pali" on IRC. + +commit 694e04720b886060fe3eefdce59741f218c8269f +Author: Michel Dänzer +Date: Tue Mar 17 16:32:09 2015 +0900 + + Simplify includes in radeon_{dri3,present}.c + + Just include radeon.h first. Fixes build failures against older versions + of xserver because compat-api.h wasn't getting picked up. Reported by + "Pali" on IRC. + +commit 64e1e4dbdd3caee6f5d8f6b6c094b4533fa94953 +Author: Michel Dänzer +Date: Tue Mar 10 16:53:11 2015 +0900 + + Add DRI3 support v2 + + Must be enabled with + + Option "DRI3" + + in xorg.conf. + + v2: Adapt to v2 of patches 11/12. + + Reviewed-by: Alex Deucher + +commit 69ae0194778fe4276895839db92383f63f0b5de4 +Author: David Heidelberger +Date: Fri Mar 6 17:57:22 2015 +0900 + + Handle tiling in radeon_set_shared_pixmap_backing + + [ Michel Dänzer: Fixups for glamor ] + Signed-off-by: David Heidelberger + Signed-off-by: Axel Davy + + Reviewed-by: Alex Deucher + +commit 3c65fb849e1ba9fb6454bcaa55b696548902f3fc +Author: Michel Dänzer +Date: Tue Mar 10 16:52:54 2015 +0900 + + Add support for the Present extension v2 + + v2: Fix up for struct radeon_drm_queue -> radeon_drm_queue_entry. + Swapped order of patches 11 & 12 because the Present extension uses + SYNC fences. + + Reviewed-by: Alex Deucher + +commit 8fc9a241ab59ffbcdc178d6415332c88a54e85fe +Author: Michel Dänzer +Date: Thu Mar 5 18:18:56 2015 +0900 + + Add support for SYNC extension fences v2 + + v2: Swapped order of patches 11 & 12 because the Present extension uses + SYNC fences. + + Reviewed-by: Alex Deucher + +commit 4a35e2f33d9cdfb608423046391311109f96fb6b +Author: Michel Dänzer +Date: Thu Mar 5 18:34:07 2015 +0900 + + Fold radeon_glamor_flush into radeon_cs_flush_indirect + + Reviewed-by: Alex Deucher + +commit 4b8adebb80158bcf81ada83bb88517febe931b12 +Author: Michel Dänzer +Date: Thu Mar 5 18:40:23 2015 +0900 + + Move #include "radeon_glamor.h" from radeon.h to where it's needed + + Reviewed-by: Alex Deucher + +commit 76c2923ac5c7230a8b2f9f8329c308d28b44d9c0 +Author: Michel Dänzer +Date: Wed Mar 4 10:30:19 2015 +0900 + + DRI2: Split out helper for getting UST and MSC of a specific CRTC + + Reviewed-by: Alex Deucher + +commit 6c3a721cde9317233072b573f9502348dcd21b16 +Author: Michel Dänzer +Date: Tue Mar 10 16:52:18 2015 +0900 + + DRI2: Use helper functions for DRM event queue management v3 + + This is mostly in preparation for Present support, but it also simplifies + the DRI2 specific code a little. + + v2: Fix up for struct radeon_drm_queue -> radeon_drm_queue_entry. + v3: Removed excess 0s from conversion from microseconds to seconds, + thanks to Richard Wilbur for the catch! + + Reviewed-by: Alex Deucher + +commit c3fa22a479e61d1899fa9d327d9c4e2a7f64b0c1 +Author: Michel Dänzer +Date: Wed Mar 11 17:47:59 2015 +0900 + + DRI2: Move radeon_dri2_flip_event_handler + + In preparation for the next change, which will modify it to a static + function which needs to be in the new place. No functional change. + + Reviewed-by: Alex Deucher + +commit 65045112fdc8a9fa36e0e00f46739a6152b775ff +Author: Michel Dänzer +Date: Wed Mar 11 17:33:54 2015 +0900 + + DRI2: Remove superfluous assignments to *_info->frame + + That field is only used for page flipping. + + Reviewed-by: Alex Deucher + +commit ad27f16f308079d06a2b1c788b3cb0947531253a +Author: Michel Dänzer +Date: Wed Mar 11 17:30:11 2015 +0900 + + DRI2: Simplify blit fallback handling for scheduled swaps + + Also use radeon_dri2_schedule_event when possible. + + Reviewed-by: Alex Deucher + +commit b4af8a327ed8420f0ff4ea0f113f4a59406ed4d3 +Author: Michel Dänzer +Date: Mon Mar 2 18:59:54 2015 +0900 + + Add DRM event queue helpers v2 + + v2: Rename struct radeon_drm_queue to struct radeon_drm_queue_event, + thanks to Richard Wilbur for the suggestion. + Also changed the corresponding parameter and local variable names from + 'q' to 'e'. + + Reviewed-by: Alex Deucher + +commit 7c3470f4b659206ed23f761948936ede3a2dba3d +Author: Michel Dänzer +Date: Fri Mar 6 18:51:29 2015 +0900 + + Move xorg_list backwards compatibility to new radeon_list.h header + + Reviewed-by: Alex Deucher + +commit 7388d0b6c54b9d536fdb161e3aa61b326627b939 +Author: Michel Dänzer +Date: Thu Mar 5 17:35:06 2015 +0900 + + Require at least xserver 1.8 + + So we can rely on the list.h header. + + xserver 1.8 was released in April 2010. + + Reviewed-by: Alex Deucher + +commit b8ec9ed4fe86952763b963c86f0af0dcae69aa6c +Author: Jerome Glisse +Date: Thu Feb 19 14:47:41 2015 -0500 + + Proper leak fix, previous leak fix was bogus. + + Signed-off-by: Jérôme Glisse + +commit 63dc36dc49f93cb00111b497ab6805194bc9d240 +Author: Jerome Glisse +Date: Thu Feb 19 11:43:08 2015 -0500 + + Avoid leaking memory on output. + + Signed-off-by: Jérôme Glisse + +commit c80ea1e3e8c5f155cedadbe4588870fb1f410ab4 +Author: Rolf Eike Beer +Date: Tue Jan 13 12:11:26 2015 +0100 + + radeon: remove unneeded inclusion of sarea.h + + None of the structs or defines from that header is used. + + Signed-off-by: Rolf Eike Beer + +commit 04da199231bb3f11cf17f94574a8df05855a7b82 +Author: Adam Jackson +Date: Wed Dec 17 14:03:58 2014 -0500 + + Remove dead accelDFS flag + + Signed-off-by: Adam Jackson + +commit c9f8f642fd495937400618a4fc25ecae3f8888fc +Author: Michel Dänzer +Date: Mon Nov 17 12:32:29 2014 +0900 + + Prefer drmModeSetCursor2 over drmModeSetCursor + + The former includes information about the position of the hotspot within + the cursor image. + + Copied from xf86-video-modesetting. + + Reviewed-by: Alex Deucher + +commit 2f11dcd43966cf2ee26e61960fd72e6644f5e037 +Author: Dave Airlie +Date: Mon Nov 10 13:49:29 2014 +1000 + + radeon: add support for DP 1.2 display hotplug (v2) + + This allows for dynamic creation of conneectors when the + kernel tells us. + + v2: fix dpms off crash + + Reviewed-by: Alex Deucher + Signed-off-by: Dave Airlie + +commit c88424d1f4aaa78b569e5d44f0b4a47de2f422f4 +Author: Dave Airlie +Date: Mon Nov 10 14:17:54 2014 +1000 + + radeon: move output name creation to its own function + + The secondary indent is deliberate to make the next patch more + parseable for mst support. + + Reviewed-by: Alex Deucher + Signed-off-by: Dave Airlie + +commit 32b003cb7657e07d5af6338ad44d768eda87fd33 +Author: Dave Airlie +Date: Mon Nov 10 14:12:34 2014 +1000 + + radeon: stop caching mode resources + + This is step one towards MST connector hotplug support, + it stop caching the mode resources structure, and + just passes a pointer to it around. + + Reviewed-by: Alex Deucher + Signed-off-by: Dave Airlie + +commit 7c7b38e0b375b6e8853ad2d1092302ea83f6f570 +Author: David Heidelberger +Date: Sun Oct 12 16:34:21 2014 +0200 + + radeon/vdpau: don't report VDPAU for < r300 + + Signed-off-by: David Heidelberger + +commit c74de9fec13fac2c836bb2a07ae6f90e1d61e667 +Author: Michel Dänzer +Date: Wed Aug 6 11:08:00 2014 +0900 + + PRIME: Don't advertise offload capabilities when acceleration is disabled + + Xorg tends to crash if the user tries to actually use the offload + capabilities with acceleration disabled. + + Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=57200 + Reviewed-by: Alex Deucher + +commit 636a6382f80412ae4e28abe0cd9f98f84cd52291 +Author: Michel Dänzer +Date: Wed Oct 15 12:02:17 2014 +0900 + + Remove duplicate OPTION_PAGE_FLIP entry + + Reported by 'amanual' on IRC + +commit c854b4479ec5122390ede81b655b259efd9b1800 +Author: Alex Deucher +Date: Thu Oct 2 10:22:22 2014 -0400 + + radeon: bump version post release + + Signed-off-by: Alex Deucher + commit 068a59e010ce6bfcd54f5a18cc08c55c54b8618d Author: Alex Deucher Date: Wed Oct 1 23:38:52 2014 -0400 diff --git a/driver/xf86-video-ati/config.h.in b/driver/xf86-video-ati/config.h.in index f8b7f7890..ba7522f06 100644 --- a/driver/xf86-video-ati/config.h.in +++ b/driver/xf86-video-ati/config.h.in @@ -8,6 +8,15 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H +/* Define to 1 if you have the header file. */ +#undef HAVE_DRI3_H + +/* Have fbGlyphs API */ +#undef HAVE_FBGLYPHS + +/* Have glamor_glyphs_init API */ +#undef HAVE_GLAMOR_GLYPHS_INIT + /* Define to 1 if you have the header file. */ #undef HAVE_GLAMOR_H @@ -17,12 +26,15 @@ /* libudev support */ #undef HAVE_LIBUDEV -/* Define to 1 if you have the header file. */ -#undef HAVE_LIST_H - /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H +/* Define to 1 if you have the header file. */ +#undef HAVE_MISYNCSHM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PRESENT_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H diff --git a/driver/xf86-video-ati/configure b/driver/xf86-video-ati/configure index 3dffa8907..c7b5d121f 100644 --- a/driver/xf86-video-ati/configure +++ b/driver/xf86-video-ati/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for xf86-video-ati 7.5.0. +# Generated by GNU Autoconf 2.69 for xf86-video-ati 7.6.1. # # Report bugs to . # @@ -591,8 +591,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='xf86-video-ati' PACKAGE_TARNAME='xf86-video-ati' -PACKAGE_VERSION='7.5.0' -PACKAGE_STRING='xf86-video-ati 7.5.0' +PACKAGE_VERSION='7.6.1' +PACKAGE_STRING='xf86-video-ati 7.6.1' PACKAGE_BUGREPORT='https://bugs.freedesktop.org/enter_bug.cgi?product=xorg' PACKAGE_URL='' @@ -1386,7 +1386,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures xf86-video-ati 7.5.0 to adapt to many kinds of systems. +\`configure' configures xf86-video-ati 7.6.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1456,7 +1456,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of xf86-video-ati 7.5.0:";; + short | recursive ) echo "Configuration of xf86-video-ati 7.6.1:";; esac cat <<\_ACEOF @@ -1609,7 +1609,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -xf86-video-ati configure 7.5.0 +xf86-video-ati configure 7.6.1 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2024,7 +2024,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by xf86-video-ati $as_me 7.5.0, which was +It was created by xf86-video-ati $as_me 7.6.1, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2855,7 +2855,7 @@ fi # Define the identity of the package. PACKAGE='xf86-video-ati' - VERSION='7.5.0' + VERSION='7.6.1' cat >>confdefs.h <<_ACEOF @@ -18438,12 +18438,12 @@ if test -n "$XORG_CFLAGS"; then pkg_cv_XORG_CFLAGS="$XORG_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-server >= 1.7 xproto fontsproto xf86driproto \$REQUIRED_MODULES\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-server >= 1.8 xproto fontsproto xf86driproto \$REQUIRED_MODULES\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_XORG_CFLAGS=`$PKG_CONFIG --cflags "xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>/dev/null` + pkg_cv_XORG_CFLAGS=`$PKG_CONFIG --cflags "xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -18455,12 +18455,12 @@ if test -n "$XORG_LIBS"; then pkg_cv_XORG_LIBS="$XORG_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ - { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-server >= 1.7 xproto fontsproto xf86driproto \$REQUIRED_MODULES\""; } >&5 - ($PKG_CONFIG --exists --print-errors "xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES") 2>&5 + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"xorg-server >= 1.8 xproto fontsproto xf86driproto \$REQUIRED_MODULES\""; } >&5 + ($PKG_CONFIG --exists --print-errors "xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then - pkg_cv_XORG_LIBS=`$PKG_CONFIG --libs "xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>/dev/null` + pkg_cv_XORG_LIBS=`$PKG_CONFIG --libs "xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes @@ -18481,14 +18481,14 @@ else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then - XORG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>&1` + XORG_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>&1` else - XORG_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>&1` + XORG_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$XORG_PKG_ERRORS" >&5 - as_fn_error $? "Package requirements (xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES) were not met: + as_fn_error $? "Package requirements (xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES) were not met: $XORG_PKG_ERRORS @@ -18736,6 +18736,16 @@ if test "x$ac_cv_have_decl_GLAMOR_NO_DRI3" = xyes; then : GLAMOR_XSERVER="yes" else GLAMOR_XSERVER="no" +fi + + + ac_fn_c_check_decl "$LINENO" "glamor_glyphs_init" "ac_cv_have_decl_glamor_glyphs_init" "#include \"xorg-server.h\" + #include \"glamor.h\" +" +if test "x$ac_cv_have_decl_glamor_glyphs_init" = xyes; then : + +$as_echo "#define HAVE_GLAMOR_GLYPHS_INIT 1" >>confdefs.h + fi fi @@ -18940,27 +18950,24 @@ else fi -for ac_header in list.h -do : - ac_fn_c_check_header_compile "$LINENO" "list.h" "ac_cv_header_list_h" "#include - #include \"xorg-server.h\" +ac_fn_c_check_decl "$LINENO" "fbGlyphs" "ac_cv_have_decl_fbGlyphs" "#include + #include + #include + #include + #include + #include + #include " -if test "x$ac_cv_header_list_h" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIST_H 1 -_ACEOF - have_list_h="yes" -else - have_list_h="no" +if test "x$ac_cv_have_decl_fbGlyphs" = xyes; then : + +$as_echo "#define HAVE_FBGLYPHS 1" >>confdefs.h + fi -done - -if test "x$have_list_h" = xyes; then - ac_fn_c_check_decl "$LINENO" "xorg_list_init" "ac_cv_have_decl_xorg_list_init" "#include - #include \"xorg-server.h\" - #include \"list.h\" +ac_fn_c_check_decl "$LINENO" "xorg_list_init" "ac_cv_have_decl_xorg_list_init" "#include + #include \"xorg-server.h\" + #include \"list.h\" " if test "x$ac_cv_have_decl_xorg_list_init" = xyes; then : @@ -18968,8 +18975,56 @@ $as_echo "#define HAVE_XORG_LIST 1" >>confdefs.h fi + +for ac_header in misyncshm.h +do : + ac_fn_c_check_header_compile "$LINENO" "misyncshm.h" "ac_cv_header_misyncshm_h" "#include + #include + #include + #include +" +if test "x$ac_cv_header_misyncshm_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_MISYNCSHM_H 1 +_ACEOF + fi +done + + +for ac_header in present.h +do : + ac_fn_c_check_header_compile "$LINENO" "present.h" "ac_cv_header_present_h" "#include + #include + #include + #include \"xorg-server.h\" +" +if test "x$ac_cv_header_present_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_PRESENT_H 1 +_ACEOF + +fi + +done + + +for ac_header in dri3.h +do : + ac_fn_c_check_header_compile "$LINENO" "dri3.h" "ac_cv_header_dri3_h" "#include + #include +" +if test "x$ac_cv_header_dri3_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DRI3_H 1 +_ACEOF + +fi + +done + + CPPFLAGS="$SAVE_CPPFLAGS" @@ -19762,7 +19817,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by xf86-video-ati $as_me 7.5.0, which was +This file was extended by xf86-video-ati $as_me 7.6.1, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19828,7 +19883,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -xf86-video-ati config.status 7.5.0 +xf86-video-ati config.status 7.6.1 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/driver/xf86-video-ati/configure.ac b/driver/xf86-video-ati/configure.ac index d30efafa7..c024d484b 100644 --- a/driver/xf86-video-ati/configure.ac +++ b/driver/xf86-video-ati/configure.ac @@ -23,7 +23,7 @@ # Initialize Autoconf AC_PREREQ([2.60]) AC_INIT([xf86-video-ati], - [7.5.0], + [7.6.1], [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg], [xf86-video-ati]) @@ -75,7 +75,7 @@ PKG_CHECK_MODULES(LIBDRM, [libdrm >= 2.4.58]) PKG_CHECK_MODULES(LIBDRM_RADEON, [libdrm_radeon]) # Obtain compiler/linker options for the driver dependencies -PKG_CHECK_MODULES(XORG, [xorg-server >= 1.7 xproto fontsproto xf86driproto $REQUIRED_MODULES]) +PKG_CHECK_MODULES(XORG, [xorg-server >= 1.8 xproto fontsproto xf86driproto $REQUIRED_MODULES]) PKG_CHECK_MODULES(XEXT, [xextproto >= 7.0.99.1], HAVE_XEXTPROTO_71="yes"; AC_DEFINE(HAVE_XEXTPROTO_71, 1, [xextproto 7.1 available]), HAVE_XEXTPROTO_71="no") @@ -113,6 +113,12 @@ if test "x$GLAMOR" != "xno"; then [GLAMOR_XSERVER="yes"], [GLAMOR_XSERVER="no"], [#include "xorg-server.h" #include "glamor.h"]) + + AC_CHECK_DECL(glamor_glyphs_init, + [AC_DEFINE(HAVE_GLAMOR_GLYPHS_INIT, 1, + [Have glamor_glyphs_init API])], [], + [#include "xorg-server.h" + #include "glamor.h"]) fi if test "x$GLAMOR_XSERVER" != xyes; then @@ -125,18 +131,37 @@ else fi AM_CONDITIONAL(GLAMOR, test x$GLAMOR != xno) -AC_CHECK_HEADERS([list.h], - [have_list_h="yes"], [have_list_h="no"], - [#include - #include "xorg-server.h"]) +AC_CHECK_DECL(fbGlyphs, + [AC_DEFINE(HAVE_FBGLYPHS, 1, [Have fbGlyphs API])], [], + [#include + #include + #include + #include + #include + #include + #include ]) -if test "x$have_list_h" = xyes; then - AC_CHECK_DECL(xorg_list_init, - [AC_DEFINE(HAVE_XORG_LIST, 1, [Have xorg_list API])], [], - [#include - #include "xorg-server.h" - #include "list.h"]) -fi +AC_CHECK_DECL(xorg_list_init, + [AC_DEFINE(HAVE_XORG_LIST, 1, [Have xorg_list API])], [], + [#include + #include "xorg-server.h" + #include "list.h"]) + +AC_CHECK_HEADERS([misyncshm.h], [], [], + [#include + #include + #include + #include ]) + +AC_CHECK_HEADERS([present.h], [], [], + [#include + #include + #include + #include "xorg-server.h"]) + +AC_CHECK_HEADERS([dri3.h], [], [], + [#include + #include ]) CPPFLAGS="$SAVE_CPPFLAGS" diff --git a/driver/xf86-video-ati/man/radeon.man b/driver/xf86-video-ati/man/radeon.man index 7dde04005..fa55c6d14 100644 --- a/driver/xf86-video-ati/man/radeon.man +++ b/driver/xf86-video-ati/man/radeon.man @@ -267,11 +267,23 @@ The default value is for R/RV6XX, R/RV7XX, RS780, RS880, EVERGREEN, CAYMAN, ARUBA, Southern Islands, and Sea Islands. .TP +.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 2 for DRI2. +.TP .BI "Option \*qEnablePageFlip\*q \*q" boolean \*q Enable DRI2 page flipping. The default is .B on. Pageflipping is supported on all radeon hardware. .TP +.BI "Option \*qTearFree\*q \*q" boolean \*q +Enable tearing prevention using the hardware page flipping mechanism. This +option currently doesn't have any effect for rotated CRTCs. It requires +allocating two separate scanout buffers for each non-rotated CRTC. Enabling +this option currently disables Option \*qEnablePageFlip\*q. The default is +.B off. +.TP .BI "Option \*qAccelMethod\*q \*q" "string" \*q Chooses between available acceleration architectures. Valid values are .B EXA @@ -282,6 +294,22 @@ Chooses between available acceleration architectures. Valid values are as of TAHITI, otherwise .B EXA. +.PP +The following driver +.B Options +are supported for +.B glamor +: +.TP +.BI "Option \*qShadowPrimary\*q \*q" boolean \*q +This option enables a so-called "shadow primary" buffer for fast CPU access to +pixel data, and separate scanout buffers for each display controller (CRTC). +This may improve performance for some 2D workloads, potentially at the expense +of other (e.g. 3D, video) workloads. +Note in particular that enabling this option currently disables page flipping. +The default is +.B off. + .PP The following driver .B Options diff --git a/driver/xf86-video-ati/src/Makefile.am b/driver/xf86-video-ati/src/Makefile.am index 9ff1ffba0..8f39e213e 100644 --- a/driver/xf86-video-ati/src/Makefile.am +++ b/driver/xf86-video-ati/src/Makefile.am @@ -27,10 +27,11 @@ # TODO: -nostdlib/-Bstatic/-lgcc platform magic, not installing the .a, etc. ati_drv_la_LIBADD = $(PCIACCESS_LIBS) -radeon_drv_la_LIBADD = $(LIBDRM_RADEON_LIBS) $(PCIACCESS_LIBS) +radeon_drv_la_LIBADD = $(LIBDRM_RADEON_LIBS) -RADEON_KMS_SRCS=radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c \ - radeon_bo_helper.c +RADEON_KMS_SRCS=radeon_dri2.c radeon_dri3.c radeon_drm_queue.c radeon_kms.c \ + radeon_present.c radeon_sync.c radeon_vbo.c radeon_bo_helper.c \ + drmmode_display.c RADEON_EXA_SOURCES = radeon_exa.c r600_exa.c r6xx_accel.c r600_textured_videofuncs.c r600_shader.c radeon_exa_shared.c \ evergreen_exa.c evergreen_accel.c evergreen_shader.c evergreen_textured_videofuncs.c cayman_accel.c cayman_shader.c @@ -64,6 +65,7 @@ if GLAMOR AM_CFLAGS += @LIBGLAMOR_CFLAGS@ radeon_drv_la_LIBADD += @LIBGLAMOR_LIBS@ radeon_drv_la_SOURCES += \ + radeon_glamor_wrappers.c \ radeon_glamor.c endif @@ -88,11 +90,13 @@ EXTRA_DIST = \ bicubic_table.h \ bicubic_table.py \ radeon_bo_helper.h \ + radeon_drm_queue.h \ radeon_exa_render.c \ radeon_exa_funcs.c \ radeon_exa_shared.h \ radeon_glamor.h \ radeon.h \ + radeon_list.h \ radeon_probe.h \ radeon_reg.h \ radeon_version.h \ diff --git a/driver/xf86-video-ati/src/Makefile.in b/driver/xf86-video-ati/src/Makefile.in index a84f7d64b..fdb64e268 100644 --- a/driver/xf86-video-ati/src/Makefile.in +++ b/driver/xf86-video-ati/src/Makefile.in @@ -81,6 +81,7 @@ host_triplet = @host@ @GLAMOR_TRUE@am__append_2 = @LIBGLAMOR_CFLAGS@ @GLAMOR_TRUE@am__append_3 = @LIBGLAMOR_LIBS@ @GLAMOR_TRUE@am__append_4 = \ +@GLAMOR_TRUE@ radeon_glamor_wrappers.c \ @GLAMOR_TRUE@ radeon_glamor.c subdir = src @@ -137,24 +138,26 @@ ati_drv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(ati_drv_la_LDFLAGS) $(LDFLAGS) -o $@ @LIBUDEV_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) radeon_drv_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) am__radeon_drv_la_SOURCES_DIST = radeon_accel.c radeon_video.c \ radeon_misc.c radeon_probe.c radeon_textured_video.c \ radeon_xvmc.c radeon_exa.c r600_exa.c r6xx_accel.c \ r600_textured_videofuncs.c r600_shader.c radeon_exa_shared.c \ evergreen_exa.c evergreen_accel.c evergreen_shader.c \ evergreen_textured_videofuncs.c cayman_accel.c cayman_shader.c \ - radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c \ - radeon_bo_helper.c radeon_glamor.c + radeon_dri2.c radeon_dri3.c radeon_drm_queue.c radeon_kms.c \ + radeon_present.c radeon_sync.c radeon_vbo.c radeon_bo_helper.c \ + drmmode_display.c radeon_glamor_wrappers.c radeon_glamor.c am__objects_1 = radeon_exa.lo r600_exa.lo r6xx_accel.lo \ r600_textured_videofuncs.lo r600_shader.lo \ radeon_exa_shared.lo evergreen_exa.lo evergreen_accel.lo \ evergreen_shader.lo evergreen_textured_videofuncs.lo \ cayman_accel.lo cayman_shader.lo -am__objects_2 = radeon_dri2.lo radeon_kms.lo drmmode_display.lo \ - radeon_vbo.lo radeon_bo_helper.lo -@GLAMOR_TRUE@am__objects_3 = radeon_glamor.lo +am__objects_2 = radeon_dri2.lo radeon_dri3.lo radeon_drm_queue.lo \ + radeon_kms.lo radeon_present.lo radeon_sync.lo radeon_vbo.lo \ + radeon_bo_helper.lo drmmode_display.lo +@GLAMOR_TRUE@am__objects_3 = radeon_glamor_wrappers.lo \ +@GLAMOR_TRUE@ radeon_glamor.lo am_radeon_drv_la_OBJECTS = radeon_accel.lo radeon_video.lo \ radeon_misc.lo radeon_probe.lo radeon_textured_video.lo \ radeon_xvmc.lo $(am__objects_1) $(am__objects_2) \ @@ -363,10 +366,11 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ ati_drv_la_LIBADD = $(PCIACCESS_LIBS) -radeon_drv_la_LIBADD = $(LIBDRM_RADEON_LIBS) $(PCIACCESS_LIBS) \ - $(am__append_1) $(am__append_3) -RADEON_KMS_SRCS = radeon_dri2.c radeon_kms.c drmmode_display.c radeon_vbo.c \ - radeon_bo_helper.c +radeon_drv_la_LIBADD = $(LIBDRM_RADEON_LIBS) $(am__append_1) \ + $(am__append_3) +RADEON_KMS_SRCS = radeon_dri2.c radeon_dri3.c radeon_drm_queue.c radeon_kms.c \ + radeon_present.c radeon_sync.c radeon_vbo.c radeon_bo_helper.c \ + drmmode_display.c RADEON_EXA_SOURCES = radeon_exa.c r600_exa.c r6xx_accel.c r600_textured_videofuncs.c r600_shader.c radeon_exa_shared.c \ evergreen_exa.c evergreen_accel.c evergreen_shader.c evergreen_textured_videofuncs.c cayman_accel.c cayman_shader.c @@ -406,11 +410,13 @@ EXTRA_DIST = \ bicubic_table.h \ bicubic_table.py \ radeon_bo_helper.h \ + radeon_drm_queue.h \ radeon_exa_render.c \ radeon_exa_funcs.c \ radeon_exa_shared.h \ radeon_glamor.h \ radeon.h \ + radeon_list.h \ radeon_probe.h \ radeon_reg.h \ radeon_version.h \ @@ -558,12 +564,17 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_accel.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_bo_helper.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_dri2.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_dri3.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_drm_queue.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_exa.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_exa_shared.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_glamor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_glamor_wrappers.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_kms.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_misc.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_present.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_probe.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_sync.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_textured_video.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_vbo.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radeon_video.Plo@am__quote@ diff --git a/driver/xf86-video-ati/src/ati_pciids_gen.h b/driver/xf86-video-ati/src/ati_pciids_gen.h index d867fa71e..c6216a54c 100644 --- a/driver/xf86-video-ati/src/ati_pciids_gen.h +++ b/driver/xf86-video-ati/src/ati_pciids_gen.h @@ -692,6 +692,7 @@ #define PCI_CHIP_OLAND_6610 0x6610 #define PCI_CHIP_OLAND_6611 0x6611 #define PCI_CHIP_OLAND_6613 0x6613 +#define PCI_CHIP_OLAND_6617 0x6617 #define PCI_CHIP_OLAND_6620 0x6620 #define PCI_CHIP_OLAND_6621 0x6621 #define PCI_CHIP_OLAND_6623 0x6623 @@ -712,6 +713,7 @@ #define PCI_CHIP_BONAIRE_6658 0x6658 #define PCI_CHIP_BONAIRE_665C 0x665C #define PCI_CHIP_BONAIRE_665D 0x665D +#define PCI_CHIP_BONAIRE_665F 0x665F #define PCI_CHIP_KABINI_9830 0x9830 #define PCI_CHIP_KABINI_9831 0x9831 #define PCI_CHIP_KABINI_9832 0x9832 diff --git a/driver/xf86-video-ati/src/drmmode_display.c b/driver/xf86-video-ati/src/drmmode_display.c index c8f060a76..4c8931eea 100644 --- a/driver/xf86-video-ati/src/drmmode_display.c +++ b/driver/xf86-video-ati/src/drmmode_display.c @@ -32,11 +32,13 @@ #include #include #include +#include "cursorstr.h" +#include "damagestr.h" #include "micmap.h" #include "xf86cmap.h" #include "radeon.h" +#include "radeon_glamor.h" #include "radeon_reg.h" -#include "sarea.h" #include "drmmode_display.h" @@ -97,7 +99,8 @@ static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, PixmapPtr pixmap; struct radeon_surface *surface; - pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); + pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, + RADEON_CREATE_PIXMAP_SCANOUT); if (!pixmap) return NULL; @@ -147,7 +150,9 @@ static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, } } - if (!radeon_glamor_create_textured_pixmap(pixmap)) { + if (info->use_glamor && + !radeon_glamor_create_textured_pixmap(pixmap, + radeon_get_pixmap_private(pixmap))) { pScreen->DestroyPixmap(pixmap); return NULL; } @@ -245,6 +250,33 @@ int drmmode_get_current_ust(int drm_fd, CARD64 *ust) return 0; } +/* + * Get current frame count and frame count timestamp of the crtc. + */ +int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) +{ + ScrnInfoPtr scrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(scrn); + drmVBlank vbl; + int ret; + + vbl.request.type = DRM_VBLANK_RELATIVE; + vbl.request.type |= radeon_populate_vbl_request_type(crtc); + vbl.request.sequence = 0; + + ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "get vblank counter failed: %s\n", strerror(errno)); + return ret; + } + + *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; + *msc = vbl.reply.sequence; + + return Success; +} + static void drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) { @@ -310,18 +342,31 @@ drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) static void drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) { - /* Nothing to do. drmmode_do_crtc_dpms() is called as appropriate */ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + + /* Disable unused CRTCs */ + if (!crtc->enabled || mode != DPMSModeOn) + drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + 0, 0, 0, NULL, 0, NULL); + else if (drmmode_crtc->dpms_mode != DPMSModeOn) + crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, + crtc->x, crtc->y); } static PixmapPtr create_pixmap_for_fbcon(drmmode_ptr drmmode, ScrnInfoPtr pScrn, int fbcon_id) { - PixmapPtr pixmap = NULL; + RADEONInfoPtr info = RADEONPTR(pScrn); + PixmapPtr pixmap = info->fbcon_pixmap; struct radeon_bo *bo; drmModeFBPtr fbcon; struct drm_gem_flink flink; + if (pixmap) + return pixmap; + fbcon = drmModeGetFB(drmmode->fd, fbcon_id); if (fbcon == NULL) return NULL; @@ -348,12 +393,32 @@ create_pixmap_for_fbcon(drmmode_ptr drmmode, pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, fbcon->depth, fbcon->bpp, fbcon->pitch, 0, bo, NULL); + info->fbcon_pixmap = pixmap; radeon_bo_unref(bo); out_free_fb: drmModeFreeFB(fbcon); return pixmap; } +static void +destroy_pixmap_for_fbcon(ScrnInfoPtr pScrn) +{ + RADEONInfoPtr info = RADEONPTR(pScrn); + + /* XXX: The current GPUVM support in the kernel doesn't allow removing + * the virtual address range for this BO, so we need to keep around + * the pixmap to avoid breaking glamor with GPUVM + */ + if (info->use_glamor && info->ChipFamily >= CHIP_FAMILY_CAYMAN) + return; + + if (info->fbcon_pixmap) + pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap); + info->fbcon_pixmap = NULL; +} + +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 + void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); @@ -361,13 +426,9 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) PixmapPtr src, dst; ScreenPtr pScreen = pScrn->pScreen; int fbcon_id = 0; + Bool force; + GCPtr gc; int i; - int pitch; - uint32_t tiling_flags = 0; - Bool ret; - - if (info->accelOn == FALSE || info->use_glamor) - goto fallback; for (i = 0; i < xf86_config->num_crtc; i++) { drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; @@ -377,7 +438,7 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) } if (!fbcon_id) - goto fallback; + return; if (fbcon_id == drmmode->fb_id) { /* in some rare case there might be no fbcon and we might already @@ -390,54 +451,165 @@ void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); if (!src) - goto fallback; - - if (info->allowColorTiling) { - if (info->ChipFamily >= CHIP_FAMILY_R600) { - if (info->allowColorTiling2D) { - tiling_flags |= RADEON_TILING_MACRO; - } else { - tiling_flags |= RADEON_TILING_MICRO; - } - } else - tiling_flags |= RADEON_TILING_MACRO; - } - - pitch = RADEON_ALIGN(pScrn->displayWidth, - drmmode_get_pitch_align(pScrn, info->pixel_bytes, tiling_flags)) * - info->pixel_bytes; - - dst = drmmode_create_bo_pixmap(pScrn, pScrn->virtualX, - pScrn->virtualY, pScrn->depth, - pScrn->bitsPerPixel, pitch, - tiling_flags, info->front_bo, &info->front_surface); - if (!dst) - goto out_free_src; - - ret = info->accel_state->exa->PrepareCopy (src, dst, - -1, -1, GXcopy, FB_ALLONES); - if (!ret) - goto out_free_src; - info->accel_state->exa->Copy (dst, 0, 0, 0, 0, - pScrn->virtualX, pScrn->virtualY); - info->accel_state->exa->DoneCopy (dst); - radeon_cs_flush_indirect(pScrn); - -#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 - pScreen->canDoBGNoneRoot = TRUE; -#endif - drmmode_destroy_bo_pixmap(dst); - out_free_src: - drmmode_destroy_bo_pixmap(src); - return; - -fallback: - /* map and memset the bo */ - if (radeon_bo_map(info->front_bo, 1)) return; - memset(info->front_bo->ptr, 0x00, info->front_bo->size); - radeon_bo_unmap(info->front_bo); + dst = pScreen->GetScreenPixmap(pScreen); + + gc = GetScratchGC(pScrn->depth, pScreen); + ValidateGC(&dst->drawable, gc); + + force = info->accel_state->force; + info->accel_state->force = TRUE; + (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, + pScrn->virtualX, pScrn->virtualY, 0, 0); + info->accel_state->force = force; + + FreeScratchGC(gc); + + radeon_cs_flush_indirect(pScrn); + radeon_bo_wait(info->front_bo); + + pScreen->canDoBGNoneRoot = TRUE; + destroy_pixmap_for_fbcon(pScrn); + return; +} + +#endif /* GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 */ + +static void +drmmode_crtc_scanout_destroy(drmmode_ptr drmmode, + struct drmmode_scanout *scanout) +{ + if (scanout->pixmap) { + drmmode_destroy_bo_pixmap(scanout->pixmap); + scanout->pixmap = NULL; + } + + if (scanout->bo) { + drmModeRmFB(drmmode->fd, scanout->fb_id); + scanout->fb_id = 0; + radeon_bo_unmap(scanout->bo); + radeon_bo_unref(scanout->bo); + scanout->bo = NULL; + } + + if (scanout->damage) { + DamageDestroy(scanout->damage); + scanout->damage = NULL; + } +} + +void +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]); + } +} + +static void * +drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc, + struct drmmode_scanout *scanout, + int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + int aligned_height; + int size; + int ret; + unsigned long rotate_pitch; + int base_align; + + if (scanout->bo) { + if (scanout->width == width && scanout->height == height) + return scanout->bo->ptr; + + drmmode_crtc_scanout_destroy(drmmode, scanout); + } + + rotate_pitch = + RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) + * drmmode->cpp; + aligned_height = RADEON_ALIGN(height, drmmode_get_height_align(pScrn, 0)); + base_align = drmmode_get_base_align(pScrn, drmmode->cpp, 0); + size = RADEON_ALIGN(rotate_pitch * aligned_height, RADEON_GPU_PAGE_SIZE); + + scanout->bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, + RADEON_GEM_DOMAIN_VRAM, 0); + if (scanout->bo == NULL) + return NULL; + + radeon_bo_map(scanout->bo, 1); + + ret = drmModeAddFB(drmmode->fd, width, height, pScrn->depth, + pScrn->bitsPerPixel, rotate_pitch, + scanout->bo->handle, + &scanout->fb_id); + if (ret) { + ErrorF("failed to add scanout fb\n"); + radeon_bo_unref(scanout->bo); + scanout->bo = NULL; + return NULL; + } + + scanout->width = width; + scanout->height = height; + return scanout->bo->ptr; +} + +static PixmapPtr +drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout, + int width, int height) +{ + ScrnInfoPtr pScrn = crtc->scrn; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + unsigned long rotate_pitch; + + if (scanout->pixmap) { + if (scanout->width == width && scanout->height == height) + return scanout->pixmap; + + drmmode_crtc_scanout_destroy(drmmode, scanout); + } + + if (!scanout->bo) { + if (!drmmode_crtc_scanout_allocate(crtc, scanout, width, height)) + return NULL; + } + + rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) + * drmmode->cpp; + + scanout->pixmap = drmmode_create_bo_pixmap(pScrn, + width, height, + pScrn->depth, + pScrn->bitsPerPixel, + rotate_pitch, + 0, scanout->bo, NULL); + if (scanout->pixmap == NULL) + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Couldn't allocate scanout pixmap for CRTC\n"); + + return scanout->pixmap; +} + +static void +radeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) +{ + /* Only keep track of the extents */ + RegionUninit(&damage->damage); + damage->damage.data = NULL; } static Bool @@ -452,7 +624,7 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, int saved_x, saved_y; Rotation saved_rotation; DisplayModeRec saved_mode; - uint32_t *output_ids; + uint32_t *output_ids = NULL; int output_count = 0; Bool ret = TRUE; int i; @@ -460,7 +632,6 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, drmModeModeInfo kmode; int pitch; uint32_t tiling_flags = 0; - int height; if (info->allowColorTiling) { if (info->ChipFamily >= CHIP_FAMILY_R600) @@ -471,14 +642,13 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, info->pixel_bytes, tiling_flags)) * info->pixel_bytes; - height = RADEON_ALIGN(pScrn->virtualY, drmmode_get_height_align(pScrn, tiling_flags)); if (info->ChipFamily >= CHIP_FAMILY_R600) { pitch = info->front_surface.level[0].pitch_bytes; } if (drmmode->fb_id == 0) { ret = drmModeAddFB(drmmode->fd, - pScrn->virtualX, height, + pScrn->virtualX, pScrn->virtualY, pScrn->depth, pScrn->bitsPerPixel, pitch, info->front_bo->handle, @@ -500,15 +670,15 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, crtc->y = y; crtc->rotation = rotation; crtc->transformPresent = FALSE; - } - output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); - if (!output_ids) { - ret = FALSE; - goto done; - } + output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); + if (!output_ids) { + ret = FALSE; + goto done; + } + + ScreenPtr pScreen = pScrn->pScreen; - if (mode) { for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; drmmode_output_private_ptr drmmode_output; @@ -532,24 +702,76 @@ 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->scanout_pixmap_x; + 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]); } else #endif - if (drmmode_crtc->rotate_fb_id) { - fb_id = drmmode_crtc->rotate_fb_id; + if (drmmode_crtc->rotate.fb_id) { + 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]); + } else if (info->tear_free || info->shadow_primary) { + for (i = 0; i < (info->tear_free ? 2 : 1); i++) { + drmmode_crtc_scanout_create(crtc, + &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); + 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)) { + drmmode_crtc->scanout_id = 0; + fb_id = drmmode_crtc->scanout[0].fb_id; + x = y = 0; + + radeon_scanout_update_handler(pScrn, 0, 0, crtc); + radeon_bo_wait(drmmode_crtc->scanout[0].bo); + } } - ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, - fb_id, x, y, output_ids, output_count, &kmode); - if (ret) + if (drmModeSetCrtc(drmmode->fd, + drmmode_crtc->mode_crtc->crtc_id, + fb_id, x, y, output_ids, + output_count, &kmode) != 0) { xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, - "failed to set mode: %s", strerror(-ret)); - else + "failed to set mode: %s", strerror(errno)); + ret = FALSE; + goto done; + } else ret = TRUE; if (crtc->scrn->pScreen) xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); + + drmmode_crtc->need_modeset = FALSE; + /* go through all the outputs and force DPMS them back on? */ for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; @@ -576,6 +798,7 @@ done: else crtc->active = TRUE; #endif + free(output_ids); return ret; } @@ -634,6 +857,22 @@ drmmode_show_cursor (xf86CrtcPtr crtc) drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; uint32_t handle = drmmode_crtc->cursor_bo->handle; + static Bool use_set_cursor2 = TRUE; + + if (use_set_cursor2) { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); + CursorPtr cursor = xf86_config->cursor; + int ret; + + ret = + drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, + handle, info->cursor_w, info->cursor_h, + cursor->bits->xhot, cursor->bits->yhot); + if (ret == -EINVAL) + use_set_cursor2 = FALSE; + else + return; + } drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, info->cursor_w, info->cursor_h); @@ -642,73 +881,22 @@ drmmode_show_cursor (xf86CrtcPtr crtc) static void * drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) { - ScrnInfoPtr pScrn = crtc->scrn; - RADEONInfoPtr info = RADEONPTR(pScrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - int size; - struct radeon_bo *rotate_bo; - int ret; - unsigned long rotate_pitch; - int base_align; - /* rotation requires acceleration */ - if (info->r600_shadow_fb) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Rotation requires acceleration!\n"); - return NULL; - } - - rotate_pitch = - RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp; - height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0)); - base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0); - size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE); - - rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0); - if (rotate_bo == NULL) - return NULL; - - radeon_bo_map(rotate_bo, 1); - - ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, - crtc->scrn->bitsPerPixel, rotate_pitch, - rotate_bo->handle, - &drmmode_crtc->rotate_fb_id); - if (ret) { - ErrorF("failed to add rotate fb\n"); - } - - drmmode_crtc->rotate_bo = rotate_bo; - return drmmode_crtc->rotate_bo->ptr; + return drmmode_crtc_scanout_allocate(crtc, &drmmode_crtc->rotate, + width, height); } static PixmapPtr drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) { - ScrnInfoPtr pScrn = crtc->scrn; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - drmmode_ptr drmmode = drmmode_crtc->drmmode; - unsigned long rotate_pitch; - PixmapPtr rotate_pixmap; - - if (!data) - data = drmmode_crtc_shadow_allocate (crtc, width, height); - - rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) * drmmode->cpp; - - rotate_pixmap = drmmode_create_bo_pixmap(pScrn, - width, height, - pScrn->depth, - pScrn->bitsPerPixel, - rotate_pitch, - 0, drmmode_crtc->rotate_bo, NULL); - if (rotate_pixmap == NULL) { - xf86DrvMsg(pScrn->scrnIndex, X_ERROR, - "Couldn't allocate shadow pixmap for rotated CRTC\n"); - } - return rotate_pixmap; + /* Xorg passes in the return value of drmmode_crtc_shadow_allocate + * for data, but that's redundant for drmmode_crtc_scanout_create. + */ + return drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, + height); } static void @@ -717,17 +905,7 @@ drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *dat drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; - if (rotate_pixmap) - drmmode_destroy_bo_pixmap(rotate_pixmap); - - if (data) { - drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); - drmmode_crtc->rotate_fb_id = 0; - radeon_bo_unmap(drmmode_crtc->rotate_bo); - radeon_bo_unref(drmmode_crtc->rotate_bo); - drmmode_crtc->rotate_bo = NULL; - } - + drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); } static void @@ -754,7 +932,7 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) if (!ppix) { if (crtc->randr_crtc->scanout_pixmap) PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix); - drmmode_crtc->scanout_pixmap_x = 0; + drmmode_crtc->prime_pixmap_x = 0; return TRUE; } @@ -793,8 +971,10 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) screen->width = screenpix->drawable.width = total_width; screen->height = screenpix->drawable.height = max_height; } - drmmode_crtc->scanout_pixmap_x = this_x; -#ifdef HAS_DIRTYTRACKING2 + drmmode_crtc->prime_pixmap_x = this_x; +#ifdef HAS_DIRTYTRACKING_ROTATION + PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0); +#elif defined(HAS_DIRTYTRACKING2) PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0); #else PixmapStartDirtyTracking(ppix, screenpix, 0, 0); @@ -803,7 +983,7 @@ drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) } #endif -static const xf86CrtcFuncsRec drmmode_crtc_funcs = { +static xf86CrtcFuncsRec drmmode_crtc_funcs = { .dpms = drmmode_crtc_dpms, .set_mode_major = drmmode_set_mode_major, .set_cursor_colors = drmmode_set_cursor_colors, @@ -849,23 +1029,29 @@ void drmmode_crtc_hw_id(xf86CrtcPtr crtc) drmmode_crtc->hw_id = tmp; } -static void -drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) +static unsigned int +drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) { xf86CrtcPtr crtc; drmmode_crtc_private_ptr drmmode_crtc; + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); if (crtc == NULL) - return; + return 0; drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); - drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); + drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]); drmmode_crtc->drmmode = drmmode; crtc->driver_private = drmmode_crtc; drmmode_crtc_hw_id(crtc); - return; + /* Mark num'th crtc as in use on this device. */ + pRADEONEnt->assigned_crtcs |= (1 << num); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Allocated crtc nr. %d to this screen.\n", num); + + return 1; } static xf86OutputStatus @@ -975,17 +1161,28 @@ static void drmmode_output_dpms(xf86OutputPtr output, int mode) { drmmode_output_private_ptr drmmode_output = output->driver_private; + xf86CrtcPtr crtc = output->crtc; drmModeConnectorPtr koutput = drmmode_output->mode_output; drmmode_ptr drmmode = drmmode_output->drmmode; - if (mode != DPMSModeOn && output->crtc) - drmmode_do_crtc_dpms(output->crtc, mode); + if (!koutput) + return; + + if (mode != DPMSModeOn && crtc) + drmmode_do_crtc_dpms(crtc, mode); drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, drmmode_output->dpms_enum_id, mode); - if (mode == DPMSModeOn && output->crtc) - drmmode_do_crtc_dpms(output->crtc, mode); + if (mode == DPMSModeOn && crtc) { + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (drmmode_crtc->need_modeset) + drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, + crtc->y); + else + drmmode_do_crtc_dpms(crtc, mode); + } } @@ -1194,22 +1391,137 @@ const char *output_names[] = { "None", #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) -static void -drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dvi, int *num_hdmi) +static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + drmmode_output_private_ptr drmmode_output; + + drmmode_output = output->driver_private; + if (drmmode_output->output_id == id) + return output; + } + return NULL; +} + +static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) +{ + char *conn; + char conn_id[5]; + int id, len; + char *blob_data; + + if (!path_blob) + return -1; + + blob_data = path_blob->data; + /* we only handle MST paths for now */ + if (strncmp(blob_data, "mst:", 4)) + return -1; + + conn = strchr(blob_data + 4, '-'); + if (!conn) + return -1; + len = conn - (blob_data + 4); + if (len + 1 > 5) + return -1; + memcpy(conn_id, blob_data + 4, len); + conn_id[len] = '\0'; + id = strtoul(conn_id, NULL, 10); + + *conn_base_id = id; + + *path = conn + 1; + return 0; +} + +static void +drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, + drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) +{ + xf86OutputPtr output; + int conn_id; + char *extra_path; + + output = NULL; + if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) + output = find_output(pScrn, conn_id); + if (output) { + snprintf(name, 32, "%s-%s", output->name, extra_path); + } else { + if (koutput->connector_type >= NUM_OUTPUT_NAMES) + snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, + koutput->connector_type_id - 1); +#ifdef RADEON_PIXMAP_SHARING + else if (pScrn->is_gpu) + snprintf(name, 32, "%s-%d-%d", + output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, + koutput->connector_type_id - 1); +#endif + else { + /* need to do smart conversion here for compat with non-kms ATI driver */ + if (koutput->connector_type_id == 1) { + switch(koutput->connector_type) { + case DRM_MODE_CONNECTOR_DVII: + case DRM_MODE_CONNECTOR_DVID: + case DRM_MODE_CONNECTOR_DVIA: + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); + (*num_dvi)++; + break; + case DRM_MODE_CONNECTOR_HDMIA: + case DRM_MODE_CONNECTOR_HDMIB: + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); + (*num_hdmi)++; + break; + case DRM_MODE_CONNECTOR_VGA: + case DRM_MODE_CONNECTOR_DisplayPort: + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], + koutput->connector_type_id - 1); + break; + default: + snprintf(name, 32, "%s", output_names[koutput->connector_type]); + break; + } + } else { + snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], + koutput->connector_type_id - 1); + } + } + } +} + +static unsigned int +drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); RADEONInfoPtr info = RADEONPTR(pScrn); xf86OutputPtr output; drmModeConnectorPtr koutput; drmModeEncoderPtr *kencoders = NULL; drmmode_output_private_ptr drmmode_output; drmModePropertyPtr props; + drmModePropertyBlobPtr path_blob = NULL; char name[32]; int i; const char *s; - koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); + koutput = drmModeGetConnector(drmmode->fd, mode_res->connectors[num]); if (!koutput) - return; + return 0; + + for (i = 0; i < koutput->count_props; i++) { + props = drmModeGetProperty(drmmode->fd, koutput->props[i]); + if (props && (props->flags & DRM_MODE_PROP_BLOB)) { + if (!strcmp(props->name, "PATH")) { + path_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); + drmModeFreeProperty(props); + break; + } + drmModeFreeProperty(props); + } + } kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); if (!kencoders) { @@ -1223,42 +1535,27 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dv } } - if (koutput->connector_type >= NUM_OUTPUT_NAMES) - snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, - koutput->connector_type_id - 1); -#ifdef RADEON_PIXMAP_SHARING - else if (pScrn->is_gpu) - snprintf(name, 32, "%s-%d-%d", - output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, - koutput->connector_type_id - 1); -#endif - else { - /* need to do smart conversion here for compat with non-kms ATI driver */ - if (koutput->connector_type_id == 1) { - switch(koutput->connector_type) { - case DRM_MODE_CONNECTOR_DVII: - case DRM_MODE_CONNECTOR_DVID: - case DRM_MODE_CONNECTOR_DVIA: - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); - (*num_dvi)++; - break; - case DRM_MODE_CONNECTOR_HDMIA: - case DRM_MODE_CONNECTOR_HDMIB: - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); - (*num_hdmi)++; - break; - case DRM_MODE_CONNECTOR_VGA: - case DRM_MODE_CONNECTOR_DisplayPort: - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], - koutput->connector_type_id - 1); - break; - default: - snprintf(name, 32, "%s", output_names[koutput->connector_type]); - break; - } - } else { - snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], - koutput->connector_type_id - 1); + drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); + if (path_blob) + drmModeFreePropertyBlob(path_blob); + + if (path_blob && dynamic) { + /* See if we have an output with this name already + * and hook stuff up. + */ + for (i = 0; i < xf86_config->num_output; i++) { + output = xf86_config->output[i]; + + if (strncmp(output->name, name, 32)) + continue; + + drmmode_output = output->driver_private; + drmmode_output->output_id = mode_res->connectors[num]; + drmmode_output->mode_output = koutput; + for (i = 0; i < koutput->count_encoders; i++) + drmModeFreeEncoder(kencoders[i]); + free(kencoders); + return 0; } } @@ -1267,7 +1564,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dv if (!RADEONZaphodStringMatches(pScrn, s, name)) goto out_free_encoders; } else { - if (info->IsPrimary && (num != 0)) + if (!info->IsSecondary && (num != 0)) goto out_free_encoders; else if (info->IsSecondary && (num != 1)) goto out_free_encoders; @@ -1285,7 +1582,7 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dv goto out_free_encoders; } - drmmode_output->output_id = drmmode->mode_res->connectors[num]; + drmmode_output->output_id = mode_res->connectors[num]; drmmode_output->mode_output = koutput; drmmode_output->mode_encoders = kencoders; drmmode_output->drmmode = drmmode; @@ -1316,7 +1613,12 @@ drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dv } } - return; + if (dynamic) { + output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); + drmmode_output_create_resources(output); + } + + return 1; out_free_encoders: if (kencoders){ for (i = 0; i < koutput->count_encoders; i++) @@ -1324,7 +1626,7 @@ out_free_encoders: free(kencoders); } drmModeFreeConnector(koutput); - + return 0; } uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) @@ -1354,7 +1656,7 @@ uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) static void -drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) +drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) { int i, j; xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); @@ -1369,8 +1671,8 @@ drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) { int k; - for (k = 0; k < drmmode->mode_res->count_encoders; k++) { - if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) + for (k = 0; k < mode_res->count_encoders; k++) { + if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) drmmode_output->enc_mask |= (1 << k); } @@ -1488,6 +1790,7 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) ScreenPtr screen = xf86ScrnToScreen(scrn); uint32_t old_fb_id; int i, pitch, old_width, old_height, old_pitch; + int aligned_height; uint32_t screen_size; int cpp = info->pixel_bytes; struct radeon_bo *front_bo; @@ -1496,6 +1799,9 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) uint32_t tiling_flags = 0, base_align; PixmapPtr ppix = screen->GetScreenPixmap(screen); void *fb_shadow; + xRectangle rect; + Bool force; + GCPtr gc; if (scrn->virtualX == width && scrn->virtualY == height) return TRUE; @@ -1506,7 +1812,7 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) if (front_bo) radeon_bo_wait(front_bo); - if (info->allowColorTiling) { + if (info->allowColorTiling && !info->shadow_primary) { if (info->ChipFamily >= CHIP_FAMILY_R600) { if (info->allowColorTiling2D) { tiling_flags |= RADEON_TILING_MACRO; @@ -1518,8 +1824,8 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) } pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp; - height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags)); - screen_size = RADEON_ALIGN(pitch * height, RADEON_GPU_PAGE_SIZE); + aligned_height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags)); + screen_size = RADEON_ALIGN(pitch * aligned_height, RADEON_GPU_PAGE_SIZE); base_align = 4096; if (info->ChipFamily >= CHIP_FAMILY_R600) { memset(&surface, 0, sizeof(struct radeon_surface)); @@ -1562,7 +1868,9 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; - tiling_flags |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; + if (surface.tile_split) + tiling_flags |= eg_tile_split(surface.tile_split) + << RADEON_TILING_EG_TILE_SPLIT_SHIFT; break; case RADEON_SURF_MODE_1D: tiling_flags |= RADEON_TILING_MICRO; @@ -1587,7 +1895,10 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) scrn->virtualY = height; scrn->displayWidth = pitch / cpp; - info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, RADEON_GEM_DOMAIN_VRAM, 0); + info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, + info->shadow_primary ? + RADEON_GEM_DOMAIN_GTT : + RADEON_GEM_DOMAIN_VRAM, 0); if (!info->front_bo) goto fail; @@ -1636,6 +1947,24 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr; #endif + if (info->use_glamor) + radeon_glamor_create_screen_resources(scrn->pScreen); + + /* Clear new buffer */ + gc = GetScratchGC(ppix->drawable.depth, scrn->pScreen); + force = info->accel_state->force; + info->accel_state->force = TRUE; + ValidateGC(&ppix->drawable, gc); + rect.x = 0; + rect.y = 0; + rect.width = width; + rect.height = height; + (*gc->ops->PolyFillRect)(&ppix->drawable, gc, 1, &rect); + FreeScratchGC(gc); + info->accel_state->force = force; + radeon_cs_flush_indirect(scrn); + radeon_bo_wait(info->front_bo); + for (i = 0; i < xf86_config->num_crtc; i++) { xf86CrtcPtr crtc = xf86_config->crtc[i]; @@ -1646,9 +1975,6 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) crtc->rotation, crtc->x, crtc->y); } - if (info->use_glamor) - radeon_glamor_create_screen_resources(scrn->pScreen); - if (old_fb_id) drmModeRmFB(drmmode->fd, old_fb_id); if (old_front) @@ -1674,45 +2000,55 @@ static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { }; static void -drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) +drmmode_flip_free(drmmode_flipevtcarrier_ptr flipcarrier) { - radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data); + drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; + + free(flipcarrier); + + if (--flipdata->flip_count > 0) + return; + + free(flipdata); } static void -drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) +drmmode_flip_abort(ScrnInfoPtr scrn, void *event_data) +{ + drmmode_flipevtcarrier_ptr flipcarrier = event_data; + drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; + + if (flipdata->flip_count == 1) + flipdata->abort(scrn, flipdata->event_data); + + drmmode_flip_free(flipcarrier); +} + +static void +drmmode_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, void *event_data) { drmmode_flipevtcarrier_ptr flipcarrier = event_data; drmmode_flipdata_ptr flipdata = flipcarrier->flipdata; - drmmode_ptr drmmode = flipdata->drmmode; /* Is this the event whose info shall be delivered to higher level? */ if (flipcarrier->dispatch_me) { /* Yes: Cache msc, ust for later delivery. */ flipdata->fe_frame = frame; - flipdata->fe_tv_sec = tv_sec; - flipdata->fe_tv_usec = tv_usec; + flipdata->fe_usec = usec; } - free(flipcarrier); - /* Last crtc completed flip? */ - flipdata->flip_count--; - if (flipdata->flip_count > 0) - return; + if (flipdata->flip_count == 1) { + /* Deliver cached msc, ust from reference crtc to flip event handler */ + if (flipdata->event_data) + flipdata->handler(scrn, flipdata->fe_frame, + flipdata->fe_usec, + flipdata->event_data); - /* Release framebuffer */ - drmModeRmFB(drmmode->fd, flipdata->old_fb_id); + /* Release framebuffer */ + drmModeRmFB(flipdata->drmmode->fd, flipdata->old_fb_id); + } - if (flipdata->event_data == NULL) - return; - - /* Deliver cached msc, ust from reference crtc to flip event handler */ - radeon_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec, - flipdata->fe_tv_usec, flipdata->event_data); - - free(flipdata); + drmmode_flip_free(flipcarrier); } @@ -1729,26 +2065,51 @@ drm_wakeup_handler(pointer data, int err, pointer p) Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) { + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + RADEONInfoPtr info = RADEONPTR(pScrn); int i, num_dvi = 0, num_hdmi = 0; + drmModeResPtr mode_res; + unsigned int crtcs_needed = 0; xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); drmmode->scrn = pScrn; drmmode->cpp = cpp; - drmmode->mode_res = drmModeGetResources(drmmode->fd); - if (!drmmode->mode_res) + mode_res = drmModeGetResources(drmmode->fd); + if (!mode_res) return FALSE; - xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); - for (i = 0; i < drmmode->mode_res->count_crtcs; i++) - if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i) - drmmode_crtc_init(pScrn, drmmode, i); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "Initializing outputs ...\n"); + for (i = 0; i < mode_res->count_connectors; i++) + crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, + i, &num_dvi, &num_hdmi, 0); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "%d crtcs needed for screen.\n", crtcs_needed); - for (i = 0; i < drmmode->mode_res->count_connectors; i++) - drmmode_output_init(pScrn, drmmode, i, &num_dvi, &num_hdmi); + if (info->r600_shadow_fb) { + /* Rotation requires hardware acceleration */ + drmmode_crtc_funcs.shadow_allocate = NULL; + drmmode_crtc_funcs.shadow_create = NULL; + drmmode_crtc_funcs.shadow_destroy = NULL; + } + + drmmode->count_crtcs = mode_res->count_crtcs; + xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height); + + for (i = 0; i < mode_res->count_crtcs; i++) + if (!xf86IsEntityShared(pScrn->entityList[0]) || + (crtcs_needed && !(pRADEONEnt->assigned_crtcs & (1 << i)))) + crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); + + /* All ZaphodHeads outputs provided with matching crtcs? */ + if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", + crtcs_needed); /* workout clones */ - drmmode_clones_init(pScrn, drmmode); + drmmode_clones_init(pScrn, drmmode, mode_res); #ifdef RADEON_PIXMAP_SHARING xf86ProviderSetup(pScrn, NULL, "radeon"); @@ -1757,9 +2118,10 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) xf86InitialConfiguration(pScrn, TRUE); drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; - drmmode->event_context.vblank_handler = drmmode_vblank_handler; - drmmode->event_context.page_flip_handler = drmmode_flip_handler; + drmmode->event_context.vblank_handler = radeon_drm_queue_handler; + drmmode->event_context.page_flip_handler = radeon_drm_queue_handler; + drmModeFreeResources(mode_res); return TRUE; } @@ -1828,13 +2190,12 @@ void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) } } -Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode) +Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, + Bool set_hw) { xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); int c; - drmmode_copy_fb(pScrn, drmmode); - for (c = 0; c < config->num_crtc; c++) { xf86CrtcPtr crtc = config->crtc[c]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; @@ -1843,9 +2204,12 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode) /* Skip disabled CRTCs */ if (!crtc->enabled) { - drmmode_do_crtc_dpms(crtc, DPMSModeOff); - drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, - 0, 0, 0, NULL, 0, NULL); + if (set_hw) { + drmmode_do_crtc_dpms(crtc, DPMSModeOff); + drmModeSetCrtc(drmmode->fd, + drmmode_crtc->mode_crtc->crtc_id, + 0, 0, 0, NULL, 0, NULL); + } continue; } @@ -1878,9 +2242,18 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode) crtc->desiredY = 0; } - if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation, - crtc->desiredX, crtc->desiredY)) - return FALSE; + if (set_hw) { + if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation, + crtc->desiredX, crtc->desiredY)) + return FALSE; + } else { + crtc->mode = crtc->desiredMode; + crtc->rotation = crtc->desiredRotation; + crtc->x = crtc->desiredX; + crtc->y = crtc->desiredY; + if (!xf86CrtcRotate(crtc)) + return FALSE; + } } return TRUE; } @@ -1970,6 +2343,75 @@ Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) return TRUE; } +void +radeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) +{ + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + drmModeResPtr mode_res; + int i, j; + Bool found; + Bool changed = FALSE; + + mode_res = drmModeGetResources(drmmode->fd); + if (!mode_res) + goto out; + +restart_destroy: + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + drmmode_output_private_ptr drmmode_output = output->driver_private; + found = FALSE; + for (j = 0; j < mode_res->count_connectors; j++) { + if (mode_res->connectors[j] == drmmode_output->output_id) { + found = TRUE; + break; + } + } + if (found) + continue; + + drmModeFreeConnector(drmmode_output->mode_output); + drmmode_output->mode_output = NULL; + drmmode_output->output_id = -1; + + changed = TRUE; + if (drmmode->delete_dp_12_displays) { + RROutputDestroy(output->randr_output); + xf86OutputDestroy(output); + goto restart_destroy; + } + } + + /* find new output ids we don't have outputs for */ + for (i = 0; i < mode_res->count_connectors; i++) { + found = FALSE; + + for (j = 0; j < config->num_output; j++) { + xf86OutputPtr output = config->output[j]; + drmmode_output_private_ptr drmmode_output; + + drmmode_output = output->driver_private; + if (mode_res->connectors[i] == drmmode_output->output_id) { + found = TRUE; + break; + } + } + if (found) + continue; + + changed = TRUE; + drmmode_output_init(scrn, drmmode, mode_res, i, NULL, NULL, 1); + } + + if (changed) { + RRSetChanged(xf86ScrnToScreen(scrn)); + RRTellChanged(xf86ScrnToScreen(scrn)); + } + + drmModeFreeResources(mode_res); +out: + RRGetInfo(xf86ScrnToScreen(scrn), TRUE); +} #ifdef HAVE_LIBUDEV static void drmmode_handle_uevents(int fd, void *closure) @@ -1981,7 +2423,7 @@ drmmode_handle_uevents(int fd, void *closure) if (!dev) return; - RRGetInfo(xf86ScrnToScreen(scrn), TRUE); + radeon_mode_hotplug(scrn, drmmode); udev_device_unref(dev); } #endif @@ -2035,18 +2477,21 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) #endif } -Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id) +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) { RADEONInfoPtr info = RADEONPTR(scrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; unsigned int pitch; - int i, old_fb_id; + int i; uint32_t tiling_flags = 0; - int height, emitted = 0; drmmode_flipdata_ptr flipdata; - drmmode_flipevtcarrier_ptr flipcarrier; + drmmode_flipevtcarrier_ptr flipcarrier = NULL; + struct radeon_drm_queue_entry *drm_queue = NULL; if (info->allowColorTiling) { if (info->ChipFamily >= CHIP_FAMILY_R600) @@ -2057,26 +2502,26 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->pixel_bytes, tiling_flags)) * info->pixel_bytes; - height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags)); if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { pitch = info->front_surface.level[0].pitch_bytes; } - /* - * Create a new handle for the back buffer - */ - old_fb_id = drmmode->fb_id; - if (drmModeAddFB(drmmode->fd, scrn->virtualX, height, - scrn->depth, scrn->bitsPerPixel, pitch, - new_front->handle, &drmmode->fb_id)) - goto error_out; - flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); if (!flipdata) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue: data alloc failed.\n"); - goto error_undo; + goto error; } + + /* + * Create a new handle for the back buffer + */ + flipdata->old_fb_id = drmmode->fb_id; + if (drmModeAddFB(drmmode->fd, scrn->virtualX, scrn->virtualY, + scrn->depth, scrn->bitsPerPixel, pitch, + new_front_handle, &drmmode->fb_id)) + goto error; + /* * Queue flips on all enabled CRTCs * Note that if/when we get per-CRTC buffers, we'll have to update this. @@ -2089,6 +2534,8 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat flipdata->event_data = data; flipdata->drmmode = drmmode; + flipdata->handler = handler; + flipdata->abort = abort; for (i = 0; i < config->num_crtc; i++) { if (!config->crtc[i]->enabled) @@ -2101,9 +2548,7 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat if (!flipcarrier) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue: carrier alloc failed.\n"); - if (emitted == 0) - free(flipdata); - goto error_undo; + goto error; } /* Only the reference crtc will finally deliver its page flip @@ -2112,28 +2557,44 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *dat flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id); flipcarrier->flipdata = flipdata; + drm_queue = radeon_drm_queue_alloc(scrn, client, id, + flipcarrier, + drmmode_flip_handler, + drmmode_flip_abort); + if (!drm_queue) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Allocating DRM queue event entry failed.\n"); + goto error; + } + if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, - drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) { + drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, + drm_queue)) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", strerror(errno)); - free(flipcarrier); - if (emitted == 0) - free(flipdata); - goto error_undo; + goto error; } - emitted++; + flipcarrier = NULL; + drm_queue = NULL; } - flipdata->old_fb_id = old_fb_id; - return TRUE; + if (flipdata->flip_count > 0) + return TRUE; -error_undo: - drmModeRmFB(drmmode->fd, drmmode->fb_id); - drmmode->fb_id = old_fb_id; +error: + if (flipdata && flipdata->flip_count <= 1) { + drmModeRmFB(drmmode->fd, drmmode->fb_id); + drmmode->fb_id = flipdata->old_fb_id; + } + + if (drm_queue) + radeon_drm_abort_entry(drm_queue); + else if (flipcarrier) + drmmode_flip_abort(scrn, flipcarrier); + else if (flipdata && flipdata->flip_count <= 1) + free(flipdata); -error_out: xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", strerror(errno)); return FALSE; } - diff --git a/driver/xf86-video-ati/src/drmmode_display.h b/driver/xf86-video-ati/src/drmmode_display.h index 41e29f624..ab6c5908a 100644 --- a/driver/xf86-video-ati/src/drmmode_display.h +++ b/driver/xf86-video-ati/src/drmmode_display.h @@ -32,6 +32,7 @@ #include "libudev.h" #endif +#include "radeon_drm_queue.h" #include "radeon_probe.h" #ifndef DRM_CAP_TIMESTAMP_MONOTONIC @@ -41,7 +42,6 @@ typedef struct { int fd; unsigned fb_id; - drmModeResPtr mode_res; drmModeFBPtr mode_fb; int cpp; struct radeon_bo_manager *bufmgr; @@ -51,6 +51,12 @@ typedef struct { InputHandlerProc uevent_handler; #endif drmEventContext event_context; + int count_crtcs; + + Bool delete_dp_12_displays; + + Bool dri2_flipping; + Bool present_flipping; } drmmode_rec, *drmmode_ptr; typedef struct { @@ -59,8 +65,9 @@ typedef struct { int flip_count; void *event_data; unsigned int fe_frame; - unsigned int fe_tv_sec; - unsigned int fe_tv_usec; + uint64_t fe_usec; + radeon_drm_handler_proc handler; + radeon_drm_abort_proc abort; } drmmode_flipdata_rec, *drmmode_flipdata_ptr; typedef struct { @@ -68,20 +75,33 @@ typedef struct { Bool dispatch_me; } drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr; +struct drmmode_scanout { + struct radeon_bo *bo; + PixmapPtr pixmap; + DamagePtr damage; + unsigned fb_id; + int width, height; +}; + typedef struct { drmmode_ptr drmmode; drmModeCrtcPtr mode_crtc; int hw_id; struct radeon_bo *cursor_bo; - struct radeon_bo *rotate_bo; - unsigned rotate_fb_id; + struct drmmode_scanout rotate; + struct drmmode_scanout scanout[2]; + unsigned scanout_id; + Bool scanout_update_pending; int dpms_mode; CARD64 dpms_last_ust; uint32_t dpms_last_seq; int dpms_last_fps; uint32_t interpolated_vblanks; uint16_t lut_r[256], lut_g[256], lut_b[256]; - int scanout_pixmap_x; + int prime_pixmap_x; + + /* Modeset needed for DPMS on */ + Bool need_modeset; } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; typedef struct { @@ -112,18 +132,28 @@ extern void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode); extern Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr); extern void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo); void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y); -extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode); +extern Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, + Bool set_hw); +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 extern void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode); +#endif extern Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn); +extern void drmmode_scanout_free(ScrnInfoPtr scrn); + extern void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode); extern void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode); +extern int drmmode_get_crtc_id(xf86CrtcPtr crtc); extern int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling); extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling); extern int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling); -Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id); +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); +int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc); int drmmode_get_current_ust(int drm_fd, CARD64 *ust); #endif diff --git a/driver/xf86-video-ati/src/evergreen_accel.c b/driver/xf86-video-ati/src/evergreen_accel.c index 41ebc1a9f..43146bbfa 100644 --- a/driver/xf86-video-ati/src/evergreen_accel.c +++ b/driver/xf86-video-ati/src/evergreen_accel.c @@ -79,9 +79,9 @@ unsigned eg_tile_split(unsigned tile_split) case 128: tile_split = 1; break; case 256: tile_split = 2; break; case 512: tile_split = 3; break; + default: case 1024: tile_split = 4; break; case 2048: tile_split = 5; break; - default: case 4096: tile_split = 6; break; } return tile_split; diff --git a/driver/xf86-video-ati/src/pcidb/ati_pciids.csv b/driver/xf86-video-ati/src/pcidb/ati_pciids.csv index 1c92f5b52..55d7b1dfd 100644 --- a/driver/xf86-video-ati/src/pcidb/ati_pciids.csv +++ b/driver/xf86-video-ati/src/pcidb/ati_pciids.csv @@ -693,6 +693,7 @@ "0x6610","OLAND_6610","OLAND",,,,,,"OLAND" "0x6611","OLAND_6611","OLAND",,,,,,"OLAND" "0x6613","OLAND_6613","OLAND",,,,,,"OLAND" +"0x6617","OLAND_6617","OLAND",1,,,,,"OLAND" "0x6620","OLAND_6620","OLAND",1,,,,,"OLAND" "0x6621","OLAND_6621","OLAND",1,,,,,"OLAND" "0x6623","OLAND_6623","OLAND",1,,,,,"OLAND" @@ -713,6 +714,7 @@ "0x6658","BONAIRE_6658","BONAIRE",,,,,,"BONAIRE" "0x665C","BONAIRE_665C","BONAIRE",,,,,,"BONAIRE" "0x665D","BONAIRE_665D","BONAIRE",,,,,,"BONAIRE" +"0x665F","BONAIRE_665F","BONAIRE",,,,,,"BONAIRE" "0x9830","KABINI_9830","KABINI",1,1,,,1,"KABINI" "0x9831","KABINI_9831","KABINI",,1,,,1,"KABINI" "0x9832","KABINI_9832","KABINI",1,1,,,1,"KABINI" diff --git a/driver/xf86-video-ati/src/radeon.h b/driver/xf86-video-ati/src/radeon.h index 6123cc26a..e2fd41cfd 100644 --- a/driver/xf86-video-ati/src/radeon.h +++ b/driver/xf86-video-ati/src/radeon.h @@ -51,8 +51,6 @@ #include "exa.h" -#include "radeon_glamor.h" - /* Exa and Cursor Support */ #include "xf86Cursor.h" @@ -92,6 +90,8 @@ #include "simple_list.h" #include "atipcirename.h" +struct _SyncFence; + #ifndef MAX #define MAX(a,b) ((a)>(b)?(a):(b)) #endif @@ -148,7 +148,12 @@ typedef enum { OPTION_ACCELMETHOD, OPTION_EXA_VSYNC, OPTION_ZAPHOD_HEADS, - OPTION_SWAPBUFFERS_WAIT + OPTION_SWAPBUFFERS_WAIT, + OPTION_DELETE_DP12, + OPTION_DRI3, + OPTION_DRI, + OPTION_SHADOW_PRIMARY, + OPTION_TEAR_FREE, } RADEONOpts; @@ -241,6 +246,47 @@ typedef enum { #define CURSOR_WIDTH_CIK 128 #define CURSOR_HEIGHT_CIK 128 + +#ifdef USE_GLAMOR + +struct radeon_pixmap { + struct radeon_surface surface; + + uint_fast32_t gpu_read; + uint_fast32_t gpu_write; + + struct radeon_bo *bo; + + uint32_t tiling_flags; + + /* GEM handle for glamor-only pixmaps shared via DRI3 */ + Bool handle_valid; + uint32_t handle; +}; + +#if HAS_DEVPRIVATEKEYREC +extern DevPrivateKeyRec glamor_pixmap_index; +#else +extern int glamor_pixmap_index; +#endif + +static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) +{ +#if HAS_DEVPRIVATEKEYREC + return dixGetPrivate(&pixmap->devPrivates, &glamor_pixmap_index); +#else + return dixLookupPrivate(&pixmap->devPrivates, &glamor_pixmap_index); +#endif +} + +static inline void radeon_set_pixmap_private(PixmapPtr pixmap, struct radeon_pixmap *priv) +{ + dixSetPrivate(&pixmap->devPrivates, &glamor_pixmap_index, priv); +} + +#endif /* USE_GLAMOR */ + + struct radeon_exa_pixmap_priv { struct radeon_bo *bo; uint32_t tiling_flags; @@ -412,6 +458,9 @@ typedef struct { void (*BlockHandler)(BLOCKHANDLER_ARGS_DECL); + void (*CreateFence) (ScreenPtr pScreen, struct _SyncFence *pFence, + Bool initially_triggered); + int pix24bpp; /* Depth of pixmap for 24bpp fb */ Bool dac6bits; /* Use 6 bit DAC? */ @@ -419,15 +468,19 @@ typedef struct { Bool directRenderingEnabled; struct radeon_dri2 dri2; - Bool accelDFS; /* accel */ Bool RenderAccel; /* Render */ Bool allowColorTiling; Bool allowColorTiling2D; + uint_fast32_t gpu_flushed; + uint_fast32_t gpu_synced; struct radeon_accel_state *accel_state; + PixmapPtr fbcon_pixmap; Bool accelOn; Bool use_glamor; + Bool shadow_primary; + Bool tear_free; Bool exa_pixmaps; Bool exa_force_create; XF86ModReqInfo exaReq; @@ -442,9 +495,11 @@ typedef struct { DisplayModePtr currentMode; CreateScreenResourcesProcPtr CreateScreenResources; +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 + CreateWindowProcPtr CreateWindow; +#endif Bool IsSecondary; - Bool IsPrimary; Bool r600_shadow_fb; void *fb_shadow; @@ -483,6 +538,31 @@ typedef struct { /* cursor size */ int cursor_w; int cursor_h; + +#ifdef USE_GLAMOR + struct { + CreateGCProcPtr SavedCreateGC; + RegionPtr (*SavedCopyArea)(DrawablePtr, DrawablePtr, GCPtr, int, int, + int, int, int, int); + void (*SavedPolyFillRect)(DrawablePtr, GCPtr, int, xRectangle*); + CloseScreenProcPtr SavedCloseScreen; + GetImageProcPtr SavedGetImage; + GetSpansProcPtr SavedGetSpans; + CreatePixmapProcPtr SavedCreatePixmap; + DestroyPixmapProcPtr SavedDestroyPixmap; + CopyWindowProcPtr SavedCopyWindow; + ChangeWindowAttributesProcPtr SavedChangeWindowAttributes; + BitmapToRegionProcPtr SavedBitmapToRegion; +#ifdef RENDER + CompositeProcPtr SavedComposite; + TrianglesProcPtr SavedTriangles; + GlyphsProcPtr SavedGlyphs; + TrapezoidsProcPtr SavedTrapezoids; + AddTrapsProcPtr SavedAddTraps; + UnrealizeGlyphProcPtr SavedUnrealizeGlyph; +#endif + } glamor; +#endif /* USE_GLAMOR */ } RADEONInfoRec, *RADEONInfoPtr; /* radeon_accel.c */ @@ -512,6 +592,20 @@ extern Bool RADEONGetDatatypeBpp(int bpp, uint32_t *type); extern Bool RADEONGetPixmapOffsetPitch(PixmapPtr pPix, uint32_t *pitch_offset); +/* radeon_dri3.c */ +Bool radeon_dri3_screen_init(ScreenPtr screen); + +/* radeon_kms.c */ +void radeon_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, + uint64_t usec, void *event_data); + +/* radeon_present.c */ +Bool radeon_present_screen_init(ScreenPtr screen); + +/* radeon_sync.c */ +extern Bool radeon_sync_init(ScreenPtr screen); +extern void radeon_sync_close(ScreenPtr screen); + /* radeon_video.c */ extern void RADEONInitVideo(ScreenPtr pScreen); extern void RADEONResetVideo(ScrnInfoPtr pScrn); @@ -630,7 +724,7 @@ static inline struct radeon_bo *radeon_get_pixmap_bo(PixmapPtr pPix) { struct radeon_exa_pixmap_priv *driver_priv; driver_priv = exaGetPixmapDriverPrivate(pPix); - return driver_priv->bo; + return driver_priv ? driver_priv->bo : NULL; } return NULL; @@ -786,6 +880,7 @@ static __inline__ void RADEON_SYNC(RADEONInfoPtr info, ScrnInfoPtr pScrn) } enum { + RADEON_CREATE_PIXMAP_SCANOUT = 0x02000000, RADEON_CREATE_PIXMAP_DRI2 = 0x04000000, RADEON_CREATE_PIXMAP_TILING_MICRO_SQUARE = 0x08000000, RADEON_CREATE_PIXMAP_TILING_MACRO = 0x10000000, diff --git a/driver/xf86-video-ati/src/radeon_accel.c b/driver/xf86-video-ati/src/radeon_accel.c index 8eff5c52a..1def2a3fb 100644 --- a/driver/xf86-video-ati/src/radeon_accel.c +++ b/driver/xf86-video-ati/src/radeon_accel.c @@ -78,6 +78,7 @@ #include /* Driver data structures */ #include "radeon.h" +#include "radeon_glamor.h" #include "radeon_reg.h" #include "r600_reg.h" #include "radeon_probe.h" diff --git a/driver/xf86-video-ati/src/radeon_bo_helper.c b/driver/xf86-video-ati/src/radeon_bo_helper.c index ed964d7b0..ce964e0ea 100644 --- a/driver/xf86-video-ati/src/radeon_bo_helper.c +++ b/driver/xf86-video-ati/src/radeon_bo_helper.c @@ -25,6 +25,7 @@ #endif #include "radeon.h" +#include "radeon_glamor.h" #ifdef RADEON_PIXMAP_SHARING #include "radeon_bo_gem.h" @@ -87,12 +88,15 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, if (usage_hint & RADEON_CREATE_PIXMAP_DEPTH) tiling |= RADEON_TILING_MACRO | RADEON_TILING_MICRO; + if ((usage_hint == CREATE_PIXMAP_USAGE_BACKING_PIXMAP && + info->shadow_primary) #ifdef CREATE_PIXMAP_USAGE_SHARED - if ((usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED) { + || (usage_hint & 0xffff) == CREATE_PIXMAP_USAGE_SHARED +#endif + ) { tiling = 0; domain = RADEON_GEM_DOMAIN_GTT; } -#endif } /* Small pixmaps must not be macrotiled on R300, hw cannot sample them @@ -164,7 +168,8 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, tiling |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; tiling |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; tiling |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; - tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; + if (surface.tile_split) + tiling |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; tiling |= eg_tile_split(surface.stencil_tile_split) << RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT; break; case RADEON_SURF_MODE_1D: @@ -187,6 +192,87 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, return bo; } +/* Get GEM handle for the pixmap */ +Bool radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t *handle) +{ + struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap); +#ifdef USE_GLAMOR + ScreenPtr screen = pixmap->drawable.pScreen; + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen)); +#endif + + if (bo) { + *handle = bo->handle; + return TRUE; + } + +#ifdef USE_GLAMOR + if (info->use_glamor) { + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + CARD16 stride; + CARD32 size; + int fd, r; + + if (!priv) { + priv = calloc(1, sizeof(*priv)); + radeon_set_pixmap_private(pixmap, priv); + } + + if (priv->handle_valid) { + *handle = priv->handle; + return TRUE; + } + + fd = glamor_fd_from_pixmap(screen, pixmap, &stride, &size); + if (fd < 0) + return FALSE; + + r = drmPrimeFDToHandle(info->dri2.drm_fd, fd, &priv->handle); + close(fd); + if (r == 0) { + struct drm_radeon_gem_set_tiling args = { .handle = priv->handle }; + + priv->handle_valid = TRUE; + *handle = priv->handle; + + if (drmCommandWriteRead(info->dri2.drm_fd, + DRM_RADEON_GEM_GET_TILING, &args, + sizeof(args)) == 0) + priv->tiling_flags = args.tiling_flags; + + return TRUE; + } + } +#endif + + return FALSE; +} + +uint32_t radeon_get_pixmap_tiling_flags(PixmapPtr pPix) +{ +#ifdef USE_GLAMOR + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pPix->drawable.pScreen)); + + if (info->use_glamor) { + struct radeon_pixmap *priv = radeon_get_pixmap_private(pPix); + + if (!priv || (!priv->bo && !priv->handle_valid)) { + uint32_t handle; + + radeon_get_pixmap_handle(pPix, &handle); + priv = radeon_get_pixmap_private(pPix); + } + + return priv ? priv->tiling_flags : 0; + } else +#endif + { + struct radeon_exa_pixmap_priv *driver_priv; + driver_priv = exaGetPixmapDriverPrivate(pPix); + return driver_priv ? driver_priv->tiling_flags : 0; + } +} + #ifdef RADEON_PIXMAP_SHARING Bool radeon_share_pixmap_backing(struct radeon_bo *bo, void **handle_p) @@ -200,6 +286,21 @@ Bool radeon_share_pixmap_backing(struct radeon_bo *bo, void **handle_p) return TRUE; } +static unsigned eg_tile_split_opp(unsigned tile_split) +{ + switch (tile_split) { + case 0: tile_split = 64; break; + case 1: tile_split = 128; break; + case 2: tile_split = 256; break; + case 3: tile_split = 512; break; + default: + case 4: tile_split = 1024; break; + case 5: tile_split = 2048; break; + case 6: tile_split = 4096; break; + } + return tile_split; +} + Bool radeon_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle, struct radeon_surface *surface) { @@ -215,7 +316,22 @@ Bool radeon_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle, memset(surface, 0, sizeof(struct radeon_surface)); + radeon_set_pixmap_bo(ppix, bo); + if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) { + uint32_t tiling_flags; + +#ifdef USE_GLAMOR + if (info->use_glamor) { + tiling_flags = radeon_get_pixmap_private(ppix)->tiling_flags; + } else +#endif + { + struct radeon_exa_pixmap_priv *driver_priv; + + driver_priv = exaGetPixmapDriverPrivate(ppix); + tiling_flags = driver_priv->tiling_flags; + } surface->npix_x = ppix->drawable.width; surface->npix_y = ppix->drawable.height; @@ -229,7 +345,17 @@ Bool radeon_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle, /* we are requiring a recent enough libdrm version */ surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX; surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE); - surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR, MODE); + if (tiling_flags & RADEON_TILING_MACRO) + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE); + else if (tiling_flags & RADEON_TILING_MICRO) + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE); + else + surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE); + surface->bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK; + surface->bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK; + surface->tile_split = eg_tile_split_opp((tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK); + surface->stencil_tile_split = (tiling_flags >> RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK; + surface->mtilea = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK; if (radeon_surface_best(info->surf_man, surface)) { return FALSE; } @@ -241,7 +367,6 @@ Bool radeon_set_shared_pixmap_backing(PixmapPtr ppix, void *fd_handle, surface->level[0].pitch_bytes = ppix->devKind; surface->level[0].nblk_x = ppix->devKind / surface->bpe; } - radeon_set_pixmap_bo(ppix, bo); close(ihandle); /* we have a reference from the alloc and one from set pixmap bo, diff --git a/driver/xf86-video-ati/src/radeon_bo_helper.h b/driver/xf86-video-ati/src/radeon_bo_helper.h index 9c3d73f97..d4a4ee018 100644 --- a/driver/xf86-video-ati/src/radeon_bo_helper.h +++ b/driver/xf86-video-ati/src/radeon_bo_helper.h @@ -28,6 +28,12 @@ radeon_alloc_pixmap_bo(ScrnInfoPtr pScrn, int width, int height, int depth, int usage_hint, int bitsPerPixel, int *new_pitch, struct radeon_surface *new_surface, uint32_t *new_tiling); +extern Bool +radeon_get_pixmap_handle(PixmapPtr pixmap, uint32_t *handle); + +extern uint32_t +radeon_get_pixmap_tiling_flags(PixmapPtr pPix); + extern Bool radeon_share_pixmap_backing(struct radeon_bo *bo, void **handle_p); diff --git a/driver/xf86-video-ati/src/radeon_chipinfo_gen.h b/driver/xf86-video-ati/src/radeon_chipinfo_gen.h index 40577c9eb..91ef8df8a 100644 --- a/driver/xf86-video-ati/src/radeon_chipinfo_gen.h +++ b/driver/xf86-video-ati/src/radeon_chipinfo_gen.h @@ -612,6 +612,7 @@ static RADEONCardInfo RADEONCards[] = { { 0x6610, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 }, { 0x6611, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 }, { 0x6613, CHIP_FAMILY_OLAND, 0, 0, 0, 0, 0 }, + { 0x6617, CHIP_FAMILY_OLAND, 1, 0, 0, 0, 0 }, { 0x6620, CHIP_FAMILY_OLAND, 1, 0, 0, 0, 0 }, { 0x6621, CHIP_FAMILY_OLAND, 1, 0, 0, 0, 0 }, { 0x6623, CHIP_FAMILY_OLAND, 1, 0, 0, 0, 0 }, @@ -632,6 +633,7 @@ static RADEONCardInfo RADEONCards[] = { { 0x6658, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 }, { 0x665C, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 }, { 0x665D, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 }, + { 0x665F, CHIP_FAMILY_BONAIRE, 0, 0, 0, 0, 0 }, { 0x9830, CHIP_FAMILY_KABINI, 1, 1, 0, 0, 1 }, { 0x9831, CHIP_FAMILY_KABINI, 0, 1, 0, 0, 1 }, { 0x9832, CHIP_FAMILY_KABINI, 1, 1, 0, 0, 1 }, diff --git a/driver/xf86-video-ati/src/radeon_chipset_gen.h b/driver/xf86-video-ati/src/radeon_chipset_gen.h index e3f23b6c9..5d6d2334e 100644 --- a/driver/xf86-video-ati/src/radeon_chipset_gen.h +++ b/driver/xf86-video-ati/src/radeon_chipset_gen.h @@ -612,6 +612,7 @@ SymTabRec RADEONChipsets[] = { { PCI_CHIP_OLAND_6610, "OLAND" }, { PCI_CHIP_OLAND_6611, "OLAND" }, { PCI_CHIP_OLAND_6613, "OLAND" }, + { PCI_CHIP_OLAND_6617, "OLAND" }, { PCI_CHIP_OLAND_6620, "OLAND" }, { PCI_CHIP_OLAND_6621, "OLAND" }, { PCI_CHIP_OLAND_6623, "OLAND" }, @@ -632,6 +633,7 @@ SymTabRec RADEONChipsets[] = { { PCI_CHIP_BONAIRE_6658, "BONAIRE" }, { PCI_CHIP_BONAIRE_665C, "BONAIRE" }, { PCI_CHIP_BONAIRE_665D, "BONAIRE" }, + { PCI_CHIP_BONAIRE_665F, "BONAIRE" }, { PCI_CHIP_KABINI_9830, "KABINI" }, { PCI_CHIP_KABINI_9831, "KABINI" }, { PCI_CHIP_KABINI_9832, "KABINI" }, diff --git a/driver/xf86-video-ati/src/radeon_dri2.c b/driver/xf86-video-ati/src/radeon_dri2.c index 9a9918b0f..d30bbd0bd 100644 --- a/driver/xf86-video-ati/src/radeon_dri2.c +++ b/driver/xf86-video-ati/src/radeon_dri2.c @@ -40,25 +40,13 @@ #include #include +#include "radeon_bo_helper.h" #include "radeon_version.h" - -#if HAVE_LIST_H -#include "list.h" -#if !HAVE_XORG_LIST -#define xorg_list list -#define xorg_list_init list_init -#define xorg_list_add list_add -#define xorg_list_del list_del -#define xorg_list_for_each_entry list_for_each_entry -#endif -#endif - +#include "radeon_list.h" #include "radeon_bo_gem.h" -#if DRI2INFOREC_VERSION >= 4 && HAVE_LIST_H -#define USE_DRI2_SCHEDULING -#endif +#include #if DRI2INFOREC_VERSION >= 9 #define USE_DRI2_PRIME @@ -66,9 +54,7 @@ #define FALLBACK_SWAP_DELAY 16 -#ifdef USE_GLAMOR -#include -#endif +#include "radeon_glamor.h" typedef DRI2BufferPtr BufferPtr; @@ -79,6 +65,28 @@ struct dri2_buffer_priv { }; +struct dri2_window_priv { + xf86CrtcPtr crtc; + int vblank_delta; +}; + +#if HAS_DEVPRIVATEKEYREC + +static DevPrivateKeyRec dri2_window_private_key_rec; +#define dri2_window_private_key (&dri2_window_private_key_rec) + +#else + +static int dri2_window_private_key_index; +DevPrivateKey dri2_window_private_key = &dri2_window_private_key_index; + +#endif /* HAS_DEVPRIVATEKEYREC */ + +#define get_dri2_window_priv(window) \ + ((struct dri2_window_priv*) \ + dixLookupPrivate(&(window)->devPrivates, dri2_window_private_key)) + + static PixmapPtr get_drawable_pixmap(DrawablePtr drawable) { if (drawable->type == DRAWABLE_PIXMAP) @@ -125,21 +133,43 @@ static PixmapPtr fixup_glamor(DrawablePtr drawable, PixmapPtr pixmap) /* And redirect the pixmap to the new bo (for 3D). */ glamor_egl_exchange_buffers(old, pixmap); radeon_set_pixmap_private(old, priv); - screen->DestroyPixmap(pixmap); old->refcnt++; screen->ModifyPixmapHeader(old, old->drawable.width, old->drawable.height, 0, 0, - priv->stride, + pixmap->devKind, NULL); + old->devPrivate.ptr = NULL; + + screen->DestroyPixmap(pixmap); #endif /* USE_GLAMOR*/ return old; } +/* Get GEM flink name for a pixmap */ +static Bool +radeon_get_flink_name(RADEONInfoPtr info, PixmapPtr pixmap, uint32_t *name) +{ + struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap); + struct drm_gem_flink flink; + + if (bo) + return radeon_gem_get_kernel_name(bo, name) == 0; + + if (radeon_get_pixmap_handle(pixmap, &flink.handle)) { + if (drmIoctl(info->dri2.drm_fd, DRM_IOCTL_GEM_FLINK, &flink) != 0) + return FALSE; + + *name = flink.name; + return TRUE; + } + + return FALSE; +} static BufferPtr radeon_dri2_create_buffer2(ScreenPtr pScreen, @@ -151,8 +181,7 @@ radeon_dri2_create_buffer2(ScreenPtr pScreen, RADEONInfoPtr info = RADEONPTR(pScrn); BufferPtr buffers; struct dri2_buffer_priv *privates; - PixmapPtr pixmap, depth_pixmap; - struct radeon_bo *bo; + PixmapPtr pixmap; int flags; unsigned front_width; uint32_t tiling = 0; @@ -180,25 +209,23 @@ radeon_dri2_create_buffer2(ScreenPtr pScreen, cpp = drawable->bitsPerPixel / 8; } - pixmap = pScreen->GetScreenPixmap(pScreen); - front_width = pixmap->drawable.width; + front_width = pScreen->GetScreenPixmap(pScreen)->drawable.width; - pixmap = depth_pixmap = NULL; + pixmap = NULL; if (attachment == DRI2BufferFrontLeft) { + uint32_t handle; + pixmap = get_drawable_pixmap(drawable); if (pScreen != pixmap->drawable.pScreen) pixmap = NULL; - else if (info->use_glamor && !radeon_get_pixmap_bo(pixmap)) { + else if (info->use_glamor && !radeon_get_pixmap_handle(pixmap, &handle)) { is_glamor_pixmap = TRUE; aligned_width = pixmap->drawable.width; height = pixmap->drawable.height; pixmap = NULL; } else pixmap->refcnt++; - } else if (attachment == DRI2BufferStencil && depth_pixmap) { - pixmap = depth_pixmap; - pixmap->refcnt++; } if (!pixmap && (is_glamor_pixmap || attachment != DRI2BufferFrontLeft)) { @@ -283,10 +310,6 @@ radeon_dri2_create_buffer2(ScreenPtr pScreen, if (buffers == NULL) goto error; - if (attachment == DRI2BufferDepth) { - depth_pixmap = pixmap; - } - if (pixmap) { if (!info->use_glamor) { info->exa_force_create = TRUE; @@ -300,8 +323,7 @@ radeon_dri2_create_buffer2(ScreenPtr pScreen, if (is_glamor_pixmap) pixmap = fixup_glamor(drawable, pixmap); - bo = radeon_get_pixmap_bo(pixmap); - if (!bo || radeon_gem_get_kernel_name(bo, &buffers->name) != 0) + if (!radeon_get_flink_name(info, pixmap, &buffers->name)) goto error; } @@ -490,8 +512,6 @@ radeon_dri2_copy_region(DrawablePtr pDraw, RegionPtr pRegion, pDstBuffer, pSrcBuffer); } -#ifdef USE_DRI2_SCHEDULING - enum DRI2FrameEventType { DRI2_SWAP, DRI2_FLIP, @@ -502,67 +522,20 @@ typedef struct _DRI2FrameEvent { XID drawable_id; ClientPtr client; enum DRI2FrameEventType type; - int frame; + unsigned frame; xf86CrtcPtr crtc; + OsTimerPtr timer; + struct radeon_drm_queue_entry *drm_queue; /* for swaps & flips only */ DRI2SwapEventPtr event_complete; void *event_data; DRI2BufferPtr front; DRI2BufferPtr back; - - Bool valid; - - struct xorg_list link; } DRI2FrameEventRec, *DRI2FrameEventPtr; -typedef struct _DRI2ClientEvents { - struct xorg_list reference_list; -} DRI2ClientEventsRec, *DRI2ClientEventsPtr; - -#if HAS_DEVPRIVATEKEYREC - static int DRI2InfoCnt; -static DevPrivateKeyRec DRI2ClientEventsPrivateKeyRec; -#define DRI2ClientEventsPrivateKey (&DRI2ClientEventsPrivateKeyRec) - -#else - -static int DRI2ClientEventsPrivateKeyIndex; -DevPrivateKey DRI2ClientEventsPrivateKey = &DRI2ClientEventsPrivateKeyIndex; - -#endif /* HAS_DEVPRIVATEKEYREC */ - -#define GetDRI2ClientEvents(pClient) ((DRI2ClientEventsPtr) \ - dixLookupPrivate(&(pClient)->devPrivates, DRI2ClientEventsPrivateKey)) - -static int -ListAddDRI2ClientEvents(ClientPtr client, struct xorg_list *entry) -{ - DRI2ClientEventsPtr pClientPriv; - pClientPriv = GetDRI2ClientEvents(client); - - if (!pClientPriv) { - return BadAlloc; - } - - xorg_list_add(entry, &pClientPriv->reference_list); - return 0; -} - -static void -ListDelDRI2ClientEvents(ClientPtr client, struct xorg_list *entry) -{ - DRI2ClientEventsPtr pClientPriv; - pClientPriv = GetDRI2ClientEvents(client); - - if (!pClientPriv) { - return; - } - xorg_list_del(entry); -} - static void radeon_dri2_ref_buffer(BufferPtr buffer) { @@ -582,52 +555,159 @@ radeon_dri2_unref_buffer(BufferPtr buffer) static void radeon_dri2_client_state_changed(CallbackListPtr *ClientStateCallback, pointer data, pointer calldata) { - DRI2ClientEventsPtr pClientEventsPriv; - DRI2FrameEventPtr ref; NewClientInfoRec *clientinfo = calldata; ClientPtr pClient = clientinfo->client; - pClientEventsPriv = GetDRI2ClientEvents(pClient); switch (pClient->clientState) { - case ClientStateInitial: - xorg_list_init(&pClientEventsPriv->reference_list); - break; - case ClientStateRunning: - break; - case ClientStateRetained: case ClientStateGone: - if (pClientEventsPriv) { - xorg_list_for_each_entry(ref, &pClientEventsPriv->reference_list, link) { - ref->valid = FALSE; - radeon_dri2_unref_buffer(ref->front); - radeon_dri2_unref_buffer(ref->back); - } - } + radeon_drm_abort_client(pClient); break; default: break; } } +/* + * Get current frame count delta for the specified drawable and CRTC + */ +static uint32_t radeon_get_msc_delta(DrawablePtr pDraw, xf86CrtcPtr crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (pDraw && pDraw->type == DRAWABLE_WINDOW) + return drmmode_crtc->interpolated_vblanks + + get_dri2_window_priv((WindowPtr)pDraw)->vblank_delta; + + return drmmode_crtc->interpolated_vblanks; +} + +/* + * Get current frame count and timestamp of the specified CRTC + */ +static Bool radeon_dri2_get_crtc_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) +{ + if (!radeon_crtc_is_enabled(crtc) || + drmmode_crtc_get_ust_msc(crtc, ust, msc) != Success) { + /* CRTC is not running, extrapolate MSC and timestamp */ + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + ScrnInfoPtr scrn = crtc->scrn; + RADEONInfoPtr info = RADEONPTR(scrn); + CARD64 now, delta_t, delta_seq; + + if (!drmmode_crtc->dpms_last_ust) + return FALSE; + + if (drmmode_get_current_ust(info->dri2.drm_fd, &now) != 0) { + xf86DrvMsg(scrn->scrnIndex, X_ERROR, + "%s cannot get current time\n", __func__); + return FALSE; + } + + delta_t = now - drmmode_crtc->dpms_last_ust; + delta_seq = delta_t * drmmode_crtc->dpms_last_fps; + delta_seq /= 1000000; + *ust = drmmode_crtc->dpms_last_ust; + delta_t = delta_seq * 1000000; + delta_t /= drmmode_crtc->dpms_last_fps; + *ust += delta_t; + *msc = drmmode_crtc->dpms_last_seq; + *msc += delta_seq; + } + + return TRUE; +} + static xf86CrtcPtr radeon_dri2_drawable_crtc(DrawablePtr pDraw, Bool consider_disabled) { ScreenPtr pScreen = pDraw->pScreen; ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); - xf86CrtcPtr crtc; + xf86CrtcPtr crtc = radeon_pick_best_crtc(pScrn, consider_disabled, + pDraw->x, pDraw->x + pDraw->width, + pDraw->y, pDraw->y + pDraw->height); - crtc = radeon_pick_best_crtc(pScrn, consider_disabled, - pDraw->x, - pDraw->x + pDraw->width, - pDraw->y, - pDraw->y + pDraw->height); + if (crtc && pDraw->type == DRAWABLE_WINDOW) { + struct dri2_window_priv *priv = get_dri2_window_priv((WindowPtr)pDraw); - /* Make sure the CRTC is valid and this is the real front buffer */ - if (crtc != NULL && !crtc->rotatedData) - return crtc; - else - return NULL; + if (priv->crtc && priv->crtc != crtc) { + CARD64 ust, mscold, mscnew; + + if (radeon_dri2_get_crtc_msc(priv->crtc, &ust, &mscold) && + radeon_dri2_get_crtc_msc(crtc, &ust, &mscnew)) + priv->vblank_delta += mscold - mscnew; + } + + priv->crtc = crtc; + } + + return crtc; +} + +static void +radeon_dri2_flip_event_abort(ScrnInfoPtr scrn, void *event_data) +{ + free(event_data); +} + +static void +radeon_dri2_flip_event_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, + void *event_data) +{ + RADEONInfoPtr info = RADEONPTR(scrn); + DRI2FrameEventPtr flip = event_data; + unsigned tv_sec, tv_usec; + DrawablePtr drawable; + ScreenPtr screen; + int status; + PixmapPtr pixmap; + + status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, + M_ANY, DixWriteAccess); + if (status != Success) + goto abort; + + if (!flip->crtc) + goto abort; + frame += radeon_get_msc_delta(drawable, flip->crtc); + + screen = scrn->pScreen; + pixmap = screen->GetScreenPixmap(screen); + xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, + "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", + __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); + + tv_sec = usec / 1000000; + tv_usec = usec % 1000000; + + /* We assume our flips arrive in order, so we don't check the frame */ + switch (flip->type) { + case DRI2_SWAP: + /* Check for too small vblank count of pageflip completion, taking wraparound + * into account. This usually means some defective kms pageflip completion, + * causing wrong (msc, ust) return values and possible visual corruption. + */ + if ((frame < flip->frame) && (flip->frame - frame < 5)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "%s: Pageflip completion event has impossible msc %u < target_msc %u\n", + __func__, frame, flip->frame); + /* All-Zero values signal failure of (msc, ust) timestamping to client. */ + frame = tv_sec = tv_usec = 0; + } + + DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, + DRI2_FLIP_COMPLETE, flip->event_complete, + flip->event_data); + info->drmmode.dri2_flipping = FALSE; + break; + default: + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); + /* Unknown type */ + break; + } + +abort: + radeon_dri2_flip_event_abort(scrn, event_data); } static Bool @@ -636,6 +716,7 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client, DRI2BufferPtr back, DRI2SwapEventPtr func, void *data, unsigned int target_msc) { + RADEONInfoPtr info = RADEONPTR(scrn); struct dri2_buffer_priv *back_priv; struct radeon_bo *bo; DRI2FrameEventPtr flip_info; @@ -662,26 +743,31 @@ radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client, back_priv = back->driverPrivate; bo = radeon_get_pixmap_bo(back_priv->pixmap); - return radeon_do_pageflip(scrn, bo, flip_info, ref_crtc_hw_id); + if (radeon_do_pageflip(scrn, client, bo->handle, + RADEON_DRM_QUEUE_ID_DEFAULT, flip_info, + ref_crtc_hw_id, + radeon_dri2_flip_event_handler, + radeon_dri2_flip_event_abort)) { + info->drmmode.dri2_flipping = TRUE; + return TRUE; + } + + return FALSE; } static Bool update_front(DrawablePtr draw, DRI2BufferPtr front) { - int r; PixmapPtr pixmap; RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(draw->pScreen)); struct dri2_buffer_priv *priv = front->driverPrivate; - struct radeon_bo *bo; pixmap = get_drawable_pixmap(draw); pixmap->refcnt++; if (!info->use_glamor) exaMoveInPixmap(pixmap); - bo = radeon_get_pixmap_bo(pixmap); - r = radeon_gem_get_kernel_name(bo, &front->name); - if (r) { + if (!radeon_get_flink_name(info, pixmap, &front->name)) { (*draw->pScreen->DestroyPixmap)(pixmap); return FALSE; } @@ -734,8 +820,11 @@ static Bool can_flip(ScrnInfoPtr pScrn, DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back) { + RADEONInfoPtr info = RADEONPTR(pScrn); + return draw->type == DRAWABLE_WINDOW && - RADEONPTR(pScrn)->allowPageFlip && + info->allowPageFlip && + !info->drmmode.present_flipping && pScrn->vtSema && DRI2CanFlip(draw) && can_exchange(pScrn, draw, front, back); @@ -784,31 +873,36 @@ radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPt DamageRegionProcessPending(&front_priv->pixmap->drawable); } -void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) +static void radeon_dri2_frame_event_abort(ScrnInfoPtr scrn, void *event_data) +{ + DRI2FrameEventPtr event = event_data; + + TimerCancel(event->timer); + TimerFree(event->timer); + radeon_dri2_unref_buffer(event->front); + radeon_dri2_unref_buffer(event->back); + free(event); +} + +static void radeon_dri2_frame_event_handler(ScrnInfoPtr scrn, uint32_t seq, + uint64_t usec, void *event_data) { DRI2FrameEventPtr event = event_data; DrawablePtr drawable; - ScreenPtr screen; - ScrnInfoPtr scrn; int status; int swap_type; BoxRec box; RegionRec region; - if (!event->valid) + if (!event->crtc) goto cleanup; status = dixLookupDrawable(&drawable, event->drawable_id, serverClient, M_ANY, DixWriteAccess); if (status != Success) goto cleanup; - if (!event->crtc) - goto cleanup; - frame += radeon_get_interpolated_vblanks(event->crtc); - screen = drawable->pScreen; - scrn = xf86ScreenToScrn(screen); + seq += radeon_get_msc_delta(drawable, event->crtc); switch (event->type) { case DRI2_FLIP: @@ -840,12 +934,14 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, swap_type = DRI2_BLIT_COMPLETE; } - DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec, - swap_type, event->event_complete, event->event_data); + DRI2SwapComplete(event->client, drawable, seq, usec / 1000000, + usec % 1000000, swap_type, event->event_complete, + event->event_data); break; case DRI2_WAITMSC: - DRI2WaitMSCComplete(event->client, drawable, frame, tv_sec, tv_usec); + DRI2WaitMSCComplete(event->client, drawable, seq, usec / 1000000, + usec % 1000000); break; default: /* Unknown type */ @@ -855,12 +951,7 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, } cleanup: - if (event->valid) { - radeon_dri2_unref_buffer(event->front); - radeon_dri2_unref_buffer(event->back); - ListDelDRI2ClientEvents(event->client, &event->link); - } - free(event); + radeon_dri2_frame_event_abort(scrn, event_data); } drmVBlankSeqType radeon_populate_vbl_request_type(xf86CrtcPtr crtc) @@ -898,8 +989,6 @@ CARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, int nominal_frame_rate = drmmode_crtc->dpms_last_fps; CARD64 last_vblank_ust = drmmode_crtc->dpms_last_ust; uint32_t last_vblank_seq = drmmode_crtc->dpms_last_seq; - int interpolated_vblanks = drmmode_crtc->interpolated_vblanks; - int target_seq; CARD64 now, target_time, delta_t; int64_t d, delta_seq; int ret; @@ -916,16 +1005,15 @@ CARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, *target_msc = 0; return FALLBACK_SWAP_DELAY; } - target_seq = (int)*target_msc - interpolated_vblanks; - delta_seq = (int64_t)target_seq - (int64_t)last_vblank_seq; + delta_seq = *target_msc - last_vblank_seq; delta_seq *= 1000000; target_time = last_vblank_ust; target_time += delta_seq / nominal_frame_rate; d = target_time - now; if (d < 0) { /* we missed the event, adjust target_msc, do the divisor magic */ - CARD64 current_msc; - current_msc = last_vblank_seq + interpolated_vblanks; + CARD64 current_msc = last_vblank_seq; + delta_t = now - last_vblank_ust; delta_seq = delta_t * nominal_frame_rate; current_msc += delta_seq / 1000000; @@ -938,8 +1026,7 @@ CARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, if ((current_msc % divisor) >= remainder) *target_msc += divisor; *target_msc &= 0xffffffff; - target_seq = (int)*target_msc - interpolated_vblanks; - delta_seq = (int64_t)target_seq - (int64_t)last_vblank_seq; + delta_seq = *target_msc - last_vblank_seq; delta_seq *= 1000000; target_time = last_vblank_ust; target_time += delta_seq / nominal_frame_rate; @@ -960,16 +1047,11 @@ CARD32 radeon_dri2_extrapolate_msc_delay(xf86CrtcPtr crtc, CARD64 *target_msc, } /* - * Get current frame count and frame count timestamp, based on drawable's - * crtc. + * Get current interpolated frame count and frame count timestamp, based on + * drawable's crtc. */ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) { - ScreenPtr screen = draw->pScreen; - ScrnInfoPtr scrn = xf86ScreenToScrn(screen); - RADEONInfoPtr info = RADEONPTR(scrn); - drmVBlank vbl; - int ret; xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); /* Drawable not displayed, make up a value */ @@ -978,47 +1060,12 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc) *msc = 0; return TRUE; } - if (radeon_crtc_is_enabled(crtc)) { - /* CRTC is running, read vblank counter and timestamp */ - vbl.request.type = DRM_VBLANK_RELATIVE; - vbl.request.type |= radeon_populate_vbl_request_type(crtc); - vbl.request.sequence = 0; - ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); - if (ret) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "get vblank counter failed: %s\n", strerror(errno)); - return FALSE; - } + if (!radeon_dri2_get_crtc_msc(crtc, ust, msc)) + return FALSE; - *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; - *msc = vbl.reply.sequence + radeon_get_interpolated_vblanks(crtc); - *msc &= 0xffffffff; - } else { - /* CRTC is not running, extrapolate MSC and timestamp */ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - CARD64 now, delta_t, delta_seq; - - if (!drmmode_crtc->dpms_last_ust) - return FALSE; - ret = drmmode_get_current_ust(info->dri2.drm_fd, &now); - if (ret) { - xf86DrvMsg(scrn->scrnIndex, X_ERROR, - "%s cannot get current time\n", __func__); - return FALSE; - } - delta_t = now - drmmode_crtc->dpms_last_ust; - delta_seq = delta_t * drmmode_crtc->dpms_last_fps; - delta_seq /= 1000000; - *ust = drmmode_crtc->dpms_last_ust; - delta_t = delta_seq * 1000000; - delta_t /= drmmode_crtc->dpms_last_fps; - *ust += delta_t; - *msc = drmmode_crtc->dpms_last_seq; - *msc += drmmode_crtc->interpolated_vblanks; - *msc += delta_seq; - *msc &= 0xffffffff; - } + *msc += radeon_get_msc_delta(draw, crtc); + *msc &= 0xffffffff; return TRUE; } @@ -1026,17 +1073,13 @@ static CARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) { DRI2FrameEventPtr event_info = (DRI2FrameEventPtr)data; - DrawablePtr drawable; - ScreenPtr screen; + xf86CrtcPtr crtc = event_info->crtc; ScrnInfoPtr scrn; RADEONInfoPtr info; - int status; CARD64 drm_now; int ret; - unsigned int tv_sec, tv_usec; CARD64 delta_t, delta_seq, frame; drmmode_crtc_private_ptr drmmode_crtc; - TimerFree(timer); /* * This is emulated event, so its time is current time, which we @@ -1047,28 +1090,26 @@ CARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) */ if (!event_info->crtc) { ErrorF("%s no crtc\n", __func__); - radeon_dri2_frame_event_handler(0, 0, 0, data); + if (event_info->drm_queue) + radeon_drm_abort_entry(event_info->drm_queue); + else + radeon_dri2_frame_event_abort(NULL, data); return 0; } - status = dixLookupDrawable(&drawable, event_info->drawable_id, serverClient, - M_ANY, DixWriteAccess); - if (status != Success) { - ErrorF("%s cannot lookup drawable\n", __func__); - radeon_dri2_frame_event_handler(0, 0, 0, data); - return 0; - } - screen = drawable->pScreen; - scrn = xf86ScreenToScrn(screen); + + scrn = crtc->scrn; info = RADEONPTR(scrn); ret = drmmode_get_current_ust(info->dri2.drm_fd, &drm_now); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_ERROR, "%s cannot get current time\n", __func__); - radeon_dri2_frame_event_handler(0, 0, 0, data); + if (event_info->drm_queue) + radeon_drm_queue_handler(info->dri2.drm_fd, 0, 0, 0, + event_info->drm_queue); + else + radeon_dri2_frame_event_handler(scrn, 0, 0, data); return 0; } - tv_sec = (unsigned int)(drm_now / 1000000); - tv_usec = (unsigned int)(drm_now - (CARD64)tv_sec * 1000000); /* * calculate the frame number from current time * that would come from CRTC if it were running @@ -1078,20 +1119,22 @@ CARD32 radeon_dri2_deferred_event(OsTimerPtr timer, CARD32 now, pointer data) delta_seq = delta_t * drmmode_crtc->dpms_last_fps; delta_seq /= 1000000; frame = (CARD64)drmmode_crtc->dpms_last_seq + delta_seq; - frame &= 0xffffffff; - radeon_dri2_frame_event_handler((unsigned int)frame, tv_sec, tv_usec, data); + if (event_info->drm_queue) + radeon_drm_queue_handler(info->dri2.drm_fd, frame, drm_now / 1000000, + drm_now % 1000000, event_info->drm_queue); + else + radeon_dri2_frame_event_handler(scrn, frame, drm_now, data); return 0; } static -void radeon_dri2_schedule_event(CARD32 delay, pointer arg) +void radeon_dri2_schedule_event(CARD32 delay, DRI2FrameEventPtr event_info) { - OsTimerPtr timer; - - timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event, arg); + event_info->timer = TimerSet(NULL, 0, delay, radeon_dri2_deferred_event, + event_info); if (delay == 0) { CARD32 now = GetTimeInMillis(); - radeon_dri2_deferred_event(timer, now, arg); + radeon_dri2_deferred_event(event_info->timer, now, event_info); } } @@ -1109,7 +1152,9 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, ScrnInfoPtr scrn = xf86ScreenToScrn(screen); RADEONInfoPtr info = RADEONPTR(scrn); DRI2FrameEventPtr wait_info = NULL; + struct radeon_drm_queue_entry *wait = NULL; xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); + uint32_t msc_delta; drmVBlank vbl; int ret; CARD64 current_msc; @@ -1124,6 +1169,8 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, if (crtc == NULL) goto out_complete; + msc_delta = radeon_get_msc_delta(draw, crtc); + wait_info = calloc(1, sizeof(DRI2FrameEventRec)); if (!wait_info) goto out_complete; @@ -1131,26 +1178,17 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, wait_info->drawable_id = draw->id; wait_info->client = client; wait_info->type = DRI2_WAITMSC; - wait_info->valid = TRUE; wait_info->crtc = crtc; - if (ListAddDRI2ClientEvents(client, &wait_info->link)) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "add events to client private failed.\n"); - free(wait_info); - wait_info = NULL; - goto out_complete; - } - /* * CRTC is in DPMS off state, calculate wait time from current time, * target_msc and last vblank time/sequence when CRTC was turned off */ if (!radeon_crtc_is_enabled(crtc)) { CARD32 delay; + target_msc -= msc_delta; delay = radeon_dri2_extrapolate_msc_delay(crtc, &target_msc, divisor, remainder); - wait_info->frame = target_msc; radeon_dri2_schedule_event(delay, wait_info); DRI2BlockClient(client, draw); return TRUE; @@ -1167,9 +1205,19 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, goto out_complete; } - current_msc = vbl.reply.sequence + radeon_get_interpolated_vblanks(crtc); + current_msc = vbl.reply.sequence + msc_delta; current_msc &= 0xffffffff; + wait = radeon_drm_queue_alloc(scrn, client, RADEON_DRM_QUEUE_ID_DEFAULT, + wait_info, radeon_dri2_frame_event_handler, + radeon_dri2_frame_event_abort); + if (!wait) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Allocating DRM queue event entry failed.\n"); + goto out_complete; + } + wait_info->drm_queue = wait; + /* * If divisor is zero, or current_msc is smaller than target_msc, * we just need to make sure target_msc passes before waking up the @@ -1186,9 +1234,8 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, target_msc = current_msc; vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; vbl.request.type |= radeon_populate_vbl_request_type(crtc); - vbl.request.sequence = target_msc; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); - vbl.request.signal = (unsigned long)wait_info; + vbl.request.sequence = target_msc - msc_delta; + vbl.request.signal = (unsigned long)wait; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, @@ -1196,8 +1243,6 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, goto out_complete; } - wait_info->frame = vbl.reply.sequence; - wait_info->frame += radeon_get_interpolated_vblanks(crtc); DRI2BlockClient(client, draw); return TRUE; } @@ -1210,7 +1255,7 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, vbl.request.type |= radeon_populate_vbl_request_type(crtc); vbl.request.sequence = current_msc - (current_msc % divisor) + - remainder; + remainder - msc_delta; /* * If calculated remainder is larger than requested remainder, @@ -1220,9 +1265,8 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, */ if ((current_msc % divisor) >= remainder) vbl.request.sequence += divisor; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); - vbl.request.signal = (unsigned long)wait_info; + vbl.request.signal = (unsigned long)wait; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, @@ -1230,79 +1274,16 @@ static int radeon_dri2_schedule_wait_msc(ClientPtr client, DrawablePtr draw, goto out_complete; } - wait_info->frame = vbl.reply.sequence; - wait_info->frame += radeon_get_interpolated_vblanks(crtc); DRI2BlockClient(client, draw); return TRUE; out_complete: - if (wait_info) { - ListDelDRI2ClientEvents(wait_info->client, &wait_info->link); - free(wait_info); - } - DRI2WaitMSCComplete(client, draw, target_msc, 0, 0); + if (wait_info) + radeon_dri2_deferred_event(NULL, 0, wait_info); return TRUE; } -void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) -{ - DRI2FrameEventPtr flip = event_data; - DrawablePtr drawable; - ScreenPtr screen; - ScrnInfoPtr scrn; - int status; - PixmapPtr pixmap; - - status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient, - M_ANY, DixWriteAccess); - if (status != Success) { - free(flip); - return; - } - if (!flip->crtc) { - free(flip); - return; - } - frame += radeon_get_interpolated_vblanks(flip->crtc); - - screen = drawable->pScreen; - scrn = xf86ScreenToScrn(screen); - - pixmap = screen->GetScreenPixmap(screen); - xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, - "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n", - __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4); - - /* We assume our flips arrive in order, so we don't check the frame */ - switch (flip->type) { - case DRI2_SWAP: - /* Check for too small vblank count of pageflip completion, taking wraparound - * into account. This usually means some defective kms pageflip completion, - * causing wrong (msc, ust) return values and possible visual corruption. - */ - if ((frame < flip->frame) && (flip->frame - frame < 5)) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "%s: Pageflip completion event has impossible msc %d < target_msc %d\n", - __func__, frame, flip->frame); - /* All-Zero values signal failure of (msc, ust) timestamping to client. */ - frame = tv_sec = tv_usec = 0; - } - - DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec, - DRI2_FLIP_COMPLETE, flip->event_complete, - flip->event_data); - break; - default: - xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__); - /* Unknown type */ - break; - } - - free(flip); -} - /* * ScheduleSwap is responsible for requesting a DRM vblank event for the * appropriate frame. @@ -1333,10 +1314,11 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, ScrnInfoPtr scrn = xf86ScreenToScrn(screen); RADEONInfoPtr info = RADEONPTR(scrn); xf86CrtcPtr crtc = radeon_dri2_drawable_crtc(draw, TRUE); + uint32_t msc_delta; drmVBlank vbl; int ret, flip = 0; DRI2FrameEventPtr swap_info = NULL; - enum DRI2FrameEventType swap_type = DRI2_SWAP; + struct radeon_drm_queue_entry *swap; CARD64 current_msc; BoxRec box; RegionRec region; @@ -1358,25 +1340,30 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, if (crtc == NULL) goto blit_fallback; + msc_delta = radeon_get_msc_delta(draw, crtc); + swap_info = calloc(1, sizeof(DRI2FrameEventRec)); if (!swap_info) goto blit_fallback; + swap_info->type = DRI2_SWAP; swap_info->drawable_id = draw->id; swap_info->client = client; swap_info->event_complete = func; swap_info->event_data = data; swap_info->front = front; swap_info->back = back; - swap_info->valid = TRUE; swap_info->crtc = crtc; - if (ListAddDRI2ClientEvents(client, &swap_info->link)) { + + swap = radeon_drm_queue_alloc(scrn, client, RADEON_DRM_QUEUE_ID_DEFAULT, + swap_info, radeon_dri2_frame_event_handler, + radeon_dri2_frame_event_abort); + if (!swap) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "add events to client private failed.\n"); - free(swap_info); - swap_info = NULL; + "Allocating DRM queue entry failed.\n"); goto blit_fallback; } + swap_info->drm_queue = swap; /* * CRTC is in DPMS off state, fallback to blit, but calculate @@ -1385,9 +1372,11 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, */ if (!radeon_crtc_is_enabled(crtc)) { CARD32 delay; + *target_msc -= msc_delta; delay = radeon_dri2_extrapolate_msc_delay(crtc, target_msc, divisor, remainder); - swap_info->frame = *target_msc; + *target_msc += msc_delta; + *target_msc &= 0xffffffff; radeon_dri2_schedule_event(delay, swap_info); return TRUE; } @@ -1401,23 +1390,19 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, xf86DrvMsg(scrn->scrnIndex, X_WARNING, "first get vblank counter failed: %s\n", strerror(errno)); - *target_msc = 0; - radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); - return TRUE; + goto blit_fallback; } - current_msc = vbl.reply.sequence + radeon_get_interpolated_vblanks(crtc); + current_msc = vbl.reply.sequence + msc_delta; current_msc &= 0xffffffff; /* Flips need to be submitted one frame before */ if (can_flip(scrn, draw, front, back)) { - swap_type = DRI2_FLIP; + swap_info->type = DRI2_FLIP; flip = 1; } - swap_info->type = swap_type; - - /* Correct target_msc by 'flip' if swap_type == DRI2_FLIP. + /* Correct target_msc by 'flip' if swap_info->type == DRI2_FLIP. * Do it early, so handling of different timing constraints * for divisor, remainder and msc vs. target_msc works. */ @@ -1446,21 +1431,17 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, if (current_msc >= *target_msc) *target_msc = current_msc; - vbl.request.sequence = *target_msc; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); - vbl.request.signal = (unsigned long)swap_info; + vbl.request.sequence = *target_msc - msc_delta; + vbl.request.signal = (unsigned long)swap; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "divisor 0 get vblank counter failed: %s\n", strerror(errno)); - *target_msc = 0; - radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); - return TRUE; + goto blit_fallback; } - *target_msc = vbl.reply.sequence + flip; - *target_msc += radeon_get_interpolated_vblanks(crtc); + *target_msc = vbl.reply.sequence + flip + msc_delta; swap_info->frame = *target_msc; return TRUE; @@ -1477,7 +1458,7 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, vbl.request.type |= radeon_populate_vbl_request_type(crtc); vbl.request.sequence = current_msc - (current_msc % divisor) + - remainder; + remainder - msc_delta; /* * If the calculated deadline vbl.request.sequence is smaller than @@ -1492,53 +1473,49 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, */ if (vbl.request.sequence <= current_msc) vbl.request.sequence += divisor; - vbl.request.sequence -= radeon_get_interpolated_vblanks(crtc); /* Account for 1 frame extra pageflip delay if flip > 0 */ vbl.request.sequence -= flip; - vbl.request.signal = (unsigned long)swap_info; + vbl.request.signal = (unsigned long)swap; ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); if (ret) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "final get vblank counter failed: %s\n", strerror(errno)); - *target_msc = 0; - radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); - return TRUE; + goto blit_fallback; } /* Adjust returned value for 1 fame pageflip offset of flip > 0 */ - *target_msc = vbl.reply.sequence + flip; - *target_msc += radeon_get_interpolated_vblanks(crtc); + *target_msc = vbl.reply.sequence + flip + msc_delta; + *target_msc &= 0xffffffff; swap_info->frame = *target_msc; return TRUE; blit_fallback: - box.x1 = 0; - box.y1 = 0; - box.x2 = draw->width; - box.y2 = draw->height; - REGION_INIT(pScreen, ®ion, &box, 0); - - radeon_dri2_copy_region(draw, ®ion, front, back); - - DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); if (swap_info) { - ListDelDRI2ClientEvents(swap_info->client, &swap_info->link); - free(swap_info); - } + swap_info->type = DRI2_SWAP; + radeon_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); + } else { + box.x1 = 0; + box.y1 = 0; + box.x2 = draw->width; + box.y2 = draw->height; + REGION_INIT(pScreen, ®ion, &box, 0); - radeon_dri2_unref_buffer(front); - radeon_dri2_unref_buffer(back); + radeon_dri2_copy_region(draw, ®ion, front, back); + + DRI2SwapComplete(client, draw, 0, 0, 0, DRI2_BLIT_COMPLETE, func, data); + + radeon_dri2_unref_buffer(front); + radeon_dri2_unref_buffer(back); + } *target_msc = 0; /* offscreen, so zero out target vblank count */ return TRUE; } -#endif /* USE_DRI2_SCHEDULING */ - Bool radeon_dri2_screen_init(ScreenPtr pScreen) @@ -1546,10 +1523,8 @@ radeon_dri2_screen_init(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); RADEONInfoPtr info = RADEONPTR(pScrn); DRI2InfoRec dri2_info = { 0 }; -#ifdef USE_DRI2_SCHEDULING const char *driverNames[2]; Bool scheduling_works = TRUE; -#endif if (!info->dri2.available) return FALSE; @@ -1574,14 +1549,13 @@ radeon_dri2_screen_init(ScreenPtr pScreen) dri2_info.DestroyBuffer = radeon_dri2_destroy_buffer; dri2_info.CopyRegion = radeon_dri2_copy_region; -#ifdef USE_DRI2_SCHEDULING if (info->dri2.pKernelDRMVersion->version_minor < 4) { xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "You need a newer kernel for " "sync extension\n"); scheduling_works = FALSE; } - if (scheduling_works && info->drmmode.mode_res->count_crtcs > 2) { + if (scheduling_works && info->drmmode.count_crtcs > 2) { #ifdef DRM_CAP_VBLANK_HIGH_CRTC uint64_t cap_value; @@ -1608,31 +1582,32 @@ radeon_dri2_screen_init(ScreenPtr pScreen) dri2_info.ScheduleWaitMSC = radeon_dri2_schedule_wait_msc; dri2_info.numDrivers = RADEON_ARRAY_SIZE(driverNames); dri2_info.driverNames = driverNames; - driverNames[0] = driverNames[1] = dri2_info.driverName; + driverNames[0] = dri2_info.driverName; + + if (info->ChipFamily >= CHIP_FAMILY_R300) + driverNames[1] = driverNames[0]; + else + driverNames[1] = NULL; /* no VDPAU support */ if (DRI2InfoCnt == 0) { #if HAS_DIXREGISTERPRIVATEKEY - if (!dixRegisterPrivateKey(DRI2ClientEventsPrivateKey, - PRIVATE_CLIENT, sizeof(DRI2ClientEventsRec))) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 registering " - "private key to client failed\n"); - return FALSE; - } + if (!dixRegisterPrivateKey(dri2_window_private_key, + PRIVATE_WINDOW, + sizeof(struct dri2_window_priv))) { #else - if (!dixRequestPrivate(DRI2ClientEventsPrivateKey, - sizeof(DRI2ClientEventsRec))) { - xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DRI2 requesting " - "private key to client failed\n"); + if (!dixRequestPrivate(dri2_window_private_key, + sizeof(struct dri2_window_priv))) { +#endif + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Failed to get DRI2 window private\n"); return FALSE; } -#endif AddCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); } DRI2InfoCnt++; } -#endif #if DRI2INFOREC_VERSION >= 9 dri2_info.version = 9; @@ -1650,10 +1625,8 @@ void radeon_dri2_close_screen(ScreenPtr pScreen) ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); RADEONInfoPtr info = RADEONPTR(pScrn); -#ifdef USE_DRI2_SCHEDULING if (--DRI2InfoCnt == 0) DeleteCallback(&ClientStateCallback, radeon_dri2_client_state_changed, 0); -#endif DRI2CloseScreen(pScreen); drmFree(info->dri2.device_name); diff --git a/driver/xf86-video-ati/src/radeon_dri2.h b/driver/xf86-video-ati/src/radeon_dri2.h index 37d46f3d0..9ba47c78f 100644 --- a/driver/xf86-video-ati/src/radeon_dri2.h +++ b/driver/xf86-video-ati/src/radeon_dri2.h @@ -43,48 +43,11 @@ struct radeon_dri2 { Bool radeon_dri2_screen_init(ScreenPtr pScreen); void radeon_dri2_close_screen(ScreenPtr pScreen); -int drmmode_get_crtc_id(xf86CrtcPtr crtc); -void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data); -void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data); - #else static inline Bool radeon_dri2_screen_init(ScreenPtr pScreen) { return FALSE; } static inline void radeon_dri2_close_screen(ScreenPtr pScreen) {} -static inline void -radeon_dri2_dummy_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data, - const char *name) -{ - static Bool warned; - - if (!warned) { - ErrorF("%s called but DRI2 disabled at build time\n", name); - warned = TRUE; - } - - free(event_data); -} - -static inline void -radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) -{ - radeon_dri2_dummy_event_handler(frame, tv_sec, tv_usec, event_data, - __func__); -} - -static inline void -radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec, - unsigned int tv_usec, void *event_data) -{ - radeon_dri2_dummy_event_handler(frame, tv_sec, tv_usec, event_data, - __func__); -} - #endif #endif /* RADEON_DRI2_H */ diff --git a/driver/xf86-video-ati/src/radeon_dri3.c b/driver/xf86-video-ati/src/radeon_dri3.c new file mode 100644 index 000000000..1415a0df7 --- /dev/null +++ b/driver/xf86-video-ati/src/radeon_dri3.c @@ -0,0 +1,215 @@ +/* + * Copyright © 2013-2014 Intel Corporation + * Copyright © 2015 Advanced Micro Devices, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "radeon.h" + +#ifdef HAVE_DRI3_H + +#include "radeon_bo_gem.h" +#include "radeon_glamor.h" +#include "dri3.h" + +#include +#include +#include +#include + + +static int +radeon_dri3_open(ScreenPtr screen, RRProviderPtr provider, int *out) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + drm_magic_t magic; + int fd; + + fd = open(info->dri2.device_name, O_RDWR | O_CLOEXEC); + if (fd < 0) + return BadAlloc; + + /* Before FD passing in the X protocol with DRI3 (and increased + * security of rendering with per-process address spaces on the + * GPU), the kernel had to come up with a way to have the server + * decide which clients got to access the GPU, which was done by + * each client getting a unique (magic) number from the kernel, + * passing it to the server, and the server then telling the + * kernel which clients were authenticated for using the device. + * + * Now that we have FD passing, the server can just set up the + * authentication on its own and hand the prepared FD off to the + * client. + */ + if (drmGetMagic(fd, &magic) < 0) { + if (errno == EACCES) { + /* Assume that we're on a render node, and the fd is + * already as authenticated as it should be. + */ + *out = fd; + return Success; + } else { + close(fd); + return BadMatch; + } + } + + if (drmAuthMagic(info->dri2.drm_fd, magic) < 0) { + close(fd); + return BadMatch; + } + + *out = fd; + return Success; +} + +static PixmapPtr radeon_dri3_pixmap_from_fd(ScreenPtr screen, + int fd, + CARD16 width, + CARD16 height, + CARD16 stride, + CARD8 depth, + CARD8 bpp) +{ + PixmapPtr pixmap; + +#ifdef USE_GLAMOR + /* Avoid generating a GEM flink name if possible */ + if (RADEONPTR(xf86ScreenToScrn(screen))->use_glamor) { + pixmap = glamor_pixmap_from_fd(screen, fd, width, height, + stride, depth, bpp); + if (pixmap) { + struct radeon_pixmap *priv = + calloc(1, sizeof(struct radeon_pixmap)); + + if (priv) { + radeon_set_pixmap_private(pixmap, priv); + return pixmap; + } + + screen->DestroyPixmap(pixmap); + } + } +#endif + + if (depth < 8) + return NULL; + + switch (bpp) { + case 8: + case 16: + case 32: + break; + default: + return NULL; + } + + pixmap = screen->CreatePixmap(screen, 0, 0, depth, RADEON_CREATE_PIXMAP_DRI2); + if (!pixmap) + return NULL; + + if (!screen->ModifyPixmapHeader(pixmap, width, height, 0, bpp, stride, + NULL)) + goto free_pixmap; + + if (screen->SetSharedPixmapBacking(pixmap, (void*)(intptr_t)fd)) + return pixmap; + +free_pixmap: + fbDestroyPixmap(pixmap); + return NULL; +} + +static int radeon_dri3_fd_from_pixmap(ScreenPtr screen, + PixmapPtr pixmap, + CARD16 *stride, + CARD32 *size) +{ + struct radeon_bo *bo; + int fd; + + bo = radeon_get_pixmap_bo(pixmap); + if (!bo) { +#ifdef USE_GLAMOR + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + + if (info->use_glamor) + return glamor_fd_from_pixmap(screen, pixmap, stride, size); +#endif + + exaMoveInPixmap(pixmap); + bo = radeon_get_pixmap_bo(pixmap); + if (!bo) + return -1; + } + + if (pixmap->devKind > UINT16_MAX) + return -1; + + if (radeon_gem_prime_share_bo(bo, &fd) < 0) + return -1; + + *stride = pixmap->devKind; + *size = bo->size; + return fd; +} + +static dri3_screen_info_rec radeon_dri3_screen_info = { + .version = 0, + + .open = radeon_dri3_open, + .pixmap_from_fd = radeon_dri3_pixmap_from_fd, + .fd_from_pixmap = radeon_dri3_fd_from_pixmap +}; + +Bool +radeon_dri3_screen_init(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + + if (!dri3_screen_init(screen, &radeon_dri3_screen_info)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "dri3_screen_init failed\n"); + return FALSE; + } + + return TRUE; +} + +#else /* !HAVE_DRI3_H */ + +Bool +radeon_dri3_screen_init(ScreenPtr screen) +{ + xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, + "Can't initialize DRI3 because dri3.h not available at " + "build time\n"); + + return FALSE; +} + +#endif diff --git a/driver/xf86-video-ati/src/radeon_drm_queue.c b/driver/xf86-video-ati/src/radeon_drm_queue.c new file mode 100644 index 000000000..5e54ef8bb --- /dev/null +++ b/driver/xf86-video-ati/src/radeon_drm_queue.c @@ -0,0 +1,181 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * Copyright © 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Dave Airlie + * + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "radeon.h" +#include "radeon_drm_queue.h" +#include "radeon_list.h" + + +struct radeon_drm_queue_entry { + struct xorg_list list; + uint64_t id; + void *data; + ClientPtr client; + ScrnInfoPtr scrn; + radeon_drm_handler_proc handler; + radeon_drm_abort_proc abort; +}; + +static int radeon_drm_queue_refcnt; +static struct xorg_list radeon_drm_queue; + + +/* + * Handle a DRM event + */ +void +radeon_drm_queue_handler(int fd, unsigned int frame, unsigned int sec, + unsigned int usec, void *user_ptr) +{ + struct radeon_drm_queue_entry *user_data = user_ptr; + struct radeon_drm_queue_entry *e, *tmp; + + xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) { + if (e == user_data) { + xorg_list_del(&e->list); + e->handler(e->scrn, frame, + (uint64_t)sec * 1000000 + usec, e->data); + free(e); + break; + } + } +} + +/* + * Enqueue a potential drm response; when the associated response + * appears, we've got data to pass to the handler from here + */ +struct radeon_drm_queue_entry * +radeon_drm_queue_alloc(ScrnInfoPtr scrn, ClientPtr client, + uint64_t id, void *data, + radeon_drm_handler_proc handler, + radeon_drm_abort_proc abort) +{ + struct radeon_drm_queue_entry *e; + + e = calloc(1, sizeof(struct radeon_drm_queue_entry)); + if (!e) + return NULL; + + e->client = client; + e->scrn = scrn; + e->id = id; + e->data = data; + e->handler = handler; + e->abort = abort; + + xorg_list_add(&e->list, &radeon_drm_queue); + + return e; +} + +/* + * Abort one queued DRM entry, removing it + * from the list, calling the abort function and + * freeing the memory + */ +static void +radeon_drm_abort_one(struct radeon_drm_queue_entry *e) +{ + xorg_list_del(&e->list); + e->abort(e->scrn, e->data); + free(e); +} + +/* + * Abort drm queue entries for a client + */ +void +radeon_drm_abort_client(ClientPtr client) +{ + struct radeon_drm_queue_entry *e, *tmp; + + xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) { + if (e->client == client) + radeon_drm_abort_one(e); + } +} + +/* + * Abort specific drm queue entry + */ +void +radeon_drm_abort_entry(struct radeon_drm_queue_entry *entry) +{ + radeon_drm_abort_one(entry); +} + +/* + * Abort specific drm queue entry by ID + */ +void +radeon_drm_abort_id(uint64_t id) +{ + struct radeon_drm_queue_entry *e, *tmp; + + xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) { + if (e->id == id) { + radeon_drm_abort_one(e); + break; + } + } +} + +/* + * Initialize the DRM event queue + */ +void +radeon_drm_queue_init() +{ + if (radeon_drm_queue_refcnt++) + return; + + xorg_list_init(&radeon_drm_queue); +} + +/* + * Deinitialize the DRM event queue + */ +void +radeon_drm_queue_close(ScrnInfoPtr scrn) +{ + struct radeon_drm_queue_entry *e, *tmp; + + xorg_list_for_each_entry_safe(e, tmp, &radeon_drm_queue, list) { + if (e->scrn == scrn) + radeon_drm_abort_one(e); + } + + radeon_drm_queue_refcnt--; +} diff --git a/driver/xf86-video-ati/src/radeon_drm_queue.h b/driver/xf86-video-ati/src/radeon_drm_queue.h new file mode 100644 index 000000000..8fc1c42e0 --- /dev/null +++ b/driver/xf86-video-ati/src/radeon_drm_queue.h @@ -0,0 +1,56 @@ +/* + * Copyright © 2007 Red Hat, Inc. + * Copyright © 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * Authors: + * Dave Airlie + * + */ + +#ifndef _RADEON_DRM_QUEUE_H_ +#define _RADEON_DRM_QUEUE_H_ + +#define RADEON_DRM_QUEUE_CLIENT_DEFAULT serverClient +#define RADEON_DRM_QUEUE_ID_DEFAULT ~0ULL + +struct radeon_drm_queue_entry; + +typedef void (*radeon_drm_handler_proc)(ScrnInfoPtr scrn, uint32_t seq, + uint64_t usec, void *data); +typedef void (*radeon_drm_abort_proc)(ScrnInfoPtr scrn, void *data); + +void radeon_drm_queue_handler(int fd, unsigned int frame, + unsigned int tv_sec, unsigned int tv_usec, + void *user_ptr); +struct radeon_drm_queue_entry *radeon_drm_queue_alloc(ScrnInfoPtr scrn, + ClientPtr client, + uint64_t id, + void *data, + radeon_drm_handler_proc handler, + radeon_drm_abort_proc abort); +void radeon_drm_abort_client(ClientPtr client); +void radeon_drm_abort_entry(struct radeon_drm_queue_entry *entry); +void radeon_drm_abort_id(uint64_t id); +void radeon_drm_queue_init(); +void radeon_drm_queue_close(ScrnInfoPtr scrn); + +#endif /* _RADEON_DRM_QUEUE_H_ */ diff --git a/driver/xf86-video-ati/src/radeon_exa.c b/driver/xf86-video-ati/src/radeon_exa.c index 0d6cd2400..1e457a8bb 100644 --- a/driver/xf86-video-ati/src/radeon_exa.c +++ b/driver/xf86-video-ati/src/radeon_exa.c @@ -330,7 +330,6 @@ Bool RADEONEXASetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle) return FALSE; driver_priv->shared = TRUE; - driver_priv->tiling_flags = 0; return TRUE; } #endif diff --git a/driver/xf86-video-ati/src/radeon_glamor.c b/driver/xf86-video-ati/src/radeon_glamor.c index 210ddcf27..fdd5aeac4 100644 --- a/driver/xf86-video-ati/src/radeon_glamor.c +++ b/driver/xf86-video-ati/src/radeon_glamor.c @@ -29,11 +29,10 @@ #endif #include -#define GLAMOR_FOR_XORG 1 -#include #include "radeon.h" #include "radeon_bo_helper.h" +#include "radeon_glamor.h" #if HAS_DEVPRIVATEKEYREC DevPrivateKeyRec glamor_pixmap_index; @@ -61,8 +60,10 @@ radeon_glamor_create_screen_resources(ScreenPtr screen) if (!info->use_glamor) return TRUE; +#ifdef HAVE_GLAMOR_GLYPHS_INIT if (!glamor_glyphs_init(screen)) return FALSE; +#endif if (!glamor_egl_create_textured_screen_ext(screen, info->front_bo->handle, @@ -152,51 +153,30 @@ radeon_glamor_pre_init(ScrnInfoPtr scrn) } Bool -radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) +radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *priv) { - ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen); - RADEONInfoPtr info = RADEONPTR(scrn); - struct radeon_pixmap *priv; - - if ((info->use_glamor) == 0) - return TRUE; - - priv = radeon_get_pixmap_private(pixmap); - if (!priv->stride) - priv->stride = pixmap->devKind; - if (glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle, - priv->stride)) - return TRUE; - else - return FALSE; + return glamor_egl_create_textured_pixmap(pixmap, priv->bo->handle, + pixmap->devKind); } -Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap) -{ - struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); - return priv && priv->bo; -} - -#ifndef CREATE_PIXMAP_USAGE_SHARED -#define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2 -#endif - -#define RADEON_CREATE_PIXMAP_SHARED(usage) \ - (((usage) & ~RADEON_CREATE_PIXMAP_TILING_FLAGS) == RADEON_CREATE_PIXMAP_DRI2 || \ - (usage) == CREATE_PIXMAP_USAGE_SHARED) - static PixmapPtr radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, unsigned usage) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); struct radeon_pixmap *priv; PixmapPtr pixmap, new_pixmap = NULL; if (!RADEON_CREATE_PIXMAP_SHARED(usage)) { - pixmap = glamor_create_pixmap(screen, w, h, depth, usage); - if (pixmap) - return pixmap; + if (info->shadow_primary) { + if (usage != CREATE_PIXMAP_USAGE_BACKING_PIXMAP) + return fbCreatePixmap(screen, w, h, depth, usage); + } else { + pixmap = glamor_create_pixmap(screen, w, h, depth, usage); + if (pixmap) + return pixmap; + } } if (w > 32767 || h > 32767) @@ -213,13 +193,15 @@ radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, return pixmap; if (w && h) { + int stride; + priv = calloc(1, sizeof (struct radeon_pixmap)); if (priv == NULL) goto fallback_pixmap; priv->bo = radeon_alloc_pixmap_bo(scrn, w, h, depth, usage, pixmap->drawable.bitsPerPixel, - &priv->stride, + &stride, &priv->surface, &priv->tiling_flags); if (!priv->bo) @@ -227,10 +209,12 @@ radeon_glamor_create_pixmap(ScreenPtr screen, int w, int h, int depth, radeon_set_pixmap_private(pixmap, priv); - screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, priv->stride, NULL); + screen->ModifyPixmapHeader(pixmap, w, h, 0, 0, stride, NULL); - if (!radeon_glamor_create_textured_pixmap(pixmap)) + if (!radeon_glamor_create_textured_pixmap(pixmap, priv)) goto fallback_glamor; + + pixmap->devPrivate.ptr = NULL; } return pixmap; @@ -269,6 +253,13 @@ fallback_pixmap: static Bool radeon_glamor_destroy_pixmap(PixmapPtr pixmap) { if (pixmap->refcnt == 1) { + if (pixmap->devPrivate.ptr) { + struct radeon_bo *bo = radeon_get_pixmap_bo(pixmap); + + if (bo) + radeon_bo_unmap(bo); + } + glamor_egl_destroy_textured_pixmap(pixmap); radeon_set_pixmap_bo(pixmap, NULL); } @@ -302,11 +293,9 @@ radeon_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle) return FALSE; priv = radeon_get_pixmap_private(pixmap); - priv->stride = pixmap->devKind; priv->surface = surface; - priv->tiling_flags = 0; - if (!radeon_glamor_create_textured_pixmap(pixmap)) { + if (!radeon_glamor_create_textured_pixmap(pixmap, priv)) { xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to get PRIME drawable for glamor pixmap.\n"); return FALSE; @@ -315,9 +304,7 @@ radeon_glamor_set_shared_pixmap_backing(PixmapPtr pixmap, void *handle) screen->ModifyPixmapHeader(pixmap, pixmap->drawable.width, pixmap->drawable.height, - 0, 0, - priv->stride, - NULL); + 0, 0, 0, NULL); return TRUE; } @@ -328,12 +315,30 @@ Bool radeon_glamor_init(ScreenPtr screen) { ScrnInfoPtr scrn = xf86ScreenToScrn(screen); - - if (!glamor_init(screen, GLAMOR_INVERTED_Y_AXIS | GLAMOR_USE_EGL_SCREEN | -#ifdef GLAMOR_NO_DRI3 - GLAMOR_NO_DRI3 | + RADEONInfoPtr info = RADEONPTR(scrn); +#ifdef RENDER +#ifdef HAVE_FBGLYPHS + UnrealizeGlyphProcPtr SavedUnrealizeGlyph = NULL; #endif - GLAMOR_USE_SCREEN | GLAMOR_USE_PICTURE_SCREEN)) { + PictureScreenPtr ps = NULL; + + if (info->shadow_primary) { + ps = GetPictureScreenIfSet(screen); + + if (ps) { +#ifdef HAVE_FBGLYPHS + SavedUnrealizeGlyph = ps->UnrealizeGlyph; +#endif + info->glamor.SavedGlyphs = ps->Glyphs; + info->glamor.SavedTriangles = ps->Triangles; + info->glamor.SavedTrapezoids = ps->Trapezoids; + } + } +#endif /* RENDER */ + + if (!glamor_init(screen, GLAMOR_USE_EGL_SCREEN | GLAMOR_USE_SCREEN | + GLAMOR_USE_PICTURE_SCREEN | GLAMOR_INVERTED_Y_AXIS | + GLAMOR_NO_DRI3)) { xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to initialize glamor.\n"); return FALSE; @@ -352,6 +357,17 @@ radeon_glamor_init(ScreenPtr screen) #endif return FALSE; + if (info->shadow_primary) + radeon_glamor_screen_init(screen); + +#if defined(RENDER) && defined(HAVE_FBGLYPHS) + /* For ShadowPrimary, we need fbUnrealizeGlyph instead of + * glamor_unrealize_glyph + */ + if (ps) + ps->UnrealizeGlyph = SavedUnrealizeGlyph; +#endif + screen->CreatePixmap = radeon_glamor_create_pixmap; screen->DestroyPixmap = radeon_glamor_destroy_pixmap; #ifdef RADEON_PIXMAP_SHARING @@ -364,15 +380,6 @@ radeon_glamor_init(ScreenPtr screen) return TRUE; } -void -radeon_glamor_flush(ScrnInfoPtr pScrn) -{ - RADEONInfoPtr info = RADEONPTR(pScrn); - - if (info->use_glamor) - glamor_block_handler(pScrn->pScreen); -} - XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt) { return glamor_xv_init(pScreen, num_adapt); diff --git a/driver/xf86-video-ati/src/radeon_glamor.h b/driver/xf86-video-ati/src/radeon_glamor.h index 36addd70d..246336b18 100644 --- a/driver/xf86-video-ati/src/radeon_glamor.h +++ b/driver/xf86-video-ati/src/radeon_glamor.h @@ -28,52 +28,51 @@ #define RADEON_GLAMOR_H #include "xf86xv.h" + +struct radeon_pixmap; + #ifdef USE_GLAMOR +#define GLAMOR_FOR_XORG 1 +#include + #include "radeon_surface.h" +#ifndef CREATE_PIXMAP_USAGE_SHARED +#define CREATE_PIXMAP_USAGE_SHARED RADEON_CREATE_PIXMAP_DRI2 +#endif + +#define RADEON_CREATE_PIXMAP_SHARED(usage) \ + (((usage) & ~RADEON_CREATE_PIXMAP_TILING_FLAGS) == RADEON_CREATE_PIXMAP_DRI2 || \ + (usage) == CREATE_PIXMAP_USAGE_SHARED) + +#ifndef GLAMOR_NO_DRI3 +#define GLAMOR_NO_DRI3 0 +#define glamor_fd_from_pixmap glamor_dri3_fd_from_pixmap +#define glamor_pixmap_from_fd glamor_egl_dri3_pixmap_from_fd +#endif + +#ifndef GLAMOR_INVERTED_Y_AXIS +#define GLAMOR_INVERTED_Y_AXIS 0 +#endif +#ifndef GLAMOR_USE_SCREEN +#define GLAMOR_USE_SCREEN 0 +#endif +#ifndef GLAMOR_USE_PICTURE_SCREEN +#define GLAMOR_USE_PICTURE_SCREEN 0 +#endif + Bool radeon_glamor_pre_init(ScrnInfoPtr scrn); Bool radeon_glamor_init(ScreenPtr screen); +void radeon_glamor_screen_init(ScreenPtr screen); Bool radeon_glamor_create_screen_resources(ScreenPtr screen); void radeon_glamor_free_screen(int scrnIndex, int flags); -void radeon_glamor_flush(ScrnInfoPtr pScrn); - -Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap); +Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *priv); void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst); -Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap); - XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt); -struct radeon_pixmap { - struct radeon_surface surface; - struct radeon_bo *bo; - - uint32_t tiling_flags; - int stride; -}; - -#if HAS_DEVPRIVATEKEYREC -extern DevPrivateKeyRec glamor_pixmap_index; -#else -extern int glamor_pixmap_index; -#endif - -static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) -{ -#if HAS_DEVPRIVATEKEYREC - return dixGetPrivate(&pixmap->devPrivates, &glamor_pixmap_index); -#else - return dixLookupPrivate(&pixmap->devPrivates, &glamor_pixmap_index); -#endif -} - -static inline void radeon_set_pixmap_private(PixmapPtr pixmap, struct radeon_pixmap *priv) -{ - dixSetPrivate(&pixmap->devPrivates, &glamor_pixmap_index, priv); -} - #else static inline Bool radeon_glamor_pre_init(ScrnInfoPtr scrn) { return FALSE; } @@ -81,14 +80,10 @@ static inline Bool radeon_glamor_init(ScreenPtr screen) { return FALSE; } static inline Bool radeon_glamor_create_screen_resources(ScreenPtr screen) { return FALSE; } static inline void radeon_glamor_free_screen(int scrnIndex, int flags) { } -static inline void radeon_glamor_flush(ScrnInfoPtr pScrn) { } - -static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap) { return TRUE; } +static inline Bool radeon_glamor_create_textured_pixmap(PixmapPtr pixmap, struct radeon_pixmap *priv) { return TRUE; } static inline void radeon_glamor_exchange_buffers(PixmapPtr src, PixmapPtr dst) {} -static inline Bool radeon_glamor_pixmap_is_offscreen(PixmapPtr pixmap) { return FALSE; } - static inline struct radeon_pixmap *radeon_get_pixmap_private(PixmapPtr pixmap) { return NULL; } static inline XF86VideoAdaptorPtr radeon_glamor_xv_init(ScreenPtr pScreen, int num_adapt) { return NULL; } diff --git a/driver/xf86-video-ati/src/radeon_glamor_wrappers.c b/driver/xf86-video-ati/src/radeon_glamor_wrappers.c new file mode 100644 index 000000000..ec81560cc --- /dev/null +++ b/driver/xf86-video-ati/src/radeon_glamor_wrappers.c @@ -0,0 +1,994 @@ +/* + * Copyright © 2001 Keith Packard + * 2010 Intel Corporation + * 2012,2015 Advanced Micro Devices, Inc. + * + * Partly based on code Copyright © 2008 Red Hat, Inc. + * Partly based on code Copyright © 2000 SuSE, Inc. + * + * Partly based on code that is Copyright © The XFree86 Project Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of the opyright holders not be used in + * advertising or publicity pertaining to distribution of the software without + * specific, written prior permission. The copyright holders make no + * representations about the suitability of this software for any purpose. It + * is provided "as is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef USE_GLAMOR + +#include "radeon.h" +#include "radeon_glamor.h" + + +/** + * get_drawable_pixmap() returns the backing pixmap for a given drawable. + * + * @param pDrawable the drawable being requested. + * + * This function returns the backing pixmap for a drawable, whether it is a + * redirected window, unredirected window, or already a pixmap. + */ +static PixmapPtr +get_drawable_pixmap(DrawablePtr pDrawable) +{ + if (pDrawable->type == DRAWABLE_WINDOW) + return pDrawable->pScreen-> + GetWindowPixmap((WindowPtr) pDrawable); + else + return (PixmapPtr) pDrawable; +} + +/* Are there any outstanding GPU operations for this pixmap? */ +static Bool +radeon_glamor_gpu_pending(uint_fast32_t gpu_synced, uint_fast32_t gpu_access) +{ + return (int_fast32_t)(gpu_access - gpu_synced) > 0; +} + +/* + * Pixmap CPU access wrappers + */ + +static Bool +radeon_glamor_prepare_access_cpu(ScrnInfoPtr scrn, RADEONInfoPtr info, + PixmapPtr pixmap, struct radeon_pixmap *priv, + Bool need_sync) +{ + struct radeon_bo *bo = priv->bo; + int ret; + + /* When falling back to swrast, flush all pending operations */ + if (need_sync) { + glamor_block_handler(scrn->pScreen); + info->gpu_flushed++; + } + + if (!pixmap->devPrivate.ptr) { + ret = radeon_bo_map(bo, 1); + if (ret) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "%s: bo map (tiling_flags %d) failed: %s\n", + __FUNCTION__, + priv->tiling_flags, + strerror(-ret)); + return FALSE; + } + + pixmap->devPrivate.ptr = bo->ptr; + info->gpu_synced = info->gpu_flushed; + } else if (need_sync) { + radeon_bo_wait(bo); + info->gpu_synced = info->gpu_flushed; + } + + return TRUE; +} + +static Bool +radeon_glamor_prepare_access_cpu_ro(ScrnInfoPtr scrn, PixmapPtr pixmap, + struct radeon_pixmap *priv) +{ + RADEONInfoPtr info; + Bool need_sync; + + if (!priv) + return TRUE; + + info = RADEONPTR(scrn); + need_sync = radeon_glamor_gpu_pending(info->gpu_synced, priv->gpu_write); + return radeon_glamor_prepare_access_cpu(scrn, RADEONPTR(scrn), pixmap, + priv, need_sync); +} + +static Bool +radeon_glamor_prepare_access_cpu_rw(ScrnInfoPtr scrn, PixmapPtr pixmap, + struct radeon_pixmap *priv) +{ + RADEONInfoPtr info; + uint_fast32_t gpu_synced; + Bool need_sync; + + if (!priv) + return TRUE; + + info = RADEONPTR(scrn); + gpu_synced = info->gpu_synced; + need_sync = radeon_glamor_gpu_pending(gpu_synced, priv->gpu_write) | + radeon_glamor_gpu_pending(gpu_synced, priv->gpu_read); + return radeon_glamor_prepare_access_cpu(scrn, info, pixmap, priv, + need_sync); +} + +static void +radeon_glamor_finish_access_cpu(PixmapPtr pixmap) +{ + /* Nothing to do */ +} + +/* + * Pixmap GPU access wrappers + */ + +static Bool +radeon_glamor_prepare_access_gpu(struct radeon_pixmap *priv) +{ + return priv != NULL; +} + +static void +radeon_glamor_finish_access_gpu_ro(RADEONInfoPtr info, + struct radeon_pixmap *priv) +{ + priv->gpu_read = info->gpu_flushed + 1; +} + +static void +radeon_glamor_finish_access_gpu_rw(RADEONInfoPtr info, + struct radeon_pixmap *priv) +{ + priv->gpu_write = priv->gpu_read = info->gpu_flushed + 1; +} + +/* + * GC CPU access wrappers + */ + +static Bool +radeon_glamor_prepare_access_gc(ScrnInfoPtr scrn, GCPtr pGC) +{ + struct radeon_pixmap *priv; + + if (pGC->stipple) { + priv = radeon_get_pixmap_private(pGC->stipple); + if (!radeon_glamor_prepare_access_cpu_ro(scrn, pGC->stipple, priv)) + return FALSE; + } + if (pGC->fillStyle == FillTiled) { + priv = radeon_get_pixmap_private(pGC->tile.pixmap); + if (!radeon_glamor_prepare_access_cpu_ro(scrn, pGC->tile.pixmap, + priv)) { + if (pGC->stipple) + radeon_glamor_finish_access_cpu(pGC->stipple); + return FALSE; + } + } + return TRUE; +} + +static void +radeon_glamor_finish_access_gc(GCPtr pGC) +{ + if (pGC->fillStyle == FillTiled) + radeon_glamor_finish_access_cpu(pGC->tile.pixmap); + if (pGC->stipple) + radeon_glamor_finish_access_cpu(pGC->stipple); +} + +/* + * Picture CPU access wrappers + */ + +static void +radeon_glamor_picture_finish_access_cpu(PicturePtr picture) +{ + /* Nothing to do */ +} + +static Bool +radeon_glamor_picture_prepare_access_cpu_ro(ScrnInfoPtr scrn, + PicturePtr picture) +{ + PixmapPtr pixmap; + struct radeon_pixmap *priv; + + if (picture->pDrawable == NULL) + return TRUE; + + pixmap = get_drawable_pixmap(picture->pDrawable); + priv = radeon_get_pixmap_private(pixmap); + if (!radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) + return FALSE; + + if (picture->alphaMap) { + pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable); + priv = radeon_get_pixmap_private(pixmap); + if (!radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) { + radeon_glamor_picture_finish_access_cpu(picture); + return FALSE; + } + } + + return TRUE; +} + +static Bool +radeon_glamor_picture_prepare_access_cpu_rw(ScrnInfoPtr scrn, + PicturePtr picture) +{ + PixmapPtr pixmap; + struct radeon_pixmap *priv; + + pixmap = get_drawable_pixmap(picture->pDrawable); + priv = radeon_get_pixmap_private(pixmap); + if (!radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) + return FALSE; + + if (picture->alphaMap) { + pixmap = get_drawable_pixmap(picture->alphaMap->pDrawable); + priv = radeon_get_pixmap_private(pixmap); + if (!radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + radeon_glamor_picture_finish_access_cpu(picture); + return FALSE; + } + } + + return TRUE; +} + +/* + * GC rendering wrappers + */ + +static void +radeon_glamor_fill_spans(DrawablePtr pDrawable, GCPtr pGC, int nspans, + DDXPointPtr ppt, int *pwidth, int fSorted) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (radeon_glamor_prepare_access_gc(scrn, pGC)) { + fbFillSpans(pDrawable, pGC, nspans, ppt, pwidth, + fSorted); + radeon_glamor_finish_access_gc(pGC); + } + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_set_spans(DrawablePtr pDrawable, GCPtr pGC, char *psrc, + DDXPointPtr ppt, int *pwidth, int nspans, int fSorted) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbSetSpans(pDrawable, pGC, psrc, ppt, pwidth, nspans, fSorted); + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_put_image(DrawablePtr pDrawable, GCPtr pGC, int depth, + int x, int y, int w, int h, int leftPad, int format, + char *bits) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbPutImage(pDrawable, pGC, depth, x, y, w, h, leftPad, format, + bits); + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static RegionPtr +radeon_glamor_copy_plane(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, int dstx, int dsty, + unsigned long bitPlane) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen); + PixmapPtr dst_pix = get_drawable_pixmap(pDst); + struct radeon_pixmap *dst_priv = radeon_get_pixmap_private(dst_pix); + RegionPtr ret = NULL; + + if (radeon_glamor_prepare_access_cpu_rw(scrn, dst_pix, dst_priv)) { + PixmapPtr src_pix = get_drawable_pixmap(pSrc); + struct radeon_pixmap *src_priv = radeon_get_pixmap_private(src_pix); + if (radeon_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) { + ret = + fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, dstx, + dsty, bitPlane); + radeon_glamor_finish_access_cpu(src_pix); + } + radeon_glamor_finish_access_cpu(dst_pix); + } + return ret; +} + +static RegionPtr +radeon_glamor_copy_plane_nodstbo(DrawablePtr pSrc, DrawablePtr pDst, GCPtr pGC, + int srcx, int srcy, int w, int h, + int dstx, int dsty, unsigned long bitPlane) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pScreen); + PixmapPtr src_pix = get_drawable_pixmap(pSrc); + struct radeon_pixmap *src_priv = radeon_get_pixmap_private(src_pix); + RegionPtr ret = NULL; + + if (radeon_glamor_prepare_access_cpu_ro(scrn, src_pix, src_priv)) { + ret = fbCopyPlane(pSrc, pDst, pGC, srcx, srcy, w, h, + dstx, dsty, bitPlane); + radeon_glamor_finish_access_cpu(src_pix); + } + return ret; +} + +static void +radeon_glamor_poly_point(DrawablePtr pDrawable, GCPtr pGC, int mode, int npt, + DDXPointPtr pptInit) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbPolyPoint(pDrawable, pGC, mode, npt, pptInit); + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_poly_lines(DrawablePtr pDrawable, GCPtr pGC, + int mode, int npt, DDXPointPtr ppt) +{ + if (pGC->lineWidth == 0) { + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (radeon_glamor_prepare_access_gc(scrn, pGC)) { + fbPolyLine(pDrawable, pGC, mode, npt, ppt); + radeon_glamor_finish_access_gc(pGC); + } + radeon_glamor_finish_access_cpu(pixmap); + } + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolyLine(pDrawable, pGC, mode, npt, ppt); +} + +static void +radeon_glamor_poly_segment(DrawablePtr pDrawable, GCPtr pGC, + int nsegInit, xSegment *pSegInit) +{ + if (pGC->lineWidth == 0) { + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (radeon_glamor_prepare_access_gc(scrn, pGC)) { + fbPolySegment(pDrawable, pGC, nsegInit, + pSegInit); + radeon_glamor_finish_access_gc(pGC); + } + radeon_glamor_finish_access_cpu(pixmap); + } + return; + } + /* fb calls mi functions in the lineWidth != 0 case. */ + fbPolySegment(pDrawable, pGC, nsegInit, pSegInit); +} + +static void +radeon_glamor_poly_fill_rect(DrawablePtr pDrawable, GCPtr pGC, + int nrect, xRectangle *prect) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + RADEONInfoPtr info = RADEONPTR(scrn); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if ((info->accel_state->force || (priv && !priv->bo)) && + radeon_glamor_prepare_access_gpu(priv)) { + info->glamor.SavedPolyFillRect(pDrawable, pGC, nrect, prect); + radeon_glamor_finish_access_gpu_rw(info, priv); + return; + } + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (radeon_glamor_prepare_access_gc(scrn, pGC)) { + fbPolyFillRect(pDrawable, pGC, nrect, prect); + radeon_glamor_finish_access_gc(pGC); + } + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_image_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (radeon_glamor_prepare_access_gc(scrn, pGC)) { + fbImageGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + radeon_glamor_finish_access_gc(pGC); + } + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_poly_glyph_blt(DrawablePtr pDrawable, GCPtr pGC, + int x, int y, unsigned int nglyph, + CharInfoPtr *ppci, pointer pglyphBase) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + if (radeon_glamor_prepare_access_gc(scrn, pGC)) { + fbPolyGlyphBlt(pDrawable, pGC, x, y, nglyph, ppci, + pglyphBase); + radeon_glamor_finish_access_gc(pGC); + } + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_push_pixels(GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, int w, int h, int x, int y) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + priv = radeon_get_pixmap_private(pBitmap); + if (radeon_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) { + if (radeon_glamor_prepare_access_gc(scrn, pGC)) { + fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, + y); + radeon_glamor_finish_access_gc(pGC); + } + radeon_glamor_finish_access_cpu(pBitmap); + } + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_push_pixels_nodstbo(GCPtr pGC, PixmapPtr pBitmap, + DrawablePtr pDrawable, int w, int h, + int x, int y) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pBitmap); + + if (radeon_glamor_prepare_access_cpu_ro(scrn, pBitmap, priv)) { + fbPushPixels(pGC, pBitmap, pDrawable, w, h, x, y); + radeon_glamor_finish_access_cpu(pBitmap); + } +} + +static RegionPtr +radeon_glamor_copy_area(DrawablePtr pSrcDrawable, DrawablePtr pDstDrawable, + GCPtr pGC, int srcx, int srcy, int width, int height, + int dstx, int dsty) +{ + ScreenPtr screen = pDstDrawable->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable); + PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable); + struct radeon_pixmap *src_priv = radeon_get_pixmap_private(src_pixmap); + struct radeon_pixmap *dst_priv = radeon_get_pixmap_private(dst_pixmap); + RegionPtr ret = NULL; + + if (info->accel_state->force || (src_priv && !src_priv->bo) || + (dst_priv && !dst_priv->bo)) { + if (!radeon_glamor_prepare_access_gpu(dst_priv)) + goto fallback; + if (src_priv != dst_priv && + !radeon_glamor_prepare_access_gpu(src_priv)) + goto fallback; + + ret = info->glamor.SavedCopyArea(pSrcDrawable, pDstDrawable, + pGC, srcx, srcy, + width, height, dstx, dsty); + radeon_glamor_finish_access_gpu_rw(info, dst_priv); + if (src_priv != dst_priv) + radeon_glamor_finish_access_gpu_ro(info, src_priv); + + return ret; + } + +fallback: + if (radeon_glamor_prepare_access_cpu_rw(scrn, dst_pixmap, dst_priv)) { + if (pSrcDrawable == pDstDrawable || + radeon_glamor_prepare_access_cpu_ro(scrn, src_pixmap, + src_priv)) { + ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC, + srcx, srcy, width, height, dstx, dsty); + if (pSrcDrawable != pDstDrawable) + radeon_glamor_finish_access_cpu(src_pixmap); + } + radeon_glamor_finish_access_cpu(dst_pixmap); + } + + return ret; +} + +static RegionPtr +radeon_glamor_copy_area_nodstbo(DrawablePtr pSrcDrawable, + DrawablePtr pDstDrawable, GCPtr pGC, + int srcx, int srcy, int width, int height, + int dstx, int dsty) +{ + ScreenPtr screen = pDstDrawable->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + PixmapPtr src_pixmap = get_drawable_pixmap(pSrcDrawable); + PixmapPtr dst_pixmap = get_drawable_pixmap(pDstDrawable); + struct radeon_pixmap *src_priv; + RegionPtr ret = NULL; + + if (src_pixmap != dst_pixmap) { + src_priv = radeon_get_pixmap_private(src_pixmap); + + if (!radeon_glamor_prepare_access_cpu_ro(scrn, src_pixmap, + src_priv)) + return ret; + } + + ret = fbCopyArea(pSrcDrawable, pDstDrawable, pGC, srcx, srcy, + width, height, dstx, dsty); + + if (src_pixmap != dst_pixmap) + radeon_glamor_finish_access_cpu(src_pixmap); + + return ret; +} + +static const GCOps radeon_glamor_ops = { + radeon_glamor_fill_spans, + radeon_glamor_set_spans, + radeon_glamor_put_image, + radeon_glamor_copy_area, + radeon_glamor_copy_plane, + radeon_glamor_poly_point, + radeon_glamor_poly_lines, + radeon_glamor_poly_segment, + miPolyRectangle, + miPolyArc, + miFillPolygon, + radeon_glamor_poly_fill_rect, + miPolyFillArc, + miPolyText8, + miPolyText16, + miImageText8, + miImageText16, + radeon_glamor_image_glyph_blt, + radeon_glamor_poly_glyph_blt, + radeon_glamor_push_pixels, +}; + +static GCOps radeon_glamor_nodstbo_ops; + +/** + * radeon_glamor_validate_gc() sets the ops to our implementations, which may be + * accelerated or may sync the card and fall back to fb. + */ +static void +radeon_glamor_validate_gc(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pGC->pScreen); + RADEONInfoPtr info = RADEONPTR(scrn); + + glamor_validate_gc(pGC, changes, pDrawable); + info->glamor.SavedCopyArea = pGC->ops->CopyArea; + info->glamor.SavedPolyFillRect = pGC->ops->PolyFillRect; + + if (radeon_get_pixmap_private(get_drawable_pixmap(pDrawable)) || + (pGC->stipple && radeon_get_pixmap_private(pGC->stipple)) || + (pGC->fillStyle == FillTiled && + radeon_get_pixmap_private(pGC->tile.pixmap))) + pGC->ops = (GCOps *)&radeon_glamor_ops; + else + pGC->ops = &radeon_glamor_nodstbo_ops; +} + +static GCFuncs glamorGCFuncs = { + radeon_glamor_validate_gc, + miChangeGC, + miCopyGC, + miDestroyGC, + miChangeClip, + miDestroyClip, + miCopyClip +}; + +/** + * radeon_glamor_create_gc makes a new GC and hooks up its funcs handler, so that + * radeon_glamor_validate_gc() will get called. + */ +static int +radeon_glamor_create_gc(GCPtr pGC) +{ + static Bool nodstbo_ops_initialized; + + if (!fbCreateGC(pGC)) + return FALSE; + + if (!nodstbo_ops_initialized) { + radeon_glamor_nodstbo_ops = radeon_glamor_ops; + + radeon_glamor_nodstbo_ops.FillSpans = pGC->ops->FillSpans; + radeon_glamor_nodstbo_ops.SetSpans = pGC->ops->SetSpans; + radeon_glamor_nodstbo_ops.PutImage = pGC->ops->PutImage; + radeon_glamor_nodstbo_ops.CopyArea = radeon_glamor_copy_area_nodstbo; + radeon_glamor_nodstbo_ops.CopyPlane = radeon_glamor_copy_plane_nodstbo; + radeon_glamor_nodstbo_ops.PolyPoint = pGC->ops->PolyPoint; + radeon_glamor_nodstbo_ops.Polylines = pGC->ops->Polylines; + radeon_glamor_nodstbo_ops.PolySegment = pGC->ops->PolySegment; + radeon_glamor_nodstbo_ops.PolyFillRect = pGC->ops->PolyFillRect; + radeon_glamor_nodstbo_ops.ImageGlyphBlt = pGC->ops->ImageGlyphBlt; + radeon_glamor_nodstbo_ops.PolyGlyphBlt = pGC->ops->PolyGlyphBlt; + radeon_glamor_nodstbo_ops.PushPixels = radeon_glamor_push_pixels_nodstbo; + + nodstbo_ops_initialized = TRUE; + } + + pGC->funcs = &glamorGCFuncs; + + return TRUE; +} + +/* + * Screen rendering wrappers + */ + +static RegionPtr +radeon_glamor_bitmap_to_region(PixmapPtr pPix) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pPix->drawable.pScreen); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pPix); + RegionPtr ret; + + if (!radeon_glamor_prepare_access_cpu_ro(scrn, pPix, priv)) + return NULL; + ret = fbPixmapToRegion(pPix); + radeon_glamor_finish_access_cpu(pPix); + return ret; +} + +static void +radeon_glamor_copy_window(WindowPtr pWin, DDXPointRec ptOldOrg, + RegionPtr prgnSrc) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pWin->drawable.pScreen); + PixmapPtr pixmap = get_drawable_pixmap(&pWin->drawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_rw(scrn, pixmap, priv)) { + fbCopyWindow(pWin, ptOldOrg, prgnSrc); + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_get_image(DrawablePtr pDrawable, int x, int y, int w, int h, + unsigned int format, unsigned long planeMask, char *d) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) { + fbGetImage(pDrawable, x, y, w, h, format, planeMask, d); + radeon_glamor_finish_access_cpu(pixmap); + } +} + +static void +radeon_glamor_get_spans(DrawablePtr pDrawable, int wMax, DDXPointPtr ppt, + int *pwidth, int nspans, char *pdstStart) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDrawable->pScreen); + PixmapPtr pixmap = get_drawable_pixmap(pDrawable); + struct radeon_pixmap *priv = radeon_get_pixmap_private(pixmap); + + if (radeon_glamor_prepare_access_cpu_ro(scrn, pixmap, priv)) { + fbGetSpans(pDrawable, wMax, ppt, pwidth, nspans, pdstStart); + radeon_glamor_finish_access_cpu(pixmap); + } +} + +/* + * Picture screen rendering wrappers + */ + +#ifdef RENDER + +static void +radeon_glamor_composite(CARD8 op, + PicturePtr pSrc, + PicturePtr pMask, + PicturePtr pDst, + INT16 xSrc, INT16 ySrc, + INT16 xMask, INT16 yMask, + INT16 xDst, INT16 yDst, + CARD16 width, CARD16 height) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pDst->pDrawable->pScreen); + RADEONInfoPtr info; + PixmapPtr pixmap; + struct radeon_pixmap *dst_priv, *src_priv = NULL, *mask_priv = NULL; + Bool gpu_done = FALSE; + + if (pDst->alphaMap || pSrc->alphaMap || (pMask && pMask->alphaMap)) + goto fallback; + + pixmap = get_drawable_pixmap(pDst->pDrawable); + if (&pixmap->drawable != pDst->pDrawable || + pixmap->usage_hint != RADEON_CREATE_PIXMAP_SCANOUT) + goto fallback; + + dst_priv = radeon_get_pixmap_private(pixmap); + if (!radeon_glamor_prepare_access_gpu(dst_priv)) + goto fallback; + + info = RADEONPTR(scrn); + if (!pSrc->pDrawable || + ((pixmap = get_drawable_pixmap(pSrc->pDrawable)) && + (src_priv = radeon_get_pixmap_private(pixmap)) && + radeon_glamor_prepare_access_gpu(src_priv))) { + if (!pMask || !pMask->pDrawable || + ((pixmap = get_drawable_pixmap(pMask->pDrawable)) && + (mask_priv = radeon_get_pixmap_private(pixmap)) && + radeon_glamor_prepare_access_gpu(mask_priv))) { + info->glamor.SavedComposite(op, pSrc, pMask, pDst, + xSrc, ySrc, xMask, yMask, + xDst, yDst, width, height); + gpu_done = TRUE; + + if (mask_priv) + radeon_glamor_finish_access_gpu_ro(info, mask_priv); + } + + if (src_priv) + radeon_glamor_finish_access_gpu_ro(info, src_priv); + } + radeon_glamor_finish_access_gpu_rw(info, dst_priv); + + if (gpu_done) + return; + +fallback: + if (radeon_glamor_picture_prepare_access_cpu_rw(scrn, pDst)) { + if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, pSrc)) { + if (!pMask || + radeon_glamor_picture_prepare_access_cpu_ro(scrn, pMask)) { + fbComposite(op, pSrc, pMask, pDst, + xSrc, ySrc, + xMask, yMask, + xDst, yDst, + width, height); + if (pMask) + radeon_glamor_picture_finish_access_cpu(pMask); + } + radeon_glamor_picture_finish_access_cpu(pSrc); + } + radeon_glamor_picture_finish_access_cpu(pDst); + } +} + +static void +radeon_glamor_add_traps(PicturePtr pPicture, + INT16 x_off, INT16 y_off, int ntrap, xTrap *traps) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(pPicture->pDrawable->pScreen); + + if (radeon_glamor_picture_prepare_access_cpu_rw(scrn, pPicture)) { + fbAddTraps(pPicture, x_off, y_off, ntrap, traps); + radeon_glamor_picture_finish_access_cpu(pPicture); + } +} + +static void +radeon_glamor_glyphs(CARD8 op, + PicturePtr src, + PicturePtr dst, + PictFormatPtr maskFormat, + INT16 xSrc, + INT16 ySrc, int nlist, GlyphListPtr list, GlyphPtr *glyphs) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen); + + if (radeon_glamor_picture_prepare_access_cpu_rw(scrn, dst)) { + if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, src)) { + RADEONInfoPtr info = RADEONPTR(scrn); + + info->glamor.SavedGlyphs(op, src, dst, maskFormat, xSrc, + ySrc, nlist, list, glyphs); + radeon_glamor_picture_finish_access_cpu(src); + } + radeon_glamor_picture_finish_access_cpu(dst); + } +} + +static void +radeon_glamor_trapezoids(CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntrap, xTrapezoid *traps) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen); + + if (radeon_glamor_picture_prepare_access_cpu_rw(scrn, dst)) { + if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, src)) { + RADEONInfoPtr info = RADEONPTR(scrn); + + info->glamor.SavedTrapezoids(op, src, dst, maskFormat, + xSrc, ySrc, ntrap, traps); + radeon_glamor_picture_finish_access_cpu(src); + } + radeon_glamor_picture_finish_access_cpu(dst); + } +} + +static void +radeon_glamor_triangles(CARD8 op, PicturePtr src, PicturePtr dst, + PictFormatPtr maskFormat, INT16 xSrc, INT16 ySrc, + int ntri, xTriangle *tri) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(dst->pDrawable->pScreen); + + if (radeon_glamor_picture_prepare_access_cpu_rw(scrn, dst)) { + if (radeon_glamor_picture_prepare_access_cpu_ro(scrn, src)) { + RADEONInfoPtr info = RADEONPTR(scrn); + + info->glamor.SavedTriangles(op, src, dst, maskFormat, + xSrc, ySrc, ntri, tri); + radeon_glamor_picture_finish_access_cpu(src); + } + radeon_glamor_picture_finish_access_cpu(dst); + } +} + +#endif /* RENDER */ + + +/** + * radeon_glamor_close_screen() unwraps its wrapped screen functions and tears + * down our screen private, before calling down to the next CloseScreen. + */ +static Bool +radeon_glamor_close_screen(CLOSE_SCREEN_ARGS_DECL) +{ + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(pScreen)); +#ifdef RENDER + PictureScreenPtr ps = GetPictureScreenIfSet(pScreen); +#endif + + pScreen->CreateGC = info->glamor.SavedCreateGC; + pScreen->CloseScreen = info->glamor.SavedCloseScreen; + pScreen->GetImage = info->glamor.SavedGetImage; + pScreen->GetSpans = info->glamor.SavedGetSpans; + pScreen->CreatePixmap = info->glamor.SavedCreatePixmap; + pScreen->DestroyPixmap = info->glamor.SavedDestroyPixmap; + pScreen->CopyWindow = info->glamor.SavedCopyWindow; + pScreen->ChangeWindowAttributes = + info->glamor.SavedChangeWindowAttributes; + pScreen->BitmapToRegion = info->glamor.SavedBitmapToRegion; +#ifdef RENDER + if (ps) { + ps->Composite = info->glamor.SavedComposite; + ps->Glyphs = info->glamor.SavedGlyphs; + ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph; + ps->Trapezoids = info->glamor.SavedTrapezoids; + ps->AddTraps = info->glamor.SavedAddTraps; + ps->Triangles = info->glamor.SavedTriangles; + + ps->UnrealizeGlyph = info->glamor.SavedUnrealizeGlyph; + } +#endif + + return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS); +} + +/** + * @param screen screen being initialized + */ +void +radeon_glamor_screen_init(ScreenPtr screen) +{ + RADEONInfoPtr info = RADEONPTR(xf86ScreenToScrn(screen)); + + /* + * Replace various fb screen functions + */ + info->glamor.SavedCloseScreen = screen->CloseScreen; + screen->CloseScreen = radeon_glamor_close_screen; + + info->glamor.SavedCreateGC = screen->CreateGC; + screen->CreateGC = radeon_glamor_create_gc; + + info->glamor.SavedGetImage = screen->GetImage; + screen->GetImage = radeon_glamor_get_image; + + info->glamor.SavedGetSpans = screen->GetSpans; + screen->GetSpans = radeon_glamor_get_spans; + + info->glamor.SavedCreatePixmap = screen->CreatePixmap; + info->glamor.SavedDestroyPixmap = screen->DestroyPixmap; + + info->glamor.SavedCopyWindow = screen->CopyWindow; + screen->CopyWindow = radeon_glamor_copy_window; + + info->glamor.SavedBitmapToRegion = screen->BitmapToRegion; + screen->BitmapToRegion = radeon_glamor_bitmap_to_region; + +#ifdef RENDER + { + PictureScreenPtr ps = GetPictureScreenIfSet(screen); + if (ps) { + info->glamor.SavedComposite = ps->Composite; + ps->Composite = radeon_glamor_composite; + + info->glamor.SavedUnrealizeGlyph = ps->UnrealizeGlyph; + + ps->Glyphs = radeon_glamor_glyphs; + ps->Triangles = radeon_glamor_triangles; + ps->Trapezoids = radeon_glamor_trapezoids; + + info->glamor.SavedAddTraps = ps->AddTraps; + ps->AddTraps = radeon_glamor_add_traps; + } + } +#endif +} + +#endif /* USE_GLAMOR */ diff --git a/driver/xf86-video-ati/src/radeon_kms.c b/driver/xf86-video-ati/src/radeon_kms.c index 1703349f1..8aa763327 100644 --- a/driver/xf86-video-ati/src/radeon_kms.c +++ b/driver/xf86-video-ati/src/radeon_kms.c @@ -32,6 +32,8 @@ #include /* Driver data structures */ #include "radeon.h" +#include "radeon_drm_queue.h" +#include "radeon_glamor.h" #include "radeon_reg.h" #include "radeon_probe.h" #include "micmap.h" @@ -68,12 +70,16 @@ const OptionInfoRec RADEONOptions_KMS[] = { { OPTION_SUBPIXEL_ORDER, "SubPixelOrder", OPTV_ANYSTR, {0}, FALSE }, #ifdef USE_GLAMOR { OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING, {0}, FALSE }, + { OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE }, #endif { OPTION_EXA_VSYNC, "EXAVSync", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_EXA_PIXMAPS, "EXAPixmaps", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE }, - { OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE }, { OPTION_SWAPBUFFERS_WAIT,"SwapbuffersWait", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_DRI, "DRI", OPTV_INTEGER, {0}, FALSE }, + { OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; @@ -82,12 +88,22 @@ const OptionInfoRec *RADEONOptionsWeak(void) { return RADEONOptions_KMS; } void radeon_cs_flush_indirect(ScrnInfoPtr pScrn) { RADEONInfoPtr info = RADEONPTR(pScrn); - struct radeon_accel_state *accel_state = info->accel_state; + struct radeon_accel_state *accel_state; int ret; +#ifdef USE_GLAMOR + if (info->use_glamor) { + glamor_block_handler(pScrn->pScreen); + info->gpu_flushed++; + return; + } +#endif + if (!info->cs->cdw) return; + accel_state = info->accel_state; + /* release the current VBO so we don't block on mapping it later */ if (info->accel_state->vbo.vb_offset && info->accel_state->vbo.vb_bo) { radeon_vbo_put(pScrn, &info->accel_state->vbo); @@ -171,6 +187,9 @@ static void RADEONFreeRec(ScrnInfoPtr pScrn) info = RADEONPTR(pScrn); + if (info->fbcon_pixmap) + pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap); + if (info->dri2.drm_fd > 0) { DevUnion *pPriv; RADEONEntPtr pRADEONEnt; @@ -230,7 +249,7 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr pScreen) return FALSE; pScreen->CreateScreenResources = RADEONCreateScreenResources_KMS; - if (!drmmode_set_desired_modes(pScrn, &info->drmmode)) + if (!drmmode_set_desired_modes(pScrn, &info->drmmode, FALSE)) return FALSE; drmmode_uevent_init(pScrn, &info->drmmode); @@ -269,7 +288,11 @@ redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty) PixmapRegionInit(&pixregion, dirty->slave_dst); DamageRegionAppend(&dirty->slave_dst->drawable, &pixregion); +#ifdef HAS_DIRTYTRACKING_ROTATION + PixmapSyncDirtyHelper(dirty); +#else PixmapSyncDirtyHelper(dirty, &pixregion); +#endif radeon_cs_flush_indirect(pScrn); DamageRegionProcessPending(&dirty->slave_dst->drawable); @@ -295,6 +318,204 @@ radeon_dirty_update(ScreenPtr screen) } #endif +static Bool +radeon_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h) +{ + extents->x1 = max(extents->x1 - x, 0); + extents->y1 = max(extents->y1 - y, 0); + extents->x2 = min(extents->x2 - x, w); + extents->y2 = min(extents->y2 - y, h); + + return (extents->x1 < extents->x2 && extents->y1 < extents->y2); +} + +static 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; + DrawablePtr pDraw; + ScreenPtr pScreen; + GCPtr gc; + BoxRec extents; + RADEONInfoPtr info; + Bool force; + + if (!xf86_crtc->enabled || + drmmode_crtc->dpms_mode != DPMSModeOn || + !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; + extents = *RegionExtents(pRegion); + RegionEmpty(pRegion); + if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y, + pDraw->width, pDraw->height)) + return FALSE; + + pScreen = pDraw->pScreen; + gc = GetScratchGC(pDraw->depth, pScreen); + scrn = xf86_crtc->scrn; + info = RADEONPTR(scrn); + force = info->accel_state->force; + info->accel_state->force = TRUE; + + ValidateGC(pDraw, gc); + (*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable, + pDraw, gc, + xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1, + extents.x2 - extents.x1, extents.y2 - extents.y1, + extents.x1, extents.y1); + FreeScratchGC(gc); + + info->accel_state->force = force; + + radeon_cs_flush_indirect(scrn); + + return TRUE; +} + +static void +radeon_scanout_update_abort(ScrnInfoPtr scrn, void *event_data) +{ + xf86CrtcPtr xf86_crtc = event_data; + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; + + drmmode_crtc->scanout_update_pending = FALSE; +} + +void +radeon_scanout_update_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, + void *event_data) +{ + radeon_scanout_do_update(event_data, 0); + + radeon_scanout_update_abort(scrn, event_data); +} + +static void +radeon_scanout_update(xf86CrtcPtr xf86_crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; + struct radeon_drm_queue_entry *drm_queue_entry; + ScrnInfoPtr scrn; + drmVBlank vbl; + DamagePtr pDamage; + RegionPtr pRegion; + DrawablePtr pDraw; + BoxRec extents; + + if (!xf86_crtc->enabled || + drmmode_crtc->scanout_update_pending || + !drmmode_crtc->scanout[0].pixmap || + drmmode_crtc->dpms_mode != DPMSModeOn) + return; + + pDamage = drmmode_crtc->scanout[0].damage; + if (!pDamage) + return; + + pRegion = DamageRegion(pDamage); + if (!RegionNotEmpty(pRegion)) + return; + + pDraw = &drmmode_crtc->scanout[0].pixmap->drawable; + extents = *RegionExtents(pRegion); + if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y, + pDraw->width, pDraw->height)) + return; + + scrn = xf86_crtc->scrn; + drm_queue_entry = radeon_drm_queue_alloc(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, + RADEON_DRM_QUEUE_ID_DEFAULT, + xf86_crtc, + radeon_scanout_update_handler, + radeon_scanout_update_abort); + if (!drm_queue_entry) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "radeon_drm_queue_alloc failed for scanout 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 = (unsigned long)drm_queue_entry; + if (drmWaitVBlank(RADEONPTR(scrn)->dri2.drm_fd, &vbl)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "drmWaitVBlank failed for scanout update: %s\n", + strerror(errno)); + radeon_drm_abort_entry(drm_queue_entry); + return; + } + + drmmode_crtc->scanout_update_pending = TRUE; +} + +static void +radeon_scanout_flip_abort(ScrnInfoPtr scrn, void *event_data) +{ + drmmode_crtc_private_ptr drmmode_crtc = event_data; + + drmmode_crtc->scanout_update_pending = FALSE; +} + +static void +radeon_scanout_flip_handler(ScrnInfoPtr scrn, uint32_t frame, uint64_t usec, void *event_data) +{ + radeon_scanout_flip_abort(scrn, event_data); +} + +static void +radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info, + xf86CrtcPtr xf86_crtc) +{ + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; + ScrnInfoPtr scrn; + struct radeon_drm_queue_entry *drm_queue_entry; + unsigned scanout_id; + + if (drmmode_crtc->scanout_update_pending) + return; + + scanout_id = drmmode_crtc->scanout_id ^ 1; + if (!radeon_scanout_do_update(xf86_crtc, scanout_id)) + return; + + scrn = xf86_crtc->scrn; + drm_queue_entry = radeon_drm_queue_alloc(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, + RADEON_DRM_QUEUE_ID_DEFAULT, + drmmode_crtc, + radeon_scanout_flip_handler, + radeon_scanout_flip_abort); + if (!drm_queue_entry) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "Allocating DRM event queue entry failed.\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, drm_queue_entry)) { + 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; +} + static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) { SCREEN_PTR(arg); @@ -305,25 +526,44 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL) (*pScreen->BlockHandler) (BLOCKHANDLER_ARGS); pScreen->BlockHandler = RADEONBlockHandler_KMS; - if (info->use_glamor) - radeon_glamor_flush(pScrn); + if (info->tear_free || info->shadow_primary) { + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int c; + + for (c = 0; c < xf86_config->num_crtc; c++) { + if (info->tear_free) + radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]); + else + radeon_scanout_update(xf86_config->crtc[c]); + } + } radeon_cs_flush_indirect(pScrn); + #ifdef RADEON_PIXMAP_SHARING radeon_dirty_update(pScreen); #endif } +static void RADEONBlockHandler_oneshot(BLOCKHANDLER_ARGS_DECL) +{ + SCREEN_PTR(arg); + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + RADEONInfoPtr info = RADEONPTR(pScrn); + + drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE); + + RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS); +} + static void radeon_flush_callback(CallbackListPtr *list, pointer user_data, pointer call_data) { ScrnInfoPtr pScrn = user_data; - if (pScrn->vtSema) { + if (pScrn->vtSema) radeon_cs_flush_indirect(pScrn); - radeon_glamor_flush(pScrn); - } } static Bool RADEONIsFastFBWorking(ScrnInfoPtr pScrn) @@ -779,14 +1019,48 @@ static void RADEONSetupCapabilities(ScrnInfoPtr pScrn) pScrn->capabilities = 0; ret = drmGetCap(info->dri2.drm_fd, DRM_CAP_PRIME, &value); if (ret == 0) { - if (value & DRM_PRIME_CAP_EXPORT) - pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SinkOffload; - if (value & DRM_PRIME_CAP_IMPORT) - pScrn->capabilities |= RR_Capability_SourceOffload | RR_Capability_SinkOutput; + if (value & DRM_PRIME_CAP_EXPORT) { + pScrn->capabilities |= RR_Capability_SourceOutput; + if (!info->r600_shadow_fb && info->dri2.available) + pScrn->capabilities |= RR_Capability_SinkOffload; + } + if (value & DRM_PRIME_CAP_IMPORT) { + pScrn->capabilities |= RR_Capability_SinkOutput; + if (!info->r600_shadow_fb && info->dri2.available) + pScrn->capabilities |= RR_Capability_SourceOffload; + } } #endif } +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 + +/* When the root window is created, initialize the screen contents from + * console if -background none was specified on the command line + */ +static Bool RADEONCreateWindow_oneshot(WindowPtr pWin) +{ + ScreenPtr pScreen = pWin->drawable.pScreen; + ScrnInfoPtr pScrn; + RADEONInfoPtr info; + Bool ret; + + if (pWin != pScreen->root) + ErrorF("%s called for non-root window %p\n", __func__, pWin); + + pScrn = xf86ScreenToScrn(pScreen); + info = RADEONPTR(pScrn); + pScreen->CreateWindow = info->CreateWindow; + ret = pScreen->CreateWindow(pWin); + + if (ret) + drmmode_copy_fb(pScrn, &info->drmmode); + + return ret; +} + +#endif + Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) { RADEONInfoPtr info; @@ -806,7 +1080,6 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) info = RADEONPTR(pScrn); info->IsSecondary = FALSE; - info->IsPrimary = FALSE; info->pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]); if (info->pEnt->location.type != BUS_PCI #ifdef XSERVER_PLATFORM_BUS @@ -824,14 +1097,10 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) if(xf86IsPrimInitDone(pScrn->entityList[0])) { info->IsSecondary = TRUE; - pRADEONEnt->pSecondaryScrn = pScrn; } else { - info->IsPrimary = TRUE; xf86SetPrimInitDone(pScrn->entityList[0]); - pRADEONEnt->pPrimaryScrn = pScrn; - pRADEONEnt->HasSecondary = FALSE; } } @@ -870,6 +1139,8 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) if (!RADEONPreInitAccel_KMS(pScrn)) goto fail; + radeon_drm_queue_init(); + info->allowColorTiling2D = FALSE; RADEONSetupCapabilities(pScrn); @@ -920,11 +1191,37 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "KMS Color Tiling 2D: %sabled\n", info->allowColorTiling2D ? "en" : "dis"); +#if USE_GLAMOR + if (info->use_glamor) { + info->shadow_primary = xf86ReturnOptValBool(info->Options, + OPTION_SHADOW_PRIMARY, FALSE); + + if (info->shadow_primary) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n"); + } +#endif + + info->tear_free = xf86ReturnOptValBool(info->Options, OPTION_TEAR_FREE, + FALSE); + + if (info->tear_free) + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "TearFree enabled\n"); + if (info->dri2.pKernelDRMVersion->version_minor >= 8) { info->allowPageFlip = xf86ReturnOptValBool(info->Options, OPTION_PAGE_FLIP, TRUE); - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis"); + + if (info->tear_free || info->shadow_primary) { + xf86DrvMsg(pScrn->scrnIndex, + info->allowPageFlip ? X_WARNING : X_DEFAULT, + "KMS Pageflipping: disabled%s\n", + info->allowPageFlip ? + " because of ShadowPrimary/TearFree" : ""); + info->allowPageFlip = FALSE; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis"); + } } info->swapBuffersWait = xf86ReturnOptValBool(info->Options, @@ -932,12 +1229,16 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "SwapBuffers wait for vsync: %sabled\n", info->swapBuffersWait ? "en" : "dis"); + if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) { + info->drmmode.delete_dp_12_displays = TRUE; + } + if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == FALSE) { xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n"); goto fail; } - if (info->drmmode.mode_res->count_crtcs == 1) + if (info->drmmode.count_crtcs == 1) pRADEONEnt->HasCRTC2 = FALSE; else pRADEONEnt->HasCRTC2 = TRUE; @@ -1158,11 +1459,16 @@ static Bool RADEONCloseScreen_KMS(CLOSE_SCREEN_ARGS_DECL) { ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); RADEONInfoPtr info = RADEONPTR(pScrn); + RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, "RADEONCloseScreen\n"); + /* Clear mask of assigned crtc's in this generation */ + pRADEONEnt->assigned_crtcs = 0; + drmmode_uevent_fini(pScrn, &info->drmmode); + radeon_drm_queue_close(pScrn); radeon_cs_flush_indirect(pScrn); DeleteCallback(&FlushCallback, radeon_flush_callback, pScrn); @@ -1173,6 +1479,8 @@ static Bool RADEONCloseScreen_KMS(CLOSE_SCREEN_ARGS_DECL) info->accel_state->exa = NULL; } + radeon_sync_close(pScreen); + if (info->accel_state->use_vbos) radeon_vbo_free_lists(pScrn); @@ -1209,6 +1517,9 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL) ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); RADEONInfoPtr info = RADEONPTR(pScrn); int subPixelOrder = SubPixelUnknown; + MessageType from; + Bool value; + int driLevel; const char *s; void *front_ptr; @@ -1319,6 +1630,28 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL) } #endif + value = FALSE; + from = X_DEFAULT; + if (xf86GetOptValBool(info->Options, OPTION_DRI3, &value)) + from = X_CONFIG; + + if (xf86GetOptValInteger(info->Options, OPTION_DRI, &driLevel) && + (driLevel == 2 || driLevel == 3)) { + from = X_CONFIG; + value = driLevel == 3; + } + + if (value) { + value = radeon_sync_init(pScreen) && + radeon_present_screen_init(pScreen) && + radeon_dri3_screen_init(pScreen); + + if (!value) + from = X_WARNING; + } + + xf86DrvMsg(pScrn->scrnIndex, from, "DRI3 %sabled\n", value ? "en" : "dis"); + pScrn->vtSema = TRUE; xf86SetBackingStore(pScreen); @@ -1388,13 +1721,20 @@ Bool RADEONScreenInit_KMS(SCREEN_INIT_ARGS_DECL) } pScrn->pScreen = pScreen; +#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 + if (serverGeneration == 1 && bgNoneRoot && info->accelOn) { + info->CreateWindow = pScreen->CreateWindow; + pScreen->CreateWindow = RADEONCreateWindow_oneshot; + } +#endif + /* Provide SaveScreen & wrap BlockHandler and CloseScreen */ /* Wrap CloseScreen */ info->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = RADEONCloseScreen_KMS; pScreen->SaveScreen = RADEONSaveScreen_KMS; info->BlockHandler = pScreen->BlockHandler; - pScreen->BlockHandler = RADEONBlockHandler_KMS; + pScreen->BlockHandler = RADEONBlockHandler_oneshot; if (!AddCallback(&FlushCallback, radeon_flush_callback, pScrn)) return FALSE; @@ -1447,7 +1787,7 @@ Bool RADEONEnterVT_KMS(VT_FUNC_ARGS_DECL) pScrn->vtSema = TRUE; - if (!drmmode_set_desired_modes(pScrn, &info->drmmode)) + if (!drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE)) return FALSE; return TRUE; @@ -1465,6 +1805,7 @@ void RADEONLeaveVT_KMS(VT_FUNC_ARGS_DECL) radeon_drop_drm_master(pScrn); xf86RotateFreeShadow(pScrn); + drmmode_scanout_free(pScrn); xf86_hide_cursors (pScrn); info->accel_state->XInited3D = FALSE; @@ -1515,7 +1856,7 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen) } } - if (info->allowColorTiling) { + if (info->allowColorTiling && !info->shadow_primary) { if (info->ChipFamily >= CHIP_FAMILY_R600) { if (info->allowColorTiling2D) { tiling_flags |= RADEON_TILING_MACRO; @@ -1578,7 +1919,9 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen) tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT; tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT; tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT; - tiling_flags |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT; + if (surface.tile_split) + tiling_flags |= eg_tile_split(surface.tile_split) + << RADEON_TILING_EG_TILE_SPLIT_SHIFT; break; case RADEON_SURF_MODE_1D: tiling_flags |= RADEON_TILING_MICRO; @@ -1618,7 +1961,10 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen) if (info->front_bo == NULL) { info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, - base_align, RADEON_GEM_DOMAIN_VRAM, 0); + base_align, + info->shadow_primary ? + RADEON_GEM_DOMAIN_GTT : + RADEON_GEM_DOMAIN_VRAM, 0); if (info->r600_shadow_fb == TRUE) { if (radeon_bo_map(info->front_bo, 1)) { ErrorF("Failed to map cursor buffer memory\n"); diff --git a/driver/xf86-video-ati/src/radeon_list.h b/driver/xf86-video-ati/src/radeon_list.h new file mode 100644 index 000000000..77f74affc --- /dev/null +++ b/driver/xf86-video-ati/src/radeon_list.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2015 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _RADEON_LIST_H_ +#define _RADEON_LIST_H_ + +#include +#include + +#if !HAVE_XORG_LIST +#define xorg_list list +#define xorg_list_init list_init +#define xorg_list_add list_add +#define xorg_list_del list_del +#define xorg_list_for_each_entry list_for_each_entry +#define xorg_list_for_each_entry_safe list_for_each_entry_safe +#endif + +#endif /* _RADEON_LIST_H_ */ diff --git a/driver/xf86-video-ati/src/radeon_pci_chipset_gen.h b/driver/xf86-video-ati/src/radeon_pci_chipset_gen.h index bd689201f..4b4b8e454 100644 --- a/driver/xf86-video-ati/src/radeon_pci_chipset_gen.h +++ b/driver/xf86-video-ati/src/radeon_pci_chipset_gen.h @@ -612,6 +612,7 @@ static PciChipsets RADEONPciChipsets[] = { { PCI_CHIP_OLAND_6610, PCI_CHIP_OLAND_6610, RES_SHARED_VGA }, { PCI_CHIP_OLAND_6611, PCI_CHIP_OLAND_6611, RES_SHARED_VGA }, { PCI_CHIP_OLAND_6613, PCI_CHIP_OLAND_6613, RES_SHARED_VGA }, + { PCI_CHIP_OLAND_6617, PCI_CHIP_OLAND_6617, RES_SHARED_VGA }, { PCI_CHIP_OLAND_6620, PCI_CHIP_OLAND_6620, RES_SHARED_VGA }, { PCI_CHIP_OLAND_6621, PCI_CHIP_OLAND_6621, RES_SHARED_VGA }, { PCI_CHIP_OLAND_6623, PCI_CHIP_OLAND_6623, RES_SHARED_VGA }, @@ -632,6 +633,7 @@ static PciChipsets RADEONPciChipsets[] = { { PCI_CHIP_BONAIRE_6658, PCI_CHIP_BONAIRE_6658, RES_SHARED_VGA }, { PCI_CHIP_BONAIRE_665C, PCI_CHIP_BONAIRE_665C, RES_SHARED_VGA }, { PCI_CHIP_BONAIRE_665D, PCI_CHIP_BONAIRE_665D, RES_SHARED_VGA }, + { PCI_CHIP_BONAIRE_665F, PCI_CHIP_BONAIRE_665F, RES_SHARED_VGA }, { PCI_CHIP_KABINI_9830, PCI_CHIP_KABINI_9830, RES_SHARED_VGA }, { PCI_CHIP_KABINI_9831, PCI_CHIP_KABINI_9831, RES_SHARED_VGA }, { PCI_CHIP_KABINI_9832, PCI_CHIP_KABINI_9832, RES_SHARED_VGA }, diff --git a/driver/xf86-video-ati/src/radeon_pci_device_match_gen.h b/driver/xf86-video-ati/src/radeon_pci_device_match_gen.h index eaf280a28..6dfe1e42f 100644 --- a/driver/xf86-video-ati/src/radeon_pci_device_match_gen.h +++ b/driver/xf86-video-ati/src/radeon_pci_device_match_gen.h @@ -612,6 +612,7 @@ static const struct pci_id_match radeon_device_match[] = { ATI_DEVICE_MATCH( PCI_CHIP_OLAND_6610, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_OLAND_6611, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_OLAND_6613, 0 ), + ATI_DEVICE_MATCH( PCI_CHIP_OLAND_6617, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_OLAND_6620, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_OLAND_6621, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_OLAND_6623, 0 ), @@ -632,6 +633,7 @@ static const struct pci_id_match radeon_device_match[] = { ATI_DEVICE_MATCH( PCI_CHIP_BONAIRE_6658, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_BONAIRE_665C, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_BONAIRE_665D, 0 ), + ATI_DEVICE_MATCH( PCI_CHIP_BONAIRE_665F, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_KABINI_9830, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_KABINI_9831, 0 ), ATI_DEVICE_MATCH( PCI_CHIP_KABINI_9832, 0 ), diff --git a/driver/xf86-video-ati/src/radeon_present.c b/driver/xf86-video-ati/src/radeon_present.c new file mode 100644 index 000000000..bd4d8f284 --- /dev/null +++ b/driver/xf86-video-ati/src/radeon_present.c @@ -0,0 +1,465 @@ +/* + * Copyright © 2014 Intel Corporation + * Copyright © 2015 Advanced Micro Devices, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "radeon.h" + +#ifdef HAVE_PRESENT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "radeon_bo_helper.h" +#include "radeon_glamor.h" +#include "radeon_video.h" + +#include "present.h" + +struct radeon_present_vblank_event { + uint64_t event_id; + xf86CrtcPtr crtc; +}; + +static uint32_t crtc_select(int crtc_id) +{ + if (crtc_id > 1) + return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT; + else if (crtc_id > 0) + return DRM_VBLANK_SECONDARY; + else + return 0; +} + +static RRCrtcPtr +radeon_present_get_crtc(WindowPtr window) +{ + ScreenPtr screen = window->drawable.pScreen; + ScrnInfoPtr pScrn = xf86ScreenToScrn(screen); + xf86CrtcPtr crtc; + RRCrtcPtr randr_crtc = NULL; + + crtc = radeon_pick_best_crtc(pScrn, FALSE, + window->drawable.x, + window->drawable.x + window->drawable.width, + window->drawable.y, + window->drawable.y + window->drawable.height); + + /* Make sure the CRTC is valid and this is the real front buffer */ + if (crtc != NULL && !crtc->rotatedData) + randr_crtc = crtc->randr_crtc; + + return randr_crtc; +} + +static int +radeon_present_get_ust_msc(RRCrtcPtr crtc, CARD64 *ust, CARD64 *msc) +{ + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; + + if (drmmode_crtc->dpms_mode != DPMSModeOn) + return BadAlloc; + + return drmmode_crtc_get_ust_msc(xf86_crtc, ust, msc); +} + +/* + * Flush the DRM event queue when full; this + * makes space for new requests + */ +static Bool +radeon_present_flush_drm_events(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); + drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[0]->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + struct pollfd p = { .fd = drmmode->fd, .events = POLLIN }; + int r; + + do { + r = poll(&p, 1, 0); + } while (r == -1 && (errno == EINTR || errno == EAGAIN)); + + if (r <= 0) + return 0; + + return drmHandleEvent(drmmode->fd, &drmmode->event_context) >= 0; +} + +/* + * Called when the queued vblank event has occurred + */ +static void +radeon_present_vblank_handler(ScrnInfoPtr scrn, unsigned int msc, + uint64_t usec, void *data) +{ + struct radeon_present_vblank_event *event = data; + + present_event_notify(event->event_id, usec, msc); + free(event); +} + +/* + * Called when the queued vblank is aborted + */ +static void +radeon_present_vblank_abort(ScrnInfoPtr scrn, void *data) +{ + struct radeon_present_vblank_event *event = data; + + free(event); +} + +/* + * Queue an event to report back to the Present extension when the specified + * MSC has past + */ +static int +radeon_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) +{ + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + ScreenPtr screen = crtc->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + int crtc_id = drmmode_get_crtc_id(xf86_crtc); + struct radeon_present_vblank_event *event; + struct radeon_drm_queue_entry *queue; + drmVBlank vbl; + int ret; + + event = calloc(sizeof(struct radeon_present_vblank_event), 1); + if (!event) + return BadAlloc; + event->event_id = event_id; + queue = radeon_drm_queue_alloc(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, + event_id, event, + radeon_present_vblank_handler, + radeon_present_vblank_abort); + if (!queue) { + free(event); + return BadAlloc; + } + + vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT | crtc_select(crtc_id); + vbl.request.sequence = msc; + vbl.request.signal = (unsigned long)queue; + for (;;) { + ret = drmWaitVBlank(info->dri2.drm_fd, &vbl); + if (!ret) + break; + if (errno != EBUSY || !radeon_present_flush_drm_events(screen)) { + radeon_drm_abort_entry(queue); + return BadAlloc; + } + } + + return Success; +} + +/* + * Remove a pending vblank event from the DRM queue so that it is not reported + * to the extension + */ +static void +radeon_present_abort_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc) +{ + radeon_drm_abort_id(event_id); +} + +/* + * Flush our batch buffer when requested by the Present extension. + */ +static void +radeon_present_flush(WindowPtr window) +{ + radeon_cs_flush_indirect(xf86ScreenToScrn(window->drawable.pScreen)); +} + +static uint32_t +radeon_present_get_pixmap_tiling_flags(RADEONInfoPtr info, PixmapPtr pixmap) +{ + uint32_t tiling_flags = radeon_get_pixmap_tiling_flags(pixmap); + + /* Micro tiling is always enabled with macro tiling on >= R600, so we + * can ignore the micro tiling bit in that case + */ + if ((tiling_flags & RADEON_TILING_MACRO) && + info->ChipFamily >= CHIP_FAMILY_R600) + tiling_flags &= ~RADEON_TILING_MICRO; + + return tiling_flags; +} + +/* + * Test to see if page flipping is possible on the target crtc + */ +static Bool +radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap, + Bool sync_flip) +{ + ScreenPtr screen = window->drawable.pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + PixmapPtr screen_pixmap; + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + int num_crtcs_on; + int i; + + if (!scrn->vtSema) + return FALSE; + + if (!info->allowPageFlip) + return FALSE; + + if (!sync_flip) + return FALSE; + + if (info->drmmode.dri2_flipping) + return FALSE; + + /* The kernel driver doesn't handle flipping between BOs with different + * tiling parameters correctly yet + */ + screen_pixmap = screen->GetScreenPixmap(screen); + if (radeon_present_get_pixmap_tiling_flags(info, pixmap) != + radeon_present_get_pixmap_tiling_flags(info, screen_pixmap)) + return FALSE; + + for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) { + drmmode_crtc_private_ptr drmmode_crtc = config->crtc[i]->driver_private; + + if (!config->crtc[i]->enabled) + continue; + + if (!drmmode_crtc || drmmode_crtc->rotate.bo != NULL) + return FALSE; + + if (drmmode_crtc->dpms_mode == DPMSModeOn) + num_crtcs_on++; + } + + return num_crtcs_on > 0; +} + +/* + * Once the flip has been completed on all CRTCs, notify the + * extension code telling it when that happened + */ +static void +radeon_present_flip_event(ScrnInfoPtr scrn, uint32_t msc, uint64_t ust, void *pageflip_data) +{ + RADEONInfoPtr info = RADEONPTR(scrn); + struct radeon_present_vblank_event *event = pageflip_data; + + if (!event->crtc) + info->drmmode.present_flipping = FALSE; + + present_event_notify(event->event_id, ust, msc); + free(event); +} + +/* + * The flip has been aborted, free the structure + */ +static void +radeon_present_flip_abort(ScrnInfoPtr scrn, void *pageflip_data) +{ + struct radeon_present_vblank_event *event = pageflip_data; + + free(event); +} + +/* + * Queue a flip on 'crtc' to 'pixmap' at 'target_msc'. If 'sync_flip' is true, + * then wait for vblank. Otherwise, flip immediately + */ +static Bool +radeon_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, + PixmapPtr pixmap, Bool sync_flip) +{ + ScreenPtr screen = crtc->pScreen; + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + struct radeon_present_vblank_event *event; + xf86CrtcPtr xf86_crtc = crtc->devPrivate; + int crtc_id = xf86_crtc ? drmmode_get_crtc_id(xf86_crtc) : -1; + uint32_t handle; + Bool ret; + + if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip)) + return FALSE; + + if (!radeon_get_pixmap_handle(pixmap, &handle)) + return FALSE; + + event = calloc(1, sizeof(struct radeon_present_vblank_event)); + if (!event) + return FALSE; + + event->event_id = event_id; + event->crtc = xf86_crtc; + + ret = radeon_do_pageflip(scrn, RADEON_DRM_QUEUE_CLIENT_DEFAULT, handle, + event_id, event, crtc_id, + radeon_present_flip_event, + radeon_present_flip_abort); + if (!ret) + xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); + else + info->drmmode.present_flipping = TRUE; + + return ret; +} + +/* + * Queue a flip back to the normal frame buffer + */ +static void +radeon_present_unflip(ScreenPtr screen, uint64_t event_id) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); + struct radeon_present_vblank_event *event; + PixmapPtr pixmap = screen->GetScreenPixmap(screen); + uint32_t handle; + int i; + + if (!radeon_present_check_flip(NULL, screen->root, pixmap, TRUE)) + goto modeset; + + if (!radeon_get_pixmap_handle(pixmap, &handle)) { + ErrorF("%s: radeon_get_pixmap_handle failed, display might freeze\n", + __func__); + goto modeset; + } + + event = calloc(1, sizeof(struct radeon_present_vblank_event)); + if (!event) { + ErrorF("%s: calloc failed, display might freeze\n", __func__); + goto modeset; + } + + event->event_id = 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)) + return; + +modeset: + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; + + if (!crtc->enabled) + continue; + + if (drmmode_crtc->dpms_mode == DPMSModeOn) + crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, + crtc->x, crtc->y); + else + drmmode_crtc->need_modeset = TRUE; + } + + present_event_notify(event_id, 0, 0); + + info->drmmode.present_flipping = FALSE; +} + +static present_screen_info_rec radeon_present_screen_info = { + .version = 0, + + .get_crtc = radeon_present_get_crtc, + .get_ust_msc = radeon_present_get_ust_msc, + .queue_vblank = radeon_present_queue_vblank, + .abort_vblank = radeon_present_abort_vblank, + .flush = radeon_present_flush, + + .capabilities = PresentCapabilityNone, + .check_flip = radeon_present_check_flip, + .flip = radeon_present_flip, + .unflip = radeon_present_unflip, +}; + +static Bool +radeon_present_has_async_flip(ScreenPtr screen) +{ +#ifdef DRM_CAP_ASYNC_PAGE_FLIP + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + int ret; + uint64_t value; + + ret = drmGetCap(info->dri2.drm_fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); + if (ret == 0) + return value == 1; +#endif + return FALSE; +} + +Bool +radeon_present_screen_init(ScreenPtr screen) +{ + if (radeon_present_has_async_flip(screen)) + radeon_present_screen_info.capabilities |= PresentCapabilityAsync; + + if (!present_screen_init(screen, &radeon_present_screen_info)) { + xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_WARNING, + "Present extension disabled because present_screen_init failed\n"); + return FALSE; + } + + xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, + "Present extension enabled\n"); + + return TRUE; +} + +#else /* !HAVE_PRESENT_H */ + +Bool +radeon_present_screen_init(ScreenPtr screen) +{ + xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, + "Present extension disabled because present.h not available at " + "build time\n"); + + return FALSE; +} + +#endif diff --git a/driver/xf86-video-ati/src/radeon_probe.c b/driver/xf86-video-ati/src/radeon_probe.c index ad1e96ea9..65cf0c9fa 100644 --- a/driver/xf86-video-ati/src/radeon_probe.c +++ b/driver/xf86-video-ati/src/radeon_probe.c @@ -154,7 +154,6 @@ radeon_get_scrninfo(int entity_num, void *pci_dev) */ { DevUnion *pPriv; - RADEONEntPtr pRADEONEnt; xf86SetEntitySharable(entity_num); @@ -166,14 +165,8 @@ radeon_get_scrninfo(int entity_num, void *pci_dev) xf86SetEntityInstanceForScreen(pScrn, pEnt->index, xf86GetNumEntityInstances(pEnt->index) - 1); - if (!pPriv->ptr) { + if (!pPriv->ptr) pPriv->ptr = xnfcalloc(sizeof(RADEONEntRec), 1); - pRADEONEnt = pPriv->ptr; - pRADEONEnt->HasSecondary = FALSE; - } else { - pRADEONEnt = pPriv->ptr; - pRADEONEnt->HasSecondary = TRUE; - } } free(pEnt); @@ -271,10 +264,8 @@ radeon_platform_probe(DriverPtr pDriver, if (!pPriv->ptr) { pPriv->ptr = xnfcalloc(sizeof(RADEONEntRec), 1); pRADEONEnt = pPriv->ptr; - pRADEONEnt->HasSecondary = FALSE; } else { pRADEONEnt = pPriv->ptr; - pRADEONEnt->HasSecondary = TRUE; } pRADEONEnt->platform_dev = dev; } diff --git a/driver/xf86-video-ati/src/radeon_probe.h b/driver/xf86-video-ati/src/radeon_probe.h index 3fe4644c3..258c7be1d 100644 --- a/driver/xf86-video-ati/src/radeon_probe.h +++ b/driver/xf86-video-ati/src/radeon_probe.h @@ -132,16 +132,13 @@ typedef struct { typedef struct { - Bool HasSecondary; Bool HasCRTC2; /* All cards except original Radeon */ - ScrnInfoPtr pSecondaryScrn; - ScrnInfoPtr pPrimaryScrn; - int fd; /* for sharing across zaphod heads */ int fd_ref; unsigned long fd_wakeup_registered; /* server generation for which fd has been registered for wakeup handling */ int fd_wakeup_ref; + unsigned int assigned_crtcs; #ifdef XSERVER_PLATFORM_BUS struct xf86_platform_device *platform_dev; #endif diff --git a/driver/xf86-video-ati/src/radeon_sync.c b/driver/xf86-video-ati/src/radeon_sync.c new file mode 100644 index 000000000..d9ffbaf8e --- /dev/null +++ b/driver/xf86-video-ati/src/radeon_sync.c @@ -0,0 +1,145 @@ +/* + * Copyright © 2013-2014 Intel Corporation + * Copyright © 2015 Advanced Micro Devices, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include "radeon.h" + +#ifdef HAVE_MISYNCSHM_H + +#include "misync.h" +#include "misyncshm.h" +#include "misyncstr.h" + +/* + * This whole file exists to wrap a sync fence trigger operation + * so that we can flush the batch buffer to provide serialization + * between the server and the shm fence client + */ + +static DevPrivateKeyRec radeon_sync_fence_private_key; + +typedef struct _radeon_sync_fence_private { + SyncFenceSetTriggeredFunc set_triggered; +} radeon_sync_fence_private; + +#define SYNC_FENCE_PRIV(pFence) \ + (radeon_sync_fence_private *) dixLookupPrivate(&pFence->devPrivates, &radeon_sync_fence_private_key) + +static void +radeon_sync_fence_set_triggered (SyncFence *fence) +{ + ScreenPtr screen = fence->pScreen; + radeon_sync_fence_private *private = SYNC_FENCE_PRIV(fence); + + /* Flush pending rendering operations */ + radeon_cs_flush_indirect(xf86ScreenToScrn(screen)); + + fence->funcs.SetTriggered = private->set_triggered; + fence->funcs.SetTriggered(fence); + private->set_triggered = fence->funcs.SetTriggered; + fence->funcs.SetTriggered = radeon_sync_fence_set_triggered; +} + +static void +radeon_sync_create_fence(ScreenPtr screen, + SyncFence *fence, + Bool initially_triggered) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + SyncScreenFuncsPtr screen_funcs = miSyncGetScreenFuncs(screen); + radeon_sync_fence_private *private = SYNC_FENCE_PRIV(fence); + + screen_funcs->CreateFence = info->CreateFence; + screen_funcs->CreateFence(screen, fence, initially_triggered); + info->CreateFence = screen_funcs->CreateFence; + screen_funcs->CreateFence = radeon_sync_create_fence; + + private->set_triggered = fence->funcs.SetTriggered; + fence->funcs.SetTriggered = radeon_sync_fence_set_triggered; +} + +Bool +radeon_sync_init(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + SyncScreenFuncsPtr screen_funcs; + + if (!miSyncShmScreenInit(screen)) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "SYNC extension fences disabled because " + "miSyncShmScreenInit failed\n"); + return FALSE; + } + + if (!dixPrivateKeyRegistered(&radeon_sync_fence_private_key)) { + if (!dixRegisterPrivateKey(&radeon_sync_fence_private_key, + PRIVATE_SYNC_FENCE, + sizeof (radeon_sync_fence_private))) { + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "SYNC extension fences disabled because " + "dixRegisterPrivateKey failed\n"); + return FALSE; + } + } + + xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, + "SYNC extension fences enabled\n"); + + screen_funcs = miSyncGetScreenFuncs(screen); + info->CreateFence = screen_funcs->CreateFence; + screen_funcs->CreateFence = radeon_sync_create_fence; + return TRUE; +} + +void +radeon_sync_close(ScreenPtr screen) +{ + ScrnInfoPtr scrn = xf86ScreenToScrn(screen); + RADEONInfoPtr info = RADEONPTR(scrn); + SyncScreenFuncsPtr screen_funcs = miSyncGetScreenFuncs(screen); + + if (screen_funcs && info->CreateFence) + screen_funcs->CreateFence = info->CreateFence; + + info->CreateFence = NULL; +} + +#else /* !HAVE_MISYNCSHM_H */ + +Bool +radeon_sync_init(ScreenPtr screen) +{ + xf86DrvMsg(xf86ScreenToScrn(screen)->scrnIndex, X_INFO, + "SYNC extension fences disabled because misyncshm.h not " + "available at build time\n"); + + return FALSE; +} + +void +radeon_sync_close(ScreenPtr screen) +{ +} + +#endif diff --git a/driver/xf86-video-ati/src/radeon_video.c b/driver/xf86-video-ati/src/radeon_video.c index cbfd554b2..48b06e26d 100644 --- a/driver/xf86-video-ati/src/radeon_video.c +++ b/driver/xf86-video-ati/src/radeon_video.c @@ -9,6 +9,7 @@ #include #include "radeon.h" +#include "radeon_glamor.h" #include "radeon_reg.h" #include "radeon_probe.h" #include "radeon_video.h" @@ -73,18 +74,12 @@ Bool radeon_crtc_is_enabled(xf86CrtcPtr crtc) return drmmode_crtc->dpms_mode == DPMSModeOn; } -uint32_t radeon_get_interpolated_vblanks(xf86CrtcPtr crtc) -{ - drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; - return drmmode_crtc->interpolated_vblanks; -} - xf86CrtcPtr radeon_pick_best_crtc(ScrnInfoPtr pScrn, Bool consider_disabled, int x1, int x2, int y1, int y2) { xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int coverage, best_coverage, c; + int coverage, best_coverage, c, cd; BoxRec box, crtc_box, cover_box; RROutputPtr primary_output = NULL; xf86CrtcPtr best_crtc = NULL, primary_crtc = NULL; @@ -108,38 +103,30 @@ radeon_pick_best_crtc(ScrnInfoPtr pScrn, Bool consider_disabled, if (primary_output && primary_output->crtc) primary_crtc = primary_output->crtc->devPrivate; - /* first consider only enabled CRTCs */ - for (c = 0; c < xf86_config->num_crtc; c++) { - xf86CrtcPtr crtc = xf86_config->crtc[c]; + /* first consider only enabled CRTCs + * then on second pass consider disabled ones + */ + for (cd = 0; cd < (consider_disabled ? 2 : 1); cd++) { + for (c = 0; c < xf86_config->num_crtc; c++) { + xf86CrtcPtr crtc = xf86_config->crtc[c]; - if (!radeon_crtc_is_enabled(crtc)) - continue; + if (!cd && !radeon_crtc_is_enabled(crtc)) + continue; - radeon_crtc_box(crtc, &crtc_box); - radeon_box_intersect(&cover_box, &crtc_box, &box); - coverage = radeon_box_area(&cover_box); - if (coverage > best_coverage || - (coverage == best_coverage && crtc == primary_crtc)) { - best_crtc = crtc; - best_coverage = coverage; + radeon_crtc_box(crtc, &crtc_box); + radeon_box_intersect(&cover_box, &crtc_box, &box); + coverage = radeon_box_area(&cover_box); + if (coverage > best_coverage || + (coverage == best_coverage && + crtc == primary_crtc)) { + best_crtc = crtc; + best_coverage = coverage; + } } + if (best_crtc) + break; } - if (best_crtc || !consider_disabled) - return best_crtc; - /* if we found nothing, repeat the search including disabled CRTCs */ - for (c = 0; c < xf86_config->num_crtc; c++) { - xf86CrtcPtr crtc = xf86_config->crtc[c]; - - radeon_crtc_box(crtc, &crtc_box); - radeon_box_intersect(&cover_box, &crtc_box, &box); - coverage = radeon_box_area(&cover_box); - if (coverage > best_coverage || - (coverage == best_coverage && crtc == primary_crtc)) { - best_crtc = crtc; - best_coverage = coverage; - } - } return best_crtc; } @@ -158,7 +145,7 @@ void RADEONInitVideo(ScreenPtr pScreen) return; num_adaptors = xf86XVListGenericAdaptors(pScrn, &adaptors); - newAdaptors = malloc((num_adaptors + 2) * sizeof(XF86VideoAdaptorPtr *)); + newAdaptors = malloc((num_adaptors + 2) * sizeof(*newAdaptors)); if (newAdaptors == NULL) return; diff --git a/driver/xf86-video-ati/src/radeon_video.h b/driver/xf86-video-ati/src/radeon_video.h index 2a0929546..e6068e86b 100644 --- a/driver/xf86-video-ati/src/radeon_video.h +++ b/driver/xf86-video-ati/src/radeon_video.h @@ -101,6 +101,5 @@ RADEONCopyMungedData(ScrnInfoPtr pScrn, unsigned int dstPitch, unsigned int h, unsigned int w); Bool radeon_crtc_is_enabled(xf86CrtcPtr crtc); -uint32_t radeon_get_interpolated_vblanks(xf86CrtcPtr crtc); #endif