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