[Mesa-dev] [PATCH] [AMD] dri3: Add adaptive_sync_enable driconf option

Nicolai Hähnle nhaehnle at gmail.com
Tue Oct 17 09:33:49 UTC 2017


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

When enabled, this will request FreeSync via the hybrid amdgpu DDX's
AMDGPU X11 protocol extension.

Due to limitations in the DDX this will only work for applications
that cover the entire X screen (which is important to keep in mind when
you have a multi-monitor setup).
--
We currently have no plans to upstream this patch in this form. So
this is mostly informational.

Still, for any future upstream solution, it would be nice to expose
the same adaptive_sync_enable option, to reduce user confusion.
The meaning of that option is basically: enable FreeSync / use
VESA Adaptive Sync in the way that makes sense for games, i.e. try
to produce frames as fast as possible, and adjust the monitor refresh
rate to the game's update rate.
---
 src/gallium/drivers/radeonsi/driinfo_radeonsi.h |  4 ++
 src/loader/loader_dri3_helper.c                 | 60 ++++++++++++++++++++++++-
 src/loader/loader_dri3_helper.h                 |  1 +
 src/util/xmlpool/t_options.h                    |  5 +++
 4 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/src/gallium/drivers/radeonsi/driinfo_radeonsi.h b/src/gallium/drivers/radeonsi/driinfo_radeonsi.h
index 402d3406d45..29b4346a726 100644
--- a/src/gallium/drivers/radeonsi/driinfo_radeonsi.h
+++ b/src/gallium/drivers/radeonsi/driinfo_radeonsi.h
@@ -1,10 +1,14 @@
 // DriConf options specific to radeonsi
+DRI_CONF_SECTION_QUALITY
+   DRI_CONF_ADAPTIVE_SYNC_ENABLE("false")
+DRI_CONF_SECTION_END
+
 DRI_CONF_SECTION_PERFORMANCE
     DRI_CONF_RADEONSI_ENABLE_SISCHED("false")
     DRI_CONF_RADEONSI_ASSUME_NO_Z_FIGHTS("false")
     DRI_CONF_RADEONSI_COMMUTATIVE_BLEND_ADD("false")
 DRI_CONF_SECTION_END
 
 DRI_CONF_SECTION_DEBUG
    DRI_CONF_RADEONSI_CLEAR_DB_META_BEFORE_CLEAR("false")
 DRI_CONF_SECTION_END
diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c
index 19ab5815100..c685afa7661 100644
--- a/src/loader/loader_dri3_helper.c
+++ b/src/loader/loader_dri3_helper.c
@@ -15,25 +15,27 @@
  * 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 <fcntl.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 
 #include <X11/xshmfence.h>
 #include <xcb/xcb.h>
+#include <xcb/xcbext.h>
 #include <xcb/dri3.h>
 #include <xcb/present.h>
 
 #include <X11/Xlib-xcb.h>
 
 #include <c11/threads.h>
 #include "loader_dri3_helper.h"
 
 /* From xmlpool/options.h, user exposed so should be stable */
 #define DRI_CONF_VBLANK_NEVER 0
@@ -240,20 +242,64 @@ loader_dri3_drawable_fini(struct loader_dri3_drawable *draw)
    if (draw->special_event) {
       xcb_void_cookie_t cookie =
          xcb_present_select_input_checked(draw->conn, draw->eid, draw->drawable,
                                           XCB_PRESENT_EVENT_MASK_NO_EVENT);
 
       xcb_discard_reply(draw->conn, cookie.sequence);
       xcb_unregister_for_special_event(draw->conn, draw->special_event);
    }
 }
 
