1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2021 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#include "vk_drm_syncobj.h"
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include <sched.h>
27bf215546Sopenharmony_ci#include <xf86drm.h>
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "drm-uapi/drm.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "util/os_time.h"
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "vk_device.h"
34bf215546Sopenharmony_ci#include "vk_log.h"
35bf215546Sopenharmony_ci#include "vk_util.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_cistatic struct vk_drm_syncobj *
38bf215546Sopenharmony_cito_drm_syncobj(struct vk_sync *sync)
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci   assert(vk_sync_type_is_drm_syncobj(sync->type));
41bf215546Sopenharmony_ci   return container_of(sync, struct vk_drm_syncobj, base);
42bf215546Sopenharmony_ci}
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_cistatic VkResult
45bf215546Sopenharmony_civk_drm_syncobj_init(struct vk_device *device,
46bf215546Sopenharmony_ci                    struct vk_sync *sync,
47bf215546Sopenharmony_ci                    uint64_t initial_value)
48bf215546Sopenharmony_ci{
49bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   uint32_t flags = 0;
52bf215546Sopenharmony_ci   if (!(sync->flags & VK_SYNC_IS_TIMELINE) && initial_value)
53bf215546Sopenharmony_ci      flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
56bf215546Sopenharmony_ci   int err = drmSyncobjCreate(device->drm_fd, flags, &sobj->syncobj);
57bf215546Sopenharmony_ci   if (err < 0) {
58bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_OUT_OF_HOST_MEMORY,
59bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_CREATE failed: %m");
60bf215546Sopenharmony_ci   }
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   if ((sync->flags & VK_SYNC_IS_TIMELINE) && initial_value) {
63bf215546Sopenharmony_ci      err = drmSyncobjTimelineSignal(device->drm_fd, &sobj->syncobj,
64bf215546Sopenharmony_ci                                     &initial_value, 1);
65bf215546Sopenharmony_ci      if (err < 0) {
66bf215546Sopenharmony_ci         vk_drm_syncobj_finish(device, sync);
67bf215546Sopenharmony_ci         return vk_errorf(device, VK_ERROR_OUT_OF_HOST_MEMORY,
68bf215546Sopenharmony_ci                          "DRM_IOCTL_SYNCOBJ_CREATE failed: %m");
69bf215546Sopenharmony_ci      }
70bf215546Sopenharmony_ci   }
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci   return VK_SUCCESS;
73bf215546Sopenharmony_ci}
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_civoid
76bf215546Sopenharmony_civk_drm_syncobj_finish(struct vk_device *device,
77bf215546Sopenharmony_ci                      struct vk_sync *sync)
78bf215546Sopenharmony_ci{
79bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
82bf215546Sopenharmony_ci   ASSERTED int err = drmSyncobjDestroy(device->drm_fd, sobj->syncobj);
83bf215546Sopenharmony_ci   assert(err == 0);
84bf215546Sopenharmony_ci}
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_cistatic VkResult
87bf215546Sopenharmony_civk_drm_syncobj_signal(struct vk_device *device,
88bf215546Sopenharmony_ci                      struct vk_sync *sync,
89bf215546Sopenharmony_ci                      uint64_t value)
90bf215546Sopenharmony_ci{
91bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
94bf215546Sopenharmony_ci   int err;
95bf215546Sopenharmony_ci   if (sync->flags & VK_SYNC_IS_TIMELINE)
96bf215546Sopenharmony_ci      err = drmSyncobjTimelineSignal(device->drm_fd, &sobj->syncobj, &value, 1);
97bf215546Sopenharmony_ci   else
98bf215546Sopenharmony_ci      err = drmSyncobjSignal(device->drm_fd, &sobj->syncobj, 1);
99bf215546Sopenharmony_ci   if (err) {
100bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
101bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_SIGNAL failed: %m");
102bf215546Sopenharmony_ci   }
103bf215546Sopenharmony_ci
104bf215546Sopenharmony_ci   return VK_SUCCESS;
105bf215546Sopenharmony_ci}
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_cistatic VkResult
108bf215546Sopenharmony_civk_drm_syncobj_get_value(struct vk_device *device,
109bf215546Sopenharmony_ci                         struct vk_sync *sync,
110bf215546Sopenharmony_ci                         uint64_t *value)
111bf215546Sopenharmony_ci{
112bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
113bf215546Sopenharmony_ci
114bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
115bf215546Sopenharmony_ci   int err = drmSyncobjQuery(device->drm_fd, &sobj->syncobj, value, 1);
116bf215546Sopenharmony_ci   if (err) {
117bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
118bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_QUERY failed: %m");
119bf215546Sopenharmony_ci   }
120bf215546Sopenharmony_ci
121bf215546Sopenharmony_ci   return VK_SUCCESS;
122bf215546Sopenharmony_ci}
123bf215546Sopenharmony_ci
124bf215546Sopenharmony_cistatic VkResult
125bf215546Sopenharmony_civk_drm_syncobj_reset(struct vk_device *device,
126bf215546Sopenharmony_ci                     struct vk_sync *sync)
127bf215546Sopenharmony_ci{
128bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
129bf215546Sopenharmony_ci
130bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
131bf215546Sopenharmony_ci   int err = drmSyncobjReset(device->drm_fd, &sobj->syncobj, 1);
132bf215546Sopenharmony_ci   if (err) {
133bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
134bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_RESET failed: %m");
135bf215546Sopenharmony_ci   }
136bf215546Sopenharmony_ci
137bf215546Sopenharmony_ci   return VK_SUCCESS;
138bf215546Sopenharmony_ci}
139bf215546Sopenharmony_ci
140bf215546Sopenharmony_cistatic VkResult
141bf215546Sopenharmony_cisync_has_sync_file(struct vk_device *device, struct vk_sync *sync)
142bf215546Sopenharmony_ci{
143bf215546Sopenharmony_ci   uint32_t handle = to_drm_syncobj(sync)->syncobj;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   int fd = -1;
146bf215546Sopenharmony_ci   int err = drmSyncobjExportSyncFile(device->drm_fd, handle, &fd);
147bf215546Sopenharmony_ci   if (!err) {
148bf215546Sopenharmony_ci      close(fd);
149bf215546Sopenharmony_ci      return VK_SUCCESS;
150bf215546Sopenharmony_ci   }
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   /* On the off chance the sync_file export repeatedly fails for some
153bf215546Sopenharmony_ci    * unexpected reason, we want to ensure this function will return success
154bf215546Sopenharmony_ci    * eventually.  Do a zero-time syncobj wait if the export failed.
155bf215546Sopenharmony_ci    */
156bf215546Sopenharmony_ci   err = drmSyncobjWait(device->drm_fd, &handle, 1, 0 /* timeout */,
157bf215546Sopenharmony_ci                        DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT,
158bf215546Sopenharmony_ci                        NULL /* first_signaled */);
159bf215546Sopenharmony_ci   if (!err) {
160bf215546Sopenharmony_ci      return VK_SUCCESS;
161bf215546Sopenharmony_ci   } else if (errno == ETIME) {
162bf215546Sopenharmony_ci      return VK_TIMEOUT;
163bf215546Sopenharmony_ci   } else {
164bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
165bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_WAIT failed: %m");
166bf215546Sopenharmony_ci   }
167bf215546Sopenharmony_ci}
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_cistatic VkResult
170bf215546Sopenharmony_cispin_wait_for_sync_file(struct vk_device *device,
171bf215546Sopenharmony_ci                        uint32_t wait_count,
172bf215546Sopenharmony_ci                        const struct vk_sync_wait *waits,
173bf215546Sopenharmony_ci                        enum vk_sync_wait_flags wait_flags,
174bf215546Sopenharmony_ci                        uint64_t abs_timeout_ns)
175bf215546Sopenharmony_ci{
176bf215546Sopenharmony_ci   if (wait_flags & VK_SYNC_WAIT_ANY) {
177bf215546Sopenharmony_ci      while (1) {
178bf215546Sopenharmony_ci         for (uint32_t i = 0; i < wait_count; i++) {
179bf215546Sopenharmony_ci            VkResult result = sync_has_sync_file(device, waits[i].sync);
180bf215546Sopenharmony_ci            if (result != VK_TIMEOUT)
181bf215546Sopenharmony_ci               return result;
182bf215546Sopenharmony_ci         }
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci         if (os_time_get_nano() >= abs_timeout_ns)
185bf215546Sopenharmony_ci            return VK_TIMEOUT;
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci         sched_yield();
188bf215546Sopenharmony_ci      }
189bf215546Sopenharmony_ci   } else {
190bf215546Sopenharmony_ci      for (uint32_t i = 0; i < wait_count; i++) {
191bf215546Sopenharmony_ci         while (1) {
192bf215546Sopenharmony_ci            VkResult result = sync_has_sync_file(device, waits[i].sync);
193bf215546Sopenharmony_ci            if (result != VK_TIMEOUT)
194bf215546Sopenharmony_ci               return result;
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci            if (os_time_get_nano() >= abs_timeout_ns)
197bf215546Sopenharmony_ci               return VK_TIMEOUT;
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci            sched_yield();
200bf215546Sopenharmony_ci         }
201bf215546Sopenharmony_ci      }
202bf215546Sopenharmony_ci   }
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   return VK_SUCCESS;
205bf215546Sopenharmony_ci}
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_cistatic VkResult
208bf215546Sopenharmony_civk_drm_syncobj_wait_many(struct vk_device *device,
209bf215546Sopenharmony_ci                         uint32_t wait_count,
210bf215546Sopenharmony_ci                         const struct vk_sync_wait *waits,
211bf215546Sopenharmony_ci                         enum vk_sync_wait_flags wait_flags,
212bf215546Sopenharmony_ci                         uint64_t abs_timeout_ns)
213bf215546Sopenharmony_ci{
214bf215546Sopenharmony_ci   if ((wait_flags & VK_SYNC_WAIT_PENDING) &&
215bf215546Sopenharmony_ci       !(waits[0].sync->type->features & VK_SYNC_FEATURE_TIMELINE)) {
216bf215546Sopenharmony_ci      /* Sadly, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE was never implemented
217bf215546Sopenharmony_ci       * for drivers that don't support timelines.  Instead, we have to spin
218bf215546Sopenharmony_ci       * on DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE until it succeeds.
219bf215546Sopenharmony_ci       */
220bf215546Sopenharmony_ci      return spin_wait_for_sync_file(device, wait_count, waits,
221bf215546Sopenharmony_ci                                     wait_flags, abs_timeout_ns);
222bf215546Sopenharmony_ci   }
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci   /* Syncobj timeouts are signed */
225bf215546Sopenharmony_ci   abs_timeout_ns = MIN2(abs_timeout_ns, (uint64_t)INT64_MAX);
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci   STACK_ARRAY(uint32_t, handles, wait_count);
228bf215546Sopenharmony_ci   STACK_ARRAY(uint64_t, wait_values, wait_count);
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   uint32_t j = 0;
231bf215546Sopenharmony_ci   bool has_timeline = false;
232bf215546Sopenharmony_ci   for (uint32_t i = 0; i < wait_count; i++) {
233bf215546Sopenharmony_ci      /* The syncobj API doesn't like wait values of 0 but it's safe to skip
234bf215546Sopenharmony_ci       * them because a wait for 0 is a no-op.
235bf215546Sopenharmony_ci       */
236bf215546Sopenharmony_ci      if (waits[i].sync->flags & VK_SYNC_IS_TIMELINE) {
237bf215546Sopenharmony_ci         if (waits[i].wait_value == 0)
238bf215546Sopenharmony_ci            continue;
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci         has_timeline = true;
241bf215546Sopenharmony_ci      }
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_ci      handles[j] = to_drm_syncobj(waits[i].sync)->syncobj;
244bf215546Sopenharmony_ci      wait_values[j] = waits[i].wait_value;
245bf215546Sopenharmony_ci      j++;
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci   assert(j <= wait_count);
248bf215546Sopenharmony_ci   wait_count = j;
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci   uint32_t syncobj_wait_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
251bf215546Sopenharmony_ci   if (!(wait_flags & VK_SYNC_WAIT_ANY))
252bf215546Sopenharmony_ci      syncobj_wait_flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
255bf215546Sopenharmony_ci   int err;
256bf215546Sopenharmony_ci   if (wait_count == 0) {
257bf215546Sopenharmony_ci      err = 0;
258bf215546Sopenharmony_ci   } else if (wait_flags & VK_SYNC_WAIT_PENDING) {
259bf215546Sopenharmony_ci      /* We always use a timeline wait for WAIT_PENDING, even for binary
260bf215546Sopenharmony_ci       * syncobjs because the non-timeline wait doesn't support
261bf215546Sopenharmony_ci       * DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE.
262bf215546Sopenharmony_ci       */
263bf215546Sopenharmony_ci      err = drmSyncobjTimelineWait(device->drm_fd, handles, wait_values,
264bf215546Sopenharmony_ci                                   wait_count, abs_timeout_ns,
265bf215546Sopenharmony_ci                                   syncobj_wait_flags |
266bf215546Sopenharmony_ci                                   DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE,
267bf215546Sopenharmony_ci                                   NULL /* first_signaled */);
268bf215546Sopenharmony_ci   } else if (has_timeline) {
269bf215546Sopenharmony_ci      err = drmSyncobjTimelineWait(device->drm_fd, handles, wait_values,
270bf215546Sopenharmony_ci                                   wait_count, abs_timeout_ns,
271bf215546Sopenharmony_ci                                   syncobj_wait_flags,
272bf215546Sopenharmony_ci                                   NULL /* first_signaled */);
273bf215546Sopenharmony_ci   } else {
274bf215546Sopenharmony_ci      err = drmSyncobjWait(device->drm_fd, handles,
275bf215546Sopenharmony_ci                           wait_count, abs_timeout_ns,
276bf215546Sopenharmony_ci                           syncobj_wait_flags,
277bf215546Sopenharmony_ci                           NULL /* first_signaled */);
278bf215546Sopenharmony_ci   }
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   STACK_ARRAY_FINISH(handles);
281bf215546Sopenharmony_ci   STACK_ARRAY_FINISH(wait_values);
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_ci   if (err && errno == ETIME) {
284bf215546Sopenharmony_ci      return VK_TIMEOUT;
285bf215546Sopenharmony_ci   } else if (err) {
286bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
287bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_WAIT failed: %m");
288bf215546Sopenharmony_ci   }
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_ci   return VK_SUCCESS;
291bf215546Sopenharmony_ci}
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_cistatic VkResult
294bf215546Sopenharmony_civk_drm_syncobj_import_opaque_fd(struct vk_device *device,
295bf215546Sopenharmony_ci                                struct vk_sync *sync,
296bf215546Sopenharmony_ci                                int fd)
297bf215546Sopenharmony_ci{
298bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
301bf215546Sopenharmony_ci   uint32_t new_handle;
302bf215546Sopenharmony_ci   int err = drmSyncobjFDToHandle(device->drm_fd, fd, &new_handle);
303bf215546Sopenharmony_ci   if (err) {
304bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
305bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE failed: %m");
306bf215546Sopenharmony_ci   }
307bf215546Sopenharmony_ci
308bf215546Sopenharmony_ci   err = drmSyncobjDestroy(device->drm_fd, sobj->syncobj);
309bf215546Sopenharmony_ci   assert(!err);
310bf215546Sopenharmony_ci
311bf215546Sopenharmony_ci   sobj->syncobj = new_handle;
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci   return VK_SUCCESS;
314bf215546Sopenharmony_ci}
315bf215546Sopenharmony_ci
316bf215546Sopenharmony_cistatic VkResult
317bf215546Sopenharmony_civk_drm_syncobj_export_opaque_fd(struct vk_device *device,
318bf215546Sopenharmony_ci                                struct vk_sync *sync,
319bf215546Sopenharmony_ci                                int *fd)
320bf215546Sopenharmony_ci{
321bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
322bf215546Sopenharmony_ci
323bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
324bf215546Sopenharmony_ci   int err = drmSyncobjHandleToFD(device->drm_fd, sobj->syncobj, fd);
325bf215546Sopenharmony_ci   if (err) {
326bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
327bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD failed: %m");
328bf215546Sopenharmony_ci   }
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   return VK_SUCCESS;
331bf215546Sopenharmony_ci}
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_cistatic VkResult
334bf215546Sopenharmony_civk_drm_syncobj_import_sync_file(struct vk_device *device,
335bf215546Sopenharmony_ci                                struct vk_sync *sync,
336bf215546Sopenharmony_ci                                int sync_file)
337bf215546Sopenharmony_ci{
338bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
341bf215546Sopenharmony_ci   int err = drmSyncobjImportSyncFile(device->drm_fd, sobj->syncobj, sync_file);
342bf215546Sopenharmony_ci   if (err) {
343bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
344bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE failed: %m");
345bf215546Sopenharmony_ci   }
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci   return VK_SUCCESS;
348bf215546Sopenharmony_ci}
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_cistatic VkResult
351bf215546Sopenharmony_civk_drm_syncobj_export_sync_file(struct vk_device *device,
352bf215546Sopenharmony_ci                                struct vk_sync *sync,
353bf215546Sopenharmony_ci                                int *sync_file)
354bf215546Sopenharmony_ci{
355bf215546Sopenharmony_ci   struct vk_drm_syncobj *sobj = to_drm_syncobj(sync);
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci   assert(device->drm_fd >= 0);
358bf215546Sopenharmony_ci   int err = drmSyncobjExportSyncFile(device->drm_fd, sobj->syncobj, sync_file);
359bf215546Sopenharmony_ci   if (err) {
360bf215546Sopenharmony_ci      return vk_errorf(device, VK_ERROR_UNKNOWN,
361bf215546Sopenharmony_ci                       "DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD failed: %m");
362bf215546Sopenharmony_ci   }
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_ci   return VK_SUCCESS;
365bf215546Sopenharmony_ci}
366bf215546Sopenharmony_ci
367bf215546Sopenharmony_cistatic VkResult
368bf215546Sopenharmony_civk_drm_syncobj_move(struct vk_device *device,
369bf215546Sopenharmony_ci                    struct vk_sync *dst,
370bf215546Sopenharmony_ci                    struct vk_sync *src)
371bf215546Sopenharmony_ci{
372bf215546Sopenharmony_ci   struct vk_drm_syncobj *dst_sobj = to_drm_syncobj(dst);
373bf215546Sopenharmony_ci   struct vk_drm_syncobj *src_sobj = to_drm_syncobj(src);
374bf215546Sopenharmony_ci   VkResult result;
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci   if (!(dst->flags & VK_SYNC_IS_SHARED) &&
377bf215546Sopenharmony_ci       !(src->flags & VK_SYNC_IS_SHARED)) {
378bf215546Sopenharmony_ci      result = vk_drm_syncobj_reset(device, dst);
379bf215546Sopenharmony_ci      if (unlikely(result != VK_SUCCESS))
380bf215546Sopenharmony_ci         return result;
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci      uint32_t tmp = dst_sobj->syncobj;
383bf215546Sopenharmony_ci      dst_sobj->syncobj = src_sobj->syncobj;
384bf215546Sopenharmony_ci      src_sobj->syncobj = tmp;
385bf215546Sopenharmony_ci
386bf215546Sopenharmony_ci      return VK_SUCCESS;
387bf215546Sopenharmony_ci   } else {
388bf215546Sopenharmony_ci      int fd;
389bf215546Sopenharmony_ci      result = vk_drm_syncobj_export_sync_file(device, src, &fd);
390bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
391bf215546Sopenharmony_ci         return result;
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci      result = vk_drm_syncobj_import_sync_file(device, dst, fd);
394bf215546Sopenharmony_ci      if (fd >= 0)
395bf215546Sopenharmony_ci         close(fd);
396bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
397bf215546Sopenharmony_ci         return result;
398bf215546Sopenharmony_ci
399bf215546Sopenharmony_ci      return vk_drm_syncobj_reset(device, src);
400bf215546Sopenharmony_ci   }
401bf215546Sopenharmony_ci}
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_cistruct vk_sync_type
404bf215546Sopenharmony_civk_drm_syncobj_get_type(int drm_fd)
405bf215546Sopenharmony_ci{
406bf215546Sopenharmony_ci   uint32_t syncobj = 0;
407bf215546Sopenharmony_ci   int err = drmSyncobjCreate(drm_fd, DRM_SYNCOBJ_CREATE_SIGNALED, &syncobj);
408bf215546Sopenharmony_ci   if (err < 0)
409bf215546Sopenharmony_ci      return (struct vk_sync_type) { .features = 0 };
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci   struct vk_sync_type type = {
412bf215546Sopenharmony_ci      .size = sizeof(struct vk_drm_syncobj),
413bf215546Sopenharmony_ci      .features = VK_SYNC_FEATURE_BINARY |
414bf215546Sopenharmony_ci                  VK_SYNC_FEATURE_GPU_WAIT |
415bf215546Sopenharmony_ci                  VK_SYNC_FEATURE_CPU_RESET |
416bf215546Sopenharmony_ci                  VK_SYNC_FEATURE_CPU_SIGNAL |
417bf215546Sopenharmony_ci                  VK_SYNC_FEATURE_WAIT_PENDING,
418bf215546Sopenharmony_ci      .init = vk_drm_syncobj_init,
419bf215546Sopenharmony_ci      .finish = vk_drm_syncobj_finish,
420bf215546Sopenharmony_ci      .signal = vk_drm_syncobj_signal,
421bf215546Sopenharmony_ci      .reset = vk_drm_syncobj_reset,
422bf215546Sopenharmony_ci      .move = vk_drm_syncobj_move,
423bf215546Sopenharmony_ci      .import_opaque_fd = vk_drm_syncobj_import_opaque_fd,
424bf215546Sopenharmony_ci      .export_opaque_fd = vk_drm_syncobj_export_opaque_fd,
425bf215546Sopenharmony_ci      .import_sync_file = vk_drm_syncobj_import_sync_file,
426bf215546Sopenharmony_ci      .export_sync_file = vk_drm_syncobj_export_sync_file,
427bf215546Sopenharmony_ci   };
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci   err = drmSyncobjWait(drm_fd, &syncobj, 1, 0,
430bf215546Sopenharmony_ci                        DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL,
431bf215546Sopenharmony_ci                        NULL /* first_signaled */);
432bf215546Sopenharmony_ci   if (err == 0) {
433bf215546Sopenharmony_ci      type.wait_many = vk_drm_syncobj_wait_many;
434bf215546Sopenharmony_ci      type.features |= VK_SYNC_FEATURE_CPU_WAIT |
435bf215546Sopenharmony_ci                       VK_SYNC_FEATURE_WAIT_ANY;
436bf215546Sopenharmony_ci   }
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   uint64_t cap;
439bf215546Sopenharmony_ci   err = drmGetCap(drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap);
440bf215546Sopenharmony_ci   if (err == 0 && cap != 0) {
441bf215546Sopenharmony_ci      type.get_value = vk_drm_syncobj_get_value;
442bf215546Sopenharmony_ci      type.features |= VK_SYNC_FEATURE_TIMELINE;
443bf215546Sopenharmony_ci   }
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci   err = drmSyncobjDestroy(drm_fd, syncobj);
446bf215546Sopenharmony_ci   assert(err == 0);
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_ci   return type;
449bf215546Sopenharmony_ci}
450