anv: Lock around fetching sync file FDs from semaphores
[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 <fcntl.h>
29 #include <unistd.h>
30
31 #include "anv_private.h"
32 #include "vk_util.h"
33
34 #include "genxml/gen7_pack.h"
35
36 uint64_t anv_gettime_ns(void)
37 {
38 struct timespec current;
39 clock_gettime(CLOCK_MONOTONIC, &current);
40 return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
41 }
42
43 uint64_t anv_get_absolute_timeout(uint64_t timeout)
44 {
45 if (timeout == 0)
46 return 0;
47 uint64_t current_time = anv_gettime_ns();
48 uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;
49
50 timeout = MIN2(max_timeout, timeout);
51
52 return (current_time + timeout);
53 }
54
55 static int64_t anv_get_relative_timeout(uint64_t abs_timeout)
56 {
57 uint64_t now = anv_gettime_ns();
58
59 /* We don't want negative timeouts.
60 *
61 * DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is
62 * supposed to block indefinitely timeouts < 0. Unfortunately,
63 * this was broken for a couple of kernel releases. Since there's
64 * no way to know whether or not the kernel we're using is one of
65 * the broken ones, the best we can do is to clamp the timeout to
66 * INT64_MAX. This limits the maximum timeout from 584 years to
67 * 292 years - likely not a big deal.
68 */
69 if (abs_timeout < now)
70 return 0;
71
72 uint64_t rel_timeout = abs_timeout - now;
73 if (rel_timeout > (uint64_t) INT64_MAX)
74 rel_timeout = INT64_MAX;
75
76 return rel_timeout;
77 }
78
79 static struct anv_semaphore *anv_semaphore_ref(struct anv_semaphore *semaphore);
80 static void anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore);
81 static void anv_semaphore_impl_cleanup(struct anv_device *device,
82 struct anv_semaphore_impl *impl);
83
84 static void
85 anv_queue_submit_free(struct anv_device *device,
86 struct anv_queue_submit *submit)
87 {
88 const VkAllocationCallbacks *alloc = submit->alloc;
89
90 for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++)
91 anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]);
92 for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++)
93 anv_semaphore_unref(device, submit->sync_fd_semaphores[i]);
94 /* Execbuf does not consume the in_fence. It's our job to close it. */
95 if (submit->in_fence != -1)
96 close(submit->in_fence);
97 if (submit->out_fence != -1)
98 close(submit->out_fence);
99 vk_free(alloc, submit->fences);
100 vk_free(alloc, submit->temporary_semaphores);
101 vk_free(alloc, submit->fence_bos);
102 vk_free(alloc, submit);
103 }
104
105 static VkResult
106 _anv_queue_submit(struct anv_queue *queue, struct anv_queue_submit **_submit)
107 {
108 struct anv_queue_submit *submit = *_submit;
109 VkResult result = anv_queue_execbuf(queue, submit);
110
111 if (result == VK_SUCCESS) {
112 /* Update signaled semaphores backed by syncfd. */
113 for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {
114 struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];
115 /* Out fences can't have temporary state because that would imply
116 * that we imported a sync file and are trying to signal it.
117 */
118 assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
119 struct anv_semaphore_impl *impl = &semaphore->permanent;
120
121 assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);
122 impl->fd = dup(submit->out_fence);
123 }
124 }
125
126 return result;
127 }
128
129 VkResult
130 anv_queue_init(struct anv_device *device, struct anv_queue *queue)
131 {
132 queue->_loader_data.loaderMagic = ICD_LOADER_MAGIC;
133 queue->device = device;
134 queue->flags = 0;
135
136 return VK_SUCCESS;
137 }
138
139 void
140 anv_queue_finish(struct anv_queue *queue)
141 {
142 }
143
144 static VkResult
145 anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,
146 struct anv_bo *bo,
147 bool signal)
148 {
149 if (submit->fence_bo_count >= submit->fence_bo_array_length) {
150 uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64);
151
152 submit->fence_bos =
153 vk_realloc(submit->alloc,
154 submit->fence_bos, new_len * sizeof(*submit->fence_bos),
155 8, submit->alloc_scope);
156 if (submit->fence_bos == NULL)
157 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
158
159 submit->fence_bo_array_length = new_len;
160 }
161
162 /* Take advantage that anv_bo are allocated at 8 byte alignement so we can
163 * use the lowest bit to store whether this is a BO we need to signal.
164 */
165 submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal);
166
167 return VK_SUCCESS;
168 }
169
170 static VkResult
171 anv_queue_submit_add_syncobj(struct anv_queue_submit* submit,
172 struct anv_device *device,
173 uint32_t handle, uint32_t flags)
174 {
175 assert(flags != 0);
176
177 if (submit->fence_count >= submit->fence_array_length) {
178 uint32_t new_len = MAX2(submit->fence_array_length * 2, 64);
179
180 submit->fences =
181 vk_realloc(submit->alloc,
182 submit->fences, new_len * sizeof(*submit->fences),
183 8, submit->alloc_scope);
184 if (submit->fences == NULL)
185 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
186
187 submit->fence_array_length = new_len;
188 }
189
190 submit->fences[submit->fence_count++] = (struct drm_i915_gem_exec_fence) {
191 .handle = handle,
192 .flags = flags,
193 };
194
195 return VK_SUCCESS;
196 }
197
198 static VkResult
199 anv_queue_submit_add_sync_fd_fence(struct anv_queue_submit *submit,
200 struct anv_semaphore *semaphore)
201 {
202 if (submit->sync_fd_semaphore_count >= submit->sync_fd_semaphore_array_length) {
203 uint32_t new_len = MAX2(submit->sync_fd_semaphore_array_length * 2, 64);
204 struct anv_semaphore **new_semaphores =
205 vk_realloc(submit->alloc, submit->sync_fd_semaphores,
206 new_len * sizeof(*submit->sync_fd_semaphores), 8,
207 submit->alloc_scope);
208 if (new_semaphores == NULL)
209 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
210
211 submit->sync_fd_semaphores = new_semaphores;
212 }
213
214 submit->sync_fd_semaphores[submit->sync_fd_semaphore_count++] =
215 anv_semaphore_ref(semaphore);
216 submit->need_out_fence = true;
217
218 return VK_SUCCESS;
219 }
220
221 static struct anv_queue_submit *
222 anv_queue_submit_alloc(struct anv_device *device)
223 {
224 const VkAllocationCallbacks *alloc = &device->alloc;
225 VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_COMMAND;
226
227 struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope);
228 if (!submit)
229 return NULL;
230
231 submit->alloc = alloc;
232 submit->alloc_scope = alloc_scope;
233 submit->in_fence = -1;
234 submit->out_fence = -1;
235
236 return submit;
237 }
238
239 VkResult
240 anv_queue_submit_simple_batch(struct anv_queue *queue,
241 struct anv_batch *batch)
242 {
243 struct anv_device *device = queue->device;
244 struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
245 if (!submit)
246 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
247
248 bool has_syncobj_wait = device->instance->physicalDevice.has_syncobj_wait;
249 VkResult result;
250 uint32_t syncobj;
251 struct anv_bo *batch_bo, *sync_bo;
252
253 if (has_syncobj_wait) {
254 syncobj = anv_gem_syncobj_create(device, 0);
255 if (!syncobj) {
256 result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
257 goto err_free_submit;
258 }
259
260 result = anv_queue_submit_add_syncobj(submit, device, syncobj,
261 I915_EXEC_FENCE_SIGNAL);
262 } else {
263 result = anv_device_alloc_bo(device, 4096,
264 ANV_BO_ALLOC_EXTERNAL |
265 ANV_BO_ALLOC_IMPLICIT_SYNC,
266 &sync_bo);
267 if (result != VK_SUCCESS)
268 goto err_free_submit;
269
270 result = anv_queue_submit_add_fence_bo(submit, sync_bo, true /* signal */);
271 }
272
273 if (result != VK_SUCCESS)
274 goto err_destroy_sync_primitive;
275
276 if (batch) {
277 uint32_t size = align_u32(batch->next - batch->start, 8);
278 result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo);
279 if (result != VK_SUCCESS)
280 goto err_destroy_sync_primitive;
281
282 memcpy(batch_bo->map, batch->start, size);
283 if (!device->info.has_llc)
284 gen_flush_range(batch_bo->map, size);
285
286 submit->simple_bo = batch_bo;
287 submit->simple_bo_size = size;
288 }
289
290 result = _anv_queue_submit(queue, &submit);
291
292 if (result == VK_SUCCESS) {
293 if (has_syncobj_wait) {
294 if (anv_gem_syncobj_wait(device, &syncobj, 1,
295 anv_get_absolute_timeout(INT64_MAX), true))
296 result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m");
297 anv_gem_syncobj_destroy(device, syncobj);
298 } else {
299 result = anv_device_wait(device, sync_bo,
300 anv_get_relative_timeout(INT64_MAX));
301 anv_device_release_bo(device, sync_bo);
302 }
303 }
304
305 if (batch)
306 anv_bo_pool_free(&device->batch_bo_pool, batch_bo);
307
308 if (submit)
309 anv_queue_submit_free(device, submit);
310
311 return result;
312
313 err_destroy_sync_primitive:
314 if (has_syncobj_wait)
315 anv_gem_syncobj_destroy(device, syncobj);
316 else
317 anv_device_release_bo(device, sync_bo);
318 err_free_submit:
319 if (submit)
320 anv_queue_submit_free(device, submit);
321
322 return result;
323 }
324
325 /* Transfer ownership of temporary semaphores from the VkSemaphore object to
326 * the anv_queue_submit object. Those temporary semaphores are then freed in
327 * anv_queue_submit_free() once the driver is finished with them.
328 */
329 static VkResult
330 maybe_transfer_temporary_semaphore(struct anv_queue_submit *submit,
331 struct anv_semaphore *semaphore,
332 struct anv_semaphore_impl **out_impl)
333 {
334 struct anv_semaphore_impl *impl = &semaphore->temporary;
335
336 if (impl->type == ANV_SEMAPHORE_TYPE_NONE) {
337 *out_impl = &semaphore->permanent;
338 return VK_SUCCESS;
339 }
340
341 /*
342 * There is a requirement to reset semaphore to their permanent state after
343 * submission. From the Vulkan 1.0.53 spec:
344 *
345 * "If the import is temporary, the implementation must restore the
346 * semaphore to its prior permanent state after submitting the next
347 * semaphore wait operation."
348 *
349 * In the case we defer the actual submission to a thread because of the
350 * wait-before-submit behavior required for timeline semaphores, we need to
351 * make copies of the temporary syncobj to ensure they stay alive until we
352 * do the actual execbuffer ioctl.
353 */
354 if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) {
355 uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8);
356 /* Make sure that if the realloc fails, we still have the old semaphore
357 * array around to properly clean things up on failure.
358 */
359 struct anv_semaphore_impl *new_array =
360 vk_realloc(submit->alloc,
361 submit->temporary_semaphores,
362 new_len * sizeof(*submit->temporary_semaphores),
363 8, submit->alloc_scope);
364 if (new_array == NULL)
365 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
366
367 submit->temporary_semaphores = new_array;
368 submit->temporary_semaphore_array_length = new_len;
369 }
370
371 /* Copy anv_semaphore_impl into anv_queue_submit. */
372 submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl;
373 *out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1];
374
375 /* Clear the incoming semaphore */
376 impl->type = ANV_SEMAPHORE_TYPE_NONE;
377
378 return VK_SUCCESS;
379 }
380
381 static VkResult
382 anv_queue_submit(struct anv_queue *queue,
383 struct anv_cmd_buffer *cmd_buffer,
384 const VkSemaphore *in_semaphores,
385 uint32_t num_in_semaphores,
386 const VkSemaphore *out_semaphores,
387 uint32_t num_out_semaphores,
388 VkFence _fence)
389 {
390 ANV_FROM_HANDLE(anv_fence, fence, _fence);
391 struct anv_device *device = queue->device;
392 UNUSED struct anv_physical_device *pdevice = &device->instance->physicalDevice;
393 struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
394 if (!submit)
395 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
396
397 submit->cmd_buffer = cmd_buffer;
398
399 VkResult result = VK_SUCCESS;
400
401 for (uint32_t i = 0; i < num_in_semaphores; i++) {
402 ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
403 struct anv_semaphore_impl *impl;
404
405 result = maybe_transfer_temporary_semaphore(submit, semaphore, &impl);
406 if (result != VK_SUCCESS)
407 goto error;
408
409 switch (impl->type) {
410 case ANV_SEMAPHORE_TYPE_BO:
411 assert(!pdevice->has_syncobj);
412 result = anv_queue_submit_add_fence_bo(submit, impl->bo, false /* signal */);
413 if (result != VK_SUCCESS)
414 goto error;
415 break;
416
417 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
418 assert(!pdevice->has_syncobj);
419 if (submit->in_fence == -1) {
420 submit->in_fence = impl->fd;
421 if (submit->in_fence == -1) {
422 result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
423 goto error;
424 }
425 impl->fd = -1;
426 } else {
427 int merge = anv_gem_sync_file_merge(device, submit->in_fence, impl->fd);
428 if (merge == -1) {
429 result = vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
430 goto error;
431 }
432 close(impl->fd);
433 close(submit->in_fence);
434 impl->fd = -1;
435 submit->in_fence = merge;
436 }
437 break;
438
439 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
440 result = anv_queue_submit_add_syncobj(submit, device,
441 impl->syncobj,
442 I915_EXEC_FENCE_WAIT);
443 if (result != VK_SUCCESS)
444 goto error;
445 break;
446 }
447
448 default:
449 break;
450 }
451 }
452
453 for (uint32_t i = 0; i < num_out_semaphores; i++) {
454 ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
455
456 /* Under most circumstances, out fences won't be temporary. However,
457 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
458 *
459 * "If the import is temporary, the implementation must restore the
460 * semaphore to its prior permanent state after submitting the next
461 * semaphore wait operation."
462 *
463 * The spec says nothing whatsoever about signal operations on
464 * temporarily imported semaphores so it appears they are allowed.
465 * There are also CTS tests that require this to work.
466 */
467 struct anv_semaphore_impl *impl =
468 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
469 &semaphore->temporary : &semaphore->permanent;
470
471 switch (impl->type) {
472 case ANV_SEMAPHORE_TYPE_BO:
473 assert(!pdevice->has_syncobj);
474 result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
475 if (result != VK_SUCCESS)
476 goto error;
477 break;
478
479 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
480 assert(!pdevice->has_syncobj);
481 result = anv_queue_submit_add_sync_fd_fence(submit, semaphore);
482 if (result != VK_SUCCESS)
483 goto error;
484 break;
485
486 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
487 result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
488 I915_EXEC_FENCE_SIGNAL);
489 if (result != VK_SUCCESS)
490 goto error;
491 break;
492 }
493
494 default:
495 break;
496 }
497 }
498
499 if (fence) {
500 /* Under most circumstances, out fences won't be temporary. However,
501 * the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
502 *
503 * "If the import is temporary, the implementation must restore the
504 * semaphore to its prior permanent state after submitting the next
505 * semaphore wait operation."
506 *
507 * The spec says nothing whatsoever about signal operations on
508 * temporarily imported semaphores so it appears they are allowed.
509 * There are also CTS tests that require this to work.
510 */
511 struct anv_fence_impl *impl =
512 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
513 &fence->temporary : &fence->permanent;
514
515 switch (impl->type) {
516 case ANV_FENCE_TYPE_BO:
517 result = anv_queue_submit_add_fence_bo(submit, impl->bo.bo, true /* signal */);
518 if (result != VK_SUCCESS)
519 goto error;
520 break;
521
522 case ANV_FENCE_TYPE_SYNCOBJ: {
523 /*
524 * For the same reason we reset the signaled binary syncobj above,
525 * also reset the fence's syncobj so that they don't contain a
526 * signaled dma-fence.
527 */
528 result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
529 I915_EXEC_FENCE_SIGNAL);
530 if (result != VK_SUCCESS)
531 goto error;
532 break;
533 }
534
535 default:
536 unreachable("Invalid fence type");
537 }
538 }
539
540 result = _anv_queue_submit(queue, &submit);
541 if (result != VK_SUCCESS)
542 goto error;
543
544 if (fence && fence->permanent.type == ANV_FENCE_TYPE_BO) {
545 /* BO fences can't be shared, so they can't be temporary. */
546 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
547
548 /* Once the execbuf has returned, we need to set the fence state to
549 * SUBMITTED. We can't do this before calling execbuf because
550 * anv_GetFenceStatus does take the global device lock before checking
551 * fence->state.
552 *
553 * We set the fence state to SUBMITTED regardless of whether or not the
554 * execbuf succeeds because we need to ensure that vkWaitForFences() and
555 * vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or
556 * VK_SUCCESS) in a finite amount of time even if execbuf fails.
557 */
558 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED;
559 }
560
561 error:
562 if (submit)
563 anv_queue_submit_free(device, submit);
564
565 return result;
566 }
567
568 VkResult anv_QueueSubmit(
569 VkQueue _queue,
570 uint32_t submitCount,
571 const VkSubmitInfo* pSubmits,
572 VkFence fence)
573 {
574 ANV_FROM_HANDLE(anv_queue, queue, _queue);
575
576 /* Query for device status prior to submitting. Technically, we don't need
577 * to do this. However, if we have a client that's submitting piles of
578 * garbage, we would rather break as early as possible to keep the GPU
579 * hanging contained. If we don't check here, we'll either be waiting for
580 * the kernel to kick us or we'll have to wait until the client waits on a
581 * fence before we actually know whether or not we've hung.
582 */
583 VkResult result = anv_device_query_status(queue->device);
584 if (result != VK_SUCCESS)
585 return result;
586
587 if (fence && submitCount == 0) {
588 /* If we don't have any command buffers, we need to submit a dummy
589 * batch to give GEM something to wait on. We could, potentially,
590 * come up with something more efficient but this shouldn't be a
591 * common case.
592 */
593 result = anv_queue_submit(queue, NULL, NULL, 0, NULL, 0, fence);
594 goto out;
595 }
596
597 for (uint32_t i = 0; i < submitCount; i++) {
598 /* Fence for this submit. NULL for all but the last one */
599 VkFence submit_fence = (i == submitCount - 1) ? fence : VK_NULL_HANDLE;
600
601 if (pSubmits[i].commandBufferCount == 0) {
602 /* If we don't have any command buffers, we need to submit a dummy
603 * batch to give GEM something to wait on. We could, potentially,
604 * come up with something more efficient but this shouldn't be a
605 * common case.
606 */
607 result = anv_queue_submit(queue, NULL,
608 pSubmits[i].pWaitSemaphores,
609 pSubmits[i].waitSemaphoreCount,
610 pSubmits[i].pSignalSemaphores,
611 pSubmits[i].signalSemaphoreCount,
612 submit_fence);
613 if (result != VK_SUCCESS)
614 goto out;
615
616 continue;
617 }
618
619 for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
620 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
621 pSubmits[i].pCommandBuffers[j]);
622 assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
623 assert(!anv_batch_has_error(&cmd_buffer->batch));
624
625 /* Fence for this execbuf. NULL for all but the last one */
626 VkFence execbuf_fence =
627 (j == pSubmits[i].commandBufferCount - 1) ?
628 submit_fence : VK_NULL_HANDLE;
629
630 const VkSemaphore *in_semaphores = NULL, *out_semaphores = NULL;
631 uint32_t num_in_semaphores = 0, num_out_semaphores = 0;
632 if (j == 0) {
633 /* Only the first batch gets the in semaphores */
634 in_semaphores = pSubmits[i].pWaitSemaphores;
635 num_in_semaphores = pSubmits[i].waitSemaphoreCount;
636 }
637
638 if (j == pSubmits[i].commandBufferCount - 1) {
639 /* Only the last batch gets the out semaphores */
640 out_semaphores = pSubmits[i].pSignalSemaphores;
641 num_out_semaphores = pSubmits[i].signalSemaphoreCount;
642 }
643
644 result = anv_queue_submit(queue, cmd_buffer,
645 in_semaphores, num_in_semaphores,
646 out_semaphores, num_out_semaphores,
647 execbuf_fence);
648 if (result != VK_SUCCESS)
649 goto out;
650 }
651 }
652
653 out:
654 if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) {
655 /* In the case that something has gone wrong we may end up with an
656 * inconsistent state from which it may not be trivial to recover.
657 * For example, we might have computed address relocations and
658 * any future attempt to re-submit this job will need to know about
659 * this and avoid computing relocation addresses again.
660 *
661 * To avoid this sort of issues, we assume that if something was
662 * wrong during submission we must already be in a really bad situation
663 * anyway (such us being out of memory) and return
664 * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
665 * submit the same job again to this device.
666 *
667 * We skip doing this on VK_ERROR_DEVICE_LOST because
668 * anv_device_set_lost() would have been called already by a callee of
669 * anv_queue_submit().
670 */
671 result = anv_device_set_lost(queue->device, "vkQueueSubmit() failed");
672 }
673
674 return result;
675 }
676
677 VkResult anv_QueueWaitIdle(
678 VkQueue _queue)
679 {
680 ANV_FROM_HANDLE(anv_queue, queue, _queue);
681
682 if (anv_device_is_lost(queue->device))
683 return VK_ERROR_DEVICE_LOST;
684
685 return anv_queue_submit_simple_batch(queue, NULL);
686 }
687
688 VkResult anv_CreateFence(
689 VkDevice _device,
690 const VkFenceCreateInfo* pCreateInfo,
691 const VkAllocationCallbacks* pAllocator,
692 VkFence* pFence)
693 {
694 ANV_FROM_HANDLE(anv_device, device, _device);
695 struct anv_fence *fence;
696
697 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
698
699 fence = vk_zalloc2(&device->alloc, pAllocator, sizeof(*fence), 8,
700 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
701 if (fence == NULL)
702 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
703
704 if (device->instance->physicalDevice.has_syncobj_wait) {
705 fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
706
707 uint32_t create_flags = 0;
708 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)
709 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
710
711 fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);
712 if (!fence->permanent.syncobj)
713 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
714 } else {
715 fence->permanent.type = ANV_FENCE_TYPE_BO;
716
717 VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096,
718 &fence->permanent.bo.bo);
719 if (result != VK_SUCCESS)
720 return result;
721
722 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
723 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
724 } else {
725 fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
726 }
727 }
728
729 *pFence = anv_fence_to_handle(fence);
730
731 return VK_SUCCESS;
732 }
733
734 static void
735 anv_fence_impl_cleanup(struct anv_device *device,
736 struct anv_fence_impl *impl)
737 {
738 switch (impl->type) {
739 case ANV_FENCE_TYPE_NONE:
740 /* Dummy. Nothing to do */
741 break;
742
743 case ANV_FENCE_TYPE_BO:
744 anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo);
745 break;
746
747 case ANV_FENCE_TYPE_SYNCOBJ:
748 anv_gem_syncobj_destroy(device, impl->syncobj);
749 break;
750
751 case ANV_FENCE_TYPE_WSI:
752 impl->fence_wsi->destroy(impl->fence_wsi);
753 break;
754
755 default:
756 unreachable("Invalid fence type");
757 }
758
759 impl->type = ANV_FENCE_TYPE_NONE;
760 }
761
762 void anv_DestroyFence(
763 VkDevice _device,
764 VkFence _fence,
765 const VkAllocationCallbacks* pAllocator)
766 {
767 ANV_FROM_HANDLE(anv_device, device, _device);
768 ANV_FROM_HANDLE(anv_fence, fence, _fence);
769
770 if (!fence)
771 return;
772
773 anv_fence_impl_cleanup(device, &fence->temporary);
774 anv_fence_impl_cleanup(device, &fence->permanent);
775
776 vk_free2(&device->alloc, pAllocator, fence);
777 }
778
779 VkResult anv_ResetFences(
780 VkDevice _device,
781 uint32_t fenceCount,
782 const VkFence* pFences)
783 {
784 ANV_FROM_HANDLE(anv_device, device, _device);
785
786 for (uint32_t i = 0; i < fenceCount; i++) {
787 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
788
789 /* From the Vulkan 1.0.53 spec:
790 *
791 * "If any member of pFences currently has its payload imported with
792 * temporary permanence, that fence’s prior permanent payload is
793 * first restored. The remaining operations described therefore
794 * operate on the restored payload.
795 */
796 if (fence->temporary.type != ANV_FENCE_TYPE_NONE)
797 anv_fence_impl_cleanup(device, &fence->temporary);
798
799 struct anv_fence_impl *impl = &fence->permanent;
800
801 switch (impl->type) {
802 case ANV_FENCE_TYPE_BO:
803 impl->bo.state = ANV_BO_FENCE_STATE_RESET;
804 break;
805
806 case ANV_FENCE_TYPE_SYNCOBJ:
807 anv_gem_syncobj_reset(device, impl->syncobj);
808 break;
809
810 default:
811 unreachable("Invalid fence type");
812 }
813 }
814
815 return VK_SUCCESS;
816 }
817
818 VkResult anv_GetFenceStatus(
819 VkDevice _device,
820 VkFence _fence)
821 {
822 ANV_FROM_HANDLE(anv_device, device, _device);
823 ANV_FROM_HANDLE(anv_fence, fence, _fence);
824
825 if (anv_device_is_lost(device))
826 return VK_ERROR_DEVICE_LOST;
827
828 struct anv_fence_impl *impl =
829 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
830 &fence->temporary : &fence->permanent;
831
832 switch (impl->type) {
833 case ANV_FENCE_TYPE_BO:
834 /* BO fences don't support import/export */
835 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
836 switch (impl->bo.state) {
837 case ANV_BO_FENCE_STATE_RESET:
838 /* If it hasn't even been sent off to the GPU yet, it's not ready */
839 return VK_NOT_READY;
840
841 case ANV_BO_FENCE_STATE_SIGNALED:
842 /* It's been signaled, return success */
843 return VK_SUCCESS;
844
845 case ANV_BO_FENCE_STATE_SUBMITTED: {
846 VkResult result = anv_device_bo_busy(device, impl->bo.bo);
847 if (result == VK_SUCCESS) {
848 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
849 return VK_SUCCESS;
850 } else {
851 return result;
852 }
853 }
854 default:
855 unreachable("Invalid fence status");
856 }
857
858 case ANV_FENCE_TYPE_SYNCOBJ: {
859 int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);
860 if (ret == -1) {
861 if (errno == ETIME) {
862 return VK_NOT_READY;
863 } else {
864 /* We don't know the real error. */
865 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
866 }
867 } else {
868 return VK_SUCCESS;
869 }
870 }
871
872 default:
873 unreachable("Invalid fence type");
874 }
875 }
876
877 static VkResult
878 anv_wait_for_syncobj_fences(struct anv_device *device,
879 uint32_t fenceCount,
880 const VkFence *pFences,
881 bool waitAll,
882 uint64_t abs_timeout_ns)
883 {
884 uint32_t *syncobjs = vk_zalloc(&device->alloc,
885 sizeof(*syncobjs) * fenceCount, 8,
886 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
887 if (!syncobjs)
888 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
889
890 for (uint32_t i = 0; i < fenceCount; i++) {
891 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
892 assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
893
894 struct anv_fence_impl *impl =
895 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
896 &fence->temporary : &fence->permanent;
897
898 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
899 syncobjs[i] = impl->syncobj;
900 }
901
902 /* The gem_syncobj_wait ioctl may return early due to an inherent
903 * limitation in the way it computes timeouts. Loop until we've actually
904 * passed the timeout.
905 */
906 int ret;
907 do {
908 ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
909 abs_timeout_ns, waitAll);
910 } while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns);
911
912 vk_free(&device->alloc, syncobjs);
913
914 if (ret == -1) {
915 if (errno == ETIME) {
916 return VK_TIMEOUT;
917 } else {
918 /* We don't know the real error. */
919 return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
920 }
921 } else {
922 return VK_SUCCESS;
923 }
924 }
925
926 static VkResult
927 anv_wait_for_bo_fences(struct anv_device *device,
928 uint32_t fenceCount,
929 const VkFence *pFences,
930 bool waitAll,
931 uint64_t abs_timeout_ns)
932 {
933 VkResult result = VK_SUCCESS;
934 uint32_t pending_fences = fenceCount;
935 while (pending_fences) {
936 pending_fences = 0;
937 bool signaled_fences = false;
938 for (uint32_t i = 0; i < fenceCount; i++) {
939 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
940
941 /* This function assumes that all fences are BO fences and that they
942 * have no temporary state. Since BO fences will never be exported,
943 * this should be a safe assumption.
944 */
945 assert(fence->permanent.type == ANV_FENCE_TYPE_BO);
946 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
947 struct anv_fence_impl *impl = &fence->permanent;
948
949 switch (impl->bo.state) {
950 case ANV_BO_FENCE_STATE_RESET:
951 /* This fence hasn't been submitted yet, we'll catch it the next
952 * time around. Yes, this may mean we dead-loop but, short of
953 * lots of locking and a condition variable, there's not much that
954 * we can do about that.
955 */
956 pending_fences++;
957 continue;
958
959 case ANV_BO_FENCE_STATE_SIGNALED:
960 /* This fence is not pending. If waitAll isn't set, we can return
961 * early. Otherwise, we have to keep going.
962 */
963 if (!waitAll) {
964 result = VK_SUCCESS;
965 goto done;
966 }
967 continue;
968
969 case ANV_BO_FENCE_STATE_SUBMITTED:
970 /* These are the fences we really care about. Go ahead and wait
971 * on it until we hit a timeout.
972 */
973 result = anv_device_wait(device, impl->bo.bo,
974 anv_get_relative_timeout(abs_timeout_ns));
975 switch (result) {
976 case VK_SUCCESS:
977 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
978 signaled_fences = true;
979 if (!waitAll)
980 goto done;
981 break;
982
983 case VK_TIMEOUT:
984 goto done;
985
986 default:
987 return result;
988 }
989 }
990 }
991
992 if (pending_fences && !signaled_fences) {
993 /* If we've hit this then someone decided to vkWaitForFences before
994 * they've actually submitted any of them to a queue. This is a
995 * fairly pessimal case, so it's ok to lock here and use a standard
996 * pthreads condition variable.
997 */
998 pthread_mutex_lock(&device->mutex);
999
1000 /* It's possible that some of the fences have changed state since the
1001 * last time we checked. Now that we have the lock, check for
1002 * pending fences again and don't wait if it's changed.
1003 */
1004 uint32_t now_pending_fences = 0;
1005 for (uint32_t i = 0; i < fenceCount; i++) {
1006 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1007 if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
1008 now_pending_fences++;
1009 }
1010 assert(now_pending_fences <= pending_fences);
1011
1012 if (now_pending_fences == pending_fences) {
1013 struct timespec abstime = {
1014 .tv_sec = abs_timeout_ns / NSEC_PER_SEC,
1015 .tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
1016 };
1017
1018 ASSERTED int ret;
1019 ret = pthread_cond_timedwait(&device->queue_submit,
1020 &device->mutex, &abstime);
1021 assert(ret != EINVAL);
1022 if (anv_gettime_ns() >= abs_timeout_ns) {
1023 pthread_mutex_unlock(&device->mutex);
1024 result = VK_TIMEOUT;
1025 goto done;
1026 }
1027 }
1028
1029 pthread_mutex_unlock(&device->mutex);
1030 }
1031 }
1032
1033 done:
1034 if (anv_device_is_lost(device))
1035 return VK_ERROR_DEVICE_LOST;
1036
1037 return result;
1038 }
1039
1040 static VkResult
1041 anv_wait_for_wsi_fence(struct anv_device *device,
1042 const VkFence _fence,
1043 uint64_t abs_timeout)
1044 {
1045 ANV_FROM_HANDLE(anv_fence, fence, _fence);
1046 struct anv_fence_impl *impl = &fence->permanent;
1047
1048 return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout);
1049 }
1050
1051 static VkResult
1052 anv_wait_for_fences(struct anv_device *device,
1053 uint32_t fenceCount,
1054 const VkFence *pFences,
1055 bool waitAll,
1056 uint64_t abs_timeout)
1057 {
1058 VkResult result = VK_SUCCESS;
1059
1060 if (fenceCount <= 1 || waitAll) {
1061 for (uint32_t i = 0; i < fenceCount; i++) {
1062 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1063 switch (fence->permanent.type) {
1064 case ANV_FENCE_TYPE_BO:
1065 result = anv_wait_for_bo_fences(device, 1, &pFences[i],
1066 true, abs_timeout);
1067 break;
1068 case ANV_FENCE_TYPE_SYNCOBJ:
1069 result = anv_wait_for_syncobj_fences(device, 1, &pFences[i],
1070 true, abs_timeout);
1071 break;
1072 case ANV_FENCE_TYPE_WSI:
1073 result = anv_wait_for_wsi_fence(device, pFences[i], abs_timeout);
1074 break;
1075 case ANV_FENCE_TYPE_NONE:
1076 result = VK_SUCCESS;
1077 break;
1078 }
1079 if (result != VK_SUCCESS)
1080 return result;
1081 }
1082 } else {
1083 do {
1084 for (uint32_t i = 0; i < fenceCount; i++) {
1085 if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS)
1086 return VK_SUCCESS;
1087 }
1088 } while (anv_gettime_ns() < abs_timeout);
1089 result = VK_TIMEOUT;
1090 }
1091 return result;
1092 }
1093
1094 static bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences)
1095 {
1096 for (uint32_t i = 0; i < fenceCount; ++i) {
1097 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1098 if (fence->permanent.type != ANV_FENCE_TYPE_SYNCOBJ)
1099 return false;
1100 }
1101 return true;
1102 }
1103
1104 static bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences)
1105 {
1106 for (uint32_t i = 0; i < fenceCount; ++i) {
1107 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1108 if (fence->permanent.type != ANV_FENCE_TYPE_BO)
1109 return false;
1110 }
1111 return true;
1112 }
1113
1114 VkResult anv_WaitForFences(
1115 VkDevice _device,
1116 uint32_t fenceCount,
1117 const VkFence* pFences,
1118 VkBool32 waitAll,
1119 uint64_t timeout)
1120 {
1121 ANV_FROM_HANDLE(anv_device, device, _device);
1122
1123 if (anv_device_is_lost(device))
1124 return VK_ERROR_DEVICE_LOST;
1125
1126 uint64_t abs_timeout = anv_get_absolute_timeout(timeout);
1127 if (anv_all_fences_syncobj(fenceCount, pFences)) {
1128 return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
1129 waitAll, abs_timeout);
1130 } else if (anv_all_fences_bo(fenceCount, pFences)) {
1131 return anv_wait_for_bo_fences(device, fenceCount, pFences,
1132 waitAll, abs_timeout);
1133 } else {
1134 return anv_wait_for_fences(device, fenceCount, pFences,
1135 waitAll, abs_timeout);
1136 }
1137 }
1138
1139 void anv_GetPhysicalDeviceExternalFenceProperties(
1140 VkPhysicalDevice physicalDevice,
1141 const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
1142 VkExternalFenceProperties* pExternalFenceProperties)
1143 {
1144 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
1145
1146 switch (pExternalFenceInfo->handleType) {
1147 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
1148 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
1149 if (device->has_syncobj_wait) {
1150 pExternalFenceProperties->exportFromImportedHandleTypes =
1151 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1152 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1153 pExternalFenceProperties->compatibleHandleTypes =
1154 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1155 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1156 pExternalFenceProperties->externalFenceFeatures =
1157 VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT |
1158 VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT;
1159 return;
1160 }
1161 break;
1162
1163 default:
1164 break;
1165 }
1166
1167 pExternalFenceProperties->exportFromImportedHandleTypes = 0;
1168 pExternalFenceProperties->compatibleHandleTypes = 0;
1169 pExternalFenceProperties->externalFenceFeatures = 0;
1170 }
1171
1172 VkResult anv_ImportFenceFdKHR(
1173 VkDevice _device,
1174 const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
1175 {
1176 ANV_FROM_HANDLE(anv_device, device, _device);
1177 ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
1178 int fd = pImportFenceFdInfo->fd;
1179
1180 assert(pImportFenceFdInfo->sType ==
1181 VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
1182
1183 struct anv_fence_impl new_impl = {
1184 .type = ANV_FENCE_TYPE_NONE,
1185 };
1186
1187 switch (pImportFenceFdInfo->handleType) {
1188 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
1189 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
1190
1191 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
1192 if (!new_impl.syncobj)
1193 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1194
1195 break;
1196
1197 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
1198 /* Sync files are a bit tricky. Because we want to continue using the
1199 * syncobj implementation of WaitForFences, we don't use the sync file
1200 * directly but instead import it into a syncobj.
1201 */
1202 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
1203
1204 new_impl.syncobj = anv_gem_syncobj_create(device, 0);
1205 if (!new_impl.syncobj)
1206 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1207
1208 if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
1209 anv_gem_syncobj_destroy(device, new_impl.syncobj);
1210 return vk_errorf(device->instance, NULL,
1211 VK_ERROR_INVALID_EXTERNAL_HANDLE,
1212 "syncobj sync file import failed: %m");
1213 }
1214 break;
1215
1216 default:
1217 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1218 }
1219
1220 /* From the Vulkan 1.0.53 spec:
1221 *
1222 * "Importing a fence payload from a file descriptor transfers
1223 * ownership of the file descriptor from the application to the
1224 * Vulkan implementation. The application must not perform any
1225 * operations on the file descriptor after a successful import."
1226 *
1227 * If the import fails, we leave the file descriptor open.
1228 */
1229 close(fd);
1230
1231 if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) {
1232 anv_fence_impl_cleanup(device, &fence->temporary);
1233 fence->temporary = new_impl;
1234 } else {
1235 anv_fence_impl_cleanup(device, &fence->permanent);
1236 fence->permanent = new_impl;
1237 }
1238
1239 return VK_SUCCESS;
1240 }
1241
1242 VkResult anv_GetFenceFdKHR(
1243 VkDevice _device,
1244 const VkFenceGetFdInfoKHR* pGetFdInfo,
1245 int* pFd)
1246 {
1247 ANV_FROM_HANDLE(anv_device, device, _device);
1248 ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
1249
1250 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
1251
1252 struct anv_fence_impl *impl =
1253 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1254 &fence->temporary : &fence->permanent;
1255
1256 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
1257 switch (pGetFdInfo->handleType) {
1258 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: {
1259 int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
1260 if (fd < 0)
1261 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1262
1263 *pFd = fd;
1264 break;
1265 }
1266
1267 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
1268 int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
1269 if (fd < 0)
1270 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1271
1272 *pFd = fd;
1273 break;
1274 }
1275
1276 default:
1277 unreachable("Invalid fence export handle type");
1278 }
1279
1280 /* From the Vulkan 1.0.53 spec:
1281 *
1282 * "Export operations have the same transference as the specified handle
1283 * type’s import operations. [...] If the fence was using a
1284 * temporarily imported payload, the fence’s prior permanent payload
1285 * will be restored.
1286 */
1287 if (impl == &fence->temporary)
1288 anv_fence_impl_cleanup(device, impl);
1289
1290 return VK_SUCCESS;
1291 }
1292
1293 // Queue semaphore functions
1294
1295 VkResult anv_CreateSemaphore(
1296 VkDevice _device,
1297 const VkSemaphoreCreateInfo* pCreateInfo,
1298 const VkAllocationCallbacks* pAllocator,
1299 VkSemaphore* pSemaphore)
1300 {
1301 ANV_FROM_HANDLE(anv_device, device, _device);
1302 struct anv_semaphore *semaphore;
1303
1304 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
1305
1306 semaphore = vk_alloc(&device->alloc, sizeof(*semaphore), 8,
1307 VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1308 if (semaphore == NULL)
1309 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1310
1311 p_atomic_set(&semaphore->refcount, 1);
1312
1313 const VkExportSemaphoreCreateInfo *export =
1314 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
1315 VkExternalSemaphoreHandleTypeFlags handleTypes =
1316 export ? export->handleTypes : 0;
1317
1318 if (handleTypes == 0) {
1319 /* The DRM execbuffer ioctl always execute in-oder so long as you stay
1320 * on the same ring. Since we don't expose the blit engine as a DMA
1321 * queue, a dummy no-op semaphore is a perfectly valid implementation.
1322 */
1323 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY;
1324 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
1325 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
1326 if (device->instance->physicalDevice.has_syncobj) {
1327 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
1328 semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
1329 if (!semaphore->permanent.syncobj) {
1330 vk_free2(&device->alloc, pAllocator, semaphore);
1331 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1332 }
1333 } else {
1334 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
1335 VkResult result = anv_device_alloc_bo(device, 4096,
1336 ANV_BO_ALLOC_EXTERNAL |
1337 ANV_BO_ALLOC_IMPLICIT_SYNC,
1338 &semaphore->permanent.bo);
1339 if (result != VK_SUCCESS) {
1340 vk_free2(&device->alloc, pAllocator, semaphore);
1341 return result;
1342 }
1343
1344 /* If we're going to use this as a fence, we need to *not* have the
1345 * EXEC_OBJECT_ASYNC bit set.
1346 */
1347 assert(!(semaphore->permanent.bo->flags & EXEC_OBJECT_ASYNC));
1348 }
1349 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
1350 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT);
1351 if (device->instance->physicalDevice.has_syncobj) {
1352 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
1353 semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
1354 } else {
1355 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
1356 semaphore->permanent.fd = -1;
1357 }
1358 } else {
1359 assert(!"Unknown handle type");
1360 vk_free2(&device->alloc, pAllocator, semaphore);
1361 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1362 }
1363
1364 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
1365
1366 *pSemaphore = anv_semaphore_to_handle(semaphore);
1367
1368 return VK_SUCCESS;
1369 }
1370
1371 static void
1372 anv_semaphore_impl_cleanup(struct anv_device *device,
1373 struct anv_semaphore_impl *impl)
1374 {
1375 switch (impl->type) {
1376 case ANV_SEMAPHORE_TYPE_NONE:
1377 case ANV_SEMAPHORE_TYPE_DUMMY:
1378 /* Dummy. Nothing to do */
1379 break;
1380
1381 case ANV_SEMAPHORE_TYPE_BO:
1382 anv_device_release_bo(device, impl->bo);
1383 break;
1384
1385 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
1386 close(impl->fd);
1387 break;
1388
1389 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
1390 anv_gem_syncobj_destroy(device, impl->syncobj);
1391 break;
1392
1393 default:
1394 unreachable("Invalid semaphore type");
1395 }
1396
1397 impl->type = ANV_SEMAPHORE_TYPE_NONE;
1398 }
1399
1400 void
1401 anv_semaphore_reset_temporary(struct anv_device *device,
1402 struct anv_semaphore *semaphore)
1403 {
1404 if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
1405 return;
1406
1407 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
1408 }
1409
1410 static struct anv_semaphore *
1411 anv_semaphore_ref(struct anv_semaphore *semaphore)
1412 {
1413 assert(semaphore->refcount);
1414 p_atomic_inc(&semaphore->refcount);
1415 return semaphore;
1416 }
1417
1418 static void
1419 anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore)
1420 {
1421 if (!p_atomic_dec_zero(&semaphore->refcount))
1422 return;
1423
1424 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
1425 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
1426 vk_free(&device->alloc, semaphore);
1427 }
1428
1429 void anv_DestroySemaphore(
1430 VkDevice _device,
1431 VkSemaphore _semaphore,
1432 const VkAllocationCallbacks* pAllocator)
1433 {
1434 ANV_FROM_HANDLE(anv_device, device, _device);
1435 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
1436
1437 if (semaphore == NULL)
1438 return;
1439
1440 anv_semaphore_unref(device, semaphore);
1441 }
1442
1443 void anv_GetPhysicalDeviceExternalSemaphoreProperties(
1444 VkPhysicalDevice physicalDevice,
1445 const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
1446 VkExternalSemaphoreProperties* pExternalSemaphoreProperties)
1447 {
1448 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
1449
1450 switch (pExternalSemaphoreInfo->handleType) {
1451 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
1452 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
1453 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
1454 pExternalSemaphoreProperties->compatibleHandleTypes =
1455 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
1456 pExternalSemaphoreProperties->externalSemaphoreFeatures =
1457 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
1458 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
1459 return;
1460
1461 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
1462 if (device->has_exec_fence) {
1463 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
1464 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1465 pExternalSemaphoreProperties->compatibleHandleTypes =
1466 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
1467 pExternalSemaphoreProperties->externalSemaphoreFeatures =
1468 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
1469 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
1470 return;
1471 }
1472 break;
1473
1474 default:
1475 break;
1476 }
1477
1478 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
1479 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
1480 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
1481 }
1482
1483 VkResult anv_ImportSemaphoreFdKHR(
1484 VkDevice _device,
1485 const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
1486 {
1487 ANV_FROM_HANDLE(anv_device, device, _device);
1488 ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
1489 int fd = pImportSemaphoreFdInfo->fd;
1490
1491 struct anv_semaphore_impl new_impl = {
1492 .type = ANV_SEMAPHORE_TYPE_NONE,
1493 };
1494
1495 switch (pImportSemaphoreFdInfo->handleType) {
1496 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
1497 if (device->instance->physicalDevice.has_syncobj) {
1498 new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
1499
1500 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
1501 if (!new_impl.syncobj)
1502 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1503 } else {
1504 new_impl.type = ANV_SEMAPHORE_TYPE_BO;
1505
1506 VkResult result = anv_device_import_bo(device, fd,
1507 ANV_BO_ALLOC_EXTERNAL |
1508 ANV_BO_ALLOC_IMPLICIT_SYNC,
1509 &new_impl.bo);
1510 if (result != VK_SUCCESS)
1511 return result;
1512
1513 if (new_impl.bo->size < 4096) {
1514 anv_device_release_bo(device, new_impl.bo);
1515 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1516 }
1517
1518 /* If we're going to use this as a fence, we need to *not* have the
1519 * EXEC_OBJECT_ASYNC bit set.
1520 */
1521 assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
1522 }
1523
1524 /* From the Vulkan spec:
1525 *
1526 * "Importing semaphore state from a file descriptor transfers
1527 * ownership of the file descriptor from the application to the
1528 * Vulkan implementation. The application must not perform any
1529 * operations on the file descriptor after a successful import."
1530 *
1531 * If the import fails, we leave the file descriptor open.
1532 */
1533 close(fd);
1534 break;
1535
1536 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
1537 if (device->instance->physicalDevice.has_syncobj) {
1538 new_impl = (struct anv_semaphore_impl) {
1539 .type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
1540 .syncobj = anv_gem_syncobj_create(device, 0),
1541 };
1542 if (!new_impl.syncobj)
1543 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1544 if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
1545 anv_gem_syncobj_destroy(device, new_impl.syncobj);
1546 return vk_errorf(device->instance, NULL,
1547 VK_ERROR_INVALID_EXTERNAL_HANDLE,
1548 "syncobj sync file import failed: %m");
1549 }
1550 /* Ownership of the FD is transfered to Anv. Since we don't need it
1551 * anymore because the associated fence has been put into a syncobj,
1552 * we must close the FD.
1553 */
1554 close(fd);
1555 } else {
1556 new_impl = (struct anv_semaphore_impl) {
1557 .type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
1558 .fd = fd,
1559 };
1560 }
1561 break;
1562
1563 default:
1564 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1565 }
1566
1567 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
1568 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
1569 semaphore->temporary = new_impl;
1570 } else {
1571 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
1572 semaphore->permanent = new_impl;
1573 }
1574
1575 return VK_SUCCESS;
1576 }
1577
1578 VkResult anv_GetSemaphoreFdKHR(
1579 VkDevice _device,
1580 const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
1581 int* pFd)
1582 {
1583 ANV_FROM_HANDLE(anv_device, device, _device);
1584 ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
1585 VkResult result;
1586 int fd;
1587
1588 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
1589
1590 struct anv_semaphore_impl *impl =
1591 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
1592 &semaphore->temporary : &semaphore->permanent;
1593
1594 switch (impl->type) {
1595 case ANV_SEMAPHORE_TYPE_BO:
1596 result = anv_device_export_bo(device, impl->bo, pFd);
1597 if (result != VK_SUCCESS)
1598 return result;
1599 break;
1600
1601 case ANV_SEMAPHORE_TYPE_SYNC_FILE: {
1602 /* There's a potential race here with vkQueueSubmit if you are trying
1603 * to export a semaphore Fd while the queue submit is still happening.
1604 * This can happen if we see all dependencies get resolved via timeline
1605 * semaphore waits completing before the execbuf completes and we
1606 * process the resulting out fence. To work around this, take a lock
1607 * around grabbing the fd.
1608 */
1609 pthread_mutex_lock(&device->mutex);
1610
1611 /* From the Vulkan 1.0.53 spec:
1612 *
1613 * "...exporting a semaphore payload to a handle with copy
1614 * transference has the same side effects on the source
1615 * semaphore’s payload as executing a semaphore wait operation."
1616 *
1617 * In other words, it may still be a SYNC_FD semaphore, but it's now
1618 * considered to have been waited on and no longer has a sync file
1619 * attached.
1620 */
1621 int fd = impl->fd;
1622 impl->fd = -1;
1623
1624 pthread_mutex_unlock(&device->mutex);
1625
1626 /* There are two reasons why this could happen:
1627 *
1628 * 1) The user is trying to export without submitting something that
1629 * signals the semaphore. If this is the case, it's their bug so
1630 * what we return here doesn't matter.
1631 *
1632 * 2) The kernel didn't give us a file descriptor. The most likely
1633 * reason for this is running out of file descriptors.
1634 */
1635 if (fd < 0)
1636 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1637
1638 *pFd = fd;
1639 return VK_SUCCESS;
1640 }
1641
1642 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
1643 if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT)
1644 fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
1645 else {
1646 assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
1647 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
1648 }
1649 if (fd < 0)
1650 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1651 *pFd = fd;
1652 break;
1653
1654 default:
1655 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
1656 }
1657
1658 /* From the Vulkan 1.0.53 spec:
1659 *
1660 * "Export operations have the same transference as the specified handle
1661 * type’s import operations. [...] If the semaphore was using a
1662 * temporarily imported payload, the semaphore’s prior permanent payload
1663 * will be restored.
1664 */
1665 if (impl == &semaphore->temporary)
1666 anv_semaphore_impl_cleanup(device, impl);
1667
1668 return VK_SUCCESS;
1669 }