anv: Add an anv_physical_device field to anv_device
[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->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->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->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->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->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 struct anv_device *device = queue->device;
568 struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
569 if (!submit)
570 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
571
572 bool has_syncobj_wait = device->physical->has_syncobj_wait;
573 VkResult result;
574 uint32_t syncobj;
575 struct anv_bo *batch_bo, *sync_bo;
576
577 if (has_syncobj_wait) {
578 syncobj = anv_gem_syncobj_create(device, 0);
579 if (!syncobj) {
580 result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
581 goto err_free_submit;
582 }
583
584 result = anv_queue_submit_add_syncobj(submit, device, syncobj,
585 I915_EXEC_FENCE_SIGNAL);
586 } else {
587 result = anv_device_alloc_bo(device, 4096,
588 ANV_BO_ALLOC_EXTERNAL |
589 ANV_BO_ALLOC_IMPLICIT_SYNC,
590 0 /* explicit_address */,
591 &sync_bo);
592 if (result != VK_SUCCESS)
593 goto err_free_submit;
594
595 result = anv_queue_submit_add_fence_bo(submit, sync_bo, true /* signal */);
596 }
597
598 if (result != VK_SUCCESS)
599 goto err_destroy_sync_primitive;
600
601 if (batch) {
602 uint32_t size = align_u32(batch->next - batch->start, 8);
603 result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo);
604 if (result != VK_SUCCESS)
605 goto err_destroy_sync_primitive;
606
607 memcpy(batch_bo->map, batch->start, size);
608 if (!device->info.has_llc)
609 gen_flush_range(batch_bo->map, size);
610
611 submit->simple_bo = batch_bo;
612 submit->simple_bo_size = size;
613 }
614
615 result = _anv_queue_submit(queue, &submit, true);
616
617 if (result == VK_SUCCESS) {
618 if (has_syncobj_wait) {
619 if (anv_gem_syncobj_wait(device, &syncobj, 1,
620 anv_get_absolute_timeout(INT64_MAX), true))
621 result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m");
622 anv_gem_syncobj_destroy(device, syncobj);
623 } else {
624 result = anv_device_wait(device, sync_bo,
625 anv_get_relative_timeout(INT64_MAX));
626 anv_device_release_bo(device, sync_bo);
627 }
628 }
629
630 if (batch)
631 anv_bo_pool_free(&device->batch_bo_pool, batch_bo);
632
633 if (submit)
634 anv_queue_submit_free(device, submit);
635
636 return result;
637
638 err_destroy_sync_primitive:
639 if (has_syncobj_wait)
640 anv_gem_syncobj_destroy(device, syncobj);
641 else
642 anv_device_release_bo(device, sync_bo);
643 err_free_submit:
644 if (submit)
645 anv_queue_submit_free(device, submit);
646
647 return result;
648 }
649
650 /* Transfer ownership of temporary semaphores from the VkSemaphore object to
651 * the anv_queue_submit object. Those temporary semaphores are then freed in
652 * anv_queue_submit_free() once the driver is finished with them.
653 */
654 static VkResult
655 maybe_transfer_temporary_semaphore(struct anv_queue_submit *submit,
656 struct anv_semaphore *semaphore,
657 struct anv_semaphore_impl **out_impl)
658 {
659 struct anv_semaphore_impl *impl = &semaphore->temporary;
660
661 if (impl->type == ANV_SEMAPHORE_TYPE_NONE) {
662 *out_impl = &semaphore->permanent;
663 return VK_SUCCESS;
664 }
665
666 /* BO backed timeline semaphores cannot be temporary. */
667 assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE);
668
669 /*
670 * There is a requirement to reset semaphore to their permanent state after
671 * submission. From the Vulkan 1.0.53 spec:
672 *
673 * "If the import is temporary, the implementation must restore the
674 * semaphore to its prior permanent state after submitting the next
675 * semaphore wait operation."
676 *
677 * In the case we defer the actual submission to a thread because of the
678 * wait-before-submit behavior required for timeline semaphores, we need to
679 * make copies of the temporary syncobj to ensure they stay alive until we
680 * do the actual execbuffer ioctl.
681 */
682 if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) {
683 uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8);
684 /* Make sure that if the realloc fails, we still have the old semaphore
685 * array around to properly clean things up on failure.
686 */
687 struct anv_semaphore_impl *new_array =
688 vk_realloc(submit->alloc,
689 submit->temporary_semaphores,
690 new_len * sizeof(*submit->temporary_semaphores),
691 8, submit->alloc_scope);
692 if (new_array == NULL)
693 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
694
695 submit->temporary_semaphores = new_array;
696 submit->temporary_semaphore_array_length = new_len;
697 }
698
699 /* Copy anv_semaphore_impl into anv_queue_submit. */
700 submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl;
701 *out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1];
702
703 /* Clear the incoming semaphore */
704 impl->type = ANV_SEMAPHORE_TYPE_NONE;
705
706 return VK_SUCCESS;
707 }
708
709 static VkResult
710 anv_queue_submit(struct anv_queue *queue,
711 struct anv_cmd_buffer *cmd_buffer,
712 const VkSemaphore *in_semaphores,
713 const uint64_t *in_values,
714 uint32_t num_in_semaphores,
715 const VkSemaphore *out_semaphores,
716 const uint64_t *out_values,
717 uint32_t num_out_semaphores,
718 struct anv_bo *wsi_signal_bo,
719 VkFence _fence)
720 {
721 ANV_FROM_HANDLE(anv_fence, fence, _fence);
722 struct anv_device *device = queue->device;
723 UNUSED struct anv_physical_device *pdevice = device->physical;
724 struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
725 if (!submit)
726 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
727
728 submit->cmd_buffer = cmd_buffer;
729
730 VkResult result = VK_SUCCESS;
731
732 for (uint32_t i = 0; i < num_in_semaphores; i++) {
733 ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
734 struct anv_semaphore_impl *impl;
735
736 result = maybe_transfer_temporary_semaphore(submit, semaphore, &impl);
737 if (result != VK_SUCCESS)
738 goto error;
739
740 switch (impl->type) {
741 case ANV_SEMAPHORE_TYPE_BO:
742 assert(!pdevice->has_syncobj);
743 result = anv_queue_submit_add_fence_bo(submit, impl->bo, false /* signal */);
744 if (result != VK_SUCCESS)
745 goto error;
746 break;
747
748 case ANV_SEMAPHORE_TYPE_WSI_BO:
749 /* When using a window-system buffer as a semaphore, always enable
750 * EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or
751 * compositor's read of the buffer and enforces that we don't start
752 * rendering until they are finished. This is exactly the
753 * synchronization we want with vkAcquireNextImage.
754 */
755 result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
756 if (result != VK_SUCCESS)
757 goto error;
758 break;
759
760 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
761 assert(!pdevice->has_syncobj);
762 if (submit->in_fence == -1) {
763 submit->in_fence = impl->fd;
764 if (submit->in_fence == -1) {
765 result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
766 goto error;
767 }
768 impl->fd = -1;
769 } else {
770 int merge = anv_gem_sync_file_merge(device, submit->in_fence, impl->fd);
771 if (merge == -1) {
772 result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
773 goto error;
774 }
775 close(impl->fd);
776 close(submit->in_fence);
777 impl->fd = -1;
778 submit->in_fence = merge;
779 }
780 break;
781
782 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
783 result = anv_queue_submit_add_syncobj(submit, device,
784 impl->syncobj,
785 I915_EXEC_FENCE_WAIT);
786 if (result != VK_SUCCESS)
787 goto error;
788 break;
789 }
790
791 case ANV_SEMAPHORE_TYPE_TIMELINE:
792 result = anv_queue_submit_add_timeline_wait(submit, device,
793 &impl->timeline,
794 in_values ? in_values[i] : 0);
795 if (result != VK_SUCCESS)
796 goto error;
797 break;
798
799 default:
800 break;
801 }
802 }
803
804 for (uint32_t i = 0; i < num_out_semaphores; i++) {
805 ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
806
807 /* Under most circumstances, out fences won't be temporary. However,
808 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
809 *
810 * "If the import is temporary, the implementation must restore the
811 * semaphore to its prior permanent state after submitting the next
812 * semaphore wait operation."
813 *
814 * The spec says nothing whatsoever about signal operations on
815 * temporarily imported semaphores so it appears they are allowed.
816 * There are also CTS tests that require this to work.
817 */
818 struct anv_semaphore_impl *impl =
819 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
820 &semaphore->temporary : &semaphore->permanent;
821
822 switch (impl->type) {
823 case ANV_SEMAPHORE_TYPE_BO:
824 assert(!pdevice->has_syncobj);
825 result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
826 if (result != VK_SUCCESS)
827 goto error;
828 break;
829
830 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
831 assert(!pdevice->has_syncobj);
832 result = anv_queue_submit_add_sync_fd_fence(submit, semaphore);
833 if (result != VK_SUCCESS)
834 goto error;
835 break;
836
837 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
838 result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
839 I915_EXEC_FENCE_SIGNAL);
840 if (result != VK_SUCCESS)
841 goto error;
842 break;
843 }
844
845 case ANV_SEMAPHORE_TYPE_TIMELINE:
846 result = anv_queue_submit_add_timeline_signal(submit, device,
847 &impl->timeline,
848 out_values ? out_values[i] : 0);
849 if (result != VK_SUCCESS)
850 goto error;
851 break;
852
853 default:
854 break;
855 }
856 }
857
858 if (wsi_signal_bo) {
859 result = anv_queue_submit_add_fence_bo(submit, wsi_signal_bo, true /* signal */);
860 if (result != VK_SUCCESS)
861 goto error;
862 }
863
864 if (fence) {
865 /* Under most circumstances, out fences won't be temporary. However,
866 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
867 *
868 * "If the import is temporary, the implementation must restore the
869 * semaphore to its prior permanent state after submitting the next
870 * semaphore wait operation."
871 *
872 * The spec says nothing whatsoever about signal operations on
873 * temporarily imported semaphores so it appears they are allowed.
874 * There are also CTS tests that require this to work.
875 */
876 struct anv_fence_impl *impl =
877 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
878 &fence->temporary : &fence->permanent;
879
880 switch (impl->type) {
881 case ANV_FENCE_TYPE_BO:
882 result = anv_queue_submit_add_fence_bo(submit, impl->bo.bo, true /* signal */);
883 if (result != VK_SUCCESS)
884 goto error;
885 break;
886
887 case ANV_FENCE_TYPE_SYNCOBJ: {
888 /*
889 * For the same reason we reset the signaled binary syncobj above,
890 * also reset the fence's syncobj so that they don't contain a
891 * signaled dma-fence.
892 */
893 result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
894 I915_EXEC_FENCE_SIGNAL);
895 if (result != VK_SUCCESS)
896 goto error;
897 break;
898 }
899
900 default:
901 unreachable("Invalid fence type");
902 }
903 }
904
905 result = _anv_queue_submit(queue, &submit, false);
906 if (result != VK_SUCCESS)
907 goto error;
908
909 if (fence && fence->permanent.type == ANV_FENCE_TYPE_BO) {
910 /* If we have permanent BO fence, the only type of temporary possible
911 * would be BO_WSI (because BO fences are not shareable). The Vulkan spec
912 * also requires that the fence passed to vkQueueSubmit() be :
913 *
914 * * unsignaled
915 * * not be associated with any other queue command that has not yet
916 * completed execution on that queue
917 *
918 * So the only acceptable type for the temporary is NONE.
919 */
920 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
921
922 /* Once the execbuf has returned, we need to set the fence state to
923 * SUBMITTED. We can't do this before calling execbuf because
924 * anv_GetFenceStatus does take the global device lock before checking
925 * fence->state.
926 *
927 * We set the fence state to SUBMITTED regardless of whether or not the
928 * execbuf succeeds because we need to ensure that vkWaitForFences() and
929 * vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or
930 * VK_SUCCESS) in a finite amount of time even if execbuf fails.
931 */
932 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED;
933 }
934
935 error:
936 if (submit)
937 anv_queue_submit_free(device, submit);
938
939 return result;
940 }
941
942 VkResult anv_QueueSubmit(
943 VkQueue _queue,
944 uint32_t submitCount,
945 const VkSubmitInfo* pSubmits,
946 VkFence fence)
947 {
948 ANV_FROM_HANDLE(anv_queue, queue, _queue);
949
950 /* Query for device status prior to submitting. Technically, we don't need
951 * to do this. However, if we have a client that's submitting piles of
952 * garbage, we would rather break as early as possible to keep the GPU
953 * hanging contained. If we don't check here, we'll either be waiting for
954 * the kernel to kick us or we'll have to wait until the client waits on a
955 * fence before we actually know whether or not we've hung.
956 */
957 VkResult result = anv_device_query_status(queue->device);
958 if (result != VK_SUCCESS)
959 return result;
960
961 if (fence && submitCount == 0) {
962 /* If we don't have any command buffers, we need to submit a dummy
963 * batch to give GEM something to wait on. We could, potentially,
964 * come up with something more efficient but this shouldn't be a
965 * common case.
966 */
967 result = anv_queue_submit(queue, NULL, NULL, NULL, 0, NULL, NULL, 0,
968 NULL, fence);
969 goto out;
970 }
971
972 for (uint32_t i = 0; i < submitCount; i++) {
973 /* Fence for this submit. NULL for all but the last one */
974 VkFence submit_fence = (i == submitCount - 1) ? fence : VK_NULL_HANDLE;
975
976 const struct wsi_memory_signal_submit_info *mem_signal_info =
977 vk_find_struct_const(pSubmits[i].pNext,
978 WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
979 struct anv_bo *wsi_signal_bo =
980 mem_signal_info && mem_signal_info->memory != VK_NULL_HANDLE ?
981 anv_device_memory_from_handle(mem_signal_info->memory)->bo : NULL;
982
983 const VkTimelineSemaphoreSubmitInfoKHR *timeline_info =
984 vk_find_struct_const(pSubmits[i].pNext,
985 TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR);
986 const uint64_t *wait_values =
987 timeline_info && timeline_info->waitSemaphoreValueCount ?
988 timeline_info->pWaitSemaphoreValues : NULL;
989 const uint64_t *signal_values =
990 timeline_info && timeline_info->signalSemaphoreValueCount ?
991 timeline_info->pSignalSemaphoreValues : NULL;
992
993 if (pSubmits[i].commandBufferCount == 0) {
994 /* If we don't have any command buffers, we need to submit a dummy
995 * batch to give GEM something to wait on. We could, potentially,
996 * come up with something more efficient but this shouldn't be a
997 * common case.
998 */
999 result = anv_queue_submit(queue, NULL,
1000 pSubmits[i].pWaitSemaphores,
1001 wait_values,
1002 pSubmits[i].waitSemaphoreCount,
1003 pSubmits[i].pSignalSemaphores,
1004 signal_values,
1005 pSubmits[i].signalSemaphoreCount,
1006 wsi_signal_bo,
1007 submit_fence);
1008 if (result != VK_SUCCESS)
1009 goto out;
1010
1011 continue;
1012 }
1013
1014 for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
1015 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
1016 pSubmits[i].pCommandBuffers[j]);
1017 assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1018 assert(!anv_batch_has_error(&cmd_buffer->batch));
1019
1020 /* Fence for this execbuf. NULL for all but the last one */
1021 VkFence execbuf_fence =
1022 (j == pSubmits[i].commandBufferCount - 1) ?
1023 submit_fence : VK_NULL_HANDLE;
1024
1025 const VkSemaphore *in_semaphores = NULL, *out_semaphores = NULL;
1026 const uint64_t *in_values = NULL, *out_values = NULL;
1027 uint32_t num_in_semaphores = 0, num_out_semaphores = 0;
1028 if (j == 0) {
1029 /* Only the first batch gets the in semaphores */
1030 in_semaphores = pSubmits[i].pWaitSemaphores;
1031 in_values = wait_values;
1032 num_in_semaphores = pSubmits[i].waitSemaphoreCount;
1033 }
1034
1035 if (j == pSubmits[i].commandBufferCount - 1) {
1036 /* Only the last batch gets the out semaphores */
1037 out_semaphores = pSubmits[i].pSignalSemaphores;
1038 out_values = signal_values;
1039 num_out_semaphores = pSubmits[i].signalSemaphoreCount;
1040 }
1041
1042 result = anv_queue_submit(queue, cmd_buffer,
1043 in_semaphores, in_values, num_in_semaphores,
1044 out_semaphores, out_values, num_out_semaphores,
1045 wsi_signal_bo, execbuf_fence);
1046 if (result != VK_SUCCESS)
1047 goto out;
1048 }
1049 }
1050
1051 out:
1052 if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) {
1053 /* In the case that something has gone wrong we may end up with an
1054 * inconsistent state from which it may not be trivial to recover.
1055 * For example, we might have computed address relocations and
1056 * any future attempt to re-submit this job will need to know about
1057 * this and avoid computing relocation addresses again.
1058 *
1059 * To avoid this sort of issues, we assume that if something was
1060 * wrong during submission we must already be in a really bad situation
1061 * anyway (such us being out of memory) and return
1062 * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
1063 * submit the same job again to this device.
1064 *
1065 * We skip doing this on VK_ERROR_DEVICE_LOST because
1066 * anv_device_set_lost() would have been called already by a callee of
1067 * anv_queue_submit().
1068 */
1069 result = anv_device_set_lost(queue->device, "vkQueueSubmit() failed");
1070 }
1071
1072 return result;
1073 }
1074
1075 VkResult anv_QueueWaitIdle(
1076 VkQueue _queue)
1077 {
1078 ANV_FROM_HANDLE(anv_queue, queue, _queue);
1079
1080 if (anv_device_is_lost(queue->device))
1081 return VK_ERROR_DEVICE_LOST;
1082
1083 return anv_queue_submit_simple_batch(queue, NULL);
1084 }
1085
1086 VkResult anv_CreateFence(
1087 VkDevice _device,
1088 const VkFenceCreateInfo* pCreateInfo,
1089 const VkAllocationCallbacks* pAllocator,
1090 VkFence* pFence)
1091 {
1092 ANV_FROM_HANDLE(anv_device, device, _device);
1093 struct anv_fence *fence;
1094
1095 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
1096
1097 fence = vk_zalloc2(&device->alloc, pAllocator, sizeof(*fence), 8,
1098 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
1099 if (fence == NULL)
1100 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1101
1102 if (device->physical->has_syncobj_wait) {
1103 fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
1104
1105 uint32_t create_flags = 0;
1106 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)
1107 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
1108
1109 fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);
1110 if (!fence->permanent.syncobj)
1111 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1112 } else {
1113 fence->permanent.type = ANV_FENCE_TYPE_BO;
1114
1115 VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096,
1116 &fence->permanent.bo.bo);
1117 if (result != VK_SUCCESS)
1118 return result;
1119
1120 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
1121 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1122 } else {
1123 fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
1124 }
1125 }
1126
1127 *pFence = anv_fence_to_handle(fence);
1128
1129 return VK_SUCCESS;
1130 }
1131
1132 static void
1133 anv_fence_impl_cleanup(struct anv_device *device,
1134 struct anv_fence_impl *impl)
1135 {
1136 switch (impl->type) {
1137 case ANV_FENCE_TYPE_NONE:
1138 /* Dummy. Nothing to do */
1139 break;
1140
1141 case ANV_FENCE_TYPE_BO:
1142 anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo);
1143 break;
1144
1145 case ANV_FENCE_TYPE_WSI_BO:
1146 anv_device_release_bo(device, impl->bo.bo);
1147 break;
1148
1149 case ANV_FENCE_TYPE_SYNCOBJ:
1150 anv_gem_syncobj_destroy(device, impl->syncobj);
1151 break;
1152
1153 case ANV_FENCE_TYPE_WSI:
1154 impl->fence_wsi->destroy(impl->fence_wsi);
1155 break;
1156
1157 default:
1158 unreachable("Invalid fence type");
1159 }
1160
1161 impl->type = ANV_FENCE_TYPE_NONE;
1162 }
1163
1164 void
1165 anv_fence_reset_temporary(struct anv_device *device,
1166 struct anv_fence *fence)
1167 {
1168 if (fence->temporary.type == ANV_FENCE_TYPE_NONE)
1169 return;
1170
1171 anv_fence_impl_cleanup(device, &fence->temporary);
1172 }
1173
1174 void anv_DestroyFence(
1175 VkDevice _device,
1176 VkFence _fence,
1177 const VkAllocationCallbacks* pAllocator)
1178 {
1179 ANV_FROM_HANDLE(anv_device, device, _device);
1180 ANV_FROM_HANDLE(anv_fence, fence, _fence);
1181
1182 if (!fence)
1183 return;
1184
1185 anv_fence_impl_cleanup(device, &fence->temporary);
1186 anv_fence_impl_cleanup(device, &fence->permanent);
1187
1188 vk_free2(&device->alloc, pAllocator, fence);
1189 }
1190
1191 VkResult anv_ResetFences(
1192 VkDevice _device,
1193 uint32_t fenceCount,
1194 const VkFence* pFences)
1195 {
1196 ANV_FROM_HANDLE(anv_device, device, _device);
1197
1198 for (uint32_t i = 0; i < fenceCount; i++) {
1199 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1200
1201 /* From the Vulkan 1.0.53 spec:
1202 *
1203 * "If any member of pFences currently has its payload imported with
1204 * temporary permanence, that fence’s prior permanent payload is
1205 * first restored. The remaining operations described therefore
1206 * operate on the restored payload.
1207 */
1208 anv_fence_reset_temporary(device, fence);
1209
1210 struct anv_fence_impl *impl = &fence->permanent;
1211
1212 switch (impl->type) {
1213 case ANV_FENCE_TYPE_BO:
1214 impl->bo.state = ANV_BO_FENCE_STATE_RESET;
1215 break;
1216
1217 case ANV_FENCE_TYPE_SYNCOBJ:
1218 anv_gem_syncobj_reset(device, impl->syncobj);
1219 break;
1220
1221 default:
1222 unreachable("Invalid fence type");
1223 }
1224 }
1225
1226 return VK_SUCCESS;
1227 }
1228
1229 VkResult anv_GetFenceStatus(
1230 VkDevice _device,
1231 VkFence _fence)
1232 {
1233 ANV_FROM_HANDLE(anv_device, device, _device);
1234 ANV_FROM_HANDLE(anv_fence, fence, _fence);
1235
1236 if (anv_device_is_lost(device))
1237 return VK_ERROR_DEVICE_LOST;
1238
1239 struct anv_fence_impl *impl =
1240 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1241 &fence->temporary : &fence->permanent;
1242
1243 switch (impl->type) {
1244 case ANV_FENCE_TYPE_BO:
1245 case ANV_FENCE_TYPE_WSI_BO:
1246 switch (impl->bo.state) {
1247 case ANV_BO_FENCE_STATE_RESET:
1248 /* If it hasn't even been sent off to the GPU yet, it's not ready */
1249 return VK_NOT_READY;
1250
1251 case ANV_BO_FENCE_STATE_SIGNALED:
1252 /* It's been signaled, return success */
1253 return VK_SUCCESS;
1254
1255 case ANV_BO_FENCE_STATE_SUBMITTED: {
1256 VkResult result = anv_device_bo_busy(device, impl->bo.bo);
1257 if (result == VK_SUCCESS) {
1258 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1259 return VK_SUCCESS;
1260 } else {
1261 return result;
1262 }
1263 }
1264 default:
1265 unreachable("Invalid fence status");
1266 }
1267
1268 case ANV_FENCE_TYPE_SYNCOBJ: {
1269 int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);
1270 if (ret == -1) {
1271 if (errno == ETIME) {
1272 return VK_NOT_READY;
1273 } else {
1274 /* We don't know the real error. */
1275 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1276 }
1277 } else {
1278 return VK_SUCCESS;
1279 }
1280 }
1281
1282 default:
1283 unreachable("Invalid fence type");
1284 }
1285 }
1286
1287 static VkResult
1288 anv_wait_for_syncobj_fences(struct anv_device *device,
1289 uint32_t fenceCount,
1290 const VkFence *pFences,
1291 bool waitAll,
1292 uint64_t abs_timeout_ns)
1293 {
1294 uint32_t *syncobjs = vk_zalloc(&device->alloc,
1295 sizeof(*syncobjs) * fenceCount, 8,
1296 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1297 if (!syncobjs)
1298 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1299
1300 for (uint32_t i = 0; i < fenceCount; i++) {
1301 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1302 assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
1303
1304 struct anv_fence_impl *impl =
1305 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1306 &fence->temporary : &fence->permanent;
1307
1308 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
1309 syncobjs[i] = impl->syncobj;
1310 }
1311
1312 /* The gem_syncobj_wait ioctl may return early due to an inherent
1313 * limitation in the way it computes timeouts. Loop until we've actually
1314 * passed the timeout.
1315 */
1316 int ret;
1317 do {
1318 ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
1319 abs_timeout_ns, waitAll);
1320 } while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns);
1321
1322 vk_free(&device->alloc, syncobjs);
1323
1324 if (ret == -1) {
1325 if (errno == ETIME) {
1326 return VK_TIMEOUT;
1327 } else {
1328 /* We don't know the real error. */
1329 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1330 }
1331 } else {
1332 return VK_SUCCESS;
1333 }
1334 }
1335
1336 static VkResult
1337 anv_wait_for_bo_fences(struct anv_device *device,
1338 uint32_t fenceCount,
1339 const VkFence *pFences,
1340 bool waitAll,
1341 uint64_t abs_timeout_ns)
1342 {
1343 VkResult result = VK_SUCCESS;
1344 uint32_t pending_fences = fenceCount;
1345 while (pending_fences) {
1346 pending_fences = 0;
1347 bool signaled_fences = false;
1348 for (uint32_t i = 0; i < fenceCount; i++) {
1349 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1350
1351 struct anv_fence_impl *impl =
1352 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1353 &fence->temporary : &fence->permanent;
1354 assert(impl->type == ANV_FENCE_TYPE_BO ||
1355 impl->type == ANV_FENCE_TYPE_WSI_BO);
1356
1357 switch (impl->bo.state) {
1358 case ANV_BO_FENCE_STATE_RESET:
1359 /* This fence hasn't been submitted yet, we'll catch it the next
1360 * time around. Yes, this may mean we dead-loop but, short of
1361 * lots of locking and a condition variable, there's not much that
1362 * we can do about that.
1363 */
1364 pending_fences++;
1365 continue;
1366
1367 case ANV_BO_FENCE_STATE_SIGNALED:
1368 /* This fence is not pending. If waitAll isn't set, we can return
1369 * early. Otherwise, we have to keep going.
1370 */
1371 if (!waitAll) {
1372 result = VK_SUCCESS;
1373 goto done;
1374 }
1375 continue;
1376
1377 case ANV_BO_FENCE_STATE_SUBMITTED:
1378 /* These are the fences we really care about. Go ahead and wait
1379 * on it until we hit a timeout.
1380 */
1381 result = anv_device_wait(device, impl->bo.bo,
1382 anv_get_relative_timeout(abs_timeout_ns));
1383 switch (result) {
1384 case VK_SUCCESS:
1385 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1386 signaled_fences = true;
1387 if (!waitAll)
1388 goto done;
1389 break;
1390
1391 case VK_TIMEOUT:
1392 goto done;
1393
1394 default:
1395 return result;
1396 }
1397 }
1398 }
1399
1400 if (pending_fences && !signaled_fences) {
1401 /* If we've hit this then someone decided to vkWaitForFences before
1402 * they've actually submitted any of them to a queue. This is a
1403 * fairly pessimal case, so it's ok to lock here and use a standard
1404 * pthreads condition variable.
1405 */
1406 pthread_mutex_lock(&device->mutex);
1407
1408 /* It's possible that some of the fences have changed state since the
1409 * last time we checked. Now that we have the lock, check for
1410 * pending fences again and don't wait if it's changed.
1411 */
1412 uint32_t now_pending_fences = 0;
1413 for (uint32_t i = 0; i < fenceCount; i++) {
1414 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1415 if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
1416 now_pending_fences++;
1417 }
1418 assert(now_pending_fences <= pending_fences);
1419
1420 if (now_pending_fences == pending_fences) {
1421 struct timespec abstime = {
1422 .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
1423 .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
1424 };
1425
1426 ASSERTED int ret;
1427 ret = pthread_cond_timedwait(&device->queue_submit,
1428 &device->mutex, &abstime);
1429 assert(ret != EINVAL);
1430 if (anv_gettime_ns() >= abs_timeout_ns) {
1431 pthread_mutex_unlock(&device->mutex);
1432 result = VK_TIMEOUT;
1433 goto done;
1434 }
1435 }
1436
1437 pthread_mutex_unlock(&device->mutex);
1438 }
1439 }
1440
1441 done:
1442 if (anv_device_is_lost(device))
1443 return VK_ERROR_DEVICE_LOST;
1444
1445 return result;
1446 }
1447
1448 static VkResult
1449 anv_wait_for_wsi_fence(struct anv_device *device,
1450 struct anv_fence_impl *impl,
1451 uint64_t abs_timeout)
1452 {
1453 return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout);
1454 }
1455
1456 static VkResult
1457 anv_wait_for_fences(struct anv_device *device,
1458 uint32_t fenceCount,
1459 const VkFence *pFences,
1460 bool waitAll,
1461 uint64_t abs_timeout)
1462 {
1463 VkResult result = VK_SUCCESS;
1464
1465 if (fenceCount <= 1 || waitAll) {
1466 for (uint32_t i = 0; i < fenceCount; i++) {
1467 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1468 struct anv_fence_impl *impl =
1469 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1470 &fence->temporary : &fence->permanent;
1471
1472 switch (impl->type) {
1473 case ANV_FENCE_TYPE_BO:
1474 case ANV_FENCE_TYPE_WSI_BO:
1475 result = anv_wait_for_bo_fences(device, 1, &pFences[i],
1476 true, abs_timeout);
1477 break;
1478 case ANV_FENCE_TYPE_SYNCOBJ:
1479 result = anv_wait_for_syncobj_fences(device, 1, &pFences[i],
1480 true, abs_timeout);
1481 break;
1482 case ANV_FENCE_TYPE_WSI:
1483 result = anv_wait_for_wsi_fence(device, impl, abs_timeout);
1484 break;
1485 case ANV_FENCE_TYPE_NONE:
1486 result = VK_SUCCESS;
1487 break;
1488 }
1489 if (result != VK_SUCCESS)
1490 return result;
1491 }
1492 } else {
1493 do {
1494 for (uint32_t i = 0; i < fenceCount; i++) {
1495 if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS)
1496 return VK_SUCCESS;
1497 }
1498 } while (anv_gettime_ns() < abs_timeout);
1499 result = VK_TIMEOUT;
1500 }
1501 return result;
1502 }
1503
1504 static bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences)
1505 {
1506 for (uint32_t i = 0; i < fenceCount; ++i) {
1507 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1508 struct anv_fence_impl *impl =
1509 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1510 &fence->temporary : &fence->permanent;
1511 if (impl->type != ANV_FENCE_TYPE_SYNCOBJ)
1512 return false;
1513 }
1514 return true;
1515 }
1516
1517 static bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences)
1518 {
1519 for (uint32_t i = 0; i < fenceCount; ++i) {
1520 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1521 struct anv_fence_impl *impl =
1522 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1523 &fence->temporary : &fence->permanent;
1524 if (impl->type != ANV_FENCE_TYPE_BO &&
1525 impl->type != ANV_FENCE_TYPE_WSI_BO)
1526 return false;
1527 }
1528 return true;
1529 }
1530
1531 VkResult anv_WaitForFences(
1532 VkDevice _device,
1533 uint32_t fenceCount,
1534 const VkFence* pFences,
1535 VkBool32 waitAll,
1536 uint64_t timeout)
1537 {
1538 ANV_FROM_HANDLE(anv_device, device, _device);
1539
1540 if (anv_device_is_lost(device))
1541 return VK_ERROR_DEVICE_LOST;
1542
1543 uint64_t abs_timeout = anv_get_absolute_timeout(timeout);
1544 if (anv_all_fences_syncobj(fenceCount, pFences)) {
1545 return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
1546 waitAll, abs_timeout);
1547 } else if (anv_all_fences_bo(fenceCount, pFences)) {
1548 return anv_wait_for_bo_fences(device, fenceCount, pFences,
1549 waitAll, abs_timeout);
1550 } else {
1551 return anv_wait_for_fences(device, fenceCount, pFences,
1552 waitAll, abs_timeout);
1553 }
1554 }
1555
1556 void anv_GetPhysicalDeviceExternalFenceProperties(
1557 VkPhysicalDevice physicalDevice,
1558 const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
1559 VkExternalFenceProperties* pExternalFenceProperties)
1560 {
1561 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
1562
1563 switch (pExternalFenceInfo->handleType) {
1564 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
1565 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
1566 if (device->has_syncobj_wait) {
1567 pExternalFenceProperties->exportFromImportedHandleTypes =
1568 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1569 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1570 pExternalFenceProperties->compatibleHandleTypes =
1571 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1572 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1573 pExternalFenceProperties->externalFenceFeatures =
1574 VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT |
1575 VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT;
1576 return;
1577 }
1578 break;
1579
1580 default:
1581 break;
1582 }
1583
1584 pExternalFenceProperties->exportFromImportedHandleTypes = 0;
1585 pExternalFenceProperties->compatibleHandleTypes = 0;
1586 pExternalFenceProperties->externalFenceFeatures = 0;
1587 }
1588
1589 VkResult anv_ImportFenceFdKHR(
1590 VkDevice _device,
1591 const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
1592 {
1593 ANV_FROM_HANDLE(anv_device, device, _device);
1594 ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
1595 int fd = pImportFenceFdInfo->fd;
1596
1597 assert(pImportFenceFdInfo->sType ==
1598 VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
1599
1600 struct anv_fence_impl new_impl = {
1601 .type = ANV_FENCE_TYPE_NONE,
1602 };
1603
1604 switch (pImportFenceFdInfo->handleType) {
1605 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
1606 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
1607
1608 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
1609 if (!new_impl.syncobj)
1610 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1611
1612 break;
1613
1614 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
1615 /* Sync files are a bit tricky. Because we want to continue using the
1616 * syncobj implementation of WaitForFences, we don't use the sync file
1617 * directly but instead import it into a syncobj.
1618 */
1619 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
1620
1621 new_impl.syncobj = anv_gem_syncobj_create(device, 0);
1622 if (!new_impl.syncobj)
1623 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1624
1625 if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
1626 anv_gem_syncobj_destroy(device, new_impl.syncobj);
1627 return vk_errorf(device->instance, NULL,
1628 VK_ERROR_INVALID_EXTERNAL_HANDLE,
1629 "syncobj sync file import failed: %m");
1630 }
1631 break;
1632
1633 default:
1634 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1635 }
1636
1637 /* From the Vulkan 1.0.53 spec:
1638 *
1639 * "Importing a fence payload from a file descriptor transfers
1640 * ownership of the file descriptor from the application to the
1641 * Vulkan implementation. The application must not perform any
1642 * operations on the file descriptor after a successful import."
1643 *
1644 * If the import fails, we leave the file descriptor open.
1645 */
1646 close(fd);
1647
1648 if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) {
1649 anv_fence_impl_cleanup(device, &fence->temporary);
1650 fence->temporary = new_impl;
1651 } else {
1652 anv_fence_impl_cleanup(device, &fence->permanent);
1653 fence->permanent = new_impl;
1654 }
1655
1656 return VK_SUCCESS;
1657 }
1658
1659 VkResult anv_GetFenceFdKHR(
1660 VkDevice _device,
1661 const VkFenceGetFdInfoKHR* pGetFdInfo,
1662 int* pFd)
1663 {
1664 ANV_FROM_HANDLE(anv_device, device, _device);
1665 ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
1666
1667 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
1668
1669 struct anv_fence_impl *impl =
1670 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1671 &fence->temporary : &fence->permanent;
1672
1673 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
1674 switch (pGetFdInfo->handleType) {
1675 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: {
1676 int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
1677 if (fd < 0)
1678 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1679
1680 *pFd = fd;
1681 break;
1682 }
1683
1684 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
1685 int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
1686 if (fd < 0)
1687 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1688
1689 *pFd = fd;
1690 break;
1691 }
1692
1693 default:
1694 unreachable("Invalid fence export handle type");
1695 }
1696
1697 /* From the Vulkan 1.0.53 spec:
1698 *
1699 * "Export operations have the same transference as the specified handle
1700 * type’s import operations. [...] If the fence was using a
1701 * temporarily imported payload, the fence’s prior permanent payload
1702 * will be restored.
1703 */
1704 if (impl == &fence->temporary)
1705 anv_fence_impl_cleanup(device, impl);
1706
1707 return VK_SUCCESS;
1708 }
1709
1710 // Queue semaphore functions
1711
1712 static VkSemaphoreTypeKHR
1713 get_semaphore_type(const void *pNext, uint64_t *initial_value)
1714 {
1715 const VkSemaphoreTypeCreateInfoKHR *type_info =
1716 vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);
1717
1718 if (!type_info)
1719 return VK_SEMAPHORE_TYPE_BINARY_KHR;
1720
1721 if (initial_value)
1722 *initial_value = type_info->initialValue;
1723 return type_info->semaphoreType;
1724 }
1725
1726 static VkResult
1727 binary_semaphore_create(struct anv_device *device,
1728 struct anv_semaphore_impl *impl,
1729 bool exportable)
1730 {
1731 if (device->physical->has_syncobj) {
1732 impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
1733 impl->syncobj = anv_gem_syncobj_create(device, 0);
1734 if (!impl->syncobj)
1735 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1736 return VK_SUCCESS;
1737 } else {
1738 impl->type = ANV_SEMAPHORE_TYPE_BO;
1739 VkResult result =
1740 anv_device_alloc_bo(device, 4096,
1741 ANV_BO_ALLOC_EXTERNAL |
1742 ANV_BO_ALLOC_IMPLICIT_SYNC,
1743 0 /* explicit_address */,
1744 &impl->bo);
1745 /* If we're going to use this as a fence, we need to *not* have the
1746 * EXEC_OBJECT_ASYNC bit set.
1747 */
1748 assert(!(impl->bo->flags & EXEC_OBJECT_ASYNC));
1749 return result;
1750 }
1751 }
1752
1753 static VkResult
1754 timeline_semaphore_create(struct anv_device *device,
1755 struct anv_semaphore_impl *impl,
1756 uint64_t initial_value)
1757 {
1758 impl->type = ANV_SEMAPHORE_TYPE_TIMELINE;
1759 anv_timeline_init(device, &impl->timeline, initial_value);
1760 return VK_SUCCESS;
1761 }
1762
1763 VkResult anv_CreateSemaphore(
1764 VkDevice _device,
1765 const VkSemaphoreCreateInfo* pCreateInfo,
1766 const VkAllocationCallbacks* pAllocator,
1767 VkSemaphore* pSemaphore)
1768 {
1769 ANV_FROM_HANDLE(anv_device, device, _device);
1770 struct anv_semaphore *semaphore;
1771
1772 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
1773
1774 uint64_t timeline_value = 0;
1775 VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);
1776
1777 semaphore = vk_alloc(&device->alloc, sizeof(*semaphore), 8,
1778 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1779 if (semaphore == NULL)
1780 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1781
1782 p_atomic_set(&semaphore->refcount, 1);
1783
1784 const VkExportSemaphoreCreateInfo *export =
1785 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
1786 VkExternalSemaphoreHandleTypeFlags handleTypes =
1787 export ? export->handleTypes : 0;
1788 VkResult result;
1789
1790 if (handleTypes == 0) {
1791 if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
1792 result = binary_semaphore_create(device, &semaphore->permanent, false);
1793 else
1794 result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
1795 if (result != VK_SUCCESS) {
1796 vk_free2(&device->alloc, pAllocator, semaphore);
1797 return result;
1798 }
1799 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
1800 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
1801 assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);
1802 result = binary_semaphore_create(device, &semaphore->permanent, true);
1803 if (result != VK_SUCCESS) {
1804 vk_free2(&device->alloc, pAllocator, semaphore);
1805 return result;
1806 }
1807 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
1808 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT);
1809 assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);
1810 if (device->physical->has_syncobj) {
1811 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
1812 semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
1813 if (!semaphore->permanent.syncobj) {
1814 vk_free2(&device->alloc, pAllocator, semaphore);
1815 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1816 }
1817 } else {
1818 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
1819 semaphore->permanent.fd = -1;
1820 }
1821 } else {
1822 assert(!"Unknown handle type");
1823 vk_free2(&device->alloc, pAllocator, semaphore);
1824 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1825 }
1826
1827 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
1828
1829 *pSemaphore = anv_semaphore_to_handle(semaphore);
1830
1831 return VK_SUCCESS;
1832 }
1833
1834 static void
1835 anv_semaphore_impl_cleanup(struct anv_device *device,
1836 struct anv_semaphore_impl *impl)
1837 {
1838 switch (impl->type) {
1839 case ANV_SEMAPHORE_TYPE_NONE:
1840 case ANV_SEMAPHORE_TYPE_DUMMY:
1841 /* Dummy. Nothing to do */
1842 break;
1843
1844 case ANV_SEMAPHORE_TYPE_BO:
1845 case ANV_SEMAPHORE_TYPE_WSI_BO:
1846 anv_device_release_bo(device, impl->bo);
1847 break;
1848
1849 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
1850 if (impl->fd >= 0)
1851 close(impl->fd);
1852 break;
1853
1854 case ANV_SEMAPHORE_TYPE_TIMELINE:
1855 anv_timeline_finish(device, &impl->timeline);
1856 break;
1857
1858 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
1859 anv_gem_syncobj_destroy(device, impl->syncobj);
1860 break;
1861
1862 default:
1863 unreachable("Invalid semaphore type");
1864 }
1865
1866 impl->type = ANV_SEMAPHORE_TYPE_NONE;
1867 }
1868
1869 void
1870 anv_semaphore_reset_temporary(struct anv_device *device,
1871 struct anv_semaphore *semaphore)
1872 {
1873 if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
1874 return;
1875
1876 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
1877 }
1878
1879 static struct anv_semaphore *
1880 anv_semaphore_ref(struct anv_semaphore *semaphore)
1881 {
1882 assert(semaphore->refcount);
1883 p_atomic_inc(&semaphore->refcount);
1884 return semaphore;
1885 }
1886
1887 static void
1888 anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore)
1889 {
1890 if (!p_atomic_dec_zero(&semaphore->refcount))
1891 return;
1892
1893 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
1894 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
1895 vk_free(&device->alloc, semaphore);
1896 }
1897
1898 void anv_DestroySemaphore(
1899 VkDevice _device,
1900 VkSemaphore _semaphore,
1901 const VkAllocationCallbacks* pAllocator)
1902 {
1903 ANV_FROM_HANDLE(anv_device, device, _device);
1904 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
1905
1906 if (semaphore == NULL)
1907 return;
1908
1909 anv_semaphore_unref(device, semaphore);
1910 }
1911
1912 void anv_GetPhysicalDeviceExternalSemaphoreProperties(
1913 VkPhysicalDevice physicalDevice,
1914 const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
1915 VkExternalSemaphoreProperties* pExternalSemaphoreProperties)
1916 {
1917 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
1918
1919 VkSemaphoreTypeKHR sem_type =
1920 get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
1921
1922 switch (pExternalSemaphoreInfo->handleType) {
1923 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
1924 /* Timeline semaphores are not exportable. */
1925 if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
1926 break;
1927 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
1928 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
1929 pExternalSemaphoreProperties->compatibleHandleTypes =
1930 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
1931 pExternalSemaphoreProperties->externalSemaphoreFeatures =
1932 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
1933 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
1934 return;
1935
1936 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
1937 if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
1938 break;
1939 if (!device->has_exec_fence)
1940 break;
1941 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
1942 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1943 pExternalSemaphoreProperties->compatibleHandleTypes =
1944 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1945 pExternalSemaphoreProperties->externalSemaphoreFeatures =
1946 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
1947 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
1948 return;
1949
1950 default:
1951 break;
1952 }
1953
1954 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
1955 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
1956 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
1957 }
1958
1959 VkResult anv_ImportSemaphoreFdKHR(
1960 VkDevice _device,
1961 const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
1962 {
1963 ANV_FROM_HANDLE(anv_device, device, _device);
1964 ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
1965 int fd = pImportSemaphoreFdInfo->fd;
1966
1967 struct anv_semaphore_impl new_impl = {
1968 .type = ANV_SEMAPHORE_TYPE_NONE,
1969 };
1970
1971 switch (pImportSemaphoreFdInfo->handleType) {
1972 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
1973 if (device->physical->has_syncobj) {
1974 new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
1975
1976 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
1977 if (!new_impl.syncobj)
1978 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1979 } else {
1980 new_impl.type = ANV_SEMAPHORE_TYPE_BO;
1981
1982 VkResult result = anv_device_import_bo(device, fd,
1983 ANV_BO_ALLOC_EXTERNAL |
1984 ANV_BO_ALLOC_IMPLICIT_SYNC,
1985 0 /* client_address */,
1986 &new_impl.bo);
1987 if (result != VK_SUCCESS)
1988 return result;
1989
1990 if (new_impl.bo->size < 4096) {
1991 anv_device_release_bo(device, new_impl.bo);
1992 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1993 }
1994
1995 /* If we're going to use this as a fence, we need to *not* have the
1996 * EXEC_OBJECT_ASYNC bit set.
1997 */
1998 assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
1999 }
2000
2001 /* From the Vulkan spec:
2002 *
2003 * "Importing semaphore state from a file descriptor transfers
2004 * ownership of the file descriptor from the application to the
2005 * Vulkan implementation. The application must not perform any
2006 * operations on the file descriptor after a successful import."
2007 *
2008 * If the import fails, we leave the file descriptor open.
2009 */
2010 close(fd);
2011 break;
2012
2013 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
2014 if (device->physical->has_syncobj) {
2015 new_impl = (struct anv_semaphore_impl) {
2016 .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
2017 .syncobj = anv_gem_syncobj_create(device, 0),
2018 };
2019 if (!new_impl.syncobj)
2020 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2021 if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
2022 anv_gem_syncobj_destroy(device, new_impl.syncobj);
2023 return vk_errorf(device->instance, NULL,
2024 VK_ERROR_INVALID_EXTERNAL_HANDLE,
2025 "syncobj sync file import failed: %m");
2026 }
2027 /* Ownership of the FD is transfered to Anv. Since we don't need it
2028 * anymore because the associated fence has been put into a syncobj,
2029 * we must close the FD.
2030 */
2031 close(fd);
2032 } else {
2033 new_impl = (struct anv_semaphore_impl) {
2034 .type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
2035 .fd = fd,
2036 };
2037 }
2038 break;
2039
2040 default:
2041 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2042 }
2043
2044 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
2045 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
2046 semaphore->temporary = new_impl;
2047 } else {
2048 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
2049 semaphore->permanent = new_impl;
2050 }
2051
2052 return VK_SUCCESS;
2053 }
2054
2055 VkResult anv_GetSemaphoreFdKHR(
2056 VkDevice _device,
2057 const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
2058 int* pFd)
2059 {
2060 ANV_FROM_HANDLE(anv_device, device, _device);
2061 ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
2062 VkResult result;
2063 int fd;
2064
2065 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
2066
2067 struct anv_semaphore_impl *impl =
2068 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2069 &semaphore->temporary : &semaphore->permanent;
2070
2071 switch (impl->type) {
2072 case ANV_SEMAPHORE_TYPE_BO:
2073 result = anv_device_export_bo(device, impl->bo, pFd);
2074 if (result != VK_SUCCESS)
2075 return result;
2076 break;
2077
2078 case ANV_SEMAPHORE_TYPE_SYNC_FILE: {
2079 /* There's a potential race here with vkQueueSubmit if you are trying
2080 * to export a semaphore Fd while the queue submit is still happening.
2081 * This can happen if we see all dependencies get resolved via timeline
2082 * semaphore waits completing before the execbuf completes and we
2083 * process the resulting out fence. To work around this, take a lock
2084 * around grabbing the fd.
2085 */
2086 pthread_mutex_lock(&device->mutex);
2087
2088 /* From the Vulkan 1.0.53 spec:
2089 *
2090 * "...exporting a semaphore payload to a handle with copy
2091 * transference has the same side effects on the source
2092 * semaphore’s payload as executing a semaphore wait operation."
2093 *
2094 * In other words, it may still be a SYNC_FD semaphore, but it's now
2095 * considered to have been waited on and no longer has a sync file
2096 * attached.
2097 */
2098 int fd = impl->fd;
2099 impl->fd = -1;
2100
2101 pthread_mutex_unlock(&device->mutex);
2102
2103 /* There are two reasons why this could happen:
2104 *
2105 * 1) The user is trying to export without submitting something that
2106 * signals the semaphore. If this is the case, it's their bug so
2107 * what we return here doesn't matter.
2108 *
2109 * 2) The kernel didn't give us a file descriptor. The most likely
2110 * reason for this is running out of file descriptors.
2111 */
2112 if (fd < 0)
2113 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2114
2115 *pFd = fd;
2116 return VK_SUCCESS;
2117 }
2118
2119 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
2120 if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)
2121 fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
2122 else {
2123 assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
2124 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
2125 }
2126 if (fd < 0)
2127 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2128 *pFd = fd;
2129 break;
2130
2131 default:
2132 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2133 }
2134
2135 /* From the Vulkan 1.0.53 spec:
2136 *
2137 * "Export operations have the same transference as the specified handle
2138 * type’s import operations. [...] If the semaphore was using a
2139 * temporarily imported payload, the semaphore’s prior permanent payload
2140 * will be restored.
2141 */
2142 if (impl == &semaphore->temporary)
2143 anv_semaphore_impl_cleanup(device, impl);
2144
2145 return VK_SUCCESS;
2146 }
2147
2148 VkResult anv_GetSemaphoreCounterValue(
2149 VkDevice _device,
2150 VkSemaphore _semaphore,
2151 uint64_t* pValue)
2152 {
2153 ANV_FROM_HANDLE(anv_device, device, _device);
2154 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
2155
2156 struct anv_semaphore_impl *impl =
2157 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2158 &semaphore->temporary : &semaphore->permanent;
2159
2160 switch (impl->type) {
2161 case ANV_SEMAPHORE_TYPE_TIMELINE: {
2162 pthread_mutex_lock(&device->mutex);
2163 *pValue = impl->timeline.highest_past;
2164 pthread_mutex_unlock(&device->mutex);
2165 return VK_SUCCESS;
2166 }
2167
2168 default:
2169 unreachable("Invalid semaphore type");
2170 }
2171 }
2172
2173 static VkResult
2174 anv_timeline_wait_locked(struct anv_device *device,
2175 struct anv_timeline *timeline,
2176 uint64_t serial, uint64_t abs_timeout_ns)
2177 {
2178 /* Wait on the queue_submit condition variable until the timeline has a
2179 * time point pending that's at least as high as serial.
2180 */
2181 while (timeline->highest_pending < serial) {
2182 struct timespec abstime = {
2183 .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
2184 .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
2185 };
2186
2187 int ret = pthread_cond_timedwait(&device->queue_submit,
2188 &device->mutex, &abstime);
2189 assert(ret != EINVAL);
2190 if (anv_gettime_ns() >= abs_timeout_ns &&
2191 timeline->highest_pending < serial)
2192 return VK_TIMEOUT;
2193 }
2194
2195 while (1) {
2196 VkResult result = anv_timeline_gc_locked(device, timeline);
2197 if (result != VK_SUCCESS)
2198 return result;
2199
2200 if (timeline->highest_past >= serial)
2201 return VK_SUCCESS;
2202
2203 /* If we got here, our earliest time point has a busy BO */
2204 struct anv_timeline_point *point =
2205 list_first_entry(&timeline->points,
2206 struct anv_timeline_point, link);
2207
2208 /* Drop the lock while we wait. */
2209 point->waiting++;
2210 pthread_mutex_unlock(&device->mutex);
2211
2212 result = anv_device_wait(device, point->bo,
2213 anv_get_relative_timeout(abs_timeout_ns));
2214
2215 /* Pick the mutex back up */
2216 pthread_mutex_lock(&device->mutex);
2217 point->waiting--;
2218
2219 /* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */
2220 if (result != VK_SUCCESS)
2221 return result;
2222 }
2223 }
2224
2225 static VkResult
2226 anv_timelines_wait(struct anv_device *device,
2227 struct anv_timeline **timelines,
2228 const uint64_t *serials,
2229 uint32_t n_timelines,
2230 bool wait_all,
2231 uint64_t abs_timeout_ns)
2232 {
2233 if (!wait_all && n_timelines > 1) {
2234 while (1) {
2235 VkResult result;
2236 pthread_mutex_lock(&device->mutex);
2237 for (uint32_t i = 0; i < n_timelines; i++) {
2238 result =
2239 anv_timeline_wait_locked(device, timelines[i], serials[i], 0);
2240 if (result != VK_TIMEOUT)
2241 break;
2242 }
2243
2244 if (result != VK_TIMEOUT ||
2245 anv_gettime_ns() >= abs_timeout_ns) {
2246 pthread_mutex_unlock(&device->mutex);
2247 return result;
2248 }
2249
2250 /* If none of them are ready do a short wait so we don't completely
2251 * spin while holding the lock. The 10us is completely arbitrary.
2252 */
2253 uint64_t abs_short_wait_ns =
2254 anv_get_absolute_timeout(
2255 MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000));
2256 struct timespec abstime = {
2257 .tv_sec = abs_short_wait_ns / NSEC_PER_SEC,
2258 .tv_nsec = abs_short_wait_ns % NSEC_PER_SEC,
2259 };
2260 ASSERTED int ret;
2261 ret = pthread_cond_timedwait(&device->queue_submit,
2262 &device->mutex, &abstime);
2263 assert(ret != EINVAL);
2264 }
2265 } else {
2266 VkResult result = VK_SUCCESS;
2267 pthread_mutex_lock(&device->mutex);
2268 for (uint32_t i = 0; i < n_timelines; i++) {
2269 result =
2270 anv_timeline_wait_locked(device, timelines[i],
2271 serials[i], abs_timeout_ns);
2272 if (result != VK_SUCCESS)
2273 break;
2274 }
2275 pthread_mutex_unlock(&device->mutex);
2276 return result;
2277 }
2278 }
2279
2280 VkResult anv_WaitSemaphores(
2281 VkDevice _device,
2282 const VkSemaphoreWaitInfoKHR* pWaitInfo,
2283 uint64_t timeout)
2284 {
2285 ANV_FROM_HANDLE(anv_device, device, _device);
2286
2287 struct anv_timeline **timelines =
2288 vk_alloc(&device->alloc,
2289 pWaitInfo->semaphoreCount * sizeof(*timelines),
2290 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2291 if (!timelines)
2292 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2293
2294 uint64_t *values = vk_alloc(&device->alloc,
2295 pWaitInfo->semaphoreCount * sizeof(*values),
2296 8, VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
2297 if (!values) {
2298 vk_free(&device->alloc, timelines);
2299 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2300 }
2301
2302 uint32_t handle_count = 0;
2303 for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) {
2304 ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]);
2305 struct anv_semaphore_impl *impl =
2306 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2307 &semaphore->temporary : &semaphore->permanent;
2308
2309 assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE);
2310
2311 if (pWaitInfo->pValues[i] == 0)
2312 continue;
2313
2314 timelines[handle_count] = &impl->timeline;
2315 values[handle_count] = pWaitInfo->pValues[i];
2316 handle_count++;
2317 }
2318
2319 VkResult result = VK_SUCCESS;
2320 if (handle_count > 0) {
2321 result = anv_timelines_wait(device, timelines, values, handle_count,
2322 !(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
2323 timeout);
2324 }
2325
2326 vk_free(&device->alloc, timelines);
2327 vk_free(&device->alloc, values);
2328
2329 return result;
2330 }
2331
2332 VkResult anv_SignalSemaphore(
2333 VkDevice _device,
2334 const VkSemaphoreSignalInfoKHR* pSignalInfo)
2335 {
2336 ANV_FROM_HANDLE(anv_device, device, _device);
2337 ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore);
2338
2339 struct anv_semaphore_impl *impl =
2340 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2341 &semaphore->temporary : &semaphore->permanent;
2342
2343 switch (impl->type) {
2344 case ANV_SEMAPHORE_TYPE_TIMELINE: {
2345 pthread_mutex_lock(&device->mutex);
2346
2347 VkResult result = anv_timeline_gc_locked(device, &impl->timeline);
2348
2349 assert(pSignalInfo->value > impl->timeline.highest_pending);
2350
2351 impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value;
2352
2353 if (result == VK_SUCCESS)
2354 result = anv_device_submit_deferred_locked(device);
2355
2356 pthread_cond_broadcast(&device->queue_submit);
2357 pthread_mutex_unlock(&device->mutex);
2358 return result;
2359 }
2360
2361 default:
2362 unreachable("Invalid semaphore type");
2363 }
2364 }