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