2 * Copyright © 2015 Intel Corporation
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:
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
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
25 * This file implements VkQueue, VkFence, and VkSemaphore
32 #include "util/os_file.h"
34 #include "anv_private.h"
37 #include "genxml/gen7_pack.h"
39 uint64_t anv_gettime_ns(void)
41 struct timespec current
;
42 clock_gettime(CLOCK_MONOTONIC
, ¤t
);
43 return (uint64_t)current
.tv_sec
* NSEC_PER_SEC
+ current
.tv_nsec
;
46 uint64_t anv_get_absolute_timeout(uint64_t timeout
)
50 uint64_t current_time
= anv_gettime_ns();
51 uint64_t max_timeout
= (uint64_t) INT64_MAX
- current_time
;
53 timeout
= MIN2(max_timeout
, timeout
);
55 return (current_time
+ timeout
);
58 static int64_t anv_get_relative_timeout(uint64_t abs_timeout
)
60 uint64_t now
= anv_gettime_ns();
62 /* We don't want negative timeouts.
64 * DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is
65 * supposed to block indefinitely timeouts < 0. Unfortunately,
66 * this was broken for a couple of kernel releases. Since there's
67 * no way to know whether or not the kernel we're using is one of
68 * the broken ones, the best we can do is to clamp the timeout to
69 * INT64_MAX. This limits the maximum timeout from 584 years to
70 * 292 years - likely not a big deal.
72 if (abs_timeout
< now
)
75 uint64_t rel_timeout
= abs_timeout
- now
;
76 if (rel_timeout
> (uint64_t) INT64_MAX
)
77 rel_timeout
= INT64_MAX
;
82 static struct anv_semaphore
*anv_semaphore_ref(struct anv_semaphore
*semaphore
);
83 static void anv_semaphore_unref(struct anv_device
*device
, struct anv_semaphore
*semaphore
);
84 static void anv_semaphore_impl_cleanup(struct anv_device
*device
,
85 struct anv_semaphore_impl
*impl
);
88 anv_queue_submit_free(struct anv_device
*device
,
89 struct anv_queue_submit
*submit
)
91 const VkAllocationCallbacks
*alloc
= submit
->alloc
;
93 for (uint32_t i
= 0; i
< submit
->temporary_semaphore_count
; i
++)
94 anv_semaphore_impl_cleanup(device
, &submit
->temporary_semaphores
[i
]);
95 for (uint32_t i
= 0; i
< submit
->sync_fd_semaphore_count
; i
++)
96 anv_semaphore_unref(device
, submit
->sync_fd_semaphores
[i
]);
97 /* Execbuf does not consume the in_fence. It's our job to close it. */
98 if (submit
->in_fence
!= -1) {
99 assert(!device
->has_thread_submit
);
100 close(submit
->in_fence
);
102 if (submit
->out_fence
!= -1) {
103 assert(!device
->has_thread_submit
);
104 close(submit
->out_fence
);
106 vk_free(alloc
, submit
->fences
);
107 vk_free(alloc
, submit
->fence_values
);
108 vk_free(alloc
, submit
->temporary_semaphores
);
109 vk_free(alloc
, submit
->wait_timelines
);
110 vk_free(alloc
, submit
->wait_timeline_values
);
111 vk_free(alloc
, submit
->signal_timelines
);
112 vk_free(alloc
, submit
->signal_timeline_values
);
113 vk_free(alloc
, submit
->fence_bos
);
114 vk_free(alloc
, submit
);
118 anv_queue_submit_ready_locked(struct anv_queue_submit
*submit
)
120 for (uint32_t i
= 0; i
< submit
->wait_timeline_count
; i
++) {
121 if (submit
->wait_timeline_values
[i
] > submit
->wait_timelines
[i
]->highest_pending
)
129 anv_timeline_init(struct anv_device
*device
,
130 struct anv_timeline
*timeline
,
131 uint64_t initial_value
)
133 timeline
->highest_past
=
134 timeline
->highest_pending
= initial_value
;
135 list_inithead(&timeline
->points
);
136 list_inithead(&timeline
->free_points
);
142 anv_timeline_finish(struct anv_device
*device
,
143 struct anv_timeline
*timeline
)
145 list_for_each_entry_safe(struct anv_timeline_point
, point
,
146 &timeline
->free_points
, link
) {
147 list_del(&point
->link
);
148 anv_device_release_bo(device
, point
->bo
);
149 vk_free(&device
->vk
.alloc
, point
);
151 list_for_each_entry_safe(struct anv_timeline_point
, point
,
152 &timeline
->points
, link
) {
153 list_del(&point
->link
);
154 anv_device_release_bo(device
, point
->bo
);
155 vk_free(&device
->vk
.alloc
, point
);
160 anv_timeline_add_point_locked(struct anv_device
*device
,
161 struct anv_timeline
*timeline
,
163 struct anv_timeline_point
**point
)
165 VkResult result
= VK_SUCCESS
;
167 if (list_is_empty(&timeline
->free_points
)) {
169 vk_zalloc(&device
->vk
.alloc
, sizeof(**point
),
170 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
);
172 result
= vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
173 if (result
== VK_SUCCESS
) {
174 result
= anv_device_alloc_bo(device
, 4096,
175 ANV_BO_ALLOC_EXTERNAL
|
176 ANV_BO_ALLOC_IMPLICIT_SYNC
,
177 0 /* explicit_address */,
179 if (result
!= VK_SUCCESS
)
180 vk_free(&device
->vk
.alloc
, *point
);
183 *point
= list_first_entry(&timeline
->free_points
,
184 struct anv_timeline_point
, link
);
185 list_del(&(*point
)->link
);
188 if (result
== VK_SUCCESS
) {
189 (*point
)->serial
= value
;
190 list_addtail(&(*point
)->link
, &timeline
->points
);
197 anv_timeline_gc_locked(struct anv_device
*device
,
198 struct anv_timeline
*timeline
)
200 list_for_each_entry_safe(struct anv_timeline_point
, point
,
201 &timeline
->points
, link
) {
202 /* timeline->higest_pending is only incremented once submission has
203 * happened. If this point has a greater serial, it means the point
204 * hasn't been submitted yet.
206 if (point
->serial
> timeline
->highest_pending
)
209 /* If someone is waiting on this time point, consider it busy and don't
210 * try to recycle it. There's a slim possibility that it's no longer
211 * busy by the time we look at it but we would be recycling it out from
212 * under a waiter and that can lead to weird races.
214 * We walk the list in-order so if this time point is still busy so is
215 * every following time point
217 assert(point
->waiting
>= 0);
221 /* Garbage collect any signaled point. */
222 VkResult result
= anv_device_bo_busy(device
, point
->bo
);
223 if (result
== VK_NOT_READY
) {
224 /* We walk the list in-order so if this time point is still busy so
225 * is every following time point
228 } else if (result
!= VK_SUCCESS
) {
232 assert(timeline
->highest_past
< point
->serial
);
233 timeline
->highest_past
= point
->serial
;
235 list_del(&point
->link
);
236 list_add(&point
->link
, &timeline
->free_points
);
242 static VkResult
anv_queue_submit_add_fence_bo(struct anv_queue_submit
*submit
,
247 anv_queue_submit_timeline_locked(struct anv_queue
*queue
,
248 struct anv_queue_submit
*submit
)
252 for (uint32_t i
= 0; i
< submit
->wait_timeline_count
; i
++) {
253 struct anv_timeline
*timeline
= submit
->wait_timelines
[i
];
254 uint64_t wait_value
= submit
->wait_timeline_values
[i
];
256 if (timeline
->highest_past
>= wait_value
)
259 list_for_each_entry(struct anv_timeline_point
, point
, &timeline
->points
, link
) {
260 if (point
->serial
< wait_value
)
262 result
= anv_queue_submit_add_fence_bo(submit
, point
->bo
, false);
263 if (result
!= VK_SUCCESS
)
268 for (uint32_t i
= 0; i
< submit
->signal_timeline_count
; i
++) {
269 struct anv_timeline
*timeline
= submit
->signal_timelines
[i
];
270 uint64_t signal_value
= submit
->signal_timeline_values
[i
];
271 struct anv_timeline_point
*point
;
273 result
= anv_timeline_add_point_locked(queue
->device
, timeline
,
274 signal_value
, &point
);
275 if (result
!= VK_SUCCESS
)
278 result
= anv_queue_submit_add_fence_bo(submit
, point
->bo
, true);
279 if (result
!= VK_SUCCESS
)
283 result
= anv_queue_execbuf_locked(queue
, submit
);
285 if (result
== VK_SUCCESS
) {
286 /* Update the pending values in the timeline objects. */
287 for (uint32_t i
= 0; i
< submit
->signal_timeline_count
; i
++) {
288 struct anv_timeline
*timeline
= submit
->signal_timelines
[i
];
289 uint64_t signal_value
= submit
->signal_timeline_values
[i
];
291 assert(signal_value
> timeline
->highest_pending
);
292 timeline
->highest_pending
= signal_value
;
295 /* Update signaled semaphores backed by syncfd. */
296 for (uint32_t i
= 0; i
< submit
->sync_fd_semaphore_count
; i
++) {
297 struct anv_semaphore
*semaphore
= submit
->sync_fd_semaphores
[i
];
298 /* Out fences can't have temporary state because that would imply
299 * that we imported a sync file and are trying to signal it.
301 assert(semaphore
->temporary
.type
== ANV_SEMAPHORE_TYPE_NONE
);
302 struct anv_semaphore_impl
*impl
= &semaphore
->permanent
;
304 assert(impl
->type
== ANV_SEMAPHORE_TYPE_SYNC_FILE
);
305 impl
->fd
= os_dupfd_cloexec(submit
->out_fence
);
308 /* Unblock any waiter by signaling the points, the application will get
309 * a device lost error code.
311 for (uint32_t i
= 0; i
< submit
->signal_timeline_count
; i
++) {
312 struct anv_timeline
*timeline
= submit
->signal_timelines
[i
];
313 uint64_t signal_value
= submit
->signal_timeline_values
[i
];
315 assert(signal_value
> timeline
->highest_pending
);
316 timeline
->highest_past
= timeline
->highest_pending
= signal_value
;
324 anv_queue_submit_deferred_locked(struct anv_queue
*queue
, uint32_t *advance
)
326 VkResult result
= VK_SUCCESS
;
328 /* Go through all the queued submissions and submit then until we find one
329 * that's waiting on a point that hasn't materialized yet.
331 list_for_each_entry_safe(struct anv_queue_submit
, submit
,
332 &queue
->queued_submits
, link
) {
333 if (!anv_queue_submit_ready_locked(submit
))
337 list_del(&submit
->link
);
339 result
= anv_queue_submit_timeline_locked(queue
, submit
);
341 anv_queue_submit_free(queue
->device
, submit
);
343 if (result
!= VK_SUCCESS
)
351 anv_device_submit_deferred_locked(struct anv_device
*device
)
353 uint32_t advance
= 0;
354 return anv_queue_submit_deferred_locked(&device
->queue
, &advance
);
358 anv_queue_submit_signal_fences(struct anv_device
*device
,
359 struct anv_queue_submit
*submit
)
361 for (uint32_t i
= 0; i
< submit
->fence_count
; i
++) {
362 if (submit
->fences
[i
].flags
& I915_EXEC_FENCE_SIGNAL
) {
363 anv_gem_syncobj_timeline_signal(device
, &submit
->fences
[i
].handle
,
364 &submit
->fence_values
[i
], 1);
370 anv_queue_task(void *_queue
)
372 struct anv_queue
*queue
= _queue
;
374 pthread_mutex_lock(&queue
->mutex
);
376 while (!queue
->quit
) {
377 while (!list_is_empty(&queue
->queued_submits
)) {
378 struct anv_queue_submit
*submit
=
379 list_first_entry(&queue
->queued_submits
, struct anv_queue_submit
, link
);
380 list_del(&submit
->link
);
382 pthread_mutex_unlock(&queue
->mutex
);
384 VkResult result
= VK_ERROR_DEVICE_LOST
;
386 /* Wait for timeline points to materialize before submitting. We need
387 * to do this because we're using threads to do the submit to i915.
388 * We could end up in a situation where the application submits to 2
389 * queues with the first submit creating the dma-fence for the
390 * second. But because the scheduling of the submission threads might
391 * wakeup the second queue thread first, this would make that execbuf
392 * fail because the dma-fence it depends on hasn't materialized yet.
394 if (!queue
->lost
&& submit
->wait_timeline_count
> 0) {
395 int ret
= queue
->device
->no_hw
? 0 :
396 anv_gem_syncobj_timeline_wait(
397 queue
->device
, submit
->wait_timeline_syncobjs
,
398 submit
->wait_timeline_values
, submit
->wait_timeline_count
,
399 anv_get_absolute_timeout(UINT64_MAX
) /* wait forever */,
400 true /* wait for all */, true /* wait for materialize */);
402 result
= anv_queue_set_lost(queue
, "timeline timeout: %s",
409 pthread_mutex_lock(&queue
->device
->mutex
);
410 result
= anv_queue_execbuf_locked(queue
, submit
);
411 pthread_mutex_unlock(&queue
->device
->mutex
);
414 for (uint32_t i
= 0; i
< submit
->sync_fd_semaphore_count
; i
++) {
415 struct anv_semaphore
*semaphore
= submit
->sync_fd_semaphores
[i
];
416 /* Out fences can't have temporary state because that would imply
417 * that we imported a sync file and are trying to signal it.
419 assert(semaphore
->temporary
.type
== ANV_SEMAPHORE_TYPE_NONE
);
420 struct anv_semaphore_impl
*impl
= &semaphore
->permanent
;
422 assert(impl
->type
== ANV_SEMAPHORE_TYPE_SYNC_FILE
);
423 impl
->fd
= dup(submit
->out_fence
);
426 if (result
!= VK_SUCCESS
) {
427 /* vkQueueSubmit or some other entry point will report the
428 * DEVICE_LOST error at some point, but until we have emptied our
429 * list of execbufs we need to wake up all potential the waiters
430 * until one of them spots the error.
432 anv_queue_submit_signal_fences(queue
->device
, submit
);
435 anv_queue_submit_free(queue
->device
, submit
);
437 pthread_mutex_lock(&queue
->mutex
);
441 pthread_cond_wait(&queue
->cond
, &queue
->mutex
);
444 pthread_mutex_unlock(&queue
->mutex
);
450 _anv_queue_submit(struct anv_queue
*queue
, struct anv_queue_submit
**_submit
,
453 struct anv_queue_submit
*submit
= *_submit
;
455 /* Wait before signal behavior means we might keep alive the
456 * anv_queue_submit object a bit longer, so transfer the ownership to the
460 if (queue
->device
->has_thread_submit
) {
461 pthread_mutex_lock(&queue
->mutex
);
462 pthread_cond_broadcast(&queue
->cond
);
463 list_addtail(&submit
->link
, &queue
->queued_submits
);
464 pthread_mutex_unlock(&queue
->mutex
);
467 pthread_mutex_lock(&queue
->device
->mutex
);
468 list_addtail(&submit
->link
, &queue
->queued_submits
);
469 VkResult result
= anv_device_submit_deferred_locked(queue
->device
);
471 while (result
== VK_SUCCESS
&& !list_is_empty(&queue
->queued_submits
)) {
472 int ret
= pthread_cond_wait(&queue
->device
->queue_submit
,
473 &queue
->device
->mutex
);
475 result
= anv_device_set_lost(queue
->device
, "wait timeout");
479 result
= anv_device_submit_deferred_locked(queue
->device
);
482 pthread_mutex_unlock(&queue
->device
->mutex
);
488 anv_queue_init(struct anv_device
*device
, struct anv_queue
*queue
)
492 queue
->device
= device
;
497 list_inithead(&queue
->queued_submits
);
499 /* We only need those additional thread/mutex when using a thread for
502 if (device
->has_thread_submit
) {
503 if (pthread_mutex_init(&queue
->mutex
, NULL
) != 0)
504 return vk_error(VK_ERROR_INITIALIZATION_FAILED
);
506 if (pthread_cond_init(&queue
->cond
, NULL
) != 0) {
507 result
= vk_error(VK_ERROR_INITIALIZATION_FAILED
);
510 if (pthread_create(&queue
->thread
, NULL
, anv_queue_task
, queue
)) {
511 result
= vk_error(VK_ERROR_INITIALIZATION_FAILED
);
516 vk_object_base_init(&device
->vk
, &queue
->base
, VK_OBJECT_TYPE_QUEUE
);
521 pthread_cond_destroy(&queue
->cond
);
523 pthread_mutex_destroy(&queue
->mutex
);
529 anv_queue_finish(struct anv_queue
*queue
)
531 vk_object_base_finish(&queue
->base
);
533 if (!queue
->device
->has_thread_submit
)
536 pthread_mutex_lock(&queue
->mutex
);
537 pthread_cond_broadcast(&queue
->cond
);
539 pthread_mutex_unlock(&queue
->mutex
);
542 pthread_join(queue
->thread
, &ret
);
544 pthread_cond_destroy(&queue
->cond
);
545 pthread_mutex_destroy(&queue
->mutex
);
549 anv_queue_submit_add_fence_bo(struct anv_queue_submit
*submit
,
553 if (submit
->fence_bo_count
>= submit
->fence_bo_array_length
) {
554 uint32_t new_len
= MAX2(submit
->fence_bo_array_length
* 2, 64);
555 uintptr_t *new_fence_bos
=
556 vk_realloc(submit
->alloc
,
557 submit
->fence_bos
, new_len
* sizeof(*submit
->fence_bos
),
558 8, submit
->alloc_scope
);
559 if (new_fence_bos
== NULL
)
560 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
562 submit
->fence_bos
= new_fence_bos
;
563 submit
->fence_bo_array_length
= new_len
;
566 /* Take advantage that anv_bo are allocated at 8 byte alignement so we can
567 * use the lowest bit to store whether this is a BO we need to signal.
569 submit
->fence_bos
[submit
->fence_bo_count
++] = anv_pack_ptr(bo
, 1, signal
);
575 anv_queue_submit_add_syncobj(struct anv_queue_submit
* submit
,
576 struct anv_device
*device
,
577 uint32_t handle
, uint32_t flags
,
582 if (device
->has_thread_submit
&& (flags
& I915_EXEC_FENCE_WAIT
)) {
583 if (submit
->wait_timeline_count
>= submit
->wait_timeline_array_length
) {
584 uint32_t new_len
= MAX2(submit
->wait_timeline_array_length
* 2, 64);
586 uint32_t *new_wait_timeline_syncobjs
=
587 vk_realloc(submit
->alloc
,
588 submit
->wait_timeline_syncobjs
,
589 new_len
* sizeof(*submit
->wait_timeline_syncobjs
),
590 8, submit
->alloc_scope
);
591 if (new_wait_timeline_syncobjs
== NULL
)
592 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
594 submit
->wait_timeline_syncobjs
= new_wait_timeline_syncobjs
;
596 uint64_t *new_wait_timeline_values
=
597 vk_realloc(submit
->alloc
,
598 submit
->wait_timeline_values
, new_len
* sizeof(*submit
->wait_timeline_values
),
599 8, submit
->alloc_scope
);
600 if (new_wait_timeline_values
== NULL
)
601 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
603 submit
->wait_timeline_values
= new_wait_timeline_values
;
604 submit
->wait_timeline_array_length
= new_len
;
607 submit
->wait_timeline_syncobjs
[submit
->wait_timeline_count
] = handle
;
608 submit
->wait_timeline_values
[submit
->wait_timeline_count
] = value
;
610 submit
->wait_timeline_count
++;
613 if (submit
->fence_count
>= submit
->fence_array_length
) {
614 uint32_t new_len
= MAX2(submit
->fence_array_length
* 2, 64);
615 struct drm_i915_gem_exec_fence
*new_fences
=
616 vk_realloc(submit
->alloc
,
617 submit
->fences
, new_len
* sizeof(*submit
->fences
),
618 8, submit
->alloc_scope
);
619 if (new_fences
== NULL
)
620 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
622 submit
->fences
= new_fences
;
624 uint64_t *new_fence_values
=
625 vk_realloc(submit
->alloc
,
626 submit
->fence_values
, new_len
* sizeof(*submit
->fence_values
),
627 8, submit
->alloc_scope
);
628 if (new_fence_values
== NULL
)
629 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
631 submit
->fence_values
= new_fence_values
;
632 submit
->fence_array_length
= new_len
;
635 submit
->fences
[submit
->fence_count
] = (struct drm_i915_gem_exec_fence
) {
639 submit
->fence_values
[submit
->fence_count
] = value
;
640 submit
->fence_count
++;
646 anv_queue_submit_add_sync_fd_fence(struct anv_queue_submit
*submit
,
647 struct anv_semaphore
*semaphore
)
649 if (submit
->sync_fd_semaphore_count
>= submit
->sync_fd_semaphore_array_length
) {
650 uint32_t new_len
= MAX2(submit
->sync_fd_semaphore_array_length
* 2, 64);
651 struct anv_semaphore
**new_semaphores
=
652 vk_realloc(submit
->alloc
, submit
->sync_fd_semaphores
,
653 new_len
* sizeof(*submit
->sync_fd_semaphores
), 8,
654 submit
->alloc_scope
);
655 if (new_semaphores
== NULL
)
656 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
658 submit
->sync_fd_semaphores
= new_semaphores
;
661 submit
->sync_fd_semaphores
[submit
->sync_fd_semaphore_count
++] =
662 anv_semaphore_ref(semaphore
);
663 submit
->need_out_fence
= true;
669 anv_queue_submit_add_timeline_wait(struct anv_queue_submit
* submit
,
670 struct anv_device
*device
,
671 struct anv_timeline
*timeline
,
674 if (submit
->wait_timeline_count
>= submit
->wait_timeline_array_length
) {
675 uint32_t new_len
= MAX2(submit
->wait_timeline_array_length
* 2, 64);
676 struct anv_timeline
**new_wait_timelines
=
677 vk_realloc(submit
->alloc
,
678 submit
->wait_timelines
, new_len
* sizeof(*submit
->wait_timelines
),
679 8, submit
->alloc_scope
);
680 if (new_wait_timelines
== NULL
)
681 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
683 submit
->wait_timelines
= new_wait_timelines
;
685 uint64_t *new_wait_timeline_values
=
686 vk_realloc(submit
->alloc
,
687 submit
->wait_timeline_values
, new_len
* sizeof(*submit
->wait_timeline_values
),
688 8, submit
->alloc_scope
);
689 if (new_wait_timeline_values
== NULL
)
690 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
692 submit
->wait_timeline_values
= new_wait_timeline_values
;
694 submit
->wait_timeline_array_length
= new_len
;
697 submit
->wait_timelines
[submit
->wait_timeline_count
] = timeline
;
698 submit
->wait_timeline_values
[submit
->wait_timeline_count
] = value
;
700 submit
->wait_timeline_count
++;
706 anv_queue_submit_add_timeline_signal(struct anv_queue_submit
* submit
,
707 struct anv_device
*device
,
708 struct anv_timeline
*timeline
,
711 assert(timeline
->highest_pending
< value
);
713 if (submit
->signal_timeline_count
>= submit
->signal_timeline_array_length
) {
714 uint32_t new_len
= MAX2(submit
->signal_timeline_array_length
* 2, 64);
715 struct anv_timeline
**new_signal_timelines
=
716 vk_realloc(submit
->alloc
,
717 submit
->signal_timelines
, new_len
* sizeof(*submit
->signal_timelines
),
718 8, submit
->alloc_scope
);
719 if (new_signal_timelines
== NULL
)
720 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
722 submit
->signal_timelines
= new_signal_timelines
;
724 uint64_t *new_signal_timeline_values
=
725 vk_realloc(submit
->alloc
,
726 submit
->signal_timeline_values
, new_len
* sizeof(*submit
->signal_timeline_values
),
727 8, submit
->alloc_scope
);
728 if (new_signal_timeline_values
== NULL
)
729 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
731 submit
->signal_timeline_values
= new_signal_timeline_values
;
733 submit
->signal_timeline_array_length
= new_len
;
736 submit
->signal_timelines
[submit
->signal_timeline_count
] = timeline
;
737 submit
->signal_timeline_values
[submit
->signal_timeline_count
] = value
;
739 submit
->signal_timeline_count
++;
744 static struct anv_queue_submit
*
745 anv_queue_submit_alloc(struct anv_device
*device
, int perf_query_pass
)
747 const VkAllocationCallbacks
*alloc
= &device
->vk
.alloc
;
748 VkSystemAllocationScope alloc_scope
= VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
;
750 struct anv_queue_submit
*submit
= vk_zalloc(alloc
, sizeof(*submit
), 8, alloc_scope
);
754 submit
->alloc
= alloc
;
755 submit
->alloc_scope
= alloc_scope
;
756 submit
->in_fence
= -1;
757 submit
->out_fence
= -1;
758 submit
->perf_query_pass
= perf_query_pass
;
764 anv_queue_submit_simple_batch(struct anv_queue
*queue
,
765 struct anv_batch
*batch
)
767 if (queue
->device
->no_hw
)
770 struct anv_device
*device
= queue
->device
;
771 struct anv_queue_submit
*submit
= anv_queue_submit_alloc(device
, -1);
773 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
775 bool has_syncobj_wait
= device
->physical
->has_syncobj_wait
;
778 struct anv_bo
*batch_bo
, *sync_bo
;
780 if (has_syncobj_wait
) {
781 syncobj
= anv_gem_syncobj_create(device
, 0);
783 result
= vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY
);
784 goto err_free_submit
;
787 result
= anv_queue_submit_add_syncobj(submit
, device
, syncobj
,
788 I915_EXEC_FENCE_SIGNAL
, 0);
790 result
= anv_device_alloc_bo(device
, 4096,
791 ANV_BO_ALLOC_EXTERNAL
|
792 ANV_BO_ALLOC_IMPLICIT_SYNC
,
793 0 /* explicit_address */,
795 if (result
!= VK_SUCCESS
)
796 goto err_free_submit
;
798 result
= anv_queue_submit_add_fence_bo(submit
, sync_bo
, true /* signal */);
801 if (result
!= VK_SUCCESS
)
802 goto err_destroy_sync_primitive
;
805 uint32_t size
= align_u32(batch
->next
- batch
->start
, 8);
806 result
= anv_bo_pool_alloc(&device
->batch_bo_pool
, size
, &batch_bo
);
807 if (result
!= VK_SUCCESS
)
808 goto err_destroy_sync_primitive
;
810 memcpy(batch_bo
->map
, batch
->start
, size
);
811 if (!device
->info
.has_llc
)
812 gen_flush_range(batch_bo
->map
, size
);
814 submit
->simple_bo
= batch_bo
;
815 submit
->simple_bo_size
= size
;
818 result
= _anv_queue_submit(queue
, &submit
, true);
820 if (result
== VK_SUCCESS
) {
821 if (has_syncobj_wait
) {
822 if (anv_gem_syncobj_wait(device
, &syncobj
, 1,
823 anv_get_absolute_timeout(INT64_MAX
), true))
824 result
= anv_device_set_lost(device
, "anv_gem_syncobj_wait failed: %m");
825 anv_gem_syncobj_destroy(device
, syncobj
);
827 result
= anv_device_wait(device
, sync_bo
,
828 anv_get_relative_timeout(INT64_MAX
));
829 anv_device_release_bo(device
, sync_bo
);
834 anv_bo_pool_free(&device
->batch_bo_pool
, batch_bo
);
837 anv_queue_submit_free(device
, submit
);
841 err_destroy_sync_primitive
:
842 if (has_syncobj_wait
)
843 anv_gem_syncobj_destroy(device
, syncobj
);
845 anv_device_release_bo(device
, sync_bo
);
848 anv_queue_submit_free(device
, submit
);
853 /* Transfer ownership of temporary semaphores from the VkSemaphore object to
854 * the anv_queue_submit object. Those temporary semaphores are then freed in
855 * anv_queue_submit_free() once the driver is finished with them.
858 maybe_transfer_temporary_semaphore(struct anv_queue_submit
*submit
,
859 struct anv_semaphore
*semaphore
,
860 struct anv_semaphore_impl
**out_impl
)
862 struct anv_semaphore_impl
*impl
= &semaphore
->temporary
;
864 if (impl
->type
== ANV_SEMAPHORE_TYPE_NONE
) {
865 *out_impl
= &semaphore
->permanent
;
869 /* BO backed timeline semaphores cannot be temporary. */
870 assert(impl
->type
!= ANV_SEMAPHORE_TYPE_TIMELINE
);
873 * There is a requirement to reset semaphore to their permanent state after
874 * submission. From the Vulkan 1.0.53 spec:
876 * "If the import is temporary, the implementation must restore the
877 * semaphore to its prior permanent state after submitting the next
878 * semaphore wait operation."
880 * In the case we defer the actual submission to a thread because of the
881 * wait-before-submit behavior required for timeline semaphores, we need to
882 * make copies of the temporary syncobj to ensure they stay alive until we
883 * do the actual execbuffer ioctl.
885 if (submit
->temporary_semaphore_count
>= submit
->temporary_semaphore_array_length
) {
886 uint32_t new_len
= MAX2(submit
->temporary_semaphore_array_length
* 2, 8);
887 /* Make sure that if the realloc fails, we still have the old semaphore
888 * array around to properly clean things up on failure.
890 struct anv_semaphore_impl
*new_array
=
891 vk_realloc(submit
->alloc
,
892 submit
->temporary_semaphores
,
893 new_len
* sizeof(*submit
->temporary_semaphores
),
894 8, submit
->alloc_scope
);
895 if (new_array
== NULL
)
896 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
898 submit
->temporary_semaphores
= new_array
;
899 submit
->temporary_semaphore_array_length
= new_len
;
902 /* Copy anv_semaphore_impl into anv_queue_submit. */
903 submit
->temporary_semaphores
[submit
->temporary_semaphore_count
++] = *impl
;
904 *out_impl
= &submit
->temporary_semaphores
[submit
->temporary_semaphore_count
- 1];
906 /* Clear the incoming semaphore */
907 impl
->type
= ANV_SEMAPHORE_TYPE_NONE
;
913 anv_queue_submit(struct anv_queue
*queue
,
914 struct anv_cmd_buffer
*cmd_buffer
,
915 const VkSemaphore
*in_semaphores
,
916 const uint64_t *in_values
,
917 uint32_t num_in_semaphores
,
918 const VkSemaphore
*out_semaphores
,
919 const uint64_t *out_values
,
920 uint32_t num_out_semaphores
,
921 struct anv_bo
*wsi_signal_bo
,
925 ANV_FROM_HANDLE(anv_fence
, fence
, _fence
);
926 struct anv_device
*device
= queue
->device
;
927 UNUSED
struct anv_physical_device
*pdevice
= device
->physical
;
928 struct anv_queue_submit
*submit
= anv_queue_submit_alloc(device
, perf_query_pass
);
930 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
932 submit
->cmd_buffer
= cmd_buffer
;
934 VkResult result
= VK_SUCCESS
;
935 for (uint32_t i
= 0; i
< num_in_semaphores
; i
++) {
936 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, in_semaphores
[i
]);
937 struct anv_semaphore_impl
*impl
;
939 result
= maybe_transfer_temporary_semaphore(submit
, semaphore
, &impl
);
940 if (result
!= VK_SUCCESS
)
943 switch (impl
->type
) {
944 case ANV_SEMAPHORE_TYPE_BO
:
945 assert(!pdevice
->has_syncobj
);
946 result
= anv_queue_submit_add_fence_bo(submit
, impl
->bo
, false /* signal */);
947 if (result
!= VK_SUCCESS
)
951 case ANV_SEMAPHORE_TYPE_WSI_BO
:
952 /* When using a window-system buffer as a semaphore, always enable
953 * EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or
954 * compositor's read of the buffer and enforces that we don't start
955 * rendering until they are finished. This is exactly the
956 * synchronization we want with vkAcquireNextImage.
958 result
= anv_queue_submit_add_fence_bo(submit
, impl
->bo
, true /* signal */);
959 if (result
!= VK_SUCCESS
)
963 case ANV_SEMAPHORE_TYPE_SYNC_FILE
:
964 assert(!pdevice
->has_syncobj
);
965 if (submit
->in_fence
== -1) {
966 submit
->in_fence
= impl
->fd
;
967 if (submit
->in_fence
== -1) {
968 result
= vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
973 int merge
= anv_gem_sync_file_merge(device
, submit
->in_fence
, impl
->fd
);
975 result
= vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
979 close(submit
->in_fence
);
981 submit
->in_fence
= merge
;
985 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
: {
986 result
= anv_queue_submit_add_syncobj(submit
, device
,
988 I915_EXEC_FENCE_WAIT
,
990 if (result
!= VK_SUCCESS
)
995 case ANV_SEMAPHORE_TYPE_TIMELINE
:
996 result
= anv_queue_submit_add_timeline_wait(submit
, device
,
998 in_values
? in_values
[i
] : 0);
999 if (result
!= VK_SUCCESS
)
1003 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
:
1004 result
= anv_queue_submit_add_syncobj(submit
, device
,
1006 I915_EXEC_FENCE_WAIT
,
1007 in_values
? in_values
[i
] : 0);
1008 if (result
!= VK_SUCCESS
)
1017 for (uint32_t i
= 0; i
< num_out_semaphores
; i
++) {
1018 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, out_semaphores
[i
]);
1020 /* Under most circumstances, out fences won't be temporary. However,
1021 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
1023 * "If the import is temporary, the implementation must restore the
1024 * semaphore to its prior permanent state after submitting the next
1025 * semaphore wait operation."
1027 * The spec says nothing whatsoever about signal operations on
1028 * temporarily imported semaphores so it appears they are allowed.
1029 * There are also CTS tests that require this to work.
1031 struct anv_semaphore_impl
*impl
=
1032 semaphore
->temporary
.type
!= ANV_SEMAPHORE_TYPE_NONE
?
1033 &semaphore
->temporary
: &semaphore
->permanent
;
1035 switch (impl
->type
) {
1036 case ANV_SEMAPHORE_TYPE_BO
:
1037 assert(!pdevice
->has_syncobj
);
1038 result
= anv_queue_submit_add_fence_bo(submit
, impl
->bo
, true /* signal */);
1039 if (result
!= VK_SUCCESS
)
1043 case ANV_SEMAPHORE_TYPE_SYNC_FILE
:
1044 assert(!pdevice
->has_syncobj
);
1045 result
= anv_queue_submit_add_sync_fd_fence(submit
, semaphore
);
1046 if (result
!= VK_SUCCESS
)
1050 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
: {
1051 result
= anv_queue_submit_add_syncobj(submit
, device
, impl
->syncobj
,
1052 I915_EXEC_FENCE_SIGNAL
,
1054 if (result
!= VK_SUCCESS
)
1059 case ANV_SEMAPHORE_TYPE_TIMELINE
:
1060 result
= anv_queue_submit_add_timeline_signal(submit
, device
,
1062 out_values
? out_values
[i
] : 0);
1063 if (result
!= VK_SUCCESS
)
1067 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
:
1068 result
= anv_queue_submit_add_syncobj(submit
, device
, impl
->syncobj
,
1069 I915_EXEC_FENCE_SIGNAL
,
1070 out_values
? out_values
[i
] : 0);
1071 if (result
!= VK_SUCCESS
)
1080 if (wsi_signal_bo
) {
1081 result
= anv_queue_submit_add_fence_bo(submit
, wsi_signal_bo
, true /* signal */);
1082 if (result
!= VK_SUCCESS
)
1087 /* Under most circumstances, out fences won't be temporary. However,
1088 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
1090 * "If the import is temporary, the implementation must restore the
1091 * semaphore to its prior permanent state after submitting the next
1092 * semaphore wait operation."
1094 * The spec says nothing whatsoever about signal operations on
1095 * temporarily imported semaphores so it appears they are allowed.
1096 * There are also CTS tests that require this to work.
1098 struct anv_fence_impl
*impl
=
1099 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1100 &fence
->temporary
: &fence
->permanent
;
1102 switch (impl
->type
) {
1103 case ANV_FENCE_TYPE_BO
:
1104 assert(!device
->has_thread_submit
);
1105 result
= anv_queue_submit_add_fence_bo(submit
, impl
->bo
.bo
, true /* signal */);
1106 if (result
!= VK_SUCCESS
)
1110 case ANV_FENCE_TYPE_SYNCOBJ
: {
1112 * For the same reason we reset the signaled binary syncobj above,
1113 * also reset the fence's syncobj so that they don't contain a
1114 * signaled dma-fence.
1116 anv_gem_syncobj_reset(device
, impl
->syncobj
);
1118 result
= anv_queue_submit_add_syncobj(submit
, device
, impl
->syncobj
,
1119 I915_EXEC_FENCE_SIGNAL
,
1121 if (result
!= VK_SUCCESS
)
1127 unreachable("Invalid fence type");
1131 result
= _anv_queue_submit(queue
, &submit
, false);
1132 if (result
!= VK_SUCCESS
)
1135 if (fence
&& fence
->permanent
.type
== ANV_FENCE_TYPE_BO
) {
1136 assert(!device
->has_thread_submit
);
1137 /* If we have permanent BO fence, the only type of temporary possible
1138 * would be BO_WSI (because BO fences are not shareable). The Vulkan spec
1139 * also requires that the fence passed to vkQueueSubmit() be :
1142 * * not be associated with any other queue command that has not yet
1143 * completed execution on that queue
1145 * So the only acceptable type for the temporary is NONE.
1147 assert(fence
->temporary
.type
== ANV_FENCE_TYPE_NONE
);
1149 /* Once the execbuf has returned, we need to set the fence state to
1150 * SUBMITTED. We can't do this before calling execbuf because
1151 * anv_GetFenceStatus does take the global device lock before checking
1154 * We set the fence state to SUBMITTED regardless of whether or not the
1155 * execbuf succeeds because we need to ensure that vkWaitForFences() and
1156 * vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or
1157 * VK_SUCCESS) in a finite amount of time even if execbuf fails.
1159 fence
->permanent
.bo
.state
= ANV_BO_FENCE_STATE_SUBMITTED
;
1164 anv_queue_submit_free(device
, submit
);
1169 VkResult
anv_QueueSubmit(
1171 uint32_t submitCount
,
1172 const VkSubmitInfo
* pSubmits
,
1175 ANV_FROM_HANDLE(anv_queue
, queue
, _queue
);
1177 if (queue
->device
->no_hw
)
1180 /* Query for device status prior to submitting. Technically, we don't need
1181 * to do this. However, if we have a client that's submitting piles of
1182 * garbage, we would rather break as early as possible to keep the GPU
1183 * hanging contained. If we don't check here, we'll either be waiting for
1184 * the kernel to kick us or we'll have to wait until the client waits on a
1185 * fence before we actually know whether or not we've hung.
1187 VkResult result
= anv_device_query_status(queue
->device
);
1188 if (result
!= VK_SUCCESS
)
1191 if (fence
&& submitCount
== 0) {
1192 /* If we don't have any command buffers, we need to submit a dummy
1193 * batch to give GEM something to wait on. We could, potentially,
1194 * come up with something more efficient but this shouldn't be a
1197 result
= anv_queue_submit(queue
, NULL
, NULL
, NULL
, 0, NULL
, NULL
, 0,
1202 for (uint32_t i
= 0; i
< submitCount
; i
++) {
1203 /* Fence for this submit. NULL for all but the last one */
1204 VkFence submit_fence
= (i
== submitCount
- 1) ? fence
: VK_NULL_HANDLE
;
1206 const struct wsi_memory_signal_submit_info
*mem_signal_info
=
1207 vk_find_struct_const(pSubmits
[i
].pNext
,
1208 WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA
);
1209 struct anv_bo
*wsi_signal_bo
=
1210 mem_signal_info
&& mem_signal_info
->memory
!= VK_NULL_HANDLE
?
1211 anv_device_memory_from_handle(mem_signal_info
->memory
)->bo
: NULL
;
1213 const VkTimelineSemaphoreSubmitInfoKHR
*timeline_info
=
1214 vk_find_struct_const(pSubmits
[i
].pNext
,
1215 TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR
);
1216 const VkPerformanceQuerySubmitInfoKHR
*perf_info
=
1217 vk_find_struct_const(pSubmits
[i
].pNext
,
1218 PERFORMANCE_QUERY_SUBMIT_INFO_KHR
);
1219 const uint64_t *wait_values
=
1220 timeline_info
&& timeline_info
->waitSemaphoreValueCount
?
1221 timeline_info
->pWaitSemaphoreValues
: NULL
;
1222 const uint64_t *signal_values
=
1223 timeline_info
&& timeline_info
->signalSemaphoreValueCount
?
1224 timeline_info
->pSignalSemaphoreValues
: NULL
;
1226 if (pSubmits
[i
].commandBufferCount
== 0) {
1227 /* If we don't have any command buffers, we need to submit a dummy
1228 * batch to give GEM something to wait on. We could, potentially,
1229 * come up with something more efficient but this shouldn't be a
1232 result
= anv_queue_submit(queue
, NULL
,
1233 pSubmits
[i
].pWaitSemaphores
,
1235 pSubmits
[i
].waitSemaphoreCount
,
1236 pSubmits
[i
].pSignalSemaphores
,
1238 pSubmits
[i
].signalSemaphoreCount
,
1242 if (result
!= VK_SUCCESS
)
1248 for (uint32_t j
= 0; j
< pSubmits
[i
].commandBufferCount
; j
++) {
1249 ANV_FROM_HANDLE(anv_cmd_buffer
, cmd_buffer
,
1250 pSubmits
[i
].pCommandBuffers
[j
]);
1251 assert(cmd_buffer
->level
== VK_COMMAND_BUFFER_LEVEL_PRIMARY
);
1252 assert(!anv_batch_has_error(&cmd_buffer
->batch
));
1254 /* Fence for this execbuf. NULL for all but the last one */
1255 VkFence execbuf_fence
=
1256 (j
== pSubmits
[i
].commandBufferCount
- 1) ?
1257 submit_fence
: VK_NULL_HANDLE
;
1259 const VkSemaphore
*in_semaphores
= NULL
, *out_semaphores
= NULL
;
1260 const uint64_t *in_values
= NULL
, *out_values
= NULL
;
1261 uint32_t num_in_semaphores
= 0, num_out_semaphores
= 0;
1263 /* Only the first batch gets the in semaphores */
1264 in_semaphores
= pSubmits
[i
].pWaitSemaphores
;
1265 in_values
= wait_values
;
1266 num_in_semaphores
= pSubmits
[i
].waitSemaphoreCount
;
1269 if (j
== pSubmits
[i
].commandBufferCount
- 1) {
1270 /* Only the last batch gets the out semaphores */
1271 out_semaphores
= pSubmits
[i
].pSignalSemaphores
;
1272 out_values
= signal_values
;
1273 num_out_semaphores
= pSubmits
[i
].signalSemaphoreCount
;
1276 result
= anv_queue_submit(queue
, cmd_buffer
,
1277 in_semaphores
, in_values
, num_in_semaphores
,
1278 out_semaphores
, out_values
, num_out_semaphores
,
1279 wsi_signal_bo
, execbuf_fence
,
1280 perf_info
? perf_info
->counterPassIndex
: 0);
1281 if (result
!= VK_SUCCESS
)
1287 if (result
!= VK_SUCCESS
&& result
!= VK_ERROR_DEVICE_LOST
) {
1288 /* In the case that something has gone wrong we may end up with an
1289 * inconsistent state from which it may not be trivial to recover.
1290 * For example, we might have computed address relocations and
1291 * any future attempt to re-submit this job will need to know about
1292 * this and avoid computing relocation addresses again.
1294 * To avoid this sort of issues, we assume that if something was
1295 * wrong during submission we must already be in a really bad situation
1296 * anyway (such us being out of memory) and return
1297 * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
1298 * submit the same job again to this device.
1300 * We skip doing this on VK_ERROR_DEVICE_LOST because
1301 * anv_device_set_lost() would have been called already by a callee of
1302 * anv_queue_submit().
1304 result
= anv_device_set_lost(queue
->device
, "vkQueueSubmit() failed");
1310 VkResult
anv_QueueWaitIdle(
1313 ANV_FROM_HANDLE(anv_queue
, queue
, _queue
);
1315 if (anv_device_is_lost(queue
->device
))
1316 return VK_ERROR_DEVICE_LOST
;
1318 return anv_queue_submit_simple_batch(queue
, NULL
);
1321 VkResult
anv_CreateFence(
1323 const VkFenceCreateInfo
* pCreateInfo
,
1324 const VkAllocationCallbacks
* pAllocator
,
1327 ANV_FROM_HANDLE(anv_device
, device
, _device
);
1328 struct anv_fence
*fence
;
1330 assert(pCreateInfo
->sType
== VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
);
1332 fence
= vk_zalloc2(&device
->vk
.alloc
, pAllocator
, sizeof(*fence
), 8,
1333 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
1335 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
1337 vk_object_base_init(&device
->vk
, &fence
->base
, VK_OBJECT_TYPE_FENCE
);
1339 if (device
->physical
->has_syncobj_wait
) {
1340 fence
->permanent
.type
= ANV_FENCE_TYPE_SYNCOBJ
;
1342 uint32_t create_flags
= 0;
1343 if (pCreateInfo
->flags
& VK_FENCE_CREATE_SIGNALED_BIT
)
1344 create_flags
|= DRM_SYNCOBJ_CREATE_SIGNALED
;
1346 fence
->permanent
.syncobj
= anv_gem_syncobj_create(device
, create_flags
);
1347 if (!fence
->permanent
.syncobj
)
1348 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
1350 fence
->permanent
.type
= ANV_FENCE_TYPE_BO
;
1352 VkResult result
= anv_bo_pool_alloc(&device
->batch_bo_pool
, 4096,
1353 &fence
->permanent
.bo
.bo
);
1354 if (result
!= VK_SUCCESS
)
1357 if (pCreateInfo
->flags
& VK_FENCE_CREATE_SIGNALED_BIT
) {
1358 fence
->permanent
.bo
.state
= ANV_BO_FENCE_STATE_SIGNALED
;
1360 fence
->permanent
.bo
.state
= ANV_BO_FENCE_STATE_RESET
;
1364 *pFence
= anv_fence_to_handle(fence
);
1370 anv_fence_impl_cleanup(struct anv_device
*device
,
1371 struct anv_fence_impl
*impl
)
1373 switch (impl
->type
) {
1374 case ANV_FENCE_TYPE_NONE
:
1375 /* Dummy. Nothing to do */
1378 case ANV_FENCE_TYPE_BO
:
1379 anv_bo_pool_free(&device
->batch_bo_pool
, impl
->bo
.bo
);
1382 case ANV_FENCE_TYPE_WSI_BO
:
1383 anv_device_release_bo(device
, impl
->bo
.bo
);
1386 case ANV_FENCE_TYPE_SYNCOBJ
:
1387 anv_gem_syncobj_destroy(device
, impl
->syncobj
);
1390 case ANV_FENCE_TYPE_WSI
:
1391 impl
->fence_wsi
->destroy(impl
->fence_wsi
);
1395 unreachable("Invalid fence type");
1398 impl
->type
= ANV_FENCE_TYPE_NONE
;
1402 anv_fence_reset_temporary(struct anv_device
*device
,
1403 struct anv_fence
*fence
)
1405 if (fence
->temporary
.type
== ANV_FENCE_TYPE_NONE
)
1408 anv_fence_impl_cleanup(device
, &fence
->temporary
);
1411 void anv_DestroyFence(
1414 const VkAllocationCallbacks
* pAllocator
)
1416 ANV_FROM_HANDLE(anv_device
, device
, _device
);
1417 ANV_FROM_HANDLE(anv_fence
, fence
, _fence
);
1422 anv_fence_impl_cleanup(device
, &fence
->temporary
);
1423 anv_fence_impl_cleanup(device
, &fence
->permanent
);
1425 vk_object_base_finish(&fence
->base
);
1426 vk_free2(&device
->vk
.alloc
, pAllocator
, fence
);
1429 VkResult
anv_ResetFences(
1431 uint32_t fenceCount
,
1432 const VkFence
* pFences
)
1434 ANV_FROM_HANDLE(anv_device
, device
, _device
);
1436 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
1437 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
1439 /* From the Vulkan 1.0.53 spec:
1441 * "If any member of pFences currently has its payload imported with
1442 * temporary permanence, that fence’s prior permanent payload is
1443 * first restored. The remaining operations described therefore
1444 * operate on the restored payload.
1446 anv_fence_reset_temporary(device
, fence
);
1448 struct anv_fence_impl
*impl
= &fence
->permanent
;
1450 switch (impl
->type
) {
1451 case ANV_FENCE_TYPE_BO
:
1452 impl
->bo
.state
= ANV_BO_FENCE_STATE_RESET
;
1455 case ANV_FENCE_TYPE_SYNCOBJ
:
1456 anv_gem_syncobj_reset(device
, impl
->syncobj
);
1460 unreachable("Invalid fence type");
1467 VkResult
anv_GetFenceStatus(
1471 ANV_FROM_HANDLE(anv_device
, device
, _device
);
1472 ANV_FROM_HANDLE(anv_fence
, fence
, _fence
);
1474 if (anv_device_is_lost(device
))
1475 return VK_ERROR_DEVICE_LOST
;
1477 struct anv_fence_impl
*impl
=
1478 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1479 &fence
->temporary
: &fence
->permanent
;
1481 switch (impl
->type
) {
1482 case ANV_FENCE_TYPE_BO
:
1483 case ANV_FENCE_TYPE_WSI_BO
:
1484 switch (impl
->bo
.state
) {
1485 case ANV_BO_FENCE_STATE_RESET
:
1486 /* If it hasn't even been sent off to the GPU yet, it's not ready */
1487 return VK_NOT_READY
;
1489 case ANV_BO_FENCE_STATE_SIGNALED
:
1490 /* It's been signaled, return success */
1493 case ANV_BO_FENCE_STATE_SUBMITTED
: {
1494 VkResult result
= anv_device_bo_busy(device
, impl
->bo
.bo
);
1495 if (result
== VK_SUCCESS
) {
1496 impl
->bo
.state
= ANV_BO_FENCE_STATE_SIGNALED
;
1503 unreachable("Invalid fence status");
1506 case ANV_FENCE_TYPE_SYNCOBJ
: {
1507 if (device
->has_thread_submit
) {
1508 uint64_t binary_value
= 0;
1509 int ret
= anv_gem_syncobj_timeline_wait(device
, &impl
->syncobj
,
1510 &binary_value
, 1, 0,
1511 true /* wait_all */,
1512 false /* wait_materialize */);
1514 if (errno
== ETIME
) {
1515 return VK_NOT_READY
;
1517 /* We don't know the real error. */
1518 return anv_device_set_lost(device
, "drm_syncobj_wait failed: %m");
1524 int ret
= anv_gem_syncobj_wait(device
, &impl
->syncobj
, 1, 0, false);
1526 if (errno
== ETIME
) {
1527 return VK_NOT_READY
;
1529 /* We don't know the real error. */
1530 return anv_device_set_lost(device
, "drm_syncobj_wait failed: %m");
1539 unreachable("Invalid fence type");
1544 anv_wait_for_syncobj_fences(struct anv_device
*device
,
1545 uint32_t fenceCount
,
1546 const VkFence
*pFences
,
1548 uint64_t abs_timeout_ns
)
1550 uint32_t *syncobjs
= vk_zalloc(&device
->vk
.alloc
,
1551 sizeof(*syncobjs
) * fenceCount
, 8,
1552 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND
);
1554 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
1556 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
1557 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
1558 assert(fence
->permanent
.type
== ANV_FENCE_TYPE_SYNCOBJ
);
1560 struct anv_fence_impl
*impl
=
1561 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1562 &fence
->temporary
: &fence
->permanent
;
1564 assert(impl
->type
== ANV_FENCE_TYPE_SYNCOBJ
);
1565 syncobjs
[i
] = impl
->syncobj
;
1569 /* The gem_syncobj_wait ioctl may return early due to an inherent
1570 * limitation in the way it computes timeouts. Loop until we've actually
1571 * passed the timeout.
1574 ret
= anv_gem_syncobj_wait(device
, syncobjs
, fenceCount
,
1575 abs_timeout_ns
, waitAll
);
1576 } while (ret
== -1 && errno
== ETIME
&& anv_gettime_ns() < abs_timeout_ns
);
1578 vk_free(&device
->vk
.alloc
, syncobjs
);
1581 if (errno
== ETIME
) {
1584 /* We don't know the real error. */
1585 return anv_device_set_lost(device
, "drm_syncobj_wait failed: %m");
1593 anv_wait_for_bo_fences(struct anv_device
*device
,
1594 uint32_t fenceCount
,
1595 const VkFence
*pFences
,
1597 uint64_t abs_timeout_ns
)
1599 VkResult result
= VK_SUCCESS
;
1600 uint32_t pending_fences
= fenceCount
;
1601 while (pending_fences
) {
1603 bool signaled_fences
= false;
1604 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
1605 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
1607 struct anv_fence_impl
*impl
=
1608 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1609 &fence
->temporary
: &fence
->permanent
;
1610 assert(impl
->type
== ANV_FENCE_TYPE_BO
||
1611 impl
->type
== ANV_FENCE_TYPE_WSI_BO
);
1613 switch (impl
->bo
.state
) {
1614 case ANV_BO_FENCE_STATE_RESET
:
1615 /* This fence hasn't been submitted yet, we'll catch it the next
1616 * time around. Yes, this may mean we dead-loop but, short of
1617 * lots of locking and a condition variable, there's not much that
1618 * we can do about that.
1623 case ANV_BO_FENCE_STATE_SIGNALED
:
1624 /* This fence is not pending. If waitAll isn't set, we can return
1625 * early. Otherwise, we have to keep going.
1628 result
= VK_SUCCESS
;
1633 case ANV_BO_FENCE_STATE_SUBMITTED
:
1634 /* These are the fences we really care about. Go ahead and wait
1635 * on it until we hit a timeout.
1637 result
= anv_device_wait(device
, impl
->bo
.bo
,
1638 anv_get_relative_timeout(abs_timeout_ns
));
1641 impl
->bo
.state
= ANV_BO_FENCE_STATE_SIGNALED
;
1642 signaled_fences
= true;
1656 if (pending_fences
&& !signaled_fences
) {
1657 /* If we've hit this then someone decided to vkWaitForFences before
1658 * they've actually submitted any of them to a queue. This is a
1659 * fairly pessimal case, so it's ok to lock here and use a standard
1660 * pthreads condition variable.
1662 pthread_mutex_lock(&device
->mutex
);
1664 /* It's possible that some of the fences have changed state since the
1665 * last time we checked. Now that we have the lock, check for
1666 * pending fences again and don't wait if it's changed.
1668 uint32_t now_pending_fences
= 0;
1669 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
1670 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
1671 if (fence
->permanent
.bo
.state
== ANV_BO_FENCE_STATE_RESET
)
1672 now_pending_fences
++;
1674 assert(now_pending_fences
<= pending_fences
);
1676 if (now_pending_fences
== pending_fences
) {
1677 struct timespec abstime
= {
1678 .tv_sec
= abs_timeout_ns
/ NSEC_PER_SEC
,
1679 .tv_nsec
= abs_timeout_ns
% NSEC_PER_SEC
,
1683 ret
= pthread_cond_timedwait(&device
->queue_submit
,
1684 &device
->mutex
, &abstime
);
1685 assert(ret
!= EINVAL
);
1686 if (anv_gettime_ns() >= abs_timeout_ns
) {
1687 pthread_mutex_unlock(&device
->mutex
);
1688 result
= VK_TIMEOUT
;
1693 pthread_mutex_unlock(&device
->mutex
);
1698 if (anv_device_is_lost(device
))
1699 return VK_ERROR_DEVICE_LOST
;
1705 anv_wait_for_wsi_fence(struct anv_device
*device
,
1706 struct anv_fence_impl
*impl
,
1707 uint64_t abs_timeout
)
1709 return impl
->fence_wsi
->wait(impl
->fence_wsi
, abs_timeout
);
1713 anv_wait_for_fences(struct anv_device
*device
,
1714 uint32_t fenceCount
,
1715 const VkFence
*pFences
,
1717 uint64_t abs_timeout
)
1719 VkResult result
= VK_SUCCESS
;
1721 if (fenceCount
<= 1 || waitAll
) {
1722 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
1723 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
1724 struct anv_fence_impl
*impl
=
1725 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1726 &fence
->temporary
: &fence
->permanent
;
1728 switch (impl
->type
) {
1729 case ANV_FENCE_TYPE_BO
:
1730 assert(!device
->physical
->has_syncobj_wait
);
1732 case ANV_FENCE_TYPE_WSI_BO
:
1733 result
= anv_wait_for_bo_fences(device
, 1, &pFences
[i
],
1736 case ANV_FENCE_TYPE_SYNCOBJ
:
1737 result
= anv_wait_for_syncobj_fences(device
, 1, &pFences
[i
],
1740 case ANV_FENCE_TYPE_WSI
:
1741 result
= anv_wait_for_wsi_fence(device
, impl
, abs_timeout
);
1743 case ANV_FENCE_TYPE_NONE
:
1744 result
= VK_SUCCESS
;
1747 if (result
!= VK_SUCCESS
)
1752 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
1753 if (anv_wait_for_fences(device
, 1, &pFences
[i
], true, 0) == VK_SUCCESS
)
1756 } while (anv_gettime_ns() < abs_timeout
);
1757 result
= VK_TIMEOUT
;
1762 static bool anv_all_fences_syncobj(uint32_t fenceCount
, const VkFence
*pFences
)
1764 for (uint32_t i
= 0; i
< fenceCount
; ++i
) {
1765 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
1766 struct anv_fence_impl
*impl
=
1767 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1768 &fence
->temporary
: &fence
->permanent
;
1769 if (impl
->type
!= ANV_FENCE_TYPE_SYNCOBJ
)
1775 static bool anv_all_fences_bo(uint32_t fenceCount
, const VkFence
*pFences
)
1777 for (uint32_t i
= 0; i
< fenceCount
; ++i
) {
1778 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
1779 struct anv_fence_impl
*impl
=
1780 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1781 &fence
->temporary
: &fence
->permanent
;
1782 if (impl
->type
!= ANV_FENCE_TYPE_BO
&&
1783 impl
->type
!= ANV_FENCE_TYPE_WSI_BO
)
1789 VkResult
anv_WaitForFences(
1791 uint32_t fenceCount
,
1792 const VkFence
* pFences
,
1796 ANV_FROM_HANDLE(anv_device
, device
, _device
);
1801 if (anv_device_is_lost(device
))
1802 return VK_ERROR_DEVICE_LOST
;
1804 uint64_t abs_timeout
= anv_get_absolute_timeout(timeout
);
1805 if (anv_all_fences_syncobj(fenceCount
, pFences
)) {
1806 return anv_wait_for_syncobj_fences(device
, fenceCount
, pFences
,
1807 waitAll
, abs_timeout
);
1808 } else if (anv_all_fences_bo(fenceCount
, pFences
)) {
1809 return anv_wait_for_bo_fences(device
, fenceCount
, pFences
,
1810 waitAll
, abs_timeout
);
1812 return anv_wait_for_fences(device
, fenceCount
, pFences
,
1813 waitAll
, abs_timeout
);
1817 void anv_GetPhysicalDeviceExternalFenceProperties(
1818 VkPhysicalDevice physicalDevice
,
1819 const VkPhysicalDeviceExternalFenceInfo
* pExternalFenceInfo
,
1820 VkExternalFenceProperties
* pExternalFenceProperties
)
1822 ANV_FROM_HANDLE(anv_physical_device
, device
, physicalDevice
);
1824 switch (pExternalFenceInfo
->handleType
) {
1825 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT
:
1826 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
:
1827 if (device
->has_syncobj_wait
) {
1828 pExternalFenceProperties
->exportFromImportedHandleTypes
=
1829 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT
|
1830 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
;
1831 pExternalFenceProperties
->compatibleHandleTypes
=
1832 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT
|
1833 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
;
1834 pExternalFenceProperties
->externalFenceFeatures
=
1835 VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT
|
1836 VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT
;
1845 pExternalFenceProperties
->exportFromImportedHandleTypes
= 0;
1846 pExternalFenceProperties
->compatibleHandleTypes
= 0;
1847 pExternalFenceProperties
->externalFenceFeatures
= 0;
1850 VkResult
anv_ImportFenceFdKHR(
1852 const VkImportFenceFdInfoKHR
* pImportFenceFdInfo
)
1854 ANV_FROM_HANDLE(anv_device
, device
, _device
);
1855 ANV_FROM_HANDLE(anv_fence
, fence
, pImportFenceFdInfo
->fence
);
1856 int fd
= pImportFenceFdInfo
->fd
;
1858 assert(pImportFenceFdInfo
->sType
==
1859 VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR
);
1861 struct anv_fence_impl new_impl
= {
1862 .type
= ANV_FENCE_TYPE_NONE
,
1865 switch (pImportFenceFdInfo
->handleType
) {
1866 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT
:
1867 new_impl
.type
= ANV_FENCE_TYPE_SYNCOBJ
;
1869 new_impl
.syncobj
= anv_gem_syncobj_fd_to_handle(device
, fd
);
1870 if (!new_impl
.syncobj
)
1871 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
1875 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
: {
1876 /* Sync files are a bit tricky. Because we want to continue using the
1877 * syncobj implementation of WaitForFences, we don't use the sync file
1878 * directly but instead import it into a syncobj.
1880 new_impl
.type
= ANV_FENCE_TYPE_SYNCOBJ
;
1882 /* "If handleType is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, the
1883 * special value -1 for fd is treated like a valid sync file descriptor
1884 * referring to an object that has already signaled. The import
1885 * operation will succeed and the VkFence will have a temporarily
1886 * imported payload as if a valid file descriptor had been provided."
1888 uint32_t create_flags
= 0;
1890 create_flags
|= DRM_SYNCOBJ_CREATE_SIGNALED
;
1892 new_impl
.syncobj
= anv_gem_syncobj_create(device
, create_flags
);
1893 if (!new_impl
.syncobj
)
1894 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
1897 anv_gem_syncobj_import_sync_file(device
, new_impl
.syncobj
, fd
)) {
1898 anv_gem_syncobj_destroy(device
, new_impl
.syncobj
);
1899 return vk_errorf(device
, NULL
, VK_ERROR_INVALID_EXTERNAL_HANDLE
,
1900 "syncobj sync file import failed: %m");
1906 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
1909 /* From the Vulkan 1.0.53 spec:
1911 * "Importing a fence payload from a file descriptor transfers
1912 * ownership of the file descriptor from the application to the
1913 * Vulkan implementation. The application must not perform any
1914 * operations on the file descriptor after a successful import."
1916 * If the import fails, we leave the file descriptor open.
1920 if (pImportFenceFdInfo
->flags
& VK_FENCE_IMPORT_TEMPORARY_BIT
) {
1921 anv_fence_impl_cleanup(device
, &fence
->temporary
);
1922 fence
->temporary
= new_impl
;
1924 anv_fence_impl_cleanup(device
, &fence
->permanent
);
1925 fence
->permanent
= new_impl
;
1931 /* The sideband payload of the DRM syncobj was incremented when the
1932 * application called vkQueueSubmit(). Here we wait for a fence with the same
1933 * value to materialize so that we can exporting (typically as a SyncFD).
1936 wait_syncobj_materialize(struct anv_device
*device
,
1940 if (!device
->has_thread_submit
)
1943 uint64_t binary_value
= 0;
1944 /* We might need to wait until the fence materializes before we can
1945 * export to a sync FD when we use a thread for submission.
1947 if (anv_gem_syncobj_timeline_wait(device
, &syncobj
, &binary_value
, 1,
1948 anv_get_absolute_timeout(5ull * NSEC_PER_SEC
),
1949 true /* wait_all */,
1950 true /* wait_materialize */))
1951 return anv_device_set_lost(device
, "anv_gem_syncobj_timeline_wait failed: %m");
1956 VkResult
anv_GetFenceFdKHR(
1958 const VkFenceGetFdInfoKHR
* pGetFdInfo
,
1961 ANV_FROM_HANDLE(anv_device
, device
, _device
);
1962 ANV_FROM_HANDLE(anv_fence
, fence
, pGetFdInfo
->fence
);
1964 assert(pGetFdInfo
->sType
== VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR
);
1966 struct anv_fence_impl
*impl
=
1967 fence
->temporary
.type
!= ANV_FENCE_TYPE_NONE
?
1968 &fence
->temporary
: &fence
->permanent
;
1970 assert(impl
->type
== ANV_FENCE_TYPE_SYNCOBJ
);
1971 switch (pGetFdInfo
->handleType
) {
1972 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT
: {
1973 int fd
= anv_gem_syncobj_handle_to_fd(device
, impl
->syncobj
);
1975 return vk_error(VK_ERROR_TOO_MANY_OBJECTS
);
1981 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT
: {
1982 VkResult result
= wait_syncobj_materialize(device
, impl
->syncobj
, pFd
);
1983 if (result
!= VK_SUCCESS
)
1986 int fd
= anv_gem_syncobj_export_sync_file(device
, impl
->syncobj
);
1988 return vk_error(VK_ERROR_TOO_MANY_OBJECTS
);
1995 unreachable("Invalid fence export handle type");
1998 /* From the Vulkan 1.0.53 spec:
2000 * "Export operations have the same transference as the specified handle
2001 * type’s import operations. [...] If the fence was using a
2002 * temporarily imported payload, the fence’s prior permanent payload
2005 if (impl
== &fence
->temporary
)
2006 anv_fence_impl_cleanup(device
, impl
);
2011 // Queue semaphore functions
2013 static VkSemaphoreTypeKHR
2014 get_semaphore_type(const void *pNext
, uint64_t *initial_value
)
2016 const VkSemaphoreTypeCreateInfoKHR
*type_info
=
2017 vk_find_struct_const(pNext
, SEMAPHORE_TYPE_CREATE_INFO_KHR
);
2020 return VK_SEMAPHORE_TYPE_BINARY_KHR
;
2023 *initial_value
= type_info
->initialValue
;
2024 return type_info
->semaphoreType
;
2028 binary_semaphore_create(struct anv_device
*device
,
2029 struct anv_semaphore_impl
*impl
,
2032 if (device
->physical
->has_syncobj
) {
2033 impl
->type
= ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
;
2034 impl
->syncobj
= anv_gem_syncobj_create(device
, 0);
2036 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
2039 impl
->type
= ANV_SEMAPHORE_TYPE_BO
;
2041 anv_device_alloc_bo(device
, 4096,
2042 ANV_BO_ALLOC_EXTERNAL
|
2043 ANV_BO_ALLOC_IMPLICIT_SYNC
,
2044 0 /* explicit_address */,
2046 /* If we're going to use this as a fence, we need to *not* have the
2047 * EXEC_OBJECT_ASYNC bit set.
2049 assert(!(impl
->bo
->flags
& EXEC_OBJECT_ASYNC
));
2055 timeline_semaphore_create(struct anv_device
*device
,
2056 struct anv_semaphore_impl
*impl
,
2057 uint64_t initial_value
)
2059 if (device
->has_thread_submit
) {
2060 impl
->type
= ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
;
2061 impl
->syncobj
= anv_gem_syncobj_create(device
, 0);
2063 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
2064 if (initial_value
) {
2065 if (anv_gem_syncobj_timeline_signal(device
,
2067 &initial_value
, 1)) {
2068 anv_gem_syncobj_destroy(device
, impl
->syncobj
);
2069 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
2073 impl
->type
= ANV_SEMAPHORE_TYPE_TIMELINE
;
2074 anv_timeline_init(device
, &impl
->timeline
, initial_value
);
2080 VkResult
anv_CreateSemaphore(
2082 const VkSemaphoreCreateInfo
* pCreateInfo
,
2083 const VkAllocationCallbacks
* pAllocator
,
2084 VkSemaphore
* pSemaphore
)
2086 ANV_FROM_HANDLE(anv_device
, device
, _device
);
2087 struct anv_semaphore
*semaphore
;
2089 assert(pCreateInfo
->sType
== VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
);
2091 uint64_t timeline_value
= 0;
2092 VkSemaphoreTypeKHR sem_type
= get_semaphore_type(pCreateInfo
->pNext
, &timeline_value
);
2094 semaphore
= vk_alloc(&device
->vk
.alloc
, sizeof(*semaphore
), 8,
2095 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE
);
2096 if (semaphore
== NULL
)
2097 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
2099 vk_object_base_init(&device
->vk
, &semaphore
->base
, VK_OBJECT_TYPE_SEMAPHORE
);
2101 p_atomic_set(&semaphore
->refcount
, 1);
2103 const VkExportSemaphoreCreateInfo
*export
=
2104 vk_find_struct_const(pCreateInfo
->pNext
, EXPORT_SEMAPHORE_CREATE_INFO
);
2105 VkExternalSemaphoreHandleTypeFlags handleTypes
=
2106 export
? export
->handleTypes
: 0;
2109 if (handleTypes
== 0) {
2110 if (sem_type
== VK_SEMAPHORE_TYPE_BINARY_KHR
)
2111 result
= binary_semaphore_create(device
, &semaphore
->permanent
, false);
2113 result
= timeline_semaphore_create(device
, &semaphore
->permanent
, timeline_value
);
2114 if (result
!= VK_SUCCESS
) {
2115 vk_free2(&device
->vk
.alloc
, pAllocator
, semaphore
);
2118 } else if (handleTypes
& VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
) {
2119 assert(handleTypes
== VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
);
2120 if (sem_type
== VK_SEMAPHORE_TYPE_BINARY_KHR
)
2121 result
= binary_semaphore_create(device
, &semaphore
->permanent
, true);
2123 result
= timeline_semaphore_create(device
, &semaphore
->permanent
, timeline_value
);
2124 if (result
!= VK_SUCCESS
) {
2125 vk_free2(&device
->vk
.alloc
, pAllocator
, semaphore
);
2128 } else if (handleTypes
& VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
) {
2129 assert(handleTypes
== VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
);
2130 assert(sem_type
== VK_SEMAPHORE_TYPE_BINARY_KHR
);
2131 if (device
->physical
->has_syncobj
) {
2132 semaphore
->permanent
.type
= ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
;
2133 semaphore
->permanent
.syncobj
= anv_gem_syncobj_create(device
, 0);
2134 if (!semaphore
->permanent
.syncobj
) {
2135 vk_free2(&device
->vk
.alloc
, pAllocator
, semaphore
);
2136 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
2139 semaphore
->permanent
.type
= ANV_SEMAPHORE_TYPE_SYNC_FILE
;
2140 semaphore
->permanent
.fd
= -1;
2143 assert(!"Unknown handle type");
2144 vk_free2(&device
->vk
.alloc
, pAllocator
, semaphore
);
2145 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
2148 semaphore
->temporary
.type
= ANV_SEMAPHORE_TYPE_NONE
;
2150 *pSemaphore
= anv_semaphore_to_handle(semaphore
);
2156 anv_semaphore_impl_cleanup(struct anv_device
*device
,
2157 struct anv_semaphore_impl
*impl
)
2159 switch (impl
->type
) {
2160 case ANV_SEMAPHORE_TYPE_NONE
:
2161 case ANV_SEMAPHORE_TYPE_DUMMY
:
2162 /* Dummy. Nothing to do */
2165 case ANV_SEMAPHORE_TYPE_BO
:
2166 case ANV_SEMAPHORE_TYPE_WSI_BO
:
2167 anv_device_release_bo(device
, impl
->bo
);
2170 case ANV_SEMAPHORE_TYPE_SYNC_FILE
:
2175 case ANV_SEMAPHORE_TYPE_TIMELINE
:
2176 anv_timeline_finish(device
, &impl
->timeline
);
2179 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
:
2180 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
:
2181 anv_gem_syncobj_destroy(device
, impl
->syncobj
);
2185 unreachable("Invalid semaphore type");
2188 impl
->type
= ANV_SEMAPHORE_TYPE_NONE
;
2192 anv_semaphore_reset_temporary(struct anv_device
*device
,
2193 struct anv_semaphore
*semaphore
)
2195 if (semaphore
->temporary
.type
== ANV_SEMAPHORE_TYPE_NONE
)
2198 anv_semaphore_impl_cleanup(device
, &semaphore
->temporary
);
2201 static struct anv_semaphore
*
2202 anv_semaphore_ref(struct anv_semaphore
*semaphore
)
2204 assert(semaphore
->refcount
);
2205 p_atomic_inc(&semaphore
->refcount
);
2210 anv_semaphore_unref(struct anv_device
*device
, struct anv_semaphore
*semaphore
)
2212 if (!p_atomic_dec_zero(&semaphore
->refcount
))
2215 anv_semaphore_impl_cleanup(device
, &semaphore
->temporary
);
2216 anv_semaphore_impl_cleanup(device
, &semaphore
->permanent
);
2218 vk_object_base_finish(&semaphore
->base
);
2219 vk_free(&device
->vk
.alloc
, semaphore
);
2222 void anv_DestroySemaphore(
2224 VkSemaphore _semaphore
,
2225 const VkAllocationCallbacks
* pAllocator
)
2227 ANV_FROM_HANDLE(anv_device
, device
, _device
);
2228 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, _semaphore
);
2230 if (semaphore
== NULL
)
2233 anv_semaphore_unref(device
, semaphore
);
2236 void anv_GetPhysicalDeviceExternalSemaphoreProperties(
2237 VkPhysicalDevice physicalDevice
,
2238 const VkPhysicalDeviceExternalSemaphoreInfo
* pExternalSemaphoreInfo
,
2239 VkExternalSemaphoreProperties
* pExternalSemaphoreProperties
)
2241 ANV_FROM_HANDLE(anv_physical_device
, device
, physicalDevice
);
2243 VkSemaphoreTypeKHR sem_type
=
2244 get_semaphore_type(pExternalSemaphoreInfo
->pNext
, NULL
);
2246 switch (pExternalSemaphoreInfo
->handleType
) {
2247 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
:
2248 /* Timeline semaphores are not exportable, unless we have threaded
2251 if (sem_type
== VK_SEMAPHORE_TYPE_TIMELINE_KHR
&& !device
->has_thread_submit
)
2253 pExternalSemaphoreProperties
->exportFromImportedHandleTypes
=
2254 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
;
2255 pExternalSemaphoreProperties
->compatibleHandleTypes
=
2256 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
;
2257 pExternalSemaphoreProperties
->externalSemaphoreFeatures
=
2258 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT
|
2259 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT
;
2262 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
:
2263 if (sem_type
== VK_SEMAPHORE_TYPE_TIMELINE_KHR
)
2265 if (!device
->has_exec_fence
)
2267 pExternalSemaphoreProperties
->exportFromImportedHandleTypes
=
2268 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
;
2269 pExternalSemaphoreProperties
->compatibleHandleTypes
=
2270 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
;
2271 pExternalSemaphoreProperties
->externalSemaphoreFeatures
=
2272 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT
|
2273 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT
;
2280 pExternalSemaphoreProperties
->exportFromImportedHandleTypes
= 0;
2281 pExternalSemaphoreProperties
->compatibleHandleTypes
= 0;
2282 pExternalSemaphoreProperties
->externalSemaphoreFeatures
= 0;
2285 VkResult
anv_ImportSemaphoreFdKHR(
2287 const VkImportSemaphoreFdInfoKHR
* pImportSemaphoreFdInfo
)
2289 ANV_FROM_HANDLE(anv_device
, device
, _device
);
2290 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, pImportSemaphoreFdInfo
->semaphore
);
2291 int fd
= pImportSemaphoreFdInfo
->fd
;
2293 struct anv_semaphore_impl new_impl
= {
2294 .type
= ANV_SEMAPHORE_TYPE_NONE
,
2297 switch (pImportSemaphoreFdInfo
->handleType
) {
2298 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
:
2299 if (device
->physical
->has_syncobj
) {
2300 /* When importing non temporarily, reuse the semaphore's existing
2301 * type. The Linux/DRM implementation allows to interchangeably use
2302 * binary & timeline semaphores and we have no way to differenciate
2305 if (pImportSemaphoreFdInfo
->flags
& VK_SEMAPHORE_IMPORT_TEMPORARY_BIT
)
2306 new_impl
.type
= ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
;
2308 new_impl
.type
= semaphore
->permanent
.type
;
2310 new_impl
.syncobj
= anv_gem_syncobj_fd_to_handle(device
, fd
);
2311 if (!new_impl
.syncobj
)
2312 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
2314 new_impl
.type
= ANV_SEMAPHORE_TYPE_BO
;
2316 VkResult result
= anv_device_import_bo(device
, fd
,
2317 ANV_BO_ALLOC_EXTERNAL
|
2318 ANV_BO_ALLOC_IMPLICIT_SYNC
,
2319 0 /* client_address */,
2321 if (result
!= VK_SUCCESS
)
2324 if (new_impl
.bo
->size
< 4096) {
2325 anv_device_release_bo(device
, new_impl
.bo
);
2326 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
2329 /* If we're going to use this as a fence, we need to *not* have the
2330 * EXEC_OBJECT_ASYNC bit set.
2332 assert(!(new_impl
.bo
->flags
& EXEC_OBJECT_ASYNC
));
2335 /* From the Vulkan spec:
2337 * "Importing semaphore state from a file descriptor transfers
2338 * ownership of the file descriptor from the application to the
2339 * Vulkan implementation. The application must not perform any
2340 * operations on the file descriptor after a successful import."
2342 * If the import fails, we leave the file descriptor open.
2347 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
:
2348 if (device
->physical
->has_syncobj
) {
2349 uint32_t create_flags
= 0;
2352 create_flags
|= DRM_SYNCOBJ_CREATE_SIGNALED
;
2354 new_impl
= (struct anv_semaphore_impl
) {
2355 .type
= ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
,
2356 .syncobj
= anv_gem_syncobj_create(device
, create_flags
),
2359 if (!new_impl
.syncobj
)
2360 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
2363 if (anv_gem_syncobj_import_sync_file(device
, new_impl
.syncobj
, fd
)) {
2364 anv_gem_syncobj_destroy(device
, new_impl
.syncobj
);
2365 return vk_errorf(device
, NULL
, VK_ERROR_INVALID_EXTERNAL_HANDLE
,
2366 "syncobj sync file import failed: %m");
2368 /* Ownership of the FD is transfered to Anv. Since we don't need it
2369 * anymore because the associated fence has been put into a syncobj,
2370 * we must close the FD.
2375 new_impl
= (struct anv_semaphore_impl
) {
2376 .type
= ANV_SEMAPHORE_TYPE_SYNC_FILE
,
2383 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
2386 if (pImportSemaphoreFdInfo
->flags
& VK_SEMAPHORE_IMPORT_TEMPORARY_BIT
) {
2387 anv_semaphore_impl_cleanup(device
, &semaphore
->temporary
);
2388 semaphore
->temporary
= new_impl
;
2390 anv_semaphore_impl_cleanup(device
, &semaphore
->permanent
);
2391 semaphore
->permanent
= new_impl
;
2397 VkResult
anv_GetSemaphoreFdKHR(
2399 const VkSemaphoreGetFdInfoKHR
* pGetFdInfo
,
2402 ANV_FROM_HANDLE(anv_device
, device
, _device
);
2403 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, pGetFdInfo
->semaphore
);
2407 assert(pGetFdInfo
->sType
== VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR
);
2409 struct anv_semaphore_impl
*impl
=
2410 semaphore
->temporary
.type
!= ANV_SEMAPHORE_TYPE_NONE
?
2411 &semaphore
->temporary
: &semaphore
->permanent
;
2413 switch (impl
->type
) {
2414 case ANV_SEMAPHORE_TYPE_BO
:
2415 result
= anv_device_export_bo(device
, impl
->bo
, pFd
);
2416 if (result
!= VK_SUCCESS
)
2420 case ANV_SEMAPHORE_TYPE_SYNC_FILE
: {
2421 /* There's a potential race here with vkQueueSubmit if you are trying
2422 * to export a semaphore Fd while the queue submit is still happening.
2423 * This can happen if we see all dependencies get resolved via timeline
2424 * semaphore waits completing before the execbuf completes and we
2425 * process the resulting out fence. To work around this, take a lock
2426 * around grabbing the fd.
2428 pthread_mutex_lock(&device
->mutex
);
2430 /* From the Vulkan 1.0.53 spec:
2432 * "...exporting a semaphore payload to a handle with copy
2433 * transference has the same side effects on the source
2434 * semaphore’s payload as executing a semaphore wait operation."
2436 * In other words, it may still be a SYNC_FD semaphore, but it's now
2437 * considered to have been waited on and no longer has a sync file
2443 pthread_mutex_unlock(&device
->mutex
);
2445 /* There are two reasons why this could happen:
2447 * 1) The user is trying to export without submitting something that
2448 * signals the semaphore. If this is the case, it's their bug so
2449 * what we return here doesn't matter.
2451 * 2) The kernel didn't give us a file descriptor. The most likely
2452 * reason for this is running out of file descriptors.
2455 return vk_error(VK_ERROR_TOO_MANY_OBJECTS
);
2461 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
:
2462 if (pGetFdInfo
->handleType
== VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT
) {
2463 VkResult result
= wait_syncobj_materialize(device
, impl
->syncobj
, pFd
);
2464 if (result
!= VK_SUCCESS
)
2467 fd
= anv_gem_syncobj_export_sync_file(device
, impl
->syncobj
);
2469 assert(pGetFdInfo
->handleType
== VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
);
2470 fd
= anv_gem_syncobj_handle_to_fd(device
, impl
->syncobj
);
2473 return vk_error(VK_ERROR_TOO_MANY_OBJECTS
);
2477 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
:
2478 assert(pGetFdInfo
->handleType
== VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT
);
2479 fd
= anv_gem_syncobj_handle_to_fd(device
, impl
->syncobj
);
2481 return vk_error(VK_ERROR_TOO_MANY_OBJECTS
);
2486 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE
);
2489 /* From the Vulkan 1.0.53 spec:
2491 * "Export operations have the same transference as the specified handle
2492 * type’s import operations. [...] If the semaphore was using a
2493 * temporarily imported payload, the semaphore’s prior permanent payload
2496 if (impl
== &semaphore
->temporary
)
2497 anv_semaphore_impl_cleanup(device
, impl
);
2502 VkResult
anv_GetSemaphoreCounterValue(
2504 VkSemaphore _semaphore
,
2507 ANV_FROM_HANDLE(anv_device
, device
, _device
);
2508 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, _semaphore
);
2510 struct anv_semaphore_impl
*impl
=
2511 semaphore
->temporary
.type
!= ANV_SEMAPHORE_TYPE_NONE
?
2512 &semaphore
->temporary
: &semaphore
->permanent
;
2514 switch (impl
->type
) {
2515 case ANV_SEMAPHORE_TYPE_TIMELINE
: {
2516 pthread_mutex_lock(&device
->mutex
);
2517 anv_timeline_gc_locked(device
, &impl
->timeline
);
2518 *pValue
= impl
->timeline
.highest_past
;
2519 pthread_mutex_unlock(&device
->mutex
);
2523 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
: {
2524 int ret
= anv_gem_syncobj_timeline_query(device
, &impl
->syncobj
, pValue
, 1);
2527 return anv_device_set_lost(device
, "unable to query timeline syncobj");
2533 unreachable("Invalid semaphore type");
2538 anv_timeline_wait_locked(struct anv_device
*device
,
2539 struct anv_timeline
*timeline
,
2540 uint64_t serial
, uint64_t abs_timeout_ns
)
2542 /* Wait on the queue_submit condition variable until the timeline has a
2543 * time point pending that's at least as high as serial.
2545 while (timeline
->highest_pending
< serial
) {
2546 struct timespec abstime
= {
2547 .tv_sec
= abs_timeout_ns
/ NSEC_PER_SEC
,
2548 .tv_nsec
= abs_timeout_ns
% NSEC_PER_SEC
,
2551 UNUSED
int ret
= pthread_cond_timedwait(&device
->queue_submit
,
2552 &device
->mutex
, &abstime
);
2553 assert(ret
!= EINVAL
);
2554 if (anv_gettime_ns() >= abs_timeout_ns
&&
2555 timeline
->highest_pending
< serial
)
2560 VkResult result
= anv_timeline_gc_locked(device
, timeline
);
2561 if (result
!= VK_SUCCESS
)
2564 if (timeline
->highest_past
>= serial
)
2567 /* If we got here, our earliest time point has a busy BO */
2568 struct anv_timeline_point
*point
=
2569 list_first_entry(&timeline
->points
,
2570 struct anv_timeline_point
, link
);
2572 /* Drop the lock while we wait. */
2574 pthread_mutex_unlock(&device
->mutex
);
2576 result
= anv_device_wait(device
, point
->bo
,
2577 anv_get_relative_timeout(abs_timeout_ns
));
2579 /* Pick the mutex back up */
2580 pthread_mutex_lock(&device
->mutex
);
2583 /* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */
2584 if (result
!= VK_SUCCESS
)
2590 anv_timelines_wait(struct anv_device
*device
,
2591 struct anv_timeline
**timelines
,
2592 const uint64_t *serials
,
2593 uint32_t n_timelines
,
2595 uint64_t abs_timeout_ns
)
2597 if (!wait_all
&& n_timelines
> 1) {
2598 pthread_mutex_lock(&device
->mutex
);
2602 for (uint32_t i
= 0; i
< n_timelines
; i
++) {
2604 anv_timeline_wait_locked(device
, timelines
[i
], serials
[i
], 0);
2605 if (result
!= VK_TIMEOUT
)
2609 if (result
!= VK_TIMEOUT
||
2610 anv_gettime_ns() >= abs_timeout_ns
) {
2611 pthread_mutex_unlock(&device
->mutex
);
2615 /* If none of them are ready do a short wait so we don't completely
2616 * spin while holding the lock. The 10us is completely arbitrary.
2618 uint64_t abs_short_wait_ns
=
2619 anv_get_absolute_timeout(
2620 MIN2((anv_gettime_ns() - abs_timeout_ns
) / 10, 10 * 1000));
2621 struct timespec abstime
= {
2622 .tv_sec
= abs_short_wait_ns
/ NSEC_PER_SEC
,
2623 .tv_nsec
= abs_short_wait_ns
% NSEC_PER_SEC
,
2626 ret
= pthread_cond_timedwait(&device
->queue_submit
,
2627 &device
->mutex
, &abstime
);
2628 assert(ret
!= EINVAL
);
2631 VkResult result
= VK_SUCCESS
;
2632 pthread_mutex_lock(&device
->mutex
);
2633 for (uint32_t i
= 0; i
< n_timelines
; i
++) {
2635 anv_timeline_wait_locked(device
, timelines
[i
],
2636 serials
[i
], abs_timeout_ns
);
2637 if (result
!= VK_SUCCESS
)
2640 pthread_mutex_unlock(&device
->mutex
);
2645 VkResult
anv_WaitSemaphores(
2647 const VkSemaphoreWaitInfoKHR
* pWaitInfo
,
2650 ANV_FROM_HANDLE(anv_device
, device
, _device
);
2652 struct anv_timeline
**timelines
;
2657 anv_multialloc_add(&ma
, &values
, pWaitInfo
->semaphoreCount
);
2658 if (device
->has_thread_submit
) {
2659 anv_multialloc_add(&ma
, &handles
, pWaitInfo
->semaphoreCount
);
2661 anv_multialloc_add(&ma
, &timelines
, pWaitInfo
->semaphoreCount
);
2664 if (!anv_multialloc_alloc(&ma
, &device
->vk
.alloc
,
2665 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND
))
2666 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
2668 uint32_t handle_count
= 0;
2669 for (uint32_t i
= 0; i
< pWaitInfo
->semaphoreCount
; i
++) {
2670 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, pWaitInfo
->pSemaphores
[i
]);
2671 struct anv_semaphore_impl
*impl
=
2672 semaphore
->temporary
.type
!= ANV_SEMAPHORE_TYPE_NONE
?
2673 &semaphore
->temporary
: &semaphore
->permanent
;
2675 if (pWaitInfo
->pValues
[i
] == 0)
2678 if (device
->has_thread_submit
) {
2679 assert(impl
->type
== ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
);
2680 handles
[handle_count
] = impl
->syncobj
;
2682 assert(impl
->type
== ANV_SEMAPHORE_TYPE_TIMELINE
);
2683 timelines
[handle_count
] = &impl
->timeline
;
2685 values
[handle_count
] = pWaitInfo
->pValues
[i
];
2689 VkResult result
= VK_SUCCESS
;
2690 if (handle_count
> 0) {
2691 if (device
->has_thread_submit
) {
2693 anv_gem_syncobj_timeline_wait(device
,
2694 handles
, values
, handle_count
,
2695 anv_get_absolute_timeout(timeout
),
2696 !(pWaitInfo
->flags
& VK_SEMAPHORE_WAIT_ANY_BIT_KHR
),
2699 result
= errno
== ETIME
? VK_TIMEOUT
:
2700 anv_device_set_lost(device
, "unable to wait on timeline syncobj");
2703 anv_timelines_wait(device
, timelines
, values
, handle_count
,
2704 !(pWaitInfo
->flags
& VK_SEMAPHORE_WAIT_ANY_BIT_KHR
),
2705 anv_get_absolute_timeout(timeout
));
2709 vk_free(&device
->vk
.alloc
, values
);
2714 VkResult
anv_SignalSemaphore(
2716 const VkSemaphoreSignalInfoKHR
* pSignalInfo
)
2718 ANV_FROM_HANDLE(anv_device
, device
, _device
);
2719 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, pSignalInfo
->semaphore
);
2721 struct anv_semaphore_impl
*impl
=
2722 semaphore
->temporary
.type
!= ANV_SEMAPHORE_TYPE_NONE
?
2723 &semaphore
->temporary
: &semaphore
->permanent
;
2725 switch (impl
->type
) {
2726 case ANV_SEMAPHORE_TYPE_TIMELINE
: {
2727 pthread_mutex_lock(&device
->mutex
);
2729 VkResult result
= anv_timeline_gc_locked(device
, &impl
->timeline
);
2731 assert(pSignalInfo
->value
> impl
->timeline
.highest_pending
);
2733 impl
->timeline
.highest_pending
= impl
->timeline
.highest_past
= pSignalInfo
->value
;
2735 if (result
== VK_SUCCESS
)
2736 result
= anv_device_submit_deferred_locked(device
);
2738 pthread_cond_broadcast(&device
->queue_submit
);
2739 pthread_mutex_unlock(&device
->mutex
);
2743 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE
: {
2744 /* Timeline semaphores are created with a value of 0, so signaling on 0
2745 * is a waste of time.
2747 if (pSignalInfo
->value
== 0)
2750 int ret
= anv_gem_syncobj_timeline_signal(device
, &impl
->syncobj
,
2751 &pSignalInfo
->value
, 1);
2753 return ret
== 0 ? VK_SUCCESS
:
2754 anv_device_set_lost(device
, "unable to signal timeline syncobj");
2758 unreachable("Invalid semaphore type");