intel/fs: Fix MOV_INDIRECT and BROADCAST of Q types on Gen11+
[mesa.git] / src / intel / vulkan / anv_queue.c
1 /*
2 * Copyright © 2015 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 /**
25 * This file implements VkQueue, VkFence, and VkSemaphore
26 */
27
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32 #include "util/os_file.h"
33
34 #include "anv_private.h"
35 #include "vk_util.h"
36
37 #include "genxml/gen7_pack.h"
38
39 uint64_t anv_gettime_ns(void)
40 {
41 struct timespec current;
42 clock_gettime(CLOCK_MONOTONIC, &current);
43 return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
44 }
45
46 uint64_t anv_get_absolute_timeout(uint64_t timeout)
47 {
48 if (timeout == 0)
49 return 0;
50 uint64_t current_time = anv_gettime_ns();
51 uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;
52
53 timeout = MIN2(max_timeout, timeout);
54
55 return (current_time + timeout);
56 }
57
58 static int64_t anv_get_relative_timeout(uint64_t abs_timeout)
59 {
60 uint64_t now = anv_gettime_ns();
61
62 /* We don't want negative timeouts.
63 *
64 * DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is
65 * supposed to block indefinitely timeouts < 0. Unfortunately,
66 * this was broken for a couple of kernel releases. Since there's
67 * no way to know whether or not the kernel we're using is one of
68 * the broken ones, the best we can do is to clamp the timeout to
69 * INT64_MAX. This limits the maximum timeout from 584 years to
70 * 292 years - likely not a big deal.
71 */
72 if (abs_timeout < now)
73 return 0;
74
75 uint64_t rel_timeout = abs_timeout - now;
76 if (rel_timeout > (uint64_t) INT64_MAX)
77 rel_timeout = INT64_MAX;
78
79 return rel_timeout;
80 }
81
82 static struct anv_semaphore *anv_semaphore_ref(struct anv_semaphore *semaphore);
83 static void anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore);
84 static void anv_semaphore_impl_cleanup(struct anv_device *device,
85 struct anv_semaphore_impl *impl);
86
87 static void
88 anv_queue_submit_free(struct anv_device *device,
89 struct anv_queue_submit *submit)
90 {
91 const VkAllocationCallbacks *alloc = submit->alloc;
92
93 for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++)
94 anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]);
95 for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++)
96 anv_semaphore_unref(device, submit->sync_fd_semaphores[i]);
97 /* Execbuf does not consume the in_fence. It's our job to close it. */
98 if (submit->in_fence != -1) {
99 assert(!device->has_thread_submit);
100 close(submit->in_fence);
101 }
102 if (submit->out_fence != -1) {
103 assert(!device->has_thread_submit);
104 close(submit->out_fence);
105 }
106 vk_free(alloc, submit->fences);
107 vk_free(alloc, submit->fence_values);
108 vk_free(alloc, submit->temporary_semaphores);
109 vk_free(alloc, submit->wait_timelines);
110 vk_free(alloc, submit->wait_timeline_values);
111 vk_free(alloc, submit->signal_timelines);
112 vk_free(alloc, submit->signal_timeline_values);
113 vk_free(alloc, submit->fence_bos);
114 vk_free(alloc, submit);
115 }
116
117 static bool
118 anv_queue_submit_ready_locked(struct anv_queue_submit *submit)
119 {
120 for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
121 if (submit->wait_timeline_values[i] > submit->wait_timelines[i]->highest_pending)
122 return false;
123 }
124
125 return true;
126 }
127
128 static VkResult
129 anv_timeline_init(struct anv_device *device,
130 struct anv_timeline *timeline,
131 uint64_t initial_value)
132 {
133 timeline->highest_past =
134 timeline->highest_pending = initial_value;
135 list_inithead(&timeline->points);
136 list_inithead(&timeline->free_points);
137
138 return VK_SUCCESS;
139 }
140
141 static void
142 anv_timeline_finish(struct anv_device *device,
143 struct anv_timeline *timeline)
144 {
145 list_for_each_entry_safe(struct anv_timeline_point, point,
146 &timeline->free_points, link) {
147 list_del(&point->link);
148 anv_device_release_bo(device, point->bo);
149 vk_free(&device->vk.alloc, point);
150 }
151 list_for_each_entry_safe(struct anv_timeline_point, point,
152 &timeline->points, link) {
153 list_del(&point->link);
154 anv_device_release_bo(device, point->bo);
155 vk_free(&device->vk.alloc, point);
156 }
157 }
158
159 static VkResult
160 anv_timeline_add_point_locked(struct anv_device *device,
161 struct anv_timeline *timeline,
162 uint64_t value,
163 struct anv_timeline_point **point)
164 {
165 VkResult result = VK_SUCCESS;
166
167 if (list_is_empty(&timeline->free_points)) {
168 *point =
169 vk_zalloc(&device->vk.alloc, sizeof(**point),
170 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
171 if (!(*point))
172 result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
173 if (result == VK_SUCCESS) {
174 result = anv_device_alloc_bo(device, 4096,
175 ANV_BO_ALLOC_EXTERNAL |
176 ANV_BO_ALLOC_IMPLICIT_SYNC,
177 0 /* explicit_address */,
178 &(*point)->bo);
179 if (result != VK_SUCCESS)
180 vk_free(&device->vk.alloc, *point);
181 }
182 } else {
183 *point = list_first_entry(&timeline->free_points,
184 struct anv_timeline_point, link);
185 list_del(&(*point)->link);
186 }
187
188 if (result == VK_SUCCESS) {
189 (*point)->serial = value;
190 list_addtail(&(*point)->link, &timeline->points);
191 }
192
193 return result;
194 }
195
196 static VkResult
197 anv_timeline_gc_locked(struct anv_device *device,
198 struct anv_timeline *timeline)
199 {
200 list_for_each_entry_safe(struct anv_timeline_point, point,
201 &timeline->points, link) {
202 /* timeline->higest_pending is only incremented once submission has
203 * happened. If this point has a greater serial, it means the point
204 * hasn't been submitted yet.
205 */
206 if (point->serial > timeline->highest_pending)
207 return VK_SUCCESS;
208
209 /* If someone is waiting on this time point, consider it busy and don't
210 * try to recycle it. There's a slim possibility that it's no longer
211 * busy by the time we look at it but we would be recycling it out from
212 * under a waiter and that can lead to weird races.
213 *
214 * We walk the list in-order so if this time point is still busy so is
215 * every following time point
216 */
217 assert(point->waiting >= 0);
218 if (point->waiting)
219 return VK_SUCCESS;
220
221 /* Garbage collect any signaled point. */
222 VkResult result = anv_device_bo_busy(device, point->bo);
223 if (result == VK_NOT_READY) {
224 /* We walk the list in-order so if this time point is still busy so
225 * is every following time point
226 */
227 return VK_SUCCESS;
228 } else if (result != VK_SUCCESS) {
229 return result;
230 }
231
232 assert(timeline->highest_past < point->serial);
233 timeline->highest_past = point->serial;
234
235 list_del(&point->link);
236 list_add(&point->link, &timeline->free_points);
237 }
238
239 return VK_SUCCESS;
240 }
241
242 static VkResult anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,
243 struct anv_bo *bo,
244 bool signal);
245
246 static VkResult
247 anv_queue_submit_timeline_locked(struct anv_queue *queue,
248 struct anv_queue_submit *submit)
249 {
250 VkResult result;
251
252 for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
253 struct anv_timeline *timeline = submit->wait_timelines[i];
254 uint64_t wait_value = submit->wait_timeline_values[i];
255
256 if (timeline->highest_past >= wait_value)
257 continue;
258
259 list_for_each_entry(struct anv_timeline_point, point, &timeline->points, link) {
260 if (point->serial < wait_value)
261 continue;
262 result = anv_queue_submit_add_fence_bo(submit, point->bo, false);
263 if (result != VK_SUCCESS)
264 return result;
265 break;
266 }
267 }
268 for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
269 struct anv_timeline *timeline = submit->signal_timelines[i];
270 uint64_t signal_value = submit->signal_timeline_values[i];
271 struct anv_timeline_point *point;
272
273 result = anv_timeline_add_point_locked(queue->device, timeline,
274 signal_value, &point);
275 if (result != VK_SUCCESS)
276 return result;
277
278 result = anv_queue_submit_add_fence_bo(submit, point->bo, true);
279 if (result != VK_SUCCESS)
280 return result;
281 }
282
283 result = anv_queue_execbuf_locked(queue, submit);
284
285 if (result == VK_SUCCESS) {
286 /* Update the pending values in the timeline objects. */
287 for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
288 struct anv_timeline *timeline = submit->signal_timelines[i];
289 uint64_t signal_value = submit->signal_timeline_values[i];
290
291 assert(signal_value > timeline->highest_pending);
292 timeline->highest_pending = signal_value;
293 }
294
295 /* Update signaled semaphores backed by syncfd. */
296 for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {
297 struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];
298 /* Out fences can't have temporary state because that would imply
299 * that we imported a sync file and are trying to signal it.
300 */
301 assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
302 struct anv_semaphore_impl *impl = &semaphore->permanent;
303
304 assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);
305 impl->fd = os_dupfd_cloexec(submit->out_fence);
306 }
307 } else {
308 /* Unblock any waiter by signaling the points, the application will get
309 * a device lost error code.
310 */
311 for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
312 struct anv_timeline *timeline = submit->signal_timelines[i];
313 uint64_t signal_value = submit->signal_timeline_values[i];
314
315 assert(signal_value > timeline->highest_pending);
316 timeline->highest_past = timeline->highest_pending = signal_value;
317 }
318 }
319
320 return result;
321 }
322
323 static VkResult
324 anv_queue_submit_deferred_locked(struct anv_queue *queue, uint32_t *advance)
325 {
326 VkResult result = VK_SUCCESS;
327
328 /* Go through all the queued submissions and submit then until we find one
329 * that's waiting on a point that hasn't materialized yet.
330 */
331 list_for_each_entry_safe(struct anv_queue_submit, submit,
332 &queue->queued_submits, link) {
333 if (!anv_queue_submit_ready_locked(submit))
334 break;
335
336 (*advance)++;
337 list_del(&submit->link);
338
339 result = anv_queue_submit_timeline_locked(queue, submit);
340
341 anv_queue_submit_free(queue->device, submit);
342
343 if (result != VK_SUCCESS)
344 break;
345 }
346
347 return result;
348 }
349
350 static VkResult
351 anv_device_submit_deferred_locked(struct anv_device *device)
352 {
353 uint32_t advance = 0;
354 return anv_queue_submit_deferred_locked(&device->queue, &advance);
355 }
356
357 static void
358 anv_queue_submit_signal_fences(struct anv_device *device,
359 struct anv_queue_submit *submit)
360 {
361 for (uint32_t i = 0; i < submit->fence_count; i++) {
362 if (submit->fences[i].flags & I915_EXEC_FENCE_SIGNAL) {
363 anv_gem_syncobj_timeline_signal(device, &submit->fences[i].handle,
364 &submit->fence_values[i], 1);
365 }
366 }
367 }
368
369 static void *
370 anv_queue_task(void *_queue)
371 {
372 struct anv_queue *queue = _queue;
373
374 pthread_mutex_lock(&queue->mutex);
375
376 while (!queue->quit) {
377 while (!list_is_empty(&queue->queued_submits)) {
378 struct anv_queue_submit *submit =
379 list_first_entry(&queue->queued_submits, struct anv_queue_submit, link);
380 list_del(&submit->link);
381
382 pthread_mutex_unlock(&queue->mutex);
383
384 VkResult result = VK_ERROR_DEVICE_LOST;
385
386 /* Wait for timeline points to materialize before submitting. We need
387 * to do this because we're using threads to do the submit to i915.
388 * We could end up in a situation where the application submits to 2
389 * queues with the first submit creating the dma-fence for the
390 * second. But because the scheduling of the submission threads might
391 * wakeup the second queue thread first, this would make that execbuf
392 * fail because the dma-fence it depends on hasn't materialized yet.
393 */
394 if (!queue->lost && submit->wait_timeline_count > 0) {
395 int ret = queue->device->no_hw ? 0 :
396 anv_gem_syncobj_timeline_wait(
397 queue->device, submit->wait_timeline_syncobjs,
398 submit->wait_timeline_values, submit->wait_timeline_count,
399 anv_get_absolute_timeout(UINT64_MAX) /* wait forever */,
400 true /* wait for all */, true /* wait for materialize */);
401 if (ret) {
402 result = anv_queue_set_lost(queue, "timeline timeout: %s",
403 strerror(errno));
404 }
405 }
406
407 /* Now submit */
408 if (!queue->lost) {
409 pthread_mutex_lock(&queue->device->mutex);
410 result = anv_queue_execbuf_locked(queue, submit);
411 pthread_mutex_unlock(&queue->device->mutex);
412 }
413
414 for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {
415 struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];
416 /* Out fences can't have temporary state because that would imply
417 * that we imported a sync file and are trying to signal it.
418 */
419 assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
420 struct anv_semaphore_impl *impl = &semaphore->permanent;
421
422 assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);
423 impl->fd = dup(submit->out_fence);
424 }
425
426 if (result != VK_SUCCESS) {
427 /* vkQueueSubmit or some other entry point will report the
428 * DEVICE_LOST error at some point, but until we have emptied our
429 * list of execbufs we need to wake up all potential the waiters
430 * until one of them spots the error.
431 */
432 anv_queue_submit_signal_fences(queue->device, submit);
433 }
434
435 anv_queue_submit_free(queue->device, submit);
436
437 pthread_mutex_lock(&queue->mutex);
438 }
439
440 if (!queue->quit)
441 pthread_cond_wait(&queue->cond, &queue->mutex);
442 }
443
444 pthread_mutex_unlock(&queue->mutex);
445
446 return NULL;
447 }
448
449 static VkResult
450 _anv_queue_submit(struct anv_queue *queue, struct anv_queue_submit **_submit,
451 bool flush_queue)
452 {
453 struct anv_queue_submit *submit = *_submit;
454
455 /* Wait before signal behavior means we might keep alive the
456 * anv_queue_submit object a bit longer, so transfer the ownership to the
457 * anv_queue.
458 */
459 *_submit = NULL;
460 if (queue->device->has_thread_submit) {
461 pthread_mutex_lock(&queue->mutex);
462 pthread_cond_broadcast(&queue->cond);
463 list_addtail(&submit->link, &queue->queued_submits);
464 pthread_mutex_unlock(&queue->mutex);
465 return VK_SUCCESS;
466 } else {
467 pthread_mutex_lock(&queue->device->mutex);
468 list_addtail(&submit->link, &queue->queued_submits);
469 VkResult result = anv_device_submit_deferred_locked(queue->device);
470 if (flush_queue) {
471 while (result == VK_SUCCESS && !list_is_empty(&queue->queued_submits)) {
472 int ret = pthread_cond_wait(&queue->device->queue_submit,
473 &queue->device->mutex);
474 if (ret != 0) {
475 result = anv_device_set_lost(queue->device, "wait timeout");
476 break;
477 }
478
479 result = anv_device_submit_deferred_locked(queue->device);
480 }
481 }
482 pthread_mutex_unlock(&queue->device->mutex);
483 return result;
484 }
485 }
486
487 VkResult
488 anv_queue_init(struct anv_device *device, struct anv_queue *queue)
489 {
490 VkResult result;
491
492 queue->device = device;
493 queue->flags = 0;
494 queue->lost = false;
495 queue->quit = false;
496
497 list_inithead(&queue->queued_submits);
498
499 /* We only need those additional thread/mutex when using a thread for
500 * submission.
501 */
502 if (device->has_thread_submit) {
503 if (pthread_mutex_init(&queue->mutex, NULL) != 0)
504 return vk_error(VK_ERROR_INITIALIZATION_FAILED);
505
506 if (pthread_cond_init(&queue->cond, NULL) != 0) {
507 result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
508 goto fail_mutex;
509 }
510 if (pthread_create(&queue->thread, NULL, anv_queue_task, queue)) {
511 result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
512 goto fail_cond;
513 }
514 }
515
516 vk_object_base_init(&device->vk, &queue->base, VK_OBJECT_TYPE_QUEUE);
517
518 return VK_SUCCESS;
519
520 fail_cond:
521 pthread_cond_destroy(&queue->cond);
522 fail_mutex:
523 pthread_mutex_destroy(&queue->mutex);
524
525 return result;
526 }
527
528 void
529 anv_queue_finish(struct anv_queue *queue)
530 {
531 vk_object_base_finish(&queue->base);
532
533 if (!queue->device->has_thread_submit)
534 return;
535
536 pthread_mutex_lock(&queue->mutex);
537 pthread_cond_broadcast(&queue->cond);
538 queue->quit = true;
539 pthread_mutex_unlock(&queue->mutex);
540
541 void *ret;
542 pthread_join(queue->thread, &ret);
543
544 pthread_cond_destroy(&queue->cond);
545 pthread_mutex_destroy(&queue->mutex);
546 }
547
548 static VkResult
549 anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,
550 struct anv_bo *bo,
551 bool signal)
552 {
553 if (submit->fence_bo_count >= submit->fence_bo_array_length) {
554 uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64);
555 uintptr_t *new_fence_bos =
556 vk_realloc(submit->alloc,
557 submit->fence_bos, new_len * sizeof(*submit->fence_bos),
558 8, submit->alloc_scope);
559 if (new_fence_bos == NULL)
560 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
561
562 submit->fence_bos = new_fence_bos;
563 submit->fence_bo_array_length = new_len;
564 }
565
566 /* Take advantage that anv_bo are allocated at 8 byte alignement so we can
567 * use the lowest bit to store whether this is a BO we need to signal.
568 */
569 submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal);
570
571 return VK_SUCCESS;
572 }
573
574 static VkResult
575 anv_queue_submit_add_syncobj(struct anv_queue_submit* submit,
576 struct anv_device *device,
577 uint32_t handle, uint32_t flags,
578 uint64_t value)
579 {
580 assert(flags != 0);
581
582 if (device->has_thread_submit && (flags & I915_EXEC_FENCE_WAIT)) {
583 if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
584 uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
585
586 uint32_t *new_wait_timeline_syncobjs =
587 vk_realloc(submit->alloc,
588 submit->wait_timeline_syncobjs,
589 new_len * sizeof(*submit->wait_timeline_syncobjs),
590 8, submit->alloc_scope);
591 if (new_wait_timeline_syncobjs == NULL)
592 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
593
594 submit->wait_timeline_syncobjs = new_wait_timeline_syncobjs;
595
596 uint64_t *new_wait_timeline_values =
597 vk_realloc(submit->alloc,
598 submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),
599 8, submit->alloc_scope);
600 if (new_wait_timeline_values == NULL)
601 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
602
603 submit->wait_timeline_values = new_wait_timeline_values;
604 submit->wait_timeline_array_length = new_len;
605 }
606
607 submit->wait_timeline_syncobjs[submit->wait_timeline_count] = handle;
608 submit->wait_timeline_values[submit->wait_timeline_count] = value;
609
610 submit->wait_timeline_count++;
611 }
612
613 if (submit->fence_count >= submit->fence_array_length) {
614 uint32_t new_len = MAX2(submit->fence_array_length * 2, 64);
615 struct drm_i915_gem_exec_fence *new_fences =
616 vk_realloc(submit->alloc,
617 submit->fences, new_len * sizeof(*submit->fences),
618 8, submit->alloc_scope);
619 if (new_fences == NULL)
620 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
621
622 submit->fences = new_fences;
623
624 uint64_t *new_fence_values =
625 vk_realloc(submit->alloc,
626 submit->fence_values, new_len * sizeof(*submit->fence_values),
627 8, submit->alloc_scope);
628 if (new_fence_values == NULL)
629 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
630
631 submit->fence_values = new_fence_values;
632 submit->fence_array_length = new_len;
633 }
634
635 submit->fences[submit->fence_count] = (struct drm_i915_gem_exec_fence) {
636 .handle = handle,
637 .flags = flags,
638 };
639 submit->fence_values[submit->fence_count] = value;
640 submit->fence_count++;
641
642 return VK_SUCCESS;
643 }
644
645 static VkResult
646 anv_queue_submit_add_sync_fd_fence(struct anv_queue_submit *submit,
647 struct anv_semaphore *semaphore)
648 {
649 if (submit->sync_fd_semaphore_count >= submit->sync_fd_semaphore_array_length) {
650 uint32_t new_len = MAX2(submit->sync_fd_semaphore_array_length * 2, 64);
651 struct anv_semaphore **new_semaphores =
652 vk_realloc(submit->alloc, submit->sync_fd_semaphores,
653 new_len * sizeof(*submit->sync_fd_semaphores), 8,
654 submit->alloc_scope);
655 if (new_semaphores == NULL)
656 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
657
658 submit->sync_fd_semaphores = new_semaphores;
659 }
660
661 submit->sync_fd_semaphores[submit->sync_fd_semaphore_count++] =
662 anv_semaphore_ref(semaphore);
663 submit->need_out_fence = true;
664
665 return VK_SUCCESS;
666 }
667
668 static VkResult
669 anv_queue_submit_add_timeline_wait(struct anv_queue_submit* submit,
670 struct anv_device *device,
671 struct anv_timeline *timeline,
672 uint64_t value)
673 {
674 if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
675 uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
676 struct anv_timeline **new_wait_timelines =
677 vk_realloc(submit->alloc,
678 submit->wait_timelines, new_len * sizeof(*submit->wait_timelines),
679 8, submit->alloc_scope);
680 if (new_wait_timelines == NULL)
681 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
682
683 submit->wait_timelines = new_wait_timelines;
684
685 uint64_t *new_wait_timeline_values =
686 vk_realloc(submit->alloc,
687 submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),
688 8, submit->alloc_scope);
689 if (new_wait_timeline_values == NULL)
690 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
691
692 submit->wait_timeline_values = new_wait_timeline_values;
693
694 submit->wait_timeline_array_length = new_len;
695 }
696
697 submit->wait_timelines[submit->wait_timeline_count] = timeline;
698 submit->wait_timeline_values[submit->wait_timeline_count] = value;
699
700 submit->wait_timeline_count++;
701
702 return VK_SUCCESS;
703 }
704
705 static VkResult
706 anv_queue_submit_add_timeline_signal(struct anv_queue_submit* submit,
707 struct anv_device *device,
708 struct anv_timeline *timeline,
709 uint64_t value)
710 {
711 assert(timeline->highest_pending < value);
712
713 if (submit->signal_timeline_count >= submit->signal_timeline_array_length) {
714 uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 64);
715 struct anv_timeline **new_signal_timelines =
716 vk_realloc(submit->alloc,
717 submit->signal_timelines, new_len * sizeof(*submit->signal_timelines),
718 8, submit->alloc_scope);
719 if (new_signal_timelines == NULL)
720 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
721
722 submit->signal_timelines = new_signal_timelines;
723
724 uint64_t *new_signal_timeline_values =
725 vk_realloc(submit->alloc,
726 submit->signal_timeline_values, new_len * sizeof(*submit->signal_timeline_values),
727 8, submit->alloc_scope);
728 if (new_signal_timeline_values == NULL)
729 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
730
731 submit->signal_timeline_values = new_signal_timeline_values;
732
733 submit->signal_timeline_array_length = new_len;
734 }
735
736 submit->signal_timelines[submit->signal_timeline_count] = timeline;
737 submit->signal_timeline_values[submit->signal_timeline_count] = value;
738
739 submit->signal_timeline_count++;
740
741 return VK_SUCCESS;
742 }
743
744 static struct anv_queue_submit *
745 anv_queue_submit_alloc(struct anv_device *device, int perf_query_pass)
746 {
747 const VkAllocationCallbacks *alloc = &device->vk.alloc;
748 VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;
749
750 struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope);
751 if (!submit)
752 return NULL;
753
754 submit->alloc = alloc;
755 submit->alloc_scope = alloc_scope;
756 submit->in_fence = -1;
757 submit->out_fence = -1;
758 submit->perf_query_pass = perf_query_pass;
759
760 return submit;
761 }
762
763 VkResult
764 anv_queue_submit_simple_batch(struct anv_queue *queue,
765 struct anv_batch *batch)
766 {
767 if (queue->device->no_hw)
768 return VK_SUCCESS;
769
770 struct anv_device *device = queue->device;
771 struct anv_queue_submit *submit = anv_queue_submit_alloc(device, -1);
772 if (!submit)
773 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
774
775 bool has_syncobj_wait = device->physical->has_syncobj_wait;
776 VkResult result;
777 uint32_t syncobj;
778 struct anv_bo *batch_bo, *sync_bo;
779
780 if (has_syncobj_wait) {
781 syncobj = anv_gem_syncobj_create(device, 0);
782 if (!syncobj) {
783 result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
784 goto err_free_submit;
785 }
786
787 result = anv_queue_submit_add_syncobj(submit, device, syncobj,
788 I915_EXEC_FENCE_SIGNAL, 0);
789 } else {
790 result = anv_device_alloc_bo(device, 4096,
791 ANV_BO_ALLOC_EXTERNAL |
792 ANV_BO_ALLOC_IMPLICIT_SYNC,
793 0 /* explicit_address */,
794 &sync_bo);
795 if (result != VK_SUCCESS)
796 goto err_free_submit;
797
798 result = anv_queue_submit_add_fence_bo(submit, sync_bo, true /* signal */);
799 }
800
801 if (result != VK_SUCCESS)
802 goto err_destroy_sync_primitive;
803
804 if (batch) {
805 uint32_t size = align_u32(batch->next - batch->start, 8);
806 result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo);
807 if (result != VK_SUCCESS)
808 goto err_destroy_sync_primitive;
809
810 memcpy(batch_bo->map, batch->start, size);
811 if (!device->info.has_llc)
812 gen_flush_range(batch_bo->map, size);
813
814 submit->simple_bo = batch_bo;
815 submit->simple_bo_size = size;
816 }
817
818 result = _anv_queue_submit(queue, &submit, true);
819
820 if (result == VK_SUCCESS) {
821 if (has_syncobj_wait) {
822 if (anv_gem_syncobj_wait(device, &syncobj, 1,
823 anv_get_absolute_timeout(INT64_MAX), true))
824 result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m");
825 anv_gem_syncobj_destroy(device, syncobj);
826 } else {
827 result = anv_device_wait(device, sync_bo,
828 anv_get_relative_timeout(INT64_MAX));
829 anv_device_release_bo(device, sync_bo);
830 }
831 }
832
833 if (batch)
834 anv_bo_pool_free(&device->batch_bo_pool, batch_bo);
835
836 if (submit)
837 anv_queue_submit_free(device, submit);
838
839 return result;
840
841 err_destroy_sync_primitive:
842 if (has_syncobj_wait)
843 anv_gem_syncobj_destroy(device, syncobj);
844 else
845 anv_device_release_bo(device, sync_bo);
846 err_free_submit:
847 if (submit)
848 anv_queue_submit_free(device, submit);
849
850 return result;
851 }
852
853 /* Transfer ownership of temporary semaphores from the VkSemaphore object to
854 * the anv_queue_submit object. Those temporary semaphores are then freed in
855 * anv_queue_submit_free() once the driver is finished with them.
856 */
857 static VkResult
858 maybe_transfer_temporary_semaphore(struct anv_queue_submit *submit,
859 struct anv_semaphore *semaphore,
860 struct anv_semaphore_impl **out_impl)
861 {
862 struct anv_semaphore_impl *impl = &semaphore->temporary;
863
864 if (impl->type == ANV_SEMAPHORE_TYPE_NONE) {
865 *out_impl = &semaphore->permanent;
866 return VK_SUCCESS;
867 }
868
869 /* BO backed timeline semaphores cannot be temporary. */
870 assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE);
871
872 /*
873 * There is a requirement to reset semaphore to their permanent state after
874 * submission. From the Vulkan 1.0.53 spec:
875 *
876 * "If the import is temporary, the implementation must restore the
877 * semaphore to its prior permanent state after submitting the next
878 * semaphore wait operation."
879 *
880 * In the case we defer the actual submission to a thread because of the
881 * wait-before-submit behavior required for timeline semaphores, we need to
882 * make copies of the temporary syncobj to ensure they stay alive until we
883 * do the actual execbuffer ioctl.
884 */
885 if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) {
886 uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8);
887 /* Make sure that if the realloc fails, we still have the old semaphore
888 * array around to properly clean things up on failure.
889 */
890 struct anv_semaphore_impl *new_array =
891 vk_realloc(submit->alloc,
892 submit->temporary_semaphores,
893 new_len * sizeof(*submit->temporary_semaphores),
894 8, submit->alloc_scope);
895 if (new_array == NULL)
896 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
897
898 submit->temporary_semaphores = new_array;
899 submit->temporary_semaphore_array_length = new_len;
900 }
901
902 /* Copy anv_semaphore_impl into anv_queue_submit. */
903 submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl;
904 *out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1];
905
906 /* Clear the incoming semaphore */
907 impl->type = ANV_SEMAPHORE_TYPE_NONE;
908
909 return VK_SUCCESS;
910 }
911
912 static VkResult
913 anv_queue_submit(struct anv_queue *queue,
914 struct anv_cmd_buffer *cmd_buffer,
915 const VkSemaphore *in_semaphores,
916 const uint64_t *in_values,
917 uint32_t num_in_semaphores,
918 const VkSemaphore *out_semaphores,
919 const uint64_t *out_values,
920 uint32_t num_out_semaphores,
921 struct anv_bo *wsi_signal_bo,
922 VkFence _fence,
923 int perf_query_pass)
924 {
925 ANV_FROM_HANDLE(anv_fence, fence, _fence);
926 struct anv_device *device = queue->device;
927 UNUSED struct anv_physical_device *pdevice = device->physical;
928 struct anv_queue_submit *submit = anv_queue_submit_alloc(device, perf_query_pass);
929 if (!submit)
930 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
931
932 submit->cmd_buffer = cmd_buffer;
933
934 VkResult result = VK_SUCCESS;
935 for (uint32_t i = 0; i < num_in_semaphores; i++) {
936 ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
937 struct anv_semaphore_impl *impl;
938
939 result = maybe_transfer_temporary_semaphore(submit, semaphore, &impl);
940 if (result != VK_SUCCESS)
941 goto error;
942
943 switch (impl->type) {
944 case ANV_SEMAPHORE_TYPE_BO:
945 assert(!pdevice->has_syncobj);
946 result = anv_queue_submit_add_fence_bo(submit, impl->bo, false /* signal */);
947 if (result != VK_SUCCESS)
948 goto error;
949 break;
950
951 case ANV_SEMAPHORE_TYPE_WSI_BO:
952 /* When using a window-system buffer as a semaphore, always enable
953 * EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or
954 * compositor's read of the buffer and enforces that we don't start
955 * rendering until they are finished. This is exactly the
956 * synchronization we want with vkAcquireNextImage.
957 */
958 result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
959 if (result != VK_SUCCESS)
960 goto error;
961 break;
962
963 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
964 assert(!pdevice->has_syncobj);
965 if (submit->in_fence == -1) {
966 submit->in_fence = impl->fd;
967 if (submit->in_fence == -1) {
968 result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
969 goto error;
970 }
971 impl->fd = -1;
972 } else {
973 int merge = anv_gem_sync_file_merge(device, submit->in_fence, impl->fd);
974 if (merge == -1) {
975 result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
976 goto error;
977 }
978 close(impl->fd);
979 close(submit->in_fence);
980 impl->fd = -1;
981 submit->in_fence = merge;
982 }
983 break;
984
985 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
986 result = anv_queue_submit_add_syncobj(submit, device,
987 impl->syncobj,
988 I915_EXEC_FENCE_WAIT,
989 0);
990 if (result != VK_SUCCESS)
991 goto error;
992 break;
993 }
994
995 case ANV_SEMAPHORE_TYPE_TIMELINE:
996 result = anv_queue_submit_add_timeline_wait(submit, device,
997 &impl->timeline,
998 in_values ? in_values[i] : 0);
999 if (result != VK_SUCCESS)
1000 goto error;
1001 break;
1002
1003 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
1004 result = anv_queue_submit_add_syncobj(submit, device,
1005 impl->syncobj,
1006 I915_EXEC_FENCE_WAIT,
1007 in_values ? in_values[i] : 0);
1008 if (result != VK_SUCCESS)
1009 goto error;
1010 break;
1011
1012 default:
1013 break;
1014 }
1015 }
1016
1017 for (uint32_t i = 0; i < num_out_semaphores; i++) {
1018 ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
1019
1020 /* Under most circumstances, out fences won't be temporary. However,
1021 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
1022 *
1023 * "If the import is temporary, the implementation must restore the
1024 * semaphore to its prior permanent state after submitting the next
1025 * semaphore wait operation."
1026 *
1027 * The spec says nothing whatsoever about signal operations on
1028 * temporarily imported semaphores so it appears they are allowed.
1029 * There are also CTS tests that require this to work.
1030 */
1031 struct anv_semaphore_impl *impl =
1032 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
1033 &semaphore->temporary : &semaphore->permanent;
1034
1035 switch (impl->type) {
1036 case ANV_SEMAPHORE_TYPE_BO:
1037 assert(!pdevice->has_syncobj);
1038 result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
1039 if (result != VK_SUCCESS)
1040 goto error;
1041 break;
1042
1043 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
1044 assert(!pdevice->has_syncobj);
1045 result = anv_queue_submit_add_sync_fd_fence(submit, semaphore);
1046 if (result != VK_SUCCESS)
1047 goto error;
1048 break;
1049
1050 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
1051 result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
1052 I915_EXEC_FENCE_SIGNAL,
1053 0);
1054 if (result != VK_SUCCESS)
1055 goto error;
1056 break;
1057 }
1058
1059 case ANV_SEMAPHORE_TYPE_TIMELINE:
1060 result = anv_queue_submit_add_timeline_signal(submit, device,
1061 &impl->timeline,
1062 out_values ? out_values[i] : 0);
1063 if (result != VK_SUCCESS)
1064 goto error;
1065 break;
1066
1067 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
1068 result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
1069 I915_EXEC_FENCE_SIGNAL,
1070 out_values ? out_values[i] : 0);
1071 if (result != VK_SUCCESS)
1072 goto error;
1073 break;
1074
1075 default:
1076 break;
1077 }
1078 }
1079
1080 if (wsi_signal_bo) {
1081 result = anv_queue_submit_add_fence_bo(submit, wsi_signal_bo, true /* signal */);
1082 if (result != VK_SUCCESS)
1083 goto error;
1084 }
1085
1086 if (fence) {
1087 /* Under most circumstances, out fences won't be temporary. However,
1088 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
1089 *
1090 * "If the import is temporary, the implementation must restore the
1091 * semaphore to its prior permanent state after submitting the next
1092 * semaphore wait operation."
1093 *
1094 * The spec says nothing whatsoever about signal operations on
1095 * temporarily imported semaphores so it appears they are allowed.
1096 * There are also CTS tests that require this to work.
1097 */
1098 struct anv_fence_impl *impl =
1099 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1100 &fence->temporary : &fence->permanent;
1101
1102 switch (impl->type) {
1103 case ANV_FENCE_TYPE_BO:
1104 assert(!device->has_thread_submit);
1105 result = anv_queue_submit_add_fence_bo(submit, impl->bo.bo, true /* signal */);
1106 if (result != VK_SUCCESS)
1107 goto error;
1108 break;
1109
1110 case ANV_FENCE_TYPE_SYNCOBJ: {
1111 /*
1112 * For the same reason we reset the signaled binary syncobj above,
1113 * also reset the fence's syncobj so that they don't contain a
1114 * signaled dma-fence.
1115 */
1116 anv_gem_syncobj_reset(device, impl->syncobj);
1117
1118 result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
1119 I915_EXEC_FENCE_SIGNAL,
1120 0);
1121 if (result != VK_SUCCESS)
1122 goto error;
1123 break;
1124 }
1125
1126 default:
1127 unreachable("Invalid fence type");
1128 }
1129 }
1130
1131 result = _anv_queue_submit(queue, &submit, false);
1132 if (result != VK_SUCCESS)
1133 goto error;
1134
1135 if (fence && fence->permanent.type == ANV_FENCE_TYPE_BO) {
1136 assert(!device->has_thread_submit);
1137 /* If we have permanent BO fence, the only type of temporary possible
1138 * would be BO_WSI (because BO fences are not shareable). The Vulkan spec
1139 * also requires that the fence passed to vkQueueSubmit() be :
1140 *
1141 * * unsignaled
1142 * * not be associated with any other queue command that has not yet
1143 * completed execution on that queue
1144 *
1145 * So the only acceptable type for the temporary is NONE.
1146 */
1147 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
1148
1149 /* Once the execbuf has returned, we need to set the fence state to
1150 * SUBMITTED. We can't do this before calling execbuf because
1151 * anv_GetFenceStatus does take the global device lock before checking
1152 * fence->state.
1153 *
1154 * We set the fence state to SUBMITTED regardless of whether or not the
1155 * execbuf succeeds because we need to ensure that vkWaitForFences() and
1156 * vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or
1157 * VK_SUCCESS) in a finite amount of time even if execbuf fails.
1158 */
1159 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED;
1160 }
1161
1162 error:
1163 if (submit)
1164 anv_queue_submit_free(device, submit);
1165
1166 return result;
1167 }
1168
1169 VkResult anv_QueueSubmit(
1170 VkQueue _queue,
1171 uint32_t submitCount,
1172 const VkSubmitInfo* pSubmits,
1173 VkFence fence)
1174 {
1175 ANV_FROM_HANDLE(anv_queue, queue, _queue);
1176
1177 if (queue->device->no_hw)
1178 return VK_SUCCESS;
1179
1180 /* Query for device status prior to submitting. Technically, we don't need
1181 * to do this. However, if we have a client that's submitting piles of
1182 * garbage, we would rather break as early as possible to keep the GPU
1183 * hanging contained. If we don't check here, we'll either be waiting for
1184 * the kernel to kick us or we'll have to wait until the client waits on a
1185 * fence before we actually know whether or not we've hung.
1186 */
1187 VkResult result = anv_device_query_status(queue->device);
1188 if (result != VK_SUCCESS)
1189 return result;
1190
1191 if (fence && submitCount == 0) {
1192 /* If we don't have any command buffers, we need to submit a dummy
1193 * batch to give GEM something to wait on. We could, potentially,
1194 * come up with something more efficient but this shouldn't be a
1195 * common case.
1196 */
1197 result = anv_queue_submit(queue, NULL, NULL, NULL, 0, NULL, NULL, 0,
1198 NULL, fence, -1);
1199 goto out;
1200 }
1201
1202 for (uint32_t i = 0; i < submitCount; i++) {
1203 /* Fence for this submit. NULL for all but the last one */
1204 VkFence submit_fence = (i == submitCount - 1) ? fence : VK_NULL_HANDLE;
1205
1206 const struct wsi_memory_signal_submit_info *mem_signal_info =
1207 vk_find_struct_const(pSubmits[i].pNext,
1208 WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
1209 struct anv_bo *wsi_signal_bo =
1210 mem_signal_info && mem_signal_info->memory != VK_NULL_HANDLE ?
1211 anv_device_memory_from_handle(mem_signal_info->memory)->bo : NULL;
1212
1213 const VkTimelineSemaphoreSubmitInfoKHR *timeline_info =
1214 vk_find_struct_const(pSubmits[i].pNext,
1215 TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR);
1216 const VkPerformanceQuerySubmitInfoKHR *perf_info =
1217 vk_find_struct_const(pSubmits[i].pNext,
1218 PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
1219 const uint64_t *wait_values =
1220 timeline_info && timeline_info->waitSemaphoreValueCount ?
1221 timeline_info->pWaitSemaphoreValues : NULL;
1222 const uint64_t *signal_values =
1223 timeline_info && timeline_info->signalSemaphoreValueCount ?
1224 timeline_info->pSignalSemaphoreValues : NULL;
1225
1226 if (pSubmits[i].commandBufferCount == 0) {
1227 /* If we don't have any command buffers, we need to submit a dummy
1228 * batch to give GEM something to wait on. We could, potentially,
1229 * come up with something more efficient but this shouldn't be a
1230 * common case.
1231 */
1232 result = anv_queue_submit(queue, NULL,
1233 pSubmits[i].pWaitSemaphores,
1234 wait_values,
1235 pSubmits[i].waitSemaphoreCount,
1236 pSubmits[i].pSignalSemaphores,
1237 signal_values,
1238 pSubmits[i].signalSemaphoreCount,
1239 wsi_signal_bo,
1240 submit_fence,
1241 -1);
1242 if (result != VK_SUCCESS)
1243 goto out;
1244
1245 continue;
1246 }
1247
1248 for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
1249 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
1250 pSubmits[i].pCommandBuffers[j]);
1251 assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1252 assert(!anv_batch_has_error(&cmd_buffer->batch));
1253
1254 /* Fence for this execbuf. NULL for all but the last one */
1255 VkFence execbuf_fence =
1256 (j == pSubmits[i].commandBufferCount - 1) ?
1257 submit_fence : VK_NULL_HANDLE;
1258
1259 const VkSemaphore *in_semaphores = NULL, *out_semaphores = NULL;
1260 const uint64_t *in_values = NULL, *out_values = NULL;
1261 uint32_t num_in_semaphores = 0, num_out_semaphores = 0;
1262 if (j == 0) {
1263 /* Only the first batch gets the in semaphores */
1264 in_semaphores = pSubmits[i].pWaitSemaphores;
1265 in_values = wait_values;
1266 num_in_semaphores = pSubmits[i].waitSemaphoreCount;
1267 }
1268
1269 if (j == pSubmits[i].commandBufferCount - 1) {
1270 /* Only the last batch gets the out semaphores */
1271 out_semaphores = pSubmits[i].pSignalSemaphores;
1272 out_values = signal_values;
1273 num_out_semaphores = pSubmits[i].signalSemaphoreCount;
1274 }
1275
1276 result = anv_queue_submit(queue, cmd_buffer,
1277 in_semaphores, in_values, num_in_semaphores,
1278 out_semaphores, out_values, num_out_semaphores,
1279 wsi_signal_bo, execbuf_fence,
1280 perf_info ? perf_info->counterPassIndex : 0);
1281 if (result != VK_SUCCESS)
1282 goto out;
1283 }
1284 }
1285
1286 out:
1287 if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) {
1288 /* In the case that something has gone wrong we may end up with an
1289 * inconsistent state from which it may not be trivial to recover.
1290 * For example, we might have computed address relocations and
1291 * any future attempt to re-submit this job will need to know about
1292 * this and avoid computing relocation addresses again.
1293 *
1294 * To avoid this sort of issues, we assume that if something was
1295 * wrong during submission we must already be in a really bad situation
1296 * anyway (such us being out of memory) and return
1297 * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
1298 * submit the same job again to this device.
1299 *
1300 * We skip doing this on VK_ERROR_DEVICE_LOST because
1301 * anv_device_set_lost() would have been called already by a callee of
1302 * anv_queue_submit().
1303 */
1304 result = anv_device_set_lost(queue->device, "vkQueueSubmit() failed");
1305 }
1306
1307 return result;
1308 }
1309
1310 VkResult anv_QueueWaitIdle(
1311 VkQueue _queue)
1312 {
1313 ANV_FROM_HANDLE(anv_queue, queue, _queue);
1314
1315 if (anv_device_is_lost(queue->device))
1316 return VK_ERROR_DEVICE_LOST;
1317
1318 return anv_queue_submit_simple_batch(queue, NULL);
1319 }
1320
1321 VkResult anv_CreateFence(
1322 VkDevice _device,
1323 const VkFenceCreateInfo* pCreateInfo,
1324 const VkAllocationCallbacks* pAllocator,
1325 VkFence* pFence)
1326 {
1327 ANV_FROM_HANDLE(anv_device, device, _device);
1328 struct anv_fence *fence;
1329
1330 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
1331
1332 fence = vk_zalloc2(&device->vk.alloc, pAllocator, sizeof(*fence), 8,
1333 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1334 if (fence == NULL)
1335 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1336
1337 vk_object_base_init(&device->vk, &fence->base, VK_OBJECT_TYPE_FENCE);
1338
1339 if (device->physical->has_syncobj_wait) {
1340 fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
1341
1342 uint32_t create_flags = 0;
1343 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)
1344 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
1345
1346 fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);
1347 if (!fence->permanent.syncobj)
1348 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1349 } else {
1350 fence->permanent.type = ANV_FENCE_TYPE_BO;
1351
1352 VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096,
1353 &fence->permanent.bo.bo);
1354 if (result != VK_SUCCESS)
1355 return result;
1356
1357 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
1358 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1359 } else {
1360 fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
1361 }
1362 }
1363
1364 *pFence = anv_fence_to_handle(fence);
1365
1366 return VK_SUCCESS;
1367 }
1368
1369 static void
1370 anv_fence_impl_cleanup(struct anv_device *device,
1371 struct anv_fence_impl *impl)
1372 {
1373 switch (impl->type) {
1374 case ANV_FENCE_TYPE_NONE:
1375 /* Dummy. Nothing to do */
1376 break;
1377
1378 case ANV_FENCE_TYPE_BO:
1379 anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo);
1380 break;
1381
1382 case ANV_FENCE_TYPE_WSI_BO:
1383 anv_device_release_bo(device, impl->bo.bo);
1384 break;
1385
1386 case ANV_FENCE_TYPE_SYNCOBJ:
1387 anv_gem_syncobj_destroy(device, impl->syncobj);
1388 break;
1389
1390 case ANV_FENCE_TYPE_WSI:
1391 impl->fence_wsi->destroy(impl->fence_wsi);
1392 break;
1393
1394 default:
1395 unreachable("Invalid fence type");
1396 }
1397
1398 impl->type = ANV_FENCE_TYPE_NONE;
1399 }
1400
1401 void
1402 anv_fence_reset_temporary(struct anv_device *device,
1403 struct anv_fence *fence)
1404 {
1405 if (fence->temporary.type == ANV_FENCE_TYPE_NONE)
1406 return;
1407
1408 anv_fence_impl_cleanup(device, &fence->temporary);
1409 }
1410
1411 void anv_DestroyFence(
1412 VkDevice _device,
1413 VkFence _fence,
1414 const VkAllocationCallbacks* pAllocator)
1415 {
1416 ANV_FROM_HANDLE(anv_device, device, _device);
1417 ANV_FROM_HANDLE(anv_fence, fence, _fence);
1418
1419 if (!fence)
1420 return;
1421
1422 anv_fence_impl_cleanup(device, &fence->temporary);
1423 anv_fence_impl_cleanup(device, &fence->permanent);
1424
1425 vk_object_base_finish(&fence->base);
1426 vk_free2(&device->vk.alloc, pAllocator, fence);
1427 }
1428
1429 VkResult anv_ResetFences(
1430 VkDevice _device,
1431 uint32_t fenceCount,
1432 const VkFence* pFences)
1433 {
1434 ANV_FROM_HANDLE(anv_device, device, _device);
1435
1436 for (uint32_t i = 0; i < fenceCount; i++) {
1437 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1438
1439 /* From the Vulkan 1.0.53 spec:
1440 *
1441 * "If any member of pFences currently has its payload imported with
1442 * temporary permanence, that fence’s prior permanent payload is
1443 * first restored. The remaining operations described therefore
1444 * operate on the restored payload.
1445 */
1446 anv_fence_reset_temporary(device, fence);
1447
1448 struct anv_fence_impl *impl = &fence->permanent;
1449
1450 switch (impl->type) {
1451 case ANV_FENCE_TYPE_BO:
1452 impl->bo.state = ANV_BO_FENCE_STATE_RESET;
1453 break;
1454
1455 case ANV_FENCE_TYPE_SYNCOBJ:
1456 anv_gem_syncobj_reset(device, impl->syncobj);
1457 break;
1458
1459 default:
1460 unreachable("Invalid fence type");
1461 }
1462 }
1463
1464 return VK_SUCCESS;
1465 }
1466
1467 VkResult anv_GetFenceStatus(
1468 VkDevice _device,
1469 VkFence _fence)
1470 {
1471 ANV_FROM_HANDLE(anv_device, device, _device);
1472 ANV_FROM_HANDLE(anv_fence, fence, _fence);
1473
1474 if (anv_device_is_lost(device))
1475 return VK_ERROR_DEVICE_LOST;
1476
1477 struct anv_fence_impl *impl =
1478 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1479 &fence->temporary : &fence->permanent;
1480
1481 switch (impl->type) {
1482 case ANV_FENCE_TYPE_BO:
1483 case ANV_FENCE_TYPE_WSI_BO:
1484 switch (impl->bo.state) {
1485 case ANV_BO_FENCE_STATE_RESET:
1486 /* If it hasn't even been sent off to the GPU yet, it's not ready */
1487 return VK_NOT_READY;
1488
1489 case ANV_BO_FENCE_STATE_SIGNALED:
1490 /* It's been signaled, return success */
1491 return VK_SUCCESS;
1492
1493 case ANV_BO_FENCE_STATE_SUBMITTED: {
1494 VkResult result = anv_device_bo_busy(device, impl->bo.bo);
1495 if (result == VK_SUCCESS) {
1496 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1497 return VK_SUCCESS;
1498 } else {
1499 return result;
1500 }
1501 }
1502 default:
1503 unreachable("Invalid fence status");
1504 }
1505
1506 case ANV_FENCE_TYPE_SYNCOBJ: {
1507 if (device->has_thread_submit) {
1508 uint64_t binary_value = 0;
1509 int ret = anv_gem_syncobj_timeline_wait(device, &impl->syncobj,
1510 &binary_value, 1, 0,
1511 true /* wait_all */,
1512 false /* wait_materialize */);
1513 if (ret == -1) {
1514 if (errno == ETIME) {
1515 return VK_NOT_READY;
1516 } else {
1517 /* We don't know the real error. */
1518 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1519 }
1520 } else {
1521 return VK_SUCCESS;
1522 }
1523 } else {
1524 int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, false);
1525 if (ret == -1) {
1526 if (errno == ETIME) {
1527 return VK_NOT_READY;
1528 } else {
1529 /* We don't know the real error. */
1530 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1531 }
1532 } else {
1533 return VK_SUCCESS;
1534 }
1535 }
1536 }
1537
1538 default:
1539 unreachable("Invalid fence type");
1540 }
1541 }
1542
1543 static VkResult
1544 anv_wait_for_syncobj_fences(struct anv_device *device,
1545 uint32_t fenceCount,
1546 const VkFence *pFences,
1547 bool waitAll,
1548 uint64_t abs_timeout_ns)
1549 {
1550 uint32_t *syncobjs = vk_zalloc(&device->vk.alloc,
1551 sizeof(*syncobjs) * fenceCount, 8,
1552 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1553 if (!syncobjs)
1554 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1555
1556 for (uint32_t i = 0; i < fenceCount; i++) {
1557 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1558 assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
1559
1560 struct anv_fence_impl *impl =
1561 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1562 &fence->temporary : &fence->permanent;
1563
1564 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
1565 syncobjs[i] = impl->syncobj;
1566 }
1567
1568 int ret = 0;
1569 /* The gem_syncobj_wait ioctl may return early due to an inherent
1570 * limitation in the way it computes timeouts. Loop until we've actually
1571 * passed the timeout.
1572 */
1573 do {
1574 ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
1575 abs_timeout_ns, waitAll);
1576 } while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns);
1577
1578 vk_free(&device->vk.alloc, syncobjs);
1579
1580 if (ret == -1) {
1581 if (errno == ETIME) {
1582 return VK_TIMEOUT;
1583 } else {
1584 /* We don't know the real error. */
1585 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1586 }
1587 } else {
1588 return VK_SUCCESS;
1589 }
1590 }
1591
1592 static VkResult
1593 anv_wait_for_bo_fences(struct anv_device *device,
1594 uint32_t fenceCount,
1595 const VkFence *pFences,
1596 bool waitAll,
1597 uint64_t abs_timeout_ns)
1598 {
1599 VkResult result = VK_SUCCESS;
1600 uint32_t pending_fences = fenceCount;
1601 while (pending_fences) {
1602 pending_fences = 0;
1603 bool signaled_fences = false;
1604 for (uint32_t i = 0; i < fenceCount; i++) {
1605 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1606
1607 struct anv_fence_impl *impl =
1608 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1609 &fence->temporary : &fence->permanent;
1610 assert(impl->type == ANV_FENCE_TYPE_BO ||
1611 impl->type == ANV_FENCE_TYPE_WSI_BO);
1612
1613 switch (impl->bo.state) {
1614 case ANV_BO_FENCE_STATE_RESET:
1615 /* This fence hasn't been submitted yet, we'll catch it the next
1616 * time around. Yes, this may mean we dead-loop but, short of
1617 * lots of locking and a condition variable, there's not much that
1618 * we can do about that.
1619 */
1620 pending_fences++;
1621 continue;
1622
1623 case ANV_BO_FENCE_STATE_SIGNALED:
1624 /* This fence is not pending. If waitAll isn't set, we can return
1625 * early. Otherwise, we have to keep going.
1626 */
1627 if (!waitAll) {
1628 result = VK_SUCCESS;
1629 goto done;
1630 }
1631 continue;
1632
1633 case ANV_BO_FENCE_STATE_SUBMITTED:
1634 /* These are the fences we really care about. Go ahead and wait
1635 * on it until we hit a timeout.
1636 */
1637 result = anv_device_wait(device, impl->bo.bo,
1638 anv_get_relative_timeout(abs_timeout_ns));
1639 switch (result) {
1640 case VK_SUCCESS:
1641 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1642 signaled_fences = true;
1643 if (!waitAll)
1644 goto done;
1645 break;
1646
1647 case VK_TIMEOUT:
1648 goto done;
1649
1650 default:
1651 return result;
1652 }
1653 }
1654 }
1655
1656 if (pending_fences && !signaled_fences) {
1657 /* If we've hit this then someone decided to vkWaitForFences before
1658 * they've actually submitted any of them to a queue. This is a
1659 * fairly pessimal case, so it's ok to lock here and use a standard
1660 * pthreads condition variable.
1661 */
1662 pthread_mutex_lock(&device->mutex);
1663
1664 /* It's possible that some of the fences have changed state since the
1665 * last time we checked. Now that we have the lock, check for
1666 * pending fences again and don't wait if it's changed.
1667 */
1668 uint32_t now_pending_fences = 0;
1669 for (uint32_t i = 0; i < fenceCount; i++) {
1670 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1671 if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
1672 now_pending_fences++;
1673 }
1674 assert(now_pending_fences <= pending_fences);
1675
1676 if (now_pending_fences == pending_fences) {
1677 struct timespec abstime = {
1678 .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
1679 .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
1680 };
1681
1682 ASSERTED int ret;
1683 ret = pthread_cond_timedwait(&device->queue_submit,
1684 &device->mutex, &abstime);
1685 assert(ret != EINVAL);
1686 if (anv_gettime_ns() >= abs_timeout_ns) {
1687 pthread_mutex_unlock(&device->mutex);
1688 result = VK_TIMEOUT;
1689 goto done;
1690 }
1691 }
1692
1693 pthread_mutex_unlock(&device->mutex);
1694 }
1695 }
1696
1697 done:
1698 if (anv_device_is_lost(device))
1699 return VK_ERROR_DEVICE_LOST;
1700
1701 return result;
1702 }
1703
1704 static VkResult
1705 anv_wait_for_wsi_fence(struct anv_device *device,
1706 struct anv_fence_impl *impl,
1707 uint64_t abs_timeout)
1708 {
1709 return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout);
1710 }
1711
1712 static VkResult
1713 anv_wait_for_fences(struct anv_device *device,
1714 uint32_t fenceCount,
1715 const VkFence *pFences,
1716 bool waitAll,
1717 uint64_t abs_timeout)
1718 {
1719 VkResult result = VK_SUCCESS;
1720
1721 if (fenceCount <= 1 || waitAll) {
1722 for (uint32_t i = 0; i < fenceCount; i++) {
1723 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1724 struct anv_fence_impl *impl =
1725 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1726 &fence->temporary : &fence->permanent;
1727
1728 switch (impl->type) {
1729 case ANV_FENCE_TYPE_BO:
1730 assert(!device->physical->has_syncobj_wait);
1731 /* fall-through */
1732 case ANV_FENCE_TYPE_WSI_BO:
1733 result = anv_wait_for_bo_fences(device, 1, &pFences[i],
1734 true, abs_timeout);
1735 break;
1736 case ANV_FENCE_TYPE_SYNCOBJ:
1737 result = anv_wait_for_syncobj_fences(device, 1, &pFences[i],
1738 true, abs_timeout);
1739 break;
1740 case ANV_FENCE_TYPE_WSI:
1741 result = anv_wait_for_wsi_fence(device, impl, abs_timeout);
1742 break;
1743 case ANV_FENCE_TYPE_NONE:
1744 result = VK_SUCCESS;
1745 break;
1746 }
1747 if (result != VK_SUCCESS)
1748 return result;
1749 }
1750 } else {
1751 do {
1752 for (uint32_t i = 0; i < fenceCount; i++) {
1753 if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS)
1754 return VK_SUCCESS;
1755 }
1756 } while (anv_gettime_ns() < abs_timeout);
1757 result = VK_TIMEOUT;
1758 }
1759 return result;
1760 }
1761
1762 static bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences)
1763 {
1764 for (uint32_t i = 0; i < fenceCount; ++i) {
1765 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1766 struct anv_fence_impl *impl =
1767 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1768 &fence->temporary : &fence->permanent;
1769 if (impl->type != ANV_FENCE_TYPE_SYNCOBJ)
1770 return false;
1771 }
1772 return true;
1773 }
1774
1775 static bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences)
1776 {
1777 for (uint32_t i = 0; i < fenceCount; ++i) {
1778 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1779 struct anv_fence_impl *impl =
1780 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1781 &fence->temporary : &fence->permanent;
1782 if (impl->type != ANV_FENCE_TYPE_BO &&
1783 impl->type != ANV_FENCE_TYPE_WSI_BO)
1784 return false;
1785 }
1786 return true;
1787 }
1788
1789 VkResult anv_WaitForFences(
1790 VkDevice _device,
1791 uint32_t fenceCount,
1792 const VkFence* pFences,
1793 VkBool32 waitAll,
1794 uint64_t timeout)
1795 {
1796 ANV_FROM_HANDLE(anv_device, device, _device);
1797
1798 if (device->no_hw)
1799 return VK_SUCCESS;
1800
1801 if (anv_device_is_lost(device))
1802 return VK_ERROR_DEVICE_LOST;
1803
1804 uint64_t abs_timeout = anv_get_absolute_timeout(timeout);
1805 if (anv_all_fences_syncobj(fenceCount, pFences)) {
1806 return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
1807 waitAll, abs_timeout);
1808 } else if (anv_all_fences_bo(fenceCount, pFences)) {
1809 return anv_wait_for_bo_fences(device, fenceCount, pFences,
1810 waitAll, abs_timeout);
1811 } else {
1812 return anv_wait_for_fences(device, fenceCount, pFences,
1813 waitAll, abs_timeout);
1814 }
1815 }
1816
1817 void anv_GetPhysicalDeviceExternalFenceProperties(
1818 VkPhysicalDevice physicalDevice,
1819 const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
1820 VkExternalFenceProperties* pExternalFenceProperties)
1821 {
1822 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
1823
1824 switch (pExternalFenceInfo->handleType) {
1825 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
1826 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
1827 if (device->has_syncobj_wait) {
1828 pExternalFenceProperties->exportFromImportedHandleTypes =
1829 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1830 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1831 pExternalFenceProperties->compatibleHandleTypes =
1832 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1833 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1834 pExternalFenceProperties->externalFenceFeatures =
1835 VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT |
1836 VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT;
1837 return;
1838 }
1839 break;
1840
1841 default:
1842 break;
1843 }
1844
1845 pExternalFenceProperties->exportFromImportedHandleTypes = 0;
1846 pExternalFenceProperties->compatibleHandleTypes = 0;
1847 pExternalFenceProperties->externalFenceFeatures = 0;
1848 }
1849
1850 VkResult anv_ImportFenceFdKHR(
1851 VkDevice _device,
1852 const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
1853 {
1854 ANV_FROM_HANDLE(anv_device, device, _device);
1855 ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
1856 int fd = pImportFenceFdInfo->fd;
1857
1858 assert(pImportFenceFdInfo->sType ==
1859 VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
1860
1861 struct anv_fence_impl new_impl = {
1862 .type = ANV_FENCE_TYPE_NONE,
1863 };
1864
1865 switch (pImportFenceFdInfo->handleType) {
1866 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
1867 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
1868
1869 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
1870 if (!new_impl.syncobj)
1871 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1872
1873 break;
1874
1875 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
1876 /* Sync files are a bit tricky. Because we want to continue using the
1877 * syncobj implementation of WaitForFences, we don't use the sync file
1878 * directly but instead import it into a syncobj.
1879 */
1880 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
1881
1882 /* "If handleType is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, the
1883 * special value -1 for fd is treated like a valid sync file descriptor
1884 * referring to an object that has already signaled. The import
1885 * operation will succeed and the VkFence will have a temporarily
1886 * imported payload as if a valid file descriptor had been provided."
1887 */
1888 uint32_t create_flags = 0;
1889 if (fd == -1)
1890 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
1891
1892 new_impl.syncobj = anv_gem_syncobj_create(device, create_flags);
1893 if (!new_impl.syncobj)
1894 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1895
1896 if (fd != -1 &&
1897 anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
1898 anv_gem_syncobj_destroy(device, new_impl.syncobj);
1899 return vk_errorf(device, NULL, VK_ERROR_INVALID_EXTERNAL_HANDLE,
1900 "syncobj sync file import failed: %m");
1901 }
1902 break;
1903 }
1904
1905 default:
1906 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1907 }
1908
1909 /* From the Vulkan 1.0.53 spec:
1910 *
1911 * "Importing a fence payload from a file descriptor transfers
1912 * ownership of the file descriptor from the application to the
1913 * Vulkan implementation. The application must not perform any
1914 * operations on the file descriptor after a successful import."
1915 *
1916 * If the import fails, we leave the file descriptor open.
1917 */
1918 close(fd);
1919
1920 if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) {
1921 anv_fence_impl_cleanup(device, &fence->temporary);
1922 fence->temporary = new_impl;
1923 } else {
1924 anv_fence_impl_cleanup(device, &fence->permanent);
1925 fence->permanent = new_impl;
1926 }
1927
1928 return VK_SUCCESS;
1929 }
1930
1931 /* The sideband payload of the DRM syncobj was incremented when the
1932 * application called vkQueueSubmit(). Here we wait for a fence with the same
1933 * value to materialize so that we can exporting (typically as a SyncFD).
1934 */
1935 static VkResult
1936 wait_syncobj_materialize(struct anv_device *device,
1937 uint32_t syncobj,
1938 int *fd)
1939 {
1940 if (!device->has_thread_submit)
1941 return VK_SUCCESS;
1942
1943 uint64_t binary_value = 0;
1944 /* We might need to wait until the fence materializes before we can
1945 * export to a sync FD when we use a thread for submission.
1946 */
1947 if (anv_gem_syncobj_timeline_wait(device, &syncobj, &binary_value, 1,
1948 anv_get_absolute_timeout(5ull * NSEC_PER_SEC),
1949 true /* wait_all */,
1950 true /* wait_materialize */))
1951 return anv_device_set_lost(device, "anv_gem_syncobj_timeline_wait failed: %m");
1952
1953 return VK_SUCCESS;
1954 }
1955
1956 VkResult anv_GetFenceFdKHR(
1957 VkDevice _device,
1958 const VkFenceGetFdInfoKHR* pGetFdInfo,
1959 int* pFd)
1960 {
1961 ANV_FROM_HANDLE(anv_device, device, _device);
1962 ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
1963
1964 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
1965
1966 struct anv_fence_impl *impl =
1967 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1968 &fence->temporary : &fence->permanent;
1969
1970 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
1971 switch (pGetFdInfo->handleType) {
1972 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: {
1973 int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
1974 if (fd < 0)
1975 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1976
1977 *pFd = fd;
1978 break;
1979 }
1980
1981 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
1982 VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);
1983 if (result != VK_SUCCESS)
1984 return result;
1985
1986 int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
1987 if (fd < 0)
1988 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1989
1990 *pFd = fd;
1991 break;
1992 }
1993
1994 default:
1995 unreachable("Invalid fence export handle type");
1996 }
1997
1998 /* From the Vulkan 1.0.53 spec:
1999 *
2000 * "Export operations have the same transference as the specified handle
2001 * type’s import operations. [...] If the fence was using a
2002 * temporarily imported payload, the fence’s prior permanent payload
2003 * will be restored.
2004 */
2005 if (impl == &fence->temporary)
2006 anv_fence_impl_cleanup(device, impl);
2007
2008 return VK_SUCCESS;
2009 }
2010
2011 // Queue semaphore functions
2012
2013 static VkSemaphoreTypeKHR
2014 get_semaphore_type(const void *pNext, uint64_t *initial_value)
2015 {
2016 const VkSemaphoreTypeCreateInfoKHR *type_info =
2017 vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);
2018
2019 if (!type_info)
2020 return VK_SEMAPHORE_TYPE_BINARY_KHR;
2021
2022 if (initial_value)
2023 *initial_value = type_info->initialValue;
2024 return type_info->semaphoreType;
2025 }
2026
2027 static VkResult
2028 binary_semaphore_create(struct anv_device *device,
2029 struct anv_semaphore_impl *impl,
2030 bool exportable)
2031 {
2032 if (device->physical->has_syncobj) {
2033 impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
2034 impl->syncobj = anv_gem_syncobj_create(device, 0);
2035 if (!impl->syncobj)
2036 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2037 return VK_SUCCESS;
2038 } else {
2039 impl->type = ANV_SEMAPHORE_TYPE_BO;
2040 VkResult result =
2041 anv_device_alloc_bo(device, 4096,
2042 ANV_BO_ALLOC_EXTERNAL |
2043 ANV_BO_ALLOC_IMPLICIT_SYNC,
2044 0 /* explicit_address */,
2045 &impl->bo);
2046 /* If we're going to use this as a fence, we need to *not* have the
2047 * EXEC_OBJECT_ASYNC bit set.
2048 */
2049 assert(!(impl->bo->flags & EXEC_OBJECT_ASYNC));
2050 return result;
2051 }
2052 }
2053
2054 static VkResult
2055 timeline_semaphore_create(struct anv_device *device,
2056 struct anv_semaphore_impl *impl,
2057 uint64_t initial_value)
2058 {
2059 if (device->has_thread_submit) {
2060 impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE;
2061 impl->syncobj = anv_gem_syncobj_create(device, 0);
2062 if (!impl->syncobj)
2063 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2064 if (initial_value) {
2065 if (anv_gem_syncobj_timeline_signal(device,
2066 &impl->syncobj,
2067 &initial_value, 1)) {
2068 anv_gem_syncobj_destroy(device, impl->syncobj);
2069 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2070 }
2071 }
2072 } else {
2073 impl->type = ANV_SEMAPHORE_TYPE_TIMELINE;
2074 anv_timeline_init(device, &impl->timeline, initial_value);
2075 }
2076
2077 return VK_SUCCESS;
2078 }
2079
2080 VkResult anv_CreateSemaphore(
2081 VkDevice _device,
2082 const VkSemaphoreCreateInfo* pCreateInfo,
2083 const VkAllocationCallbacks* pAllocator,
2084 VkSemaphore* pSemaphore)
2085 {
2086 ANV_FROM_HANDLE(anv_device, device, _device);
2087 struct anv_semaphore *semaphore;
2088
2089 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
2090
2091 uint64_t timeline_value = 0;
2092 VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);
2093
2094 semaphore = vk_alloc(&device->vk.alloc, sizeof(*semaphore), 8,
2095 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
2096 if (semaphore == NULL)
2097 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2098
2099 vk_object_base_init(&device->vk, &semaphore->base, VK_OBJECT_TYPE_SEMAPHORE);
2100
2101 p_atomic_set(&semaphore->refcount, 1);
2102
2103 const VkExportSemaphoreCreateInfo *export =
2104 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
2105 VkExternalSemaphoreHandleTypeFlags handleTypes =
2106 export ? export->handleTypes : 0;
2107 VkResult result;
2108
2109 if (handleTypes == 0) {
2110 if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
2111 result = binary_semaphore_create(device, &semaphore->permanent, false);
2112 else
2113 result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
2114 if (result != VK_SUCCESS) {
2115 vk_free2(&device->vk.alloc, pAllocator, semaphore);
2116 return result;
2117 }
2118 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
2119 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
2120 if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
2121 result = binary_semaphore_create(device, &semaphore->permanent, true);
2122 else
2123 result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
2124 if (result != VK_SUCCESS) {
2125 vk_free2(&device->vk.alloc, pAllocator, semaphore);
2126 return result;
2127 }
2128 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
2129 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT);
2130 assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);
2131 if (device->physical->has_syncobj) {
2132 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
2133 semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
2134 if (!semaphore->permanent.syncobj) {
2135 vk_free2(&device->vk.alloc, pAllocator, semaphore);
2136 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2137 }
2138 } else {
2139 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
2140 semaphore->permanent.fd = -1;
2141 }
2142 } else {
2143 assert(!"Unknown handle type");
2144 vk_free2(&device->vk.alloc, pAllocator, semaphore);
2145 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2146 }
2147
2148 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
2149
2150 *pSemaphore = anv_semaphore_to_handle(semaphore);
2151
2152 return VK_SUCCESS;
2153 }
2154
2155 static void
2156 anv_semaphore_impl_cleanup(struct anv_device *device,
2157 struct anv_semaphore_impl *impl)
2158 {
2159 switch (impl->type) {
2160 case ANV_SEMAPHORE_TYPE_NONE:
2161 case ANV_SEMAPHORE_TYPE_DUMMY:
2162 /* Dummy. Nothing to do */
2163 break;
2164
2165 case ANV_SEMAPHORE_TYPE_BO:
2166 case ANV_SEMAPHORE_TYPE_WSI_BO:
2167 anv_device_release_bo(device, impl->bo);
2168 break;
2169
2170 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
2171 if (impl->fd >= 0)
2172 close(impl->fd);
2173 break;
2174
2175 case ANV_SEMAPHORE_TYPE_TIMELINE:
2176 anv_timeline_finish(device, &impl->timeline);
2177 break;
2178
2179 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
2180 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
2181 anv_gem_syncobj_destroy(device, impl->syncobj);
2182 break;
2183
2184 default:
2185 unreachable("Invalid semaphore type");
2186 }
2187
2188 impl->type = ANV_SEMAPHORE_TYPE_NONE;
2189 }
2190
2191 void
2192 anv_semaphore_reset_temporary(struct anv_device *device,
2193 struct anv_semaphore *semaphore)
2194 {
2195 if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
2196 return;
2197
2198 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
2199 }
2200
2201 static struct anv_semaphore *
2202 anv_semaphore_ref(struct anv_semaphore *semaphore)
2203 {
2204 assert(semaphore->refcount);
2205 p_atomic_inc(&semaphore->refcount);
2206 return semaphore;
2207 }
2208
2209 static void
2210 anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore)
2211 {
2212 if (!p_atomic_dec_zero(&semaphore->refcount))
2213 return;
2214
2215 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
2216 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
2217
2218 vk_object_base_finish(&semaphore->base);
2219 vk_free(&device->vk.alloc, semaphore);
2220 }
2221
2222 void anv_DestroySemaphore(
2223 VkDevice _device,
2224 VkSemaphore _semaphore,
2225 const VkAllocationCallbacks* pAllocator)
2226 {
2227 ANV_FROM_HANDLE(anv_device, device, _device);
2228 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
2229
2230 if (semaphore == NULL)
2231 return;
2232
2233 anv_semaphore_unref(device, semaphore);
2234 }
2235
2236 void anv_GetPhysicalDeviceExternalSemaphoreProperties(
2237 VkPhysicalDevice physicalDevice,
2238 const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
2239 VkExternalSemaphoreProperties* pExternalSemaphoreProperties)
2240 {
2241 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
2242
2243 VkSemaphoreTypeKHR sem_type =
2244 get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
2245
2246 switch (pExternalSemaphoreInfo->handleType) {
2247 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
2248 /* Timeline semaphores are not exportable, unless we have threaded
2249 * submission.
2250 */
2251 if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR && !device->has_thread_submit)
2252 break;
2253 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
2254 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2255 pExternalSemaphoreProperties->compatibleHandleTypes =
2256 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2257 pExternalSemaphoreProperties->externalSemaphoreFeatures =
2258 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
2259 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
2260 return;
2261
2262 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
2263 if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
2264 break;
2265 if (!device->has_exec_fence)
2266 break;
2267 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
2268 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
2269 pExternalSemaphoreProperties->compatibleHandleTypes =
2270 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
2271 pExternalSemaphoreProperties->externalSemaphoreFeatures =
2272 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
2273 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
2274 return;
2275
2276 default:
2277 break;
2278 }
2279
2280 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
2281 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
2282 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
2283 }
2284
2285 VkResult anv_ImportSemaphoreFdKHR(
2286 VkDevice _device,
2287 const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
2288 {
2289 ANV_FROM_HANDLE(anv_device, device, _device);
2290 ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
2291 int fd = pImportSemaphoreFdInfo->fd;
2292
2293 struct anv_semaphore_impl new_impl = {
2294 .type = ANV_SEMAPHORE_TYPE_NONE,
2295 };
2296
2297 switch (pImportSemaphoreFdInfo->handleType) {
2298 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
2299 if (device->physical->has_syncobj) {
2300 /* When importing non temporarily, reuse the semaphore's existing
2301 * type. The Linux/DRM implementation allows to interchangeably use
2302 * binary & timeline semaphores and we have no way to differenciate
2303 * them.
2304 */
2305 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT)
2306 new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
2307 else
2308 new_impl.type = semaphore->permanent.type;
2309
2310 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
2311 if (!new_impl.syncobj)
2312 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2313 } else {
2314 new_impl.type = ANV_SEMAPHORE_TYPE_BO;
2315
2316 VkResult result = anv_device_import_bo(device, fd,
2317 ANV_BO_ALLOC_EXTERNAL |
2318 ANV_BO_ALLOC_IMPLICIT_SYNC,
2319 0 /* client_address */,
2320 &new_impl.bo);
2321 if (result != VK_SUCCESS)
2322 return result;
2323
2324 if (new_impl.bo->size < 4096) {
2325 anv_device_release_bo(device, new_impl.bo);
2326 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2327 }
2328
2329 /* If we're going to use this as a fence, we need to *not* have the
2330 * EXEC_OBJECT_ASYNC bit set.
2331 */
2332 assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
2333 }
2334
2335 /* From the Vulkan spec:
2336 *
2337 * "Importing semaphore state from a file descriptor transfers
2338 * ownership of the file descriptor from the application to the
2339 * Vulkan implementation. The application must not perform any
2340 * operations on the file descriptor after a successful import."
2341 *
2342 * If the import fails, we leave the file descriptor open.
2343 */
2344 close(fd);
2345 break;
2346
2347 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
2348 if (device->physical->has_syncobj) {
2349 uint32_t create_flags = 0;
2350
2351 if (fd == -1)
2352 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
2353
2354 new_impl = (struct anv_semaphore_impl) {
2355 .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
2356 .syncobj = anv_gem_syncobj_create(device, create_flags),
2357 };
2358
2359 if (!new_impl.syncobj)
2360 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2361
2362 if (fd != -1) {
2363 if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
2364 anv_gem_syncobj_destroy(device, new_impl.syncobj);
2365 return vk_errorf(device, NULL, VK_ERROR_INVALID_EXTERNAL_HANDLE,
2366 "syncobj sync file import failed: %m");
2367 }
2368 /* Ownership of the FD is transfered to Anv. Since we don't need it
2369 * anymore because the associated fence has been put into a syncobj,
2370 * we must close the FD.
2371 */
2372 close(fd);
2373 }
2374 } else {
2375 new_impl = (struct anv_semaphore_impl) {
2376 .type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
2377 .fd = fd,
2378 };
2379 }
2380 break;
2381
2382 default:
2383 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2384 }
2385
2386 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
2387 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
2388 semaphore->temporary = new_impl;
2389 } else {
2390 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
2391 semaphore->permanent = new_impl;
2392 }
2393
2394 return VK_SUCCESS;
2395 }
2396
2397 VkResult anv_GetSemaphoreFdKHR(
2398 VkDevice _device,
2399 const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
2400 int* pFd)
2401 {
2402 ANV_FROM_HANDLE(anv_device, device, _device);
2403 ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
2404 VkResult result;
2405 int fd;
2406
2407 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
2408
2409 struct anv_semaphore_impl *impl =
2410 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2411 &semaphore->temporary : &semaphore->permanent;
2412
2413 switch (impl->type) {
2414 case ANV_SEMAPHORE_TYPE_BO:
2415 result = anv_device_export_bo(device, impl->bo, pFd);
2416 if (result != VK_SUCCESS)
2417 return result;
2418 break;
2419
2420 case ANV_SEMAPHORE_TYPE_SYNC_FILE: {
2421 /* There's a potential race here with vkQueueSubmit if you are trying
2422 * to export a semaphore Fd while the queue submit is still happening.
2423 * This can happen if we see all dependencies get resolved via timeline
2424 * semaphore waits completing before the execbuf completes and we
2425 * process the resulting out fence. To work around this, take a lock
2426 * around grabbing the fd.
2427 */
2428 pthread_mutex_lock(&device->mutex);
2429
2430 /* From the Vulkan 1.0.53 spec:
2431 *
2432 * "...exporting a semaphore payload to a handle with copy
2433 * transference has the same side effects on the source
2434 * semaphore’s payload as executing a semaphore wait operation."
2435 *
2436 * In other words, it may still be a SYNC_FD semaphore, but it's now
2437 * considered to have been waited on and no longer has a sync file
2438 * attached.
2439 */
2440 int fd = impl->fd;
2441 impl->fd = -1;
2442
2443 pthread_mutex_unlock(&device->mutex);
2444
2445 /* There are two reasons why this could happen:
2446 *
2447 * 1) The user is trying to export without submitting something that
2448 * signals the semaphore. If this is the case, it's their bug so
2449 * what we return here doesn't matter.
2450 *
2451 * 2) The kernel didn't give us a file descriptor. The most likely
2452 * reason for this is running out of file descriptors.
2453 */
2454 if (fd < 0)
2455 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2456
2457 *pFd = fd;
2458 return VK_SUCCESS;
2459 }
2460
2461 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
2462 if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
2463 VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);
2464 if (result != VK_SUCCESS)
2465 return result;
2466
2467 fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
2468 } else {
2469 assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
2470 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
2471 }
2472 if (fd < 0)
2473 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2474 *pFd = fd;
2475 break;
2476
2477 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
2478 assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
2479 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
2480 if (fd < 0)
2481 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2482 *pFd = fd;
2483 break;
2484
2485 default:
2486 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2487 }
2488
2489 /* From the Vulkan 1.0.53 spec:
2490 *
2491 * "Export operations have the same transference as the specified handle
2492 * type’s import operations. [...] If the semaphore was using a
2493 * temporarily imported payload, the semaphore’s prior permanent payload
2494 * will be restored.
2495 */
2496 if (impl == &semaphore->temporary)
2497 anv_semaphore_impl_cleanup(device, impl);
2498
2499 return VK_SUCCESS;
2500 }
2501
2502 VkResult anv_GetSemaphoreCounterValue(
2503 VkDevice _device,
2504 VkSemaphore _semaphore,
2505 uint64_t* pValue)
2506 {
2507 ANV_FROM_HANDLE(anv_device, device, _device);
2508 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
2509
2510 struct anv_semaphore_impl *impl =
2511 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2512 &semaphore->temporary : &semaphore->permanent;
2513
2514 switch (impl->type) {
2515 case ANV_SEMAPHORE_TYPE_TIMELINE: {
2516 pthread_mutex_lock(&device->mutex);
2517 anv_timeline_gc_locked(device, &impl->timeline);
2518 *pValue = impl->timeline.highest_past;
2519 pthread_mutex_unlock(&device->mutex);
2520 return VK_SUCCESS;
2521 }
2522
2523 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {
2524 int ret = anv_gem_syncobj_timeline_query(device, &impl->syncobj, pValue, 1);
2525
2526 if (ret != 0)
2527 return anv_device_set_lost(device, "unable to query timeline syncobj");
2528
2529 return VK_SUCCESS;
2530 }
2531
2532 default:
2533 unreachable("Invalid semaphore type");
2534 }
2535 }
2536
2537 static VkResult
2538 anv_timeline_wait_locked(struct anv_device *device,
2539 struct anv_timeline *timeline,
2540 uint64_t serial, uint64_t abs_timeout_ns)
2541 {
2542 /* Wait on the queue_submit condition variable until the timeline has a
2543 * time point pending that's at least as high as serial.
2544 */
2545 while (timeline->highest_pending < serial) {
2546 struct timespec abstime = {
2547 .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
2548 .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
2549 };
2550
2551 UNUSED int ret = pthread_cond_timedwait(&device->queue_submit,
2552 &device->mutex, &abstime);
2553 assert(ret != EINVAL);
2554 if (anv_gettime_ns() >= abs_timeout_ns &&
2555 timeline->highest_pending < serial)
2556 return VK_TIMEOUT;
2557 }
2558
2559 while (1) {
2560 VkResult result = anv_timeline_gc_locked(device, timeline);
2561 if (result != VK_SUCCESS)
2562 return result;
2563
2564 if (timeline->highest_past >= serial)
2565 return VK_SUCCESS;
2566
2567 /* If we got here, our earliest time point has a busy BO */
2568 struct anv_timeline_point *point =
2569 list_first_entry(&timeline->points,
2570 struct anv_timeline_point, link);
2571
2572 /* Drop the lock while we wait. */
2573 point->waiting++;
2574 pthread_mutex_unlock(&device->mutex);
2575
2576 result = anv_device_wait(device, point->bo,
2577 anv_get_relative_timeout(abs_timeout_ns));
2578
2579 /* Pick the mutex back up */
2580 pthread_mutex_lock(&device->mutex);
2581 point->waiting--;
2582
2583 /* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */
2584 if (result != VK_SUCCESS)
2585 return result;
2586 }
2587 }
2588
2589 static VkResult
2590 anv_timelines_wait(struct anv_device *device,
2591 struct anv_timeline **timelines,
2592 const uint64_t *serials,
2593 uint32_t n_timelines,
2594 bool wait_all,
2595 uint64_t abs_timeout_ns)
2596 {
2597 if (!wait_all && n_timelines > 1) {
2598 pthread_mutex_lock(&device->mutex);
2599
2600 while (1) {
2601 VkResult result;
2602 for (uint32_t i = 0; i < n_timelines; i++) {
2603 result =
2604 anv_timeline_wait_locked(device, timelines[i], serials[i], 0);
2605 if (result != VK_TIMEOUT)
2606 break;
2607 }
2608
2609 if (result != VK_TIMEOUT ||
2610 anv_gettime_ns() >= abs_timeout_ns) {
2611 pthread_mutex_unlock(&device->mutex);
2612 return result;
2613 }
2614
2615 /* If none of them are ready do a short wait so we don't completely
2616 * spin while holding the lock. The 10us is completely arbitrary.
2617 */
2618 uint64_t abs_short_wait_ns =
2619 anv_get_absolute_timeout(
2620 MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000));
2621 struct timespec abstime = {
2622 .tv_sec = abs_short_wait_ns / NSEC_PER_SEC,
2623 .tv_nsec = abs_short_wait_ns % NSEC_PER_SEC,
2624 };
2625 ASSERTED int ret;
2626 ret = pthread_cond_timedwait(&device->queue_submit,
2627 &device->mutex, &abstime);
2628 assert(ret != EINVAL);
2629 }
2630 } else {
2631 VkResult result = VK_SUCCESS;
2632 pthread_mutex_lock(&device->mutex);
2633 for (uint32_t i = 0; i < n_timelines; i++) {
2634 result =
2635 anv_timeline_wait_locked(device, timelines[i],
2636 serials[i], abs_timeout_ns);
2637 if (result != VK_SUCCESS)
2638 break;
2639 }
2640 pthread_mutex_unlock(&device->mutex);
2641 return result;
2642 }
2643 }
2644
2645 VkResult anv_WaitSemaphores(
2646 VkDevice _device,
2647 const VkSemaphoreWaitInfoKHR* pWaitInfo,
2648 uint64_t timeout)
2649 {
2650 ANV_FROM_HANDLE(anv_device, device, _device);
2651 uint32_t *handles;
2652 struct anv_timeline **timelines;
2653 uint64_t *values;
2654
2655 ANV_MULTIALLOC(ma);
2656
2657 anv_multialloc_add(&ma, &values, pWaitInfo->semaphoreCount);
2658 if (device->has_thread_submit) {
2659 anv_multialloc_add(&ma, &handles, pWaitInfo->semaphoreCount);
2660 } else {
2661 anv_multialloc_add(&ma, &timelines, pWaitInfo->semaphoreCount);
2662 }
2663
2664 if (!anv_multialloc_alloc(&ma, &device->vk.alloc,
2665 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND))
2666 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2667
2668 uint32_t handle_count = 0;
2669 for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) {
2670 ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]);
2671 struct anv_semaphore_impl *impl =
2672 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2673 &semaphore->temporary : &semaphore->permanent;
2674
2675 if (pWaitInfo->pValues[i] == 0)
2676 continue;
2677
2678 if (device->has_thread_submit) {
2679 assert(impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE);
2680 handles[handle_count] = impl->syncobj;
2681 } else {
2682 assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE);
2683 timelines[handle_count] = &impl->timeline;
2684 }
2685 values[handle_count] = pWaitInfo->pValues[i];
2686 handle_count++;
2687 }
2688
2689 VkResult result = VK_SUCCESS;
2690 if (handle_count > 0) {
2691 if (device->has_thread_submit) {
2692 int ret =
2693 anv_gem_syncobj_timeline_wait(device,
2694 handles, values, handle_count,
2695 anv_get_absolute_timeout(timeout),
2696 !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
2697 false);
2698 if (ret != 0)
2699 result = errno == ETIME ? VK_TIMEOUT :
2700 anv_device_set_lost(device, "unable to wait on timeline syncobj");
2701 } else {
2702 result =
2703 anv_timelines_wait(device, timelines, values, handle_count,
2704 !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
2705 anv_get_absolute_timeout(timeout));
2706 }
2707 }
2708
2709 vk_free(&device->vk.alloc, values);
2710
2711 return result;
2712 }
2713
2714 VkResult anv_SignalSemaphore(
2715 VkDevice _device,
2716 const VkSemaphoreSignalInfoKHR* pSignalInfo)
2717 {
2718 ANV_FROM_HANDLE(anv_device, device, _device);
2719 ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore);
2720
2721 struct anv_semaphore_impl *impl =
2722 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2723 &semaphore->temporary : &semaphore->permanent;
2724
2725 switch (impl->type) {
2726 case ANV_SEMAPHORE_TYPE_TIMELINE: {
2727 pthread_mutex_lock(&device->mutex);
2728
2729 VkResult result = anv_timeline_gc_locked(device, &impl->timeline);
2730
2731 assert(pSignalInfo->value > impl->timeline.highest_pending);
2732
2733 impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value;
2734
2735 if (result == VK_SUCCESS)
2736 result = anv_device_submit_deferred_locked(device);
2737
2738 pthread_cond_broadcast(&device->queue_submit);
2739 pthread_mutex_unlock(&device->mutex);
2740 return result;
2741 }
2742
2743 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {
2744 /* Timeline semaphores are created with a value of 0, so signaling on 0
2745 * is a waste of time.
2746 */
2747 if (pSignalInfo->value == 0)
2748 return VK_SUCCESS;
2749
2750 int ret = anv_gem_syncobj_timeline_signal(device, &impl->syncobj,
2751 &pSignalInfo->value, 1);
2752
2753 return ret == 0 ? VK_SUCCESS :
2754 anv_device_set_lost(device, "unable to signal timeline syncobj");
2755 }
2756
2757 default:
2758 unreachable("Invalid semaphore type");
2759 }
2760 }