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