216 lines
7.7 KiB
Diff
216 lines
7.7 KiB
Diff
From 07ba23c3baab75df2ad7928b021cde89d8551c35 Mon Sep 17 00:00:00 2001
|
|
From: Imagination Technologies <powervr@imgtec.com>
|
|
Date: Mon, 2 Sep 2019 09:32:01 +0100
|
|
Subject: [PATCH 031/168] null_platform: add support for explicit
|
|
synchronisation
|
|
|
|
This change adds support for the 'in' fence, the 'out' fence will
|
|
potentially be added in subsequent optimisation changes.
|
|
|
|
Explicit synchronisation KMS 'in' and 'out' properties have been first
|
|
added in Linux kernel 4.10 as an additional feature to the atomic mode
|
|
setting.
|
|
|
|
9626014258a5957ff120b3987ee72decdbe0c798 - 'in' property
|
|
beaf5af48034c9e2ebb8b2b1fb12dc4d8aeba99e - 'out' property
|
|
|
|
Unlike many other features - it doesn't have an in kernel capability
|
|
flag, so the support for it can be tested in the following way:
|
|
KMS creates an additional set of properties when the version of kernel
|
|
is new enough to support it ('in' and 'out' fence properties). When
|
|
the user-space requests all the properties from the kernel via
|
|
drmModeObjectGetProperties it is possible to determine whether the
|
|
required property is supported by the kernel or not.
|
|
|
|
The explicit synchronisation is used when available, otherwise the
|
|
implicit sync model is used instead. If explicit synchronisation is
|
|
available but 'in' fence failed to attach in KMS, the system falls
|
|
back to the implicit synchronisation model.
|
|
|
|
egl_dri2.c already creates the GPU 'out' fence that is then used by
|
|
the null_platform as KMS 'in' fence. null_platform takes owenership of
|
|
this fence fd during the swap buffers operation, at which point the
|
|
fence fd is no longer available to be used outside of null_platform.
|
|
|
|
EGL_LOG_LEVEL=debug should give some useful information in case of
|
|
explicit synchronisation failure. As mentioned above, this failure
|
|
will result in implicit synchronisation being used instead.
|
|
|
|
Change-Id: Ib9c4a0bc3ea1b21192ee37909d7580d6b7b366ec
|
|
---
|
|
src/egl/drivers/dri2/egl_dri2.h | 2 +
|
|
src/egl/drivers/dri2/platform_null.c | 77 +++++++++++++++++++++++++++-
|
|
2 files changed, 77 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h
|
|
index 4baff09e80b..9aab57356f7 100644
|
|
--- a/src/egl/drivers/dri2/egl_dri2.h
|
|
+++ b/src/egl/drivers/dri2/egl_dri2.h
|
|
@@ -102,6 +102,7 @@ struct wl_buffer;
|
|
#ifdef HAVE_NULL_PLATFORM
|
|
struct display_output {
|
|
bool in_use;
|
|
+ bool in_fence_supported;
|
|
uint32_t connector_id;
|
|
drmModePropertyRes **connector_prop_res;
|
|
uint32_t crtc_id;
|
|
@@ -345,6 +346,7 @@ struct swap_queue_elem
|
|
uint32_t swap_interval;
|
|
uint32_t back_id;
|
|
uint32_t fb_id;
|
|
+ int kms_in_fence_fd;
|
|
};
|
|
|
|
enum {
|
|
diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c
|
|
index 5b7c1ec426c..d36dc0ced2a 100644
|
|
--- a/src/egl/drivers/dri2/platform_null.c
|
|
+++ b/src/egl/drivers/dri2/platform_null.c
|
|
@@ -401,6 +401,9 @@ display_output_atomic_init(int fd, struct display_output *output)
|
|
if (!output->atomic_state)
|
|
goto err_destroy_mode_prop_blob;
|
|
|
|
+ if (property_id_get_for_name(plane_prop_res, "IN_FENCE_FD"))
|
|
+ output->in_fence_supported = true;
|
|
+
|
|
output->connector_prop_res = connector_prop_res;
|
|
output->crtc_prop_res = crtc_prop_res;
|
|
output->plane_prop_res = plane_prop_res;
|
|
@@ -418,6 +421,53 @@ err_free_connector_prop_res:
|
|
return false;
|
|
}
|
|
|
|
+static void
|
|
+display_output_atomic_add_in_fence(struct display_output *output,
|
|
+ int kms_in_fence_fd)
|
|
+{
|
|
+ const struct object_property obj_sync_props[] = {
|
|
+ object_property_set_named(output, plane, "IN_FENCE_FD", kms_in_fence_fd),
|
|
+ };
|
|
+ int err;
|
|
+
|
|
+ /* Explicit synchronisation is not being used */
|
|
+ if (kms_in_fence_fd < 0)
|
|
+ return;
|
|
+
|
|
+ err = atomic_state_add_object_properties(output->atomic_state,
|
|
+ obj_sync_props,
|
|
+ ARRAY_SIZE(obj_sync_props));
|
|
+ if (err)
|
|
+ _eglLog(_EGL_DEBUG, "%s: failed to add props ERR = %d", __func__, err);
|
|
+}
|
|
+
|
|
+static void
|
|
+atomic_claim_in_fence_fd(struct dri2_egl_surface *dri2_surf,
|
|
+ struct swap_queue_elem *swap_data)
|
|
+{
|
|
+ /* Explicit synchronisation is not being used */
|
|
+ if (!dri2_surf->enable_out_fence)
|
|
+ return;
|
|
+
|
|
+ if (dri2_surf->out_fence_fd < 0) {
|
|
+ _eglLog(_EGL_DEBUG, "%s: missing 'in' fence", __func__);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ /* Take ownership of the fd */
|
|
+ swap_data->kms_in_fence_fd = dri2_surf->out_fence_fd;
|
|
+ dri2_surf->out_fence_fd = -1;
|
|
+}
|
|
+
|
|
+static void
|
|
+atomic_relinquish_in_fence_fd(struct dri2_egl_surface *dri2_surf,
|
|
+ struct swap_queue_elem *swap_data)
|
|
+{
|
|
+ /* KMS is now in control of the fence (post drmModeAtomicCommit) */
|
|
+ close(swap_data->kms_in_fence_fd);
|
|
+ swap_data->kms_in_fence_fd = -1;
|
|
+}
|
|
+
|
|
static int
|
|
display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id,
|
|
uint32_t flags, void *flip_data)
|
|
@@ -425,6 +475,8 @@ display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id
|
|
const struct object_property obj_props[] = {
|
|
object_property_set_named(output, plane, "FB_ID", fb_id),
|
|
};
|
|
+ struct dri2_egl_surface *dri2_surf = flip_data;
|
|
+ struct swap_queue_elem *swap_data = dri2_surf->swap_data;
|
|
int err;
|
|
|
|
/* Reset atomic state */
|
|
@@ -435,13 +487,19 @@ display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id
|
|
if (err)
|
|
return err;
|
|
|
|
+ display_output_atomic_add_in_fence(output, swap_data->kms_in_fence_fd);
|
|
+
|
|
/*
|
|
* Don't block - like drmModePageFlip, drmModeAtomicCommit will return
|
|
* -EBUSY if the commit can't be queued in the kernel.
|
|
*/
|
|
flags |= DRM_MODE_ATOMIC_NONBLOCK;
|
|
|
|
- return drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data);
|
|
+ err = drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data);
|
|
+
|
|
+ atomic_relinquish_in_fence_fd(dri2_surf, swap_data);
|
|
+
|
|
+ return err;
|
|
}
|
|
|
|
static int
|
|
@@ -489,6 +547,8 @@ swap_enqueue_data(struct dri2_egl_surface *dri2_surf, uint32_t back_id,
|
|
swap_data->fb_id = dri2_surf->back->fb_id;
|
|
swap_data->back_id = back_id;
|
|
|
|
+ atomic_claim_in_fence_fd(dri2_surf, swap_data);
|
|
+
|
|
dri2_surf->swap_queue_idx_tail++;
|
|
dri2_surf->swap_queue_idx_tail %= ARRAY_SIZE(dri2_surf->swap_queue);
|
|
|
|
@@ -1025,11 +1085,21 @@ err_unlock:
|
|
return false;
|
|
}
|
|
|
|
+static void surface_swap_queue_init(struct dri2_egl_surface *dri2_surf)
|
|
+{
|
|
+ struct swap_queue_elem *swap_queue = &dri2_surf->swap_queue[0];
|
|
+ const int num_el = ARRAY_SIZE(dri2_surf->swap_queue);
|
|
+
|
|
+ for (int i = 0; i < num_el; i++)
|
|
+ swap_queue[i].kms_in_fence_fd = -1;
|
|
+}
|
|
+
|
|
static _EGLSurface *
|
|
create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
|
|
const EGLint *attrib_list)
|
|
{
|
|
struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
|
|
+ struct display_output *output = &dri2_dpy->output;
|
|
struct dri2_egl_config *dri2_config = dri2_egl_config(config);
|
|
struct dri2_egl_surface *dri2_surf;
|
|
const __DRIconfig *dri_config;
|
|
@@ -1043,7 +1113,8 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
|
|
}
|
|
surf = &dri2_surf->base;
|
|
|
|
- if (!dri2_init_surface(surf, disp, type, config, attrib_list, false, NULL))
|
|
+ if (!dri2_init_surface(surf, disp, type, config, attrib_list,
|
|
+ output->in_fence_supported, NULL))
|
|
goto err_free_surface;
|
|
|
|
dri_config = dri2_get_dri_config(dri2_config, type,
|
|
@@ -1066,6 +1137,8 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type,
|
|
|
|
dri2_surf->format = dri2_null_formats[format_idx].dri_image_format;
|
|
|
|
+ surface_swap_queue_init(dri2_surf);
|
|
+
|
|
return surf;
|
|
|
|
err_free_surface:
|
|
--
|
|
2.17.1
|
|
|