[PATCH] Enable/disable freesync when enter/exit fullscreen game

The change add amdgpu specific x extension as the protocol for OGL driver to notify there is a freesync capable application/client DDX driver would rely on this to enable freesync before fullscreen flip and disable freesync before unflip or client exit. Change-Id: I22606e4384dc05ae20b09910ab5aef2a0fe457c0 Signed-off-by: Hawking Zhang <Hawking.Zhang at amd.com> --- src/Makefile.am | 2 + src/amdgpu_dri2.c | 30 ++++++++- src/amdgpu_drv.h | 5 ++ src/amdgpu_extension.c | 173 +++++++++++++++++++++++++++++++++++++++++++++++++ src/amdgpu_extension.h | 51 +++++++++++++++ src/amdgpu_kms.c | 4 ++ src/amdgpu_present.c | 21 ++++++ 7 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 src/amdgpu_extension.c create mode 100644 src/amdgpu_extension.h diff --git a/src/Makefile.am b/src/Makefile.am index 8fcd04b..43ef8e5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -46,6 +46,7 @@ amdgpu_drv_ladir = @moduledir@/drivers amdgpu_drv_la_SOURCES = \ amdgpu_video.c \ amdgpu_misc.c amdgpu_probe.c \ + amdgpu_extension.c \ $(AMDGPU_KMS_SRCS) AM_CFLAGS += @LIBGLAMOR_CFLAGS@ @XORG_CFLAGS@ @@ -64,6 +65,7 @@ EXTRA_DIST = \ amdgpu_list.h \ amdgpu_pixmap.h \ amdgpu_probe.h \ + amdgpu_extension.h \ amdgpu_version.h \ amdgpu_video.h \ simple_list.h \ diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c index 5e2367f..2ff1e90 100644 --- a/src/amdgpu_dri2.c +++ b/src/amdgpu_dri2.c @@ -34,6 +34,7 @@ #include "amdgpu_glamor.h" #include "amdgpu_video.h" #include "amdgpu_pixmap.h" +#include "amdgpu_extension.h" #ifdef DRI2 @@ -47,7 +48,6 @@ #include "amdgpu_bo_helper.h" #include "amdgpu_version.h" - #include "amdgpu_list.h" #include <xf86Priv.h> @@ -555,6 +555,15 @@ amdgpu_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, "%s:%d fevent[%p]

