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