[PATCH] Enable/disable freesync when enter/exit fullscreen game
Hawking Zhang
Hawking.Zhang at amd.com
Tue Aug 2 02:27:06 UTC 2016
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]\n", __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\n");
+ 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.\n");
+
+ } else {
+ args.op = AMDGPU_FREESYNC_FULLSCREEN_EXIT;
+ ret = drmCommandWriteRead(fd, DRM_AMDGPU_FREESYNC,
+ &args, sizeof(args));
+ if (ret)
+ ErrorF("Fail to disable freesync mode.\n");
+ }
+
+ 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\n");
}
+ /* AMDGPU extension setup */
+ AMDGPUExtensionSetup();
+
/* Init DPMS */
xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
"Initializing DPMS\n");
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\n", __func__);
--
2.7.4
More information about the amd-gfx
mailing list