", __func__, __LINE__, flip_info); + if ((info->fullscreen_client) && + (info->freesync_enabled == FALSE)) { + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); + int ret = -1; + ret = AMDGPUFreesyncControl(pAMDGPUEnt->fd, TRUE); + if (!ret) + info->freesync_enabled = TRUE; + } + /* Page flip the full screen buffer */ back_priv = back->driverPrivate; if (amdgpu_do_pageflip(scrn, client, back_priv->pixmap, @@ -707,6 +716,8 @@ static void amdgpu_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq, { DRI2FrameEventPtr event = event_data; ScrnInfoPtr scrn = crtc->scrn; + AMDGPUInfoPtr info = AMDGPUPTR(scrn); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); DrawablePtr drawable; int status; int swap_type; @@ -737,6 +748,14 @@ static void amdgpu_dri2_frame_event_handler(xf86CrtcPtr crtc, uint32_t seq, } /* else fall through to exchange/blit */ case DRI2_SWAP: + if ((info->fullscreen_client) && + (info->freesync_enabled == TRUE)) { + int ret = -1; + ret = AMDGPUFreesyncControl(pAMDGPUEnt->fd, FALSE); + if (!ret) + info->freesync_enabled = FALSE; + } + if (DRI2CanExchange(drawable) && can_exchange(scrn, drawable, event->front, event->back)) { amdgpu_dri2_exchange_buffers(drawable, event->front, @@ -1135,6 +1154,7 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, ScreenPtr screen = draw->pScreen; ScrnInfoPtr scrn = xf86ScreenToScrn(screen); AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); + AMDGPUInfoPtr info = AMDGPUPTR(scrn); xf86CrtcPtr crtc = amdgpu_dri2_drawable_crtc(draw, TRUE); uint32_t msc_delta; drmVBlank vbl; @@ -1317,6 +1337,14 @@ static int amdgpu_dri2_schedule_swap(ClientPtr client, DrawablePtr draw, return TRUE; blit_fallback: + if ((info->fullscreen_client) && + (info->freesync_enabled == TRUE)) { + int ret = -1; + ret = AMDGPUFreesyncControl(pAMDGPUEnt->fd, FALSE); + if (!ret) + info->freesync_enabled = FALSE; + } + if (swap_info) { swap_info->type = DRI2_SWAP; amdgpu_dri2_schedule_event(FALLBACK_SWAP_DELAY, swap_info); diff --git a/src/amdgpu_drv.h b/src/amdgpu_drv.h index 60aa0be..c530e1f 100644 --- a/src/amdgpu_drv.h +++ b/src/amdgpu_drv.h @@ -244,6 +244,11 @@ typedef struct { /* kms pageflipping */ Bool allowPageFlip; + /* fressync */ + ClientPtr fullscreen_client; + uint32_t client_resource_id; + Bool freesync_enabled; + /* cursor size */ int cursor_w; int cursor_h; diff --git a/src/amdgpu_extension.c b/src/amdgpu_extension.c new file mode 100644 index 0000000..6e3b67f --- /dev/null +++ b/src/amdgpu_extension.c @@ -0,0 +1,173 @@ +/* + * Copyright © 2016 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 "xf86.h" +#include "xf86Crtc.h" +#include "xf86drm.h" +#include "dix.h" +#include "dixstruct.h" +#include "extnsionst.h" +#include "resource.h" +#include "scrnintstr.h" + +#include "amdgpu_drm.h" +#include "amdgpu_extension.h" +#include "amdgpu_drv.h" + +static RESTYPE RT_AMDGPUCLIENT; + +static int ProcAMDGPUFreesyncCapability(ClientPtr client) +{ + REQUEST(xAMDGPUFreesyncCapabilityReq); + REQUEST_SIZE_MATCH(xAMDGPUFreesyncCapabilityReq); + + if (stuff->screen >= screenInfo.numScreens) { + client->errorValue = stuff->screen; + return BadValue; + } + + ScreenPtr pScreen = screenInfo.screens[stuff->screen]; + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + XID cliResId = FakeClientID(client->index); + + info->fullscreen_client = client; + + if (AddResource(cliResId, RT_AMDGPUCLIENT, (void *)pScrn)) + info->client_resource_id = cliResId; + + return client->noClientException; +} + +static int AMDGPUDispatch(ClientPtr client) +{ + REQUEST(xReq); + + switch(stuff->data) { + case X_AMDGPUFreesyncCapability: + return ProcAMDGPUFreesyncCapability(client); + default: + return BadRequest; + } +} + +static int AMDGPUSwapDispatch(ClientPtr client __attribute__((unused))) +{ + return BadRequest; +} + +static void AMDGPUResetExtension(ExtensionEntry *extEntry __attribute__((unused))) +{ + RT_AMDGPUCLIENT = RT_NONE; +} + +static void AMDGPUExtensionInit (void) +{ + ExtensionEntry *extEntry = NULL; + + extEntry = AddExtension(AMDGPU_EXTENSION_NAME, + AMDGPU_EXTENSION_EVENTS, + AMDGPU_EXTENSION_ERRORS, + AMDGPUDispatch, + AMDGPUSwapDispatch, + AMDGPUResetExtension, + StandardMinorOpcode); + if (!extEntry) { + ErrorF("AddExtension failed

"); + return; + } + RT_AMDGPUCLIENT = CreateNewResourceType(AMDGPUClientGone, "AMDGPUClient"); +} + +static ExtensionModule AMDGPU_Ext = { + AMDGPUExtensionInit, + AMDGPU_EXTENSION_NAME, + NULL +}; + +void AMDGPUExtensionSetup(void) +{ +#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,0,0,0) + LoadExtension(&AMDGPU_Ext, FALSE); +#else + int size = 1; + LoadExtensionList(&AMDGPU_Ext, size, FALSE); +#endif +} + +int AMDGPUFreesyncControl(int fd, Bool enable_freesync) +{ + int ret = -1; + struct drm_amdgpu_freesync args; + + memset(&args, 0, sizeof(args)); + if (enable_freesync) { + args.op = AMDGPU_FREESYNC_FULLSCREEN_ENTER; + ret = drmCommandWriteRead(fd, DRM_AMDGPU_FREESYNC, + &args, sizeof(args)); + if (ret) + ErrorF("Fail to enable freesync mode.

"); + + } else { + args.op = AMDGPU_FREESYNC_FULLSCREEN_EXIT; + ret = drmCommandWriteRead(fd, DRM_AMDGPU_FREESYNC, + &args, sizeof(args)); + if (ret) + ErrorF("Fail to disable freesync mode.