+#define X_AMDGPUFreesyncCapability	0
+
+/* Requests must be mulitple of 4 bytes */
+typedef struct _AMDGPUFreesyncCapabilityReq {
+   uint8_t reqType;
+   uint8_t amdgpuReqType;
+   uint16_t length;
+   uint32_t screen;
+   uint32_t drawable;
+} xAMDGPUFreesyncCapabilityReq;
+
+static xcb_extension_t amdgpu_ext_id = { "AMDGPU", 0 };
+
+static bool
+loader_dri3_amdgpu_freesync_enable(xcb_connection_t *conn,
+                                   xcb_drawable_t drawable)
+{
+   const xcb_query_extension_reply_t *extension;
+
+   extension = xcb_get_extension_data(conn, &amdgpu_ext_id);
+   if (!(extension && extension->present)) {
+      fprintf(stderr, "AMDGPU extension not present -- cannot enable FreeSync\n");
+      return false;
+   }
+
+   const xcb_protocol_request_t xcb_req = {
+      .count = 1,
+      .ext = &amdgpu_ext_id,
+      .opcode = X_AMDGPUFreesyncCapability,
+      .isvoid = 1,
+   };
+   xAMDGPUFreesyncCapabilityReq req;
+   struct iovec xcb_parts[3];
+
+   req.screen = 0; /* TODO: do we need to support multiple screens? */
+   req.drawable = drawable;
+
+   xcb_parts[2].iov_base = (char *)&req;
+   xcb_parts[2].iov_len = sizeof(req);
+
+   xcb_send_request(conn, 0, xcb_parts + 2, &xcb_req);
+   return true;
+}
+
 int
 loader_dri3_drawable_init(xcb_connection_t *conn,
                           xcb_drawable_t drawable,
                           __DRIscreen *dri_screen,
                           bool is_different_gpu,
                           const __DRIconfig *dri_config,
                           struct loader_dri3_extensions *ext,
                           const struct loader_dri3_vtable *vtable,
                           struct loader_dri3_drawable *draw)
 {
@@ -269,25 +315,32 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
    draw->drawable = drawable;
    draw->dri_screen = dri_screen;
    draw->is_different_gpu = is_different_gpu;
 
    draw->have_back = 0;
    draw->have_fake_front = 0;
    draw->first_init = true;
 
    draw->cur_blit_source = -1;
    draw->back_format = __DRI_IMAGE_FORMAT_NONE;
+   draw->adaptive_sync = false;
 
-   if (draw->ext->config)
+   if (draw->ext->config) {
       draw->ext->config->configQueryi(draw->dri_screen,
                                       "vblank_mode", &vblank_mode);
 
+      unsigned char adaptive_sync_enable = 1;
+      draw->ext->config->configQueryb(draw->dri_screen,
+                                      "adaptive_sync_enable", &adaptive_sync_enable);
+      draw->adaptive_sync = adaptive_sync_enable;
+   }
+
    switch (vblank_mode) {
    case DRI_CONF_VBLANK_NEVER:
    case DRI_CONF_VBLANK_DEF_INTERVAL_0:
       swap_interval = 0;
       break;
    case DRI_CONF_VBLANK_DEF_INTERVAL_1:
    case DRI_CONF_VBLANK_ALWAYS_SYNC:
    default:
       swap_interval = 1;
       break;
@@ -767,20 +820,25 @@ loader_dri3_swap_buffers_msc(struct loader_dri3_drawable *draw,
                              bool force_copy)
 {
    struct loader_dri3_buffer *back;
    int64_t ret = 0;
    uint32_t options = XCB_PRESENT_OPTION_NONE;
 
    draw->vtable->flush_drawable(draw, flush_flags);
 
    back = dri3_find_back_alloc(draw);
 
+   if (draw->adaptive_sync) {
+      if (!loader_dri3_amdgpu_freesync_enable(draw->conn, draw->drawable))
+         draw->adaptive_sync = false;
+   }
+
    if (draw->is_different_gpu && back) {
       /* Update the linear buffer before presenting the pixmap */
       (void) loader_dri3_blit_image(draw,
                                     back->linear_buffer,
                                     back->image,
                                     0, 0, back->width, back->height,
                                     0, 0, __BLIT_FLAG_FLUSH);
    }
 
    /* If we need to preload the new back buffer, remember the source.
diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h
index d3f4b0c00a9..40286e0759d 100644
--- a/src/loader/loader_dri3_helper.h
+++ b/src/loader/loader_dri3_helper.h
@@ -145,20 +145,21 @@ struct loader_dri3_drawable {
    int num_back;
    int cur_blit_source;
 
    uint32_t *stamp;
 
    xcb_present_event_t eid;
    xcb_gcontext_t gc;
    xcb_special_event_t *special_event;
 
    bool first_init;
+   bool adaptive_sync;
    int swap_interval;
 
    struct loader_dri3_extensions *ext;
    const struct loader_dri3_vtable *vtable;
 
    unsigned int swap_method;
    unsigned int back_format;
 };
 
 void
diff --git a/src/util/xmlpool/t_options.h b/src/util/xmlpool/t_options.h
index 957ed615048..664547a953b 100644
--- a/src/util/xmlpool/t_options.h
+++ b/src/util/xmlpool/t_options.h
@@ -286,20 +286,25 @@ DRI_CONF_OPT_END
 #define DRI_CONF_VBLANK_MODE(def) \
 DRI_CONF_OPT_BEGIN_V(vblank_mode,enum,def,"0:3") \
         DRI_CONF_DESC_BEGIN(en,gettext("Synchronization with vertical refresh (swap intervals)")) \
                 DRI_CONF_ENUM(0,gettext("Never synchronize with vertical refresh, ignore application's choice")) \
                 DRI_CONF_ENUM(1,gettext("Initial swap interval 0, obey application's choice")) \
                 DRI_CONF_ENUM(2,gettext("Initial swap interval 1, obey application's choice")) \
                 DRI_CONF_ENUM(3,gettext("Always synchronize with vertical refresh, application chooses the minimum swap interval")) \
         DRI_CONF_DESC_END \
 DRI_CONF_OPT_END
 
+#define DRI_CONF_ADAPTIVE_SYNC_ENABLE(def) \
+DRI_CONF_OPT_BEGIN_B(adaptive_sync_enable,def) \
+        DRI_CONF_DESC(en,gettext("Adapt the monitor sync to the application performance (when possible)")) \
+DRI_CONF_OPT_END
+
 #define DRI_CONF_HYPERZ_DISABLED 0
 #define DRI_CONF_HYPERZ_ENABLED 1
 #define DRI_CONF_HYPERZ(def) \
 DRI_CONF_OPT_BEGIN_B(hyperz, def) \
         DRI_CONF_DESC(en,gettext("Use HyperZ to boost performance")) \
 DRI_CONF_OPT_END
 
 #define DRI_CONF_MAX_TEXTURE_UNITS(def,min,max) \
 DRI_CONF_OPT_BEGIN_V(texture_units,int,def, # min ":" # max ) \
         DRI_CONF_DESC(en,gettext("Number of texture units used")) \
-- 
2.11.0



More information about the mesa-dev mailing list