summarylogtreecommitdiffstats
path: root/0032-null_platform-add-support-for-explicit-synchronisati.patch
blob: e2c40a4362d06f26e3dc18f877c7966094316165 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
From f9a46628162bd375821cd405e47105f4fe2629af Mon Sep 17 00:00:00 2001
From: Silvestrs Timofejevs <silvestrs.timofejevs@imgtec.com>
Date: Mon, 2 Sep 2019 09:32:01 +0100
Subject: [PATCH] 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 f74ee28..e234844 100644
--- a/src/egl/drivers/dri2/egl_dri2.h
+++ b/src/egl/drivers/dri2/egl_dri2.h
@@ -101,6 +101,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;
@@ -336,6 +337,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 5b7c1ec..d36dc0c 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: