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