• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2018 Google, Inc.
3  * Copyright © 2015 Intel Corporation
4  * SPDX-License-Identifier: MIT
5  */
6 
7 #include "tu_drm.h"
8 
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <sys/ioctl.h>
12 #include <sys/mman.h>
13 #include <xf86drm.h>
14 
15 #ifdef MAJOR_IN_MKDEV
16 #include <sys/mkdev.h>
17 #endif
18 #ifdef MAJOR_IN_SYSMACROS
19 #include <sys/sysmacros.h>
20 #endif
21 
22 #include "vk_util.h"
23 
24 #include "drm-uapi/msm_drm.h"
25 #include "util/debug.h"
26 #include "util/timespec.h"
27 #include "util/os_time.h"
28 
29 #include "tu_cmd_buffer.h"
30 #include "tu_cs.h"
31 #include "tu_device.h"
32 #include "tu_dynamic_rendering.h"
33 
34 struct tu_queue_submit
35 {
36    struct vk_queue_submit *vk_submit;
37    struct tu_u_trace_submission_data *u_trace_submission_data;
38 
39    struct tu_cmd_buffer **cmd_buffers;
40    struct drm_msm_gem_submit_cmd *cmds;
41    struct drm_msm_gem_submit_syncobj *in_syncobjs;
42    struct drm_msm_gem_submit_syncobj *out_syncobjs;
43 
44    uint32_t nr_cmd_buffers;
45    uint32_t nr_in_syncobjs;
46    uint32_t nr_out_syncobjs;
47    uint32_t entry_count;
48    uint32_t perf_pass_index;
49 
50    bool     autotune_fence;
51 };
52 
53 struct tu_u_trace_syncobj
54 {
55    uint32_t msm_queue_id;
56    uint32_t fence;
57 };
58 
59 static int
tu_drm_get_param(const struct tu_physical_device * dev,uint32_t param,uint64_t * value)60 tu_drm_get_param(const struct tu_physical_device *dev,
61                  uint32_t param,
62                  uint64_t *value)
63 {
64    /* Technically this requires a pipe, but the kernel only supports one pipe
65     * anyway at the time of writing and most of these are clearly pipe
66     * independent. */
67    struct drm_msm_param req = {
68       .pipe = MSM_PIPE_3D0,
69       .param = param,
70    };
71 
72    int ret = drmCommandWriteRead(dev->local_fd, DRM_MSM_GET_PARAM, &req,
73                                  sizeof(req));
74    if (ret)
75       return ret;
76 
77    *value = req.value;
78 
79    return 0;
80 }
81 
82 static int
tu_drm_get_gpu_id(const struct tu_physical_device * dev,uint32_t * id)83 tu_drm_get_gpu_id(const struct tu_physical_device *dev, uint32_t *id)
84 {
85    uint64_t value;
86    int ret = tu_drm_get_param(dev, MSM_PARAM_GPU_ID, &value);
87    if (ret)
88       return ret;
89 
90    *id = value;
91    return 0;
92 }
93 
94 static int
tu_drm_get_gmem_size(const struct tu_physical_device * dev,uint32_t * size)95 tu_drm_get_gmem_size(const struct tu_physical_device *dev, uint32_t *size)
96 {
97    uint64_t value;
98    int ret = tu_drm_get_param(dev, MSM_PARAM_GMEM_SIZE, &value);
99    if (ret)
100       return ret;
101 
102    *size = value;
103    return 0;
104 }
105 
106 static int
tu_drm_get_gmem_base(const struct tu_physical_device * dev,uint64_t * base)107 tu_drm_get_gmem_base(const struct tu_physical_device *dev, uint64_t *base)
108 {
109    return tu_drm_get_param(dev, MSM_PARAM_GMEM_BASE, base);
110 }
111 
112 int
tu_device_get_gpu_timestamp(struct tu_device * dev,uint64_t * ts)113 tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts)
114 {
115    return tu_drm_get_param(dev->physical_device, MSM_PARAM_TIMESTAMP, ts);
116 }
117 
118 int
tu_device_get_suspend_count(struct tu_device * dev,uint64_t * suspend_count)119 tu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count)
120 {
121    int ret = tu_drm_get_param(dev->physical_device, MSM_PARAM_SUSPENDS, suspend_count);
122    return ret;
123 }
124 
125 VkResult
tu_device_check_status(struct vk_device * vk_device)126 tu_device_check_status(struct vk_device *vk_device)
127 {
128    struct tu_device *device = container_of(vk_device, struct tu_device, vk);
129    struct tu_physical_device *physical_device = device->physical_device;
130 
131    uint64_t last_fault_count = physical_device->fault_count;
132    int ret = tu_drm_get_param(physical_device, MSM_PARAM_FAULTS, &physical_device->fault_count);
133    if (ret != 0)
134       return vk_device_set_lost(&device->vk, "error getting GPU fault count: %d", ret);
135 
136    if (last_fault_count != physical_device->fault_count)
137       return vk_device_set_lost(&device->vk, "GPU faulted or hung");
138 
139    return VK_SUCCESS;
140 }
141 
142 int
tu_drm_submitqueue_new(const struct tu_device * dev,int priority,uint32_t * queue_id)143 tu_drm_submitqueue_new(const struct tu_device *dev,
144                        int priority,
145                        uint32_t *queue_id)
146 {
147    uint64_t nr_rings = 1;
148    tu_drm_get_param(dev->physical_device, MSM_PARAM_NR_RINGS, &nr_rings);
149 
150    struct drm_msm_submitqueue req = {
151       .flags = 0,
152       .prio = MIN2(priority, MAX2(nr_rings, 1) - 1),
153    };
154 
155    int ret = drmCommandWriteRead(dev->fd,
156                                  DRM_MSM_SUBMITQUEUE_NEW, &req, sizeof(req));
157    if (ret)
158       return ret;
159 
160    *queue_id = req.id;
161    return 0;
162 }
163 
164 void
tu_drm_submitqueue_close(const struct tu_device * dev,uint32_t queue_id)165 tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)
166 {
167    drmCommandWrite(dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE,
168                    &queue_id, sizeof(uint32_t));
169 }
170 
171 static void
tu_gem_close(const struct tu_device * dev,uint32_t gem_handle)172 tu_gem_close(const struct tu_device *dev, uint32_t gem_handle)
173 {
174    struct drm_gem_close req = {
175       .handle = gem_handle,
176    };
177 
178    drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
179 }
180 
181 /** Helper for DRM_MSM_GEM_INFO, returns 0 on error. */
182 static uint64_t
tu_gem_info(const struct tu_device * dev,uint32_t gem_handle,uint32_t info)183 tu_gem_info(const struct tu_device *dev, uint32_t gem_handle, uint32_t info)
184 {
185    struct drm_msm_gem_info req = {
186       .handle = gem_handle,
187       .info = info,
188    };
189 
190    int ret = drmCommandWriteRead(dev->fd,
191                                  DRM_MSM_GEM_INFO, &req, sizeof(req));
192    if (ret < 0)
193       return 0;
194 
195    return req.value;
196 }
197 
198 static VkResult
tu_bo_init(struct tu_device * dev,struct tu_bo * bo,uint32_t gem_handle,uint64_t size,bool dump)199 tu_bo_init(struct tu_device *dev,
200            struct tu_bo *bo,
201            uint32_t gem_handle,
202            uint64_t size,
203            bool dump)
204 {
205    uint64_t iova = tu_gem_info(dev, gem_handle, MSM_INFO_GET_IOVA);
206    if (!iova) {
207       tu_gem_close(dev, gem_handle);
208       return VK_ERROR_OUT_OF_DEVICE_MEMORY;
209    }
210 
211    mtx_lock(&dev->bo_mutex);
212    uint32_t idx = dev->bo_count++;
213 
214    /* grow the bo list if needed */
215    if (idx >= dev->bo_list_size) {
216       uint32_t new_len = idx + 64;
217       struct drm_msm_gem_submit_bo *new_ptr =
218          vk_realloc(&dev->vk.alloc, dev->bo_list, new_len * sizeof(*dev->bo_list),
219                     8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
220       if (!new_ptr)
221          goto fail_bo_list;
222 
223       dev->bo_list = new_ptr;
224       dev->bo_list_size = new_len;
225    }
226 
227    dev->bo_list[idx] = (struct drm_msm_gem_submit_bo) {
228       .flags = MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE |
229                COND(dump, MSM_SUBMIT_BO_DUMP),
230       .handle = gem_handle,
231       .presumed = iova,
232    };
233 
234    *bo = (struct tu_bo) {
235       .gem_handle = gem_handle,
236       .size = size,
237       .iova = iova,
238       .refcnt = 1,
239       .bo_list_idx = idx,
240    };
241 
242    mtx_unlock(&dev->bo_mutex);
243 
244    return VK_SUCCESS;
245 
246 fail_bo_list:
247    tu_gem_close(dev, gem_handle);
248    return VK_ERROR_OUT_OF_HOST_MEMORY;
249 }
250 
251 VkResult
tu_bo_init_new(struct tu_device * dev,struct tu_bo ** out_bo,uint64_t size,enum tu_bo_alloc_flags flags)252 tu_bo_init_new(struct tu_device *dev, struct tu_bo **out_bo, uint64_t size,
253                enum tu_bo_alloc_flags flags)
254 {
255    /* TODO: Choose better flags. As of 2018-11-12, freedreno/drm/msm_bo.c
256     * always sets `flags = MSM_BO_WC`, and we copy that behavior here.
257     */
258    struct drm_msm_gem_new req = {
259       .size = size,
260       .flags = MSM_BO_WC
261    };
262 
263    if (flags & TU_BO_ALLOC_GPU_READ_ONLY)
264       req.flags |= MSM_BO_GPU_READONLY;
265 
266    int ret = drmCommandWriteRead(dev->fd,
267                                  DRM_MSM_GEM_NEW, &req, sizeof(req));
268    if (ret)
269       return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
270 
271    struct tu_bo* bo = tu_device_lookup_bo(dev, req.handle);
272    assert(bo && bo->gem_handle == 0);
273 
274    VkResult result =
275       tu_bo_init(dev, bo, req.handle, size, flags & TU_BO_ALLOC_ALLOW_DUMP);
276 
277    if (result != VK_SUCCESS)
278       memset(bo, 0, sizeof(*bo));
279    else
280       *out_bo = bo;
281 
282    return result;
283 }
284 
285 VkResult
tu_bo_init_dmabuf(struct tu_device * dev,struct tu_bo ** out_bo,uint64_t size,int prime_fd)286 tu_bo_init_dmabuf(struct tu_device *dev,
287                   struct tu_bo **out_bo,
288                   uint64_t size,
289                   int prime_fd)
290 {
291    /* lseek() to get the real size */
292    off_t real_size = lseek(prime_fd, 0, SEEK_END);
293    lseek(prime_fd, 0, SEEK_SET);
294    if (real_size < 0 || (uint64_t) real_size < size)
295       return vk_error(dev, VK_ERROR_INVALID_EXTERNAL_HANDLE);
296 
297    /* Importing the same dmabuf several times would yield the same
298     * gem_handle. Thus there could be a race when destroying
299     * BO and importing the same dmabuf from different threads.
300     * We must not permit the creation of dmabuf BO and its release
301     * to happen in parallel.
302     */
303    u_rwlock_wrlock(&dev->dma_bo_lock);
304 
305    uint32_t gem_handle;
306    int ret = drmPrimeFDToHandle(dev->fd, prime_fd,
307                                 &gem_handle);
308    if (ret) {
309       u_rwlock_wrunlock(&dev->dma_bo_lock);
310       return vk_error(dev, VK_ERROR_INVALID_EXTERNAL_HANDLE);
311    }
312 
313    struct tu_bo* bo = tu_device_lookup_bo(dev, gem_handle);
314 
315    if (bo->refcnt != 0) {
316       p_atomic_inc(&bo->refcnt);
317       u_rwlock_wrunlock(&dev->dma_bo_lock);
318 
319       *out_bo = bo;
320       return VK_SUCCESS;
321    }
322 
323    VkResult result = tu_bo_init(dev, bo, gem_handle, size, false);
324 
325    if (result != VK_SUCCESS)
326       memset(bo, 0, sizeof(*bo));
327    else
328       *out_bo = bo;
329 
330    u_rwlock_wrunlock(&dev->dma_bo_lock);
331 
332    return result;
333 }
334 
335 int
tu_bo_export_dmabuf(struct tu_device * dev,struct tu_bo * bo)336 tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)
337 {
338    int prime_fd;
339    int ret = drmPrimeHandleToFD(dev->fd, bo->gem_handle,
340                                 DRM_CLOEXEC | DRM_RDWR, &prime_fd);
341 
342    return ret == 0 ? prime_fd : -1;
343 }
344 
345 VkResult
tu_bo_map(struct tu_device * dev,struct tu_bo * bo)346 tu_bo_map(struct tu_device *dev, struct tu_bo *bo)
347 {
348    if (bo->map)
349       return VK_SUCCESS;
350 
351    uint64_t offset = tu_gem_info(dev, bo->gem_handle, MSM_INFO_GET_OFFSET);
352    if (!offset)
353       return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
354 
355    /* TODO: Should we use the wrapper os_mmap() like Freedreno does? */
356    void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
357                     dev->fd, offset);
358    if (map == MAP_FAILED)
359       return vk_error(dev, VK_ERROR_MEMORY_MAP_FAILED);
360 
361    bo->map = map;
362    return VK_SUCCESS;
363 }
364 
365 void
tu_bo_finish(struct tu_device * dev,struct tu_bo * bo)366 tu_bo_finish(struct tu_device *dev, struct tu_bo *bo)
367 {
368    assert(bo->gem_handle);
369 
370    u_rwlock_rdlock(&dev->dma_bo_lock);
371 
372    if (!p_atomic_dec_zero(&bo->refcnt)) {
373       u_rwlock_rdunlock(&dev->dma_bo_lock);
374       return;
375    }
376 
377    if (bo->map)
378       munmap(bo->map, bo->size);
379 
380    mtx_lock(&dev->bo_mutex);
381    dev->bo_count--;
382    dev->bo_list[bo->bo_list_idx] = dev->bo_list[dev->bo_count];
383 
384    struct tu_bo* exchanging_bo = tu_device_lookup_bo(dev, dev->bo_list[bo->bo_list_idx].handle);
385    exchanging_bo->bo_list_idx = bo->bo_list_idx;
386 
387    if (bo->implicit_sync)
388       dev->implicit_sync_bo_count--;
389 
390    mtx_unlock(&dev->bo_mutex);
391 
392    /* Our BO structs are stored in a sparse array in the physical device,
393     * so we don't want to free the BO pointer, instead we want to reset it
394     * to 0, to signal that array entry as being free.
395     */
396    uint32_t gem_handle = bo->gem_handle;
397    memset(bo, 0, sizeof(*bo));
398 
399    tu_gem_close(dev, gem_handle);
400 
401    u_rwlock_rdunlock(&dev->dma_bo_lock);
402 }
403 
404 extern const struct vk_sync_type tu_timeline_sync_type;
405 
406 static inline bool
vk_sync_is_tu_timeline_sync(const struct vk_sync * sync)407 vk_sync_is_tu_timeline_sync(const struct vk_sync *sync)
408 {
409    return sync->type == &tu_timeline_sync_type;
410 }
411 
412 static struct tu_timeline_sync *
to_tu_timeline_sync(struct vk_sync * sync)413 to_tu_timeline_sync(struct vk_sync *sync)
414 {
415    assert(sync->type == &tu_timeline_sync_type);
416    return container_of(sync, struct tu_timeline_sync, base);
417 }
418 
419 static uint32_t
tu_syncobj_from_vk_sync(struct vk_sync * sync)420 tu_syncobj_from_vk_sync(struct vk_sync *sync)
421 {
422    uint32_t syncobj = -1;
423    if (vk_sync_is_tu_timeline_sync(sync)) {
424       syncobj = to_tu_timeline_sync(sync)->syncobj;
425    } else if (vk_sync_type_is_drm_syncobj(sync->type)) {
426       syncobj = vk_sync_as_drm_syncobj(sync)->syncobj;
427    }
428 
429    assert(syncobj != -1);
430 
431    return syncobj;
432 }
433 
434 static VkResult
tu_timeline_sync_init(struct vk_device * vk_device,struct vk_sync * vk_sync,uint64_t initial_value)435 tu_timeline_sync_init(struct vk_device *vk_device,
436                       struct vk_sync *vk_sync,
437                       uint64_t initial_value)
438 {
439    struct tu_device *device = container_of(vk_device, struct tu_device, vk);
440    struct tu_timeline_sync *sync = to_tu_timeline_sync(vk_sync);
441    uint32_t flags = 0;
442 
443    assert(device->fd >= 0);
444 
445    int err = drmSyncobjCreate(device->fd, flags, &sync->syncobj);
446 
447    if (err < 0) {
448         return vk_error(device, VK_ERROR_DEVICE_LOST);
449    }
450 
451    sync->state = initial_value ? TU_TIMELINE_SYNC_STATE_SIGNALED :
452                                     TU_TIMELINE_SYNC_STATE_RESET;
453 
454    return VK_SUCCESS;
455 }
456 
457 static void
tu_timeline_sync_finish(struct vk_device * vk_device,struct vk_sync * vk_sync)458 tu_timeline_sync_finish(struct vk_device *vk_device,
459                    struct vk_sync *vk_sync)
460 {
461    struct tu_device *dev = container_of(vk_device, struct tu_device, vk);
462    struct tu_timeline_sync *sync = to_tu_timeline_sync(vk_sync);
463 
464    assert(dev->fd >= 0);
465    ASSERTED int err = drmSyncobjDestroy(dev->fd, sync->syncobj);
466    assert(err == 0);
467 }
468 
469 static VkResult
tu_timeline_sync_reset(struct vk_device * vk_device,struct vk_sync * vk_sync)470 tu_timeline_sync_reset(struct vk_device *vk_device,
471                   struct vk_sync *vk_sync)
472 {
473    struct tu_device *dev = container_of(vk_device, struct tu_device, vk);
474    struct tu_timeline_sync *sync = to_tu_timeline_sync(vk_sync);
475 
476    int err = drmSyncobjReset(dev->fd, &sync->syncobj, 1);
477    if (err) {
478       return vk_errorf(dev, VK_ERROR_UNKNOWN,
479                        "DRM_IOCTL_SYNCOBJ_RESET failed: %m");
480    } else {
481        sync->state = TU_TIMELINE_SYNC_STATE_RESET;
482    }
483 
484    return VK_SUCCESS;
485 }
486 
487 static VkResult
drm_syncobj_wait(struct tu_device * device,uint32_t * handles,uint32_t count_handles,uint64_t timeout_nsec,bool wait_all)488 drm_syncobj_wait(struct tu_device *device,
489                  uint32_t *handles, uint32_t count_handles,
490                  uint64_t timeout_nsec, bool wait_all)
491 {
492    uint32_t syncobj_wait_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT;
493    if (wait_all) syncobj_wait_flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL;
494 
495    /* syncobj absolute timeouts are signed.  clamp OS_TIMEOUT_INFINITE down. */
496    timeout_nsec = MIN2(timeout_nsec, (uint64_t)INT64_MAX);
497 
498    int err = drmSyncobjWait(device->fd, handles,
499                             count_handles, timeout_nsec,
500                             syncobj_wait_flags,
501                             NULL /* first_signaled */);
502    if (err && errno == ETIME) {
503       return VK_TIMEOUT;
504    } else if (err) {
505       return vk_errorf(device, VK_ERROR_UNKNOWN,
506                        "DRM_IOCTL_SYNCOBJ_WAIT failed: %m");
507    }
508 
509    return VK_SUCCESS;
510 }
511 
512 /* Based on anv_bo_sync_wait */
513 static VkResult
tu_timeline_sync_wait(struct vk_device * vk_device,uint32_t wait_count,const struct vk_sync_wait * waits,enum vk_sync_wait_flags wait_flags,uint64_t abs_timeout_ns)514 tu_timeline_sync_wait(struct vk_device *vk_device,
515                  uint32_t wait_count,
516                  const struct vk_sync_wait *waits,
517                  enum vk_sync_wait_flags wait_flags,
518                  uint64_t abs_timeout_ns)
519 {
520    struct tu_device *dev = container_of(vk_device, struct tu_device, vk);
521    bool wait_all = !(wait_flags & VK_SYNC_WAIT_ANY);
522 
523    uint32_t handles[wait_count];
524    uint32_t submit_count;
525    VkResult ret = VK_SUCCESS;
526    uint32_t pending = wait_count;
527    struct tu_timeline_sync *submitted_syncs[wait_count];
528 
529    while (pending) {
530       pending = 0;
531       submit_count = 0;
532 
533       for (unsigned i = 0; i < wait_count; ++i) {
534          struct tu_timeline_sync *sync = to_tu_timeline_sync(waits[i].sync);
535 
536          if (sync->state == TU_TIMELINE_SYNC_STATE_RESET) {
537             assert(!(wait_flags & VK_SYNC_WAIT_PENDING));
538             pending++;
539          } else if (sync->state == TU_TIMELINE_SYNC_STATE_SIGNALED) {
540             if (wait_flags & VK_SYNC_WAIT_ANY)
541                return VK_SUCCESS;
542          } else if (sync->state == TU_TIMELINE_SYNC_STATE_SUBMITTED) {
543             if (!(wait_flags & VK_SYNC_WAIT_PENDING)) {
544                handles[submit_count] = sync->syncobj;
545                submitted_syncs[submit_count++] = sync;
546             }
547          }
548       }
549 
550       if (submit_count > 0) {
551          do {
552             ret = drm_syncobj_wait(dev, handles, submit_count, abs_timeout_ns, wait_all);
553          } while (ret == VK_TIMEOUT && os_time_get_nano() < abs_timeout_ns);
554 
555          if (ret == VK_SUCCESS) {
556             for (unsigned i = 0; i < submit_count; ++i) {
557                struct tu_timeline_sync *sync = submitted_syncs[i];
558                sync->state = TU_TIMELINE_SYNC_STATE_SIGNALED;
559             }
560          } else {
561             /* return error covering timeout */
562             return ret;
563          }
564       } else if (pending > 0) {
565          /* If we've hit this then someone decided to vkWaitForFences before
566           * they've actually submitted any of them to a queue.  This is a
567           * fairly pessimal case, so it's ok to lock here and use a standard
568           * pthreads condition variable.
569           */
570          pthread_mutex_lock(&dev->submit_mutex);
571 
572          /* It's possible that some of the fences have changed state since the
573           * last time we checked.  Now that we have the lock, check for
574           * pending fences again and don't wait if it's changed.
575           */
576          uint32_t now_pending = 0;
577          for (uint32_t i = 0; i < wait_count; i++) {
578             struct tu_timeline_sync *sync = to_tu_timeline_sync(waits[i].sync);
579             if (sync->state == TU_TIMELINE_SYNC_STATE_RESET)
580                now_pending++;
581          }
582          assert(now_pending <= pending);
583 
584          if (now_pending == pending) {
585             struct timespec abstime = {
586                .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
587                .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
588             };
589 
590             ASSERTED int ret;
591             ret = pthread_cond_timedwait(&dev->timeline_cond,
592                                          &dev->submit_mutex, &abstime);
593             assert(ret != EINVAL);
594             if (os_time_get_nano() >= abs_timeout_ns) {
595                pthread_mutex_unlock(&dev->submit_mutex);
596                return VK_TIMEOUT;
597             }
598          }
599 
600          pthread_mutex_unlock(&dev->submit_mutex);
601       }
602    }
603 
604    return ret;
605 }
606 
607 const struct vk_sync_type tu_timeline_sync_type = {
608    .size = sizeof(struct tu_timeline_sync),
609    .features = VK_SYNC_FEATURE_BINARY |
610                VK_SYNC_FEATURE_GPU_WAIT |
611                VK_SYNC_FEATURE_GPU_MULTI_WAIT |
612                VK_SYNC_FEATURE_CPU_WAIT |
613                VK_SYNC_FEATURE_CPU_RESET |
614                VK_SYNC_FEATURE_WAIT_ANY |
615                VK_SYNC_FEATURE_WAIT_PENDING,
616    .init = tu_timeline_sync_init,
617    .finish = tu_timeline_sync_finish,
618    .reset = tu_timeline_sync_reset,
619    .wait_many = tu_timeline_sync_wait,
620 };
621 
622 static VkResult
tu_drm_device_init(struct tu_physical_device * device,struct tu_instance * instance,drmDevicePtr drm_device)623 tu_drm_device_init(struct tu_physical_device *device,
624                    struct tu_instance *instance,
625                    drmDevicePtr drm_device)
626 {
627    const char *primary_path = drm_device->nodes[DRM_NODE_PRIMARY];
628    const char *path = drm_device->nodes[DRM_NODE_RENDER];
629    VkResult result = VK_SUCCESS;
630    drmVersionPtr version;
631    int fd;
632    int master_fd = -1;
633 
634    fd = open(path, O_RDWR | O_CLOEXEC);
635    if (fd < 0) {
636       return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
637                                "failed to open device %s", path);
638    }
639 
640    /* Version 1.6 added SYNCOBJ support. */
641    const int min_version_major = 1;
642    const int min_version_minor = 6;
643 
644    version = drmGetVersion(fd);
645    if (!version) {
646       close(fd);
647       return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
648                                "failed to query kernel driver version for device %s",
649                                path);
650    }
651 
652    if (strcmp(version->name, "msm")) {
653       drmFreeVersion(version);
654       close(fd);
655       return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
656                                "device %s does not use the msm kernel driver",
657                                path);
658    }
659 
660    if (version->version_major != min_version_major ||
661        version->version_minor < min_version_minor) {
662       result = vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
663                                  "kernel driver for device %s has version %d.%d, "
664                                  "but Vulkan requires version >= %d.%d",
665                                  path,
666                                  version->version_major, version->version_minor,
667                                  min_version_major, min_version_minor);
668       drmFreeVersion(version);
669       close(fd);
670       return result;
671    }
672 
673    device->msm_major_version = version->version_major;
674    device->msm_minor_version = version->version_minor;
675 
676    drmFreeVersion(version);
677 
678    if (instance->debug_flags & TU_DEBUG_STARTUP)
679       mesa_logi("Found compatible device '%s'.", path);
680 
681    device->instance = instance;
682 
683    if (instance->vk.enabled_extensions.KHR_display) {
684       master_fd = open(primary_path, O_RDWR | O_CLOEXEC);
685       if (master_fd >= 0) {
686          /* TODO: free master_fd is accel is not working? */
687       }
688    }
689 
690    device->master_fd = master_fd;
691    device->local_fd = fd;
692 
693    if (tu_drm_get_gpu_id(device, &device->dev_id.gpu_id)) {
694       result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
695                                  "could not get GPU ID");
696       goto fail;
697    }
698 
699    if (tu_drm_get_param(device, MSM_PARAM_CHIP_ID, &device->dev_id.chip_id)) {
700       result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
701                                  "could not get CHIP ID");
702       goto fail;
703    }
704 
705    if (tu_drm_get_gmem_size(device, &device->gmem_size)) {
706       result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
707                                 "could not get GMEM size");
708       goto fail;
709    }
710    device->gmem_size = env_var_as_unsigned("TU_GMEM", device->gmem_size);
711 
712    if (tu_drm_get_gmem_base(device, &device->gmem_base)) {
713       result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
714                                  "could not get GMEM size");
715       goto fail;
716    }
717 
718    struct stat st;
719 
720    if (stat(primary_path, &st) == 0) {
721       device->has_master = true;
722       device->master_major = major(st.st_rdev);
723       device->master_minor = minor(st.st_rdev);
724    } else {
725       device->has_master = false;
726       device->master_major = 0;
727       device->master_minor = 0;
728    }
729 
730    if (stat(path, &st) == 0) {
731       device->has_local = true;
732       device->local_major = major(st.st_rdev);
733       device->local_minor = minor(st.st_rdev);
734    } else {
735       result = vk_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
736                          "failed to stat DRM render node %s", path);
737       goto fail;
738    }
739 
740    int ret = tu_drm_get_param(device, MSM_PARAM_FAULTS, &device->fault_count);
741    if (ret != 0) {
742       result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
743                                  "Failed to get initial fault count: %d", ret);
744       goto fail;
745    }
746 
747    device->syncobj_type = vk_drm_syncobj_get_type(fd);
748    /* we don't support DRM_CAP_SYNCOBJ_TIMELINE, but drm-shim does */
749    if (!(device->syncobj_type.features & VK_SYNC_FEATURE_TIMELINE))
750       device->timeline_type = vk_sync_timeline_get_type(&tu_timeline_sync_type);
751 
752    device->sync_types[0] = &device->syncobj_type;
753    device->sync_types[1] = &device->timeline_type.sync;
754    device->sync_types[2] = NULL;
755 
756    device->heap.size = tu_get_system_heap_size();
757    device->heap.used = 0u;
758    device->heap.flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
759 
760    result = tu_physical_device_init(device, instance);
761 
762    if (result == VK_SUCCESS)
763        return result;
764 
765 fail:
766    close(fd);
767    if (master_fd != -1)
768       close(master_fd);
769    return result;
770 }
771 
772 VkResult
tu_enumerate_devices(struct tu_instance * instance)773 tu_enumerate_devices(struct tu_instance *instance)
774 {
775    /* TODO: Check for more devices ? */
776    drmDevicePtr devices[8];
777    VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
778    int max_devices;
779 
780    instance->physical_device_count = 0;
781 
782    max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
783 
784    if (instance->debug_flags & TU_DEBUG_STARTUP) {
785       if (max_devices < 0)
786          mesa_logi("drmGetDevices2 returned error: %s\n", strerror(max_devices));
787       else
788          mesa_logi("Found %d drm nodes", max_devices);
789    }
790 
791    if (max_devices < 1)
792       return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
793                                "No DRM devices found");
794 
795    for (unsigned i = 0; i < (unsigned) max_devices; i++) {
796       if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
797           devices[i]->bustype == DRM_BUS_PLATFORM) {
798 
799          result = tu_drm_device_init(
800             instance->physical_devices + instance->physical_device_count,
801             instance, devices[i]);
802          if (result == VK_SUCCESS)
803             ++instance->physical_device_count;
804          else if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
805             break;
806       }
807    }
808    drmFreeDevices(devices, max_devices);
809 
810    return result;
811 }
812 
813 static VkResult
tu_queue_submit_create_locked(struct tu_queue * queue,struct vk_queue_submit * vk_submit,const uint32_t nr_in_syncobjs,const uint32_t nr_out_syncobjs,uint32_t perf_pass_index,struct tu_queue_submit * new_submit)814 tu_queue_submit_create_locked(struct tu_queue *queue,
815                               struct vk_queue_submit *vk_submit,
816                               const uint32_t nr_in_syncobjs,
817                               const uint32_t nr_out_syncobjs,
818                               uint32_t perf_pass_index,
819                               struct tu_queue_submit *new_submit)
820 {
821    VkResult result;
822 
823    bool u_trace_enabled = u_trace_context_actively_tracing(&queue->device->trace_context);
824    bool has_trace_points = false;
825 
826    struct vk_command_buffer **vk_cmd_buffers = vk_submit->command_buffers;
827 
828    memset(new_submit, 0, sizeof(struct tu_queue_submit));
829 
830    new_submit->cmd_buffers = (void *)vk_cmd_buffers;
831    new_submit->nr_cmd_buffers = vk_submit->command_buffer_count;
832    tu_insert_dynamic_cmdbufs(queue->device, &new_submit->cmd_buffers,
833                              &new_submit->nr_cmd_buffers);
834 
835    uint32_t entry_count = 0;
836    for (uint32_t j = 0; j < new_submit->nr_cmd_buffers; ++j) {
837       struct tu_cmd_buffer *cmdbuf = new_submit->cmd_buffers[j];
838 
839       if (perf_pass_index != ~0)
840          entry_count++;
841 
842       entry_count += cmdbuf->cs.entry_count;
843 
844       if (u_trace_enabled && u_trace_has_points(&cmdbuf->trace)) {
845          if (!(cmdbuf->usage_flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT))
846             entry_count++;
847 
848          has_trace_points = true;
849       }
850    }
851 
852    new_submit->autotune_fence =
853       tu_autotune_submit_requires_fence(new_submit->cmd_buffers, new_submit->nr_cmd_buffers);
854    if (new_submit->autotune_fence)
855       entry_count++;
856 
857    new_submit->cmds = vk_zalloc(&queue->device->vk.alloc,
858          entry_count * sizeof(*new_submit->cmds), 8,
859          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
860 
861    if (new_submit->cmds == NULL) {
862       result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
863       goto fail_cmds;
864    }
865 
866    if (has_trace_points) {
867       result =
868          tu_u_trace_submission_data_create(
869             queue->device, new_submit->cmd_buffers,
870             new_submit->nr_cmd_buffers,
871             &new_submit->u_trace_submission_data);
872 
873       if (result != VK_SUCCESS) {
874          goto fail_u_trace_submission_data;
875       }
876    }
877 
878    /* Allocate without wait timeline semaphores */
879    new_submit->in_syncobjs = vk_zalloc(&queue->device->vk.alloc,
880          nr_in_syncobjs * sizeof(*new_submit->in_syncobjs), 8,
881          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
882 
883    if (new_submit->in_syncobjs == NULL) {
884       result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
885       goto fail_in_syncobjs;
886    }
887 
888    /* Allocate with signal timeline semaphores considered */
889    new_submit->out_syncobjs = vk_zalloc(&queue->device->vk.alloc,
890          nr_out_syncobjs * sizeof(*new_submit->out_syncobjs), 8,
891          VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
892 
893    if (new_submit->out_syncobjs == NULL) {
894       result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
895       goto fail_out_syncobjs;
896    }
897 
898    new_submit->entry_count = entry_count;
899    new_submit->nr_in_syncobjs = nr_in_syncobjs;
900    new_submit->nr_out_syncobjs = nr_out_syncobjs;
901    new_submit->perf_pass_index = perf_pass_index;
902    new_submit->vk_submit = vk_submit;
903 
904    return VK_SUCCESS;
905 
906 fail_out_syncobjs:
907    vk_free(&queue->device->vk.alloc, new_submit->in_syncobjs);
908 fail_in_syncobjs:
909    if (new_submit->u_trace_submission_data)
910       tu_u_trace_submission_data_finish(queue->device,
911                                         new_submit->u_trace_submission_data);
912 fail_u_trace_submission_data:
913    vk_free(&queue->device->vk.alloc, new_submit->cmds);
914 fail_cmds:
915    return result;
916 }
917 
918 static void
tu_queue_submit_finish(struct tu_queue * queue,struct tu_queue_submit * submit)919 tu_queue_submit_finish(struct tu_queue *queue, struct tu_queue_submit *submit)
920 {
921    vk_free(&queue->device->vk.alloc, submit->cmds);
922    vk_free(&queue->device->vk.alloc, submit->in_syncobjs);
923    vk_free(&queue->device->vk.alloc, submit->out_syncobjs);
924    if (submit->cmd_buffers != (void *) submit->vk_submit->command_buffers)
925       vk_free(&queue->device->vk.alloc, submit->cmd_buffers);
926 }
927 
928 static void
tu_fill_msm_gem_submit(struct tu_device * dev,struct drm_msm_gem_submit_cmd * cmd,struct tu_cs_entry * cs_entry)929 tu_fill_msm_gem_submit(struct tu_device *dev,
930                        struct drm_msm_gem_submit_cmd *cmd,
931                        struct tu_cs_entry *cs_entry)
932 {
933    cmd->type = MSM_SUBMIT_CMD_BUF;
934    cmd->submit_idx = cs_entry->bo->bo_list_idx;
935    cmd->submit_offset = cs_entry->offset;
936    cmd->size = cs_entry->size;
937    cmd->pad = 0;
938    cmd->nr_relocs = 0;
939    cmd->relocs = 0;
940 }
941 
942 static void
tu_queue_build_msm_gem_submit_cmds(struct tu_queue * queue,struct tu_queue_submit * submit,struct tu_cs * autotune_cs)943 tu_queue_build_msm_gem_submit_cmds(struct tu_queue *queue,
944                                    struct tu_queue_submit *submit,
945                                    struct tu_cs *autotune_cs)
946 {
947    struct tu_device *dev = queue->device;
948    struct drm_msm_gem_submit_cmd *cmds = submit->cmds;
949 
950    uint32_t entry_idx = 0;
951    for (uint32_t j = 0; j < submit->nr_cmd_buffers; ++j) {
952       struct tu_device *dev = queue->device;
953       struct tu_cmd_buffer *cmdbuf = submit->cmd_buffers[j];
954       struct tu_cs *cs = &cmdbuf->cs;
955 
956       if (submit->perf_pass_index != ~0) {
957          struct tu_cs_entry *perf_cs_entry =
958             &dev->perfcntrs_pass_cs_entries[submit->perf_pass_index];
959 
960          tu_fill_msm_gem_submit(dev, &cmds[entry_idx], perf_cs_entry);
961          entry_idx++;
962       }
963 
964       for (unsigned i = 0; i < cs->entry_count; ++i, ++entry_idx) {
965          tu_fill_msm_gem_submit(dev, &cmds[entry_idx], &cs->entries[i]);
966       }
967 
968       if (submit->u_trace_submission_data) {
969          struct tu_cs *ts_cs =
970             submit->u_trace_submission_data->cmd_trace_data[j].timestamp_copy_cs;
971          if (ts_cs) {
972             tu_fill_msm_gem_submit(dev, &cmds[entry_idx], &ts_cs->entries[0]);
973             entry_idx++;
974          }
975       }
976    }
977 
978    if (autotune_cs) {
979       assert(autotune_cs->entry_count == 1);
980       tu_fill_msm_gem_submit(dev, &cmds[entry_idx], &autotune_cs->entries[0]);
981       entry_idx++;
982    }
983 }
984 
985 static VkResult
tu_queue_submit_locked(struct tu_queue * queue,struct tu_queue_submit * submit)986 tu_queue_submit_locked(struct tu_queue *queue, struct tu_queue_submit *submit)
987 {
988    queue->device->submit_count++;
989 
990    struct tu_cs *autotune_cs = NULL;
991    if (submit->autotune_fence) {
992       autotune_cs = tu_autotune_on_submit(queue->device,
993                                           &queue->device->autotune,
994                                           submit->cmd_buffers,
995                                           submit->nr_cmd_buffers);
996    }
997 
998    uint32_t flags = MSM_PIPE_3D0;
999 
1000    if (submit->vk_submit->wait_count)
1001       flags |= MSM_SUBMIT_SYNCOBJ_IN;
1002 
1003    if (submit->vk_submit->signal_count)
1004       flags |= MSM_SUBMIT_SYNCOBJ_OUT;
1005 
1006    mtx_lock(&queue->device->bo_mutex);
1007 
1008    if (queue->device->implicit_sync_bo_count == 0)
1009       flags |= MSM_SUBMIT_NO_IMPLICIT;
1010 
1011    /* drm_msm_gem_submit_cmd requires index of bo which could change at any
1012     * time when bo_mutex is not locked. So we build submit cmds here the real
1013     * place to submit.
1014     */
1015    tu_queue_build_msm_gem_submit_cmds(queue, submit, autotune_cs);
1016 
1017    struct drm_msm_gem_submit req = {
1018       .flags = flags,
1019       .queueid = queue->msm_queue_id,
1020       .bos = (uint64_t)(uintptr_t) queue->device->bo_list,
1021       .nr_bos = submit->entry_count ? queue->device->bo_count : 0,
1022       .cmds = (uint64_t)(uintptr_t)submit->cmds,
1023       .nr_cmds = submit->entry_count,
1024       .in_syncobjs = (uint64_t)(uintptr_t)submit->in_syncobjs,
1025       .out_syncobjs = (uint64_t)(uintptr_t)submit->out_syncobjs,
1026       .nr_in_syncobjs = submit->nr_in_syncobjs,
1027       .nr_out_syncobjs = submit->nr_out_syncobjs,
1028       .syncobj_stride = sizeof(struct drm_msm_gem_submit_syncobj),
1029    };
1030 
1031    int ret = drmCommandWriteRead(queue->device->fd,
1032                                  DRM_MSM_GEM_SUBMIT,
1033                                  &req, sizeof(req));
1034 
1035    mtx_unlock(&queue->device->bo_mutex);
1036 
1037    if (ret)
1038       return vk_device_set_lost(&queue->device->vk, "submit failed: %m");
1039 
1040 #if HAVE_PERFETTO
1041    tu_perfetto_submit(queue->device, queue->device->submit_count);
1042 #endif
1043 
1044    if (submit->u_trace_submission_data) {
1045       struct tu_u_trace_submission_data *submission_data =
1046          submit->u_trace_submission_data;
1047       submission_data->submission_id = queue->device->submit_count;
1048       /* We have to allocate it here since it is different between drm/kgsl */
1049       submission_data->syncobj =
1050          vk_alloc(&queue->device->vk.alloc, sizeof(struct tu_u_trace_syncobj),
1051                8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1052       submission_data->syncobj->fence = req.fence;
1053       submission_data->syncobj->msm_queue_id = queue->msm_queue_id;
1054 
1055       submit->u_trace_submission_data = NULL;
1056 
1057       for (uint32_t i = 0; i < submission_data->cmd_buffer_count; i++) {
1058          bool free_data = i == submission_data->last_buffer_with_tracepoints;
1059          if (submission_data->cmd_trace_data[i].trace)
1060             u_trace_flush(submission_data->cmd_trace_data[i].trace,
1061                           submission_data, free_data);
1062 
1063          if (!submission_data->cmd_trace_data[i].timestamp_copy_cs) {
1064             /* u_trace is owned by cmd_buffer */
1065             submission_data->cmd_trace_data[i].trace = NULL;
1066          }
1067       }
1068    }
1069 
1070    for (uint32_t i = 0; i < submit->vk_submit->wait_count; i++) {
1071       if (!vk_sync_is_tu_timeline_sync(submit->vk_submit->waits[i].sync))
1072          continue;
1073 
1074       struct tu_timeline_sync *sync =
1075          container_of(submit->vk_submit->waits[i].sync, struct tu_timeline_sync, base);
1076 
1077       assert(sync->state != TU_TIMELINE_SYNC_STATE_RESET);
1078 
1079       /* Set SIGNALED to the state of the wait timeline sync since this means the syncobj
1080        * is done and ready again so this can be garbage-collectioned later.
1081        */
1082       sync->state = TU_TIMELINE_SYNC_STATE_SIGNALED;
1083    }
1084 
1085    for (uint32_t i = 0; i < submit->vk_submit->signal_count; i++) {
1086       if (!vk_sync_is_tu_timeline_sync(submit->vk_submit->signals[i].sync))
1087          continue;
1088 
1089       struct tu_timeline_sync *sync =
1090          container_of(submit->vk_submit->signals[i].sync, struct tu_timeline_sync, base);
1091 
1092       assert(sync->state == TU_TIMELINE_SYNC_STATE_RESET);
1093       /* Set SUBMITTED to the state of the signal timeline sync so we could wait for
1094        * this timeline sync until completed if necessary.
1095        */
1096       sync->state = TU_TIMELINE_SYNC_STATE_SUBMITTED;
1097    }
1098 
1099    pthread_cond_broadcast(&queue->device->timeline_cond);
1100 
1101    return VK_SUCCESS;
1102 }
1103 
1104 static inline void
get_abs_timeout(struct drm_msm_timespec * tv,uint64_t ns)1105 get_abs_timeout(struct drm_msm_timespec *tv, uint64_t ns)
1106 {
1107    struct timespec t;
1108    clock_gettime(CLOCK_MONOTONIC, &t);
1109    tv->tv_sec = t.tv_sec + ns / 1000000000;
1110    tv->tv_nsec = t.tv_nsec + ns % 1000000000;
1111 }
1112 
1113 VkResult
tu_device_wait_u_trace(struct tu_device * dev,struct tu_u_trace_syncobj * syncobj)1114 tu_device_wait_u_trace(struct tu_device *dev, struct tu_u_trace_syncobj *syncobj)
1115 {
1116    struct drm_msm_wait_fence req = {
1117       .fence = syncobj->fence,
1118       .queueid = syncobj->msm_queue_id,
1119    };
1120    int ret;
1121 
1122    get_abs_timeout(&req.timeout, 1000000000);
1123 
1124    ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req));
1125    if (ret && (ret != -ETIMEDOUT)) {
1126       fprintf(stderr, "wait-fence failed! %d (%s)", ret, strerror(errno));
1127       return VK_TIMEOUT;
1128    }
1129 
1130    return VK_SUCCESS;
1131 }
1132 
1133 VkResult
tu_queue_submit(struct vk_queue * vk_queue,struct vk_queue_submit * submit)1134 tu_queue_submit(struct vk_queue *vk_queue, struct vk_queue_submit *submit)
1135 {
1136    struct tu_queue *queue = container_of(vk_queue, struct tu_queue, vk);
1137    uint32_t perf_pass_index = queue->device->perfcntrs_pass_cs ?
1138                               submit->perf_pass_index : ~0;
1139    struct tu_queue_submit submit_req;
1140 
1141    if (unlikely(queue->device->physical_device->instance->debug_flags &
1142                  TU_DEBUG_LOG_SKIP_GMEM_OPS)) {
1143       tu_dbg_log_gmem_load_store_skips(queue->device);
1144    }
1145 
1146    pthread_mutex_lock(&queue->device->submit_mutex);
1147 
1148    VkResult ret = tu_queue_submit_create_locked(queue, submit,
1149          submit->wait_count, submit->signal_count,
1150          perf_pass_index, &submit_req);
1151 
1152    if (ret != VK_SUCCESS) {
1153       pthread_mutex_unlock(&queue->device->submit_mutex);
1154       return ret;
1155    }
1156 
1157    /* note: assuming there won't be any very large semaphore counts */
1158    struct drm_msm_gem_submit_syncobj *in_syncobjs = submit_req.in_syncobjs;
1159    struct drm_msm_gem_submit_syncobj *out_syncobjs = submit_req.out_syncobjs;
1160 
1161    uint32_t nr_in_syncobjs = 0, nr_out_syncobjs = 0;
1162 
1163    for (uint32_t i = 0; i < submit->wait_count; i++) {
1164       struct vk_sync *sync = submit->waits[i].sync;
1165 
1166       in_syncobjs[nr_in_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
1167          .handle = tu_syncobj_from_vk_sync(sync),
1168          .flags = 0,
1169       };
1170    }
1171 
1172    for (uint32_t i = 0; i < submit->signal_count; i++) {
1173       struct vk_sync *sync = submit->signals[i].sync;
1174 
1175       out_syncobjs[nr_out_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
1176          .handle = tu_syncobj_from_vk_sync(sync),
1177          .flags = 0,
1178       };
1179    }
1180 
1181    ret = tu_queue_submit_locked(queue, &submit_req);
1182 
1183    pthread_mutex_unlock(&queue->device->submit_mutex);
1184    tu_queue_submit_finish(queue, &submit_req);
1185 
1186    if (ret != VK_SUCCESS)
1187        return ret;
1188 
1189    u_trace_context_process(&queue->device->trace_context, true);
1190 
1191    return VK_SUCCESS;
1192 }
1193 
1194 int
tu_syncobj_to_fd(struct tu_device * device,struct vk_sync * sync)1195 tu_syncobj_to_fd(struct tu_device *device, struct vk_sync *sync)
1196 {
1197    VkResult ret;
1198    int fd;
1199    ret = vk_sync_export_opaque_fd(&device->vk, sync, &fd);
1200    return ret ? -1 : fd;
1201 }
1202