"); + } + + return ret; +} + +void AMDGPUFreeResourceByType(ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + + if (info->client_resource_id) + FreeResourceByType(info->client_resource_id, + RT_AMDGPUCLIENT, FALSE); + return; +} + +int AMDGPUClientGone(void *data, XID id) +{ + ScrnInfoPtr pScrn = (ScrnInfoPtr)data; + AMDGPUInfoPtr info = AMDGPUPTR(pScrn); + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); + + if (id == (XID)info->client_resource_id) { + info->client_resource_id = None; + info->fullscreen_client = NULL; + } + + if (info->freesync_enabled == TRUE) { + if (!AMDGPUFreesyncControl(pAMDGPUEnt->fd, FALSE)) + info->freesync_enabled = FALSE; + } + + return 1; +} diff --git a/src/amdgpu_extension.h b/src/amdgpu_extension.h new file mode 100644 index 0000000..4af17f3 --- /dev/null +++ b/src/amdgpu_extension.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2016 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. + */ +#ifndef _AMDGPU_EXTENSION_H_ +#define _AMDGPU_EXTENSION_H_ + +#include "screenint.h" + +#define AMDGPU_EXTENSION_NAME "AMDGPU" +#define AMDGPU_EXTENSION_EVENTS 1 +#define AMDGPU_EXTENSION_ERRORS 0 + +#ifndef XREQ_SZ +#define XREQ_SZ(name) sizeof(x##name##Req) +#endif + +#define X_AMDGPUFreesyncCapability 0 + +/* Requests must be mulitple of 4 bytes */ +typedef struct _AMDGPUFreesyncCapabilityReq { + CARD8 reqType; + CARD8 amdgpuReqType; + CARD16 length B16; + CARD32 screen B32; +} xAMDGPUFreesyncCapabilityReq; + +#define sz_xAMDGPUFreesyncCapabilityReq XREQ_SZ(AMDGPUFreesyncCapability) + +extern void AMDGPUExtensionSetup(void); +extern int AMDGPUFreesyncControl(int fd, Bool enable_freesync); +extern void AMDGPUFreeResourceByType(ScreenPtr pScreen); +extern int AMDGPUClientGone(void *data, XID id); +#endif /* _AMDGPU_EXTENSION_H_ */ diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c index 36506ea..8f229c2 100644 --- a/src/amdgpu_kms.c +++ b/src/amdgpu_kms.c @@ -53,6 +53,7 @@ #include "amdgpu_chipinfo_gen.h" #include "amdgpu_bo_helper.h" #include "amdgpu_pixmap.h" +#include "amdgpu_extension.h" #include <gbm.h> @@ -1329,6 +1330,9 @@ Bool AMDGPUScreenInit_KMS(SCREEN_INIT_ARGS_DECL) xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D and 3D cceleration disabled

"); } + /* AMDGPU extension setup */ + AMDGPUExtensionSetup(); + /* Init DPMS */ xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, "Initializing DPMS

"); diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c index 3f2ab12..73a3496 100644 --- a/src/amdgpu_present.c +++ b/src/amdgpu_present.c @@ -45,6 +45,7 @@ #include "amdgpu_glamor.h" #include "amdgpu_pixmap.h" #include "amdgpu_video.h" +#include "amdgpu_extension.h" #include "present.h" @@ -324,6 +325,15 @@ amdgpu_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, if (!amdgpu_present_check_flip(crtc, screen->root, pixmap, sync_flip)) return FALSE; + if ((info->fullscreen_client) && + (info->freesync_enabled == FALSE)) { + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); + int ret = -1; + ret = AMDGPUFreesyncControl(pAMDGPUEnt->fd, TRUE); + if (!ret) + info->freesync_enabled = TRUE; + } + event = calloc(1, sizeof(struct amdgpu_present_vblank_event)); if (!event) return FALSE; @@ -360,6 +370,17 @@ amdgpu_present_unflip(ScreenPtr screen, uint64_t event_id) if (!amdgpu_present_check_unflip(scrn)) goto modeset; + if ((info->fullscreen_client) && + (info->freesync_enabled == TRUE)) { + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); + int ret = -1; + ret = AMDGPUFreesyncControl(pAMDGPUEnt->fd, FALSE); + if (!ret) + info->freesync_enabled = FALSE; + if (info->client_resource_id) + AMDGPUFreeResourceByType(screen); + } + event = calloc(1, sizeof(struct amdgpu_present_vblank_event)); if (!event) { ErrorF("%s: calloc failed, display might freeze

", __func__); -- 2.7.4