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