anv: Add support for the SYNC_FD handle type for fences
[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 #include <sys/eventfd.h>
31
32 #include "anv_private.h"
33 #include "vk_util.h"
34
35 #include "genxml/gen7_pack.h"
36
37 VkResult
38 anv_device_execbuf(struct anv_device *device,
39 struct drm_i915_gem_execbuffer2 *execbuf,
40 struct anv_bo **execbuf_bos)
41 {
42 int ret = anv_gem_execbuffer(device, execbuf);
43 if (ret != 0) {
44 /* We don't know the real error. */
45 device->lost = true;
46 return vk_errorf(VK_ERROR_DEVICE_LOST, "execbuf2 failed: %m");
47 }
48
49 struct drm_i915_gem_exec_object2 *objects =
50 (void *)(uintptr_t)execbuf->buffers_ptr;
51 for (uint32_t k = 0; k < execbuf->buffer_count; k++)
52 execbuf_bos[k]->offset = objects[k].offset;
53
54 return VK_SUCCESS;
55 }
56
57 VkResult
58 anv_device_submit_simple_batch(struct anv_device *device,
59 struct anv_batch *batch)
60 {
61 struct drm_i915_gem_execbuffer2 execbuf;
62 struct drm_i915_gem_exec_object2 exec2_objects[1];
63 struct anv_bo bo, *exec_bos[1];
64 VkResult result = VK_SUCCESS;
65 uint32_t size;
66
67 /* Kernel driver requires 8 byte aligned batch length */
68 size = align_u32(batch->next - batch->start, 8);
69 result = anv_bo_pool_alloc(&device->batch_bo_pool, &bo, size);
70 if (result != VK_SUCCESS)
71 return result;
72
73 memcpy(bo.map, batch->start, size);
74 if (!device->info.has_llc)
75 gen_flush_range(bo.map, size);
76
77 exec_bos[0] = &bo;
78 exec2_objects[0].handle = bo.gem_handle;
79 exec2_objects[0].relocation_count = 0;
80 exec2_objects[0].relocs_ptr = 0;
81 exec2_objects[0].alignment = 0;
82 exec2_objects[0].offset = bo.offset;
83 exec2_objects[0].flags = 0;
84 exec2_objects[0].rsvd1 = 0;
85 exec2_objects[0].rsvd2 = 0;
86
87 execbuf.buffers_ptr = (uintptr_t) exec2_objects;
88 execbuf.buffer_count = 1;
89 execbuf.batch_start_offset = 0;
90 execbuf.batch_len = size;
91 execbuf.cliprects_ptr = 0;
92 execbuf.num_cliprects = 0;
93 execbuf.DR1 = 0;
94 execbuf.DR4 = 0;
95
96 execbuf.flags =
97 I915_EXEC_HANDLE_LUT | I915_EXEC_NO_RELOC | I915_EXEC_RENDER;
98 execbuf.rsvd1 = device->context_id;
99 execbuf.rsvd2 = 0;
100
101 result = anv_device_execbuf(device, &execbuf, exec_bos);
102 if (result != VK_SUCCESS)
103 goto fail;
104
105 result = anv_device_wait(device, &bo, INT64_MAX);
106
107 fail:
108 anv_bo_pool_free(&device->batch_bo_pool, &bo);
109
110 return result;
111 }
112
113 VkResult anv_QueueSubmit(
114 VkQueue _queue,
115 uint32_t submitCount,
116 const VkSubmitInfo* pSubmits,
117 VkFence fence)
118 {
119 ANV_FROM_HANDLE(anv_queue, queue, _queue);
120 struct anv_device *device = queue->device;
121
122 /* Query for device status prior to submitting. Technically, we don't need
123 * to do this. However, if we have a client that's submitting piles of
124 * garbage, we would rather break as early as possible to keep the GPU
125 * hanging contained. If we don't check here, we'll either be waiting for
126 * the kernel to kick us or we'll have to wait until the client waits on a
127 * fence before we actually know whether or not we've hung.
128 */
129 VkResult result = anv_device_query_status(device);
130 if (result != VK_SUCCESS)
131 return result;
132
133 /* We lock around QueueSubmit for three main reasons:
134 *
135 * 1) When a block pool is resized, we create a new gem handle with a
136 * different size and, in the case of surface states, possibly a
137 * different center offset but we re-use the same anv_bo struct when
138 * we do so. If this happens in the middle of setting up an execbuf,
139 * we could end up with our list of BOs out of sync with our list of
140 * gem handles.
141 *
142 * 2) The algorithm we use for building the list of unique buffers isn't
143 * thread-safe. While the client is supposed to syncronize around
144 * QueueSubmit, this would be extremely difficult to debug if it ever
145 * came up in the wild due to a broken app. It's better to play it
146 * safe and just lock around QueueSubmit.
147 *
148 * 3) The anv_cmd_buffer_execbuf function may perform relocations in
149 * userspace. Due to the fact that the surface state buffer is shared
150 * between batches, we can't afford to have that happen from multiple
151 * threads at the same time. Even though the user is supposed to
152 * ensure this doesn't happen, we play it safe as in (2) above.
153 *
154 * Since the only other things that ever take the device lock such as block
155 * pool resize only rarely happen, this will almost never be contended so
156 * taking a lock isn't really an expensive operation in this case.
157 */
158 pthread_mutex_lock(&device->mutex);
159
160 if (fence && submitCount == 0) {
161 /* If we don't have any command buffers, we need to submit a dummy
162 * batch to give GEM something to wait on. We could, potentially,
163 * come up with something more efficient but this shouldn't be a
164 * common case.
165 */
166 result = anv_cmd_buffer_execbuf(device, NULL, NULL, 0, NULL, 0, fence);
167 goto out;
168 }
169
170 for (uint32_t i = 0; i < submitCount; i++) {
171 /* Fence for this submit. NULL for all but the last one */
172 VkFence submit_fence = (i == submitCount - 1) ? fence : NULL;
173
174 if (pSubmits[i].commandBufferCount == 0) {
175 /* If we don't have any command buffers, we need to submit a dummy
176 * batch to give GEM something to wait on. We could, potentially,
177 * come up with something more efficient but this shouldn't be a
178 * common case.
179 */
180 result = anv_cmd_buffer_execbuf(device, NULL,
181 pSubmits[i].pWaitSemaphores,
182 pSubmits[i].waitSemaphoreCount,
183 pSubmits[i].pSignalSemaphores,
184 pSubmits[i].signalSemaphoreCount,
185 submit_fence);
186 if (result != VK_SUCCESS)
187 goto out;
188
189 continue;
190 }
191
192 for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
193 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
194 pSubmits[i].pCommandBuffers[j]);
195 assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
196 assert(!anv_batch_has_error(&cmd_buffer->batch));
197
198 /* Fence for this execbuf. NULL for all but the last one */
199 VkFence execbuf_fence =
200 (j == pSubmits[i].commandBufferCount - 1) ? submit_fence : NULL;
201
202 const VkSemaphore *in_semaphores = NULL, *out_semaphores = NULL;
203 uint32_t num_in_semaphores = 0, num_out_semaphores = 0;
204 if (j == 0) {
205 /* Only the first batch gets the in semaphores */
206 in_semaphores = pSubmits[i].pWaitSemaphores;
207 num_in_semaphores = pSubmits[i].waitSemaphoreCount;
208 }
209
210 if (j == pSubmits[i].commandBufferCount - 1) {
211 /* Only the last batch gets the out semaphores */
212 out_semaphores = pSubmits[i].pSignalSemaphores;
213 num_out_semaphores = pSubmits[i].signalSemaphoreCount;
214 }
215
216 result = anv_cmd_buffer_execbuf(device, cmd_buffer,
217 in_semaphores, num_in_semaphores,
218 out_semaphores, num_out_semaphores,
219 execbuf_fence);
220 if (result != VK_SUCCESS)
221 goto out;
222 }
223 }
224
225 pthread_cond_broadcast(&device->queue_submit);
226
227 out:
228 if (result != VK_SUCCESS) {
229 /* In the case that something has gone wrong we may end up with an
230 * inconsistent state from which it may not be trivial to recover.
231 * For example, we might have computed address relocations and
232 * any future attempt to re-submit this job will need to know about
233 * this and avoid computing relocation addresses again.
234 *
235 * To avoid this sort of issues, we assume that if something was
236 * wrong during submission we must already be in a really bad situation
237 * anyway (such us being out of memory) and return
238 * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
239 * submit the same job again to this device.
240 */
241 result = vk_errorf(VK_ERROR_DEVICE_LOST, "vkQueueSubmit() failed");
242 device->lost = true;
243 }
244
245 pthread_mutex_unlock(&device->mutex);
246
247 return result;
248 }
249
250 VkResult anv_QueueWaitIdle(
251 VkQueue _queue)
252 {
253 ANV_FROM_HANDLE(anv_queue, queue, _queue);
254
255 return anv_DeviceWaitIdle(anv_device_to_handle(queue->device));
256 }
257
258 VkResult anv_CreateFence(
259 VkDevice _device,
260 const VkFenceCreateInfo* pCreateInfo,
261 const VkAllocationCallbacks* pAllocator,
262 VkFence* pFence)
263 {
264 ANV_FROM_HANDLE(anv_device, device, _device);
265 struct anv_fence *fence;
266
267 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
268
269 fence = vk_zalloc2(&device->alloc, pAllocator, sizeof(*fence), 8,
270 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
271 if (fence == NULL)
272 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
273
274 if (device->instance->physicalDevice.has_syncobj_wait) {
275 fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
276
277 uint32_t create_flags = 0;
278 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)
279 create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
280
281 fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);
282 if (!fence->permanent.syncobj)
283 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
284 } else {
285 fence->permanent.type = ANV_FENCE_TYPE_BO;
286
287 VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool,
288 &fence->permanent.bo.bo, 4096);
289 if (result != VK_SUCCESS)
290 return result;
291
292 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
293 fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
294 } else {
295 fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
296 }
297 }
298
299 *pFence = anv_fence_to_handle(fence);
300
301 return VK_SUCCESS;
302 }
303
304 static void
305 anv_fence_impl_cleanup(struct anv_device *device,
306 struct anv_fence_impl *impl)
307 {
308 switch (impl->type) {
309 case ANV_FENCE_TYPE_NONE:
310 /* Dummy. Nothing to do */
311 return;
312
313 case ANV_FENCE_TYPE_BO:
314 anv_bo_pool_free(&device->batch_bo_pool, &impl->bo.bo);
315 return;
316
317 case ANV_FENCE_TYPE_SYNCOBJ:
318 anv_gem_syncobj_destroy(device, impl->syncobj);
319 return;
320 }
321
322 unreachable("Invalid fence type");
323 }
324
325 void anv_DestroyFence(
326 VkDevice _device,
327 VkFence _fence,
328 const VkAllocationCallbacks* pAllocator)
329 {
330 ANV_FROM_HANDLE(anv_device, device, _device);
331 ANV_FROM_HANDLE(anv_fence, fence, _fence);
332
333 if (!fence)
334 return;
335
336 anv_fence_impl_cleanup(device, &fence->temporary);
337 anv_fence_impl_cleanup(device, &fence->permanent);
338
339 vk_free2(&device->alloc, pAllocator, fence);
340 }
341
342 VkResult anv_ResetFences(
343 VkDevice _device,
344 uint32_t fenceCount,
345 const VkFence* pFences)
346 {
347 ANV_FROM_HANDLE(anv_device, device, _device);
348
349 for (uint32_t i = 0; i < fenceCount; i++) {
350 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
351
352 /* From the Vulkan 1.0.53 spec:
353 *
354 * "If any member of pFences currently has its payload imported with
355 * temporary permanence, that fence’s prior permanent payload is
356 * first restored. The remaining operations described therefore
357 * operate on the restored payload.
358 */
359 if (fence->temporary.type != ANV_FENCE_TYPE_NONE) {
360 anv_fence_impl_cleanup(device, &fence->temporary);
361 fence->temporary.type = ANV_FENCE_TYPE_NONE;
362 }
363
364 struct anv_fence_impl *impl = &fence->permanent;
365
366 switch (impl->type) {
367 case ANV_FENCE_TYPE_BO:
368 impl->bo.state = ANV_BO_FENCE_STATE_RESET;
369 break;
370
371 case ANV_FENCE_TYPE_SYNCOBJ:
372 anv_gem_syncobj_reset(device, impl->syncobj);
373 break;
374
375 default:
376 unreachable("Invalid fence type");
377 }
378 }
379
380 return VK_SUCCESS;
381 }
382
383 VkResult anv_GetFenceStatus(
384 VkDevice _device,
385 VkFence _fence)
386 {
387 ANV_FROM_HANDLE(anv_device, device, _device);
388 ANV_FROM_HANDLE(anv_fence, fence, _fence);
389
390 if (unlikely(device->lost))
391 return VK_ERROR_DEVICE_LOST;
392
393 struct anv_fence_impl *impl =
394 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
395 &fence->temporary : &fence->permanent;
396
397 switch (impl->type) {
398 case ANV_FENCE_TYPE_BO:
399 /* BO fences don't support import/export */
400 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
401 switch (impl->bo.state) {
402 case ANV_BO_FENCE_STATE_RESET:
403 /* If it hasn't even been sent off to the GPU yet, it's not ready */
404 return VK_NOT_READY;
405
406 case ANV_BO_FENCE_STATE_SIGNALED:
407 /* It's been signaled, return success */
408 return VK_SUCCESS;
409
410 case ANV_BO_FENCE_STATE_SUBMITTED: {
411 VkResult result = anv_device_bo_busy(device, &impl->bo.bo);
412 if (result == VK_SUCCESS) {
413 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
414 return VK_SUCCESS;
415 } else {
416 return result;
417 }
418 }
419 default:
420 unreachable("Invalid fence status");
421 }
422
423 case ANV_FENCE_TYPE_SYNCOBJ: {
424 int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, true);
425 if (ret == -1) {
426 if (errno == ETIME) {
427 return VK_NOT_READY;
428 } else {
429 /* We don't know the real error. */
430 device->lost = true;
431 return vk_errorf(VK_ERROR_DEVICE_LOST,
432 "drm_syncobj_wait failed: %m");
433 }
434 } else {
435 return VK_SUCCESS;
436 }
437 }
438
439 default:
440 unreachable("Invalid fence type");
441 }
442 }
443
444 #define NSEC_PER_SEC 1000000000
445 #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)
446
447 static uint64_t
448 gettime_ns(void)
449 {
450 struct timespec current;
451 clock_gettime(CLOCK_MONOTONIC, &current);
452 return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
453 }
454
455 static VkResult
456 anv_wait_for_syncobj_fences(struct anv_device *device,
457 uint32_t fenceCount,
458 const VkFence *pFences,
459 bool waitAll,
460 uint64_t _timeout)
461 {
462 uint32_t *syncobjs = vk_zalloc(&device->alloc,
463 sizeof(*syncobjs) * fenceCount, 8,
464 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
465 if (!syncobjs)
466 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
467
468 for (uint32_t i = 0; i < fenceCount; i++) {
469 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
470 assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
471
472 struct anv_fence_impl *impl =
473 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
474 &fence->temporary : &fence->permanent;
475
476 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
477 syncobjs[i] = impl->syncobj;
478 }
479
480 int64_t abs_timeout_ns = 0;
481 if (_timeout > 0) {
482 uint64_t current_ns = gettime_ns();
483
484 /* Add but saturate to INT32_MAX */
485 if (current_ns + _timeout < current_ns)
486 abs_timeout_ns = INT64_MAX;
487 else if (current_ns + _timeout > INT64_MAX)
488 abs_timeout_ns = INT64_MAX;
489 else
490 abs_timeout_ns = current_ns + _timeout;
491 }
492
493 /* The gem_syncobj_wait ioctl may return early due to an inherent
494 * limitation in the way it computes timeouts. Loop until we've actually
495 * passed the timeout.
496 */
497 int ret;
498 do {
499 ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
500 abs_timeout_ns, waitAll);
501 } while (ret == -1 && errno == ETIME && gettime_ns() < abs_timeout_ns);
502
503 vk_free(&device->alloc, syncobjs);
504
505 if (ret == -1) {
506 if (errno == ETIME) {
507 return VK_TIMEOUT;
508 } else {
509 /* We don't know the real error. */
510 device->lost = true;
511 return vk_errorf(VK_ERROR_DEVICE_LOST,
512 "drm_syncobj_wait failed: %m");
513 }
514 } else {
515 return VK_SUCCESS;
516 }
517 }
518
519 static VkResult
520 anv_wait_for_bo_fences(struct anv_device *device,
521 uint32_t fenceCount,
522 const VkFence *pFences,
523 bool waitAll,
524 uint64_t _timeout)
525 {
526 int ret;
527
528 /* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is supposed
529 * to block indefinitely timeouts <= 0. Unfortunately, this was broken
530 * for a couple of kernel releases. Since there's no way to know
531 * whether or not the kernel we're using is one of the broken ones, the
532 * best we can do is to clamp the timeout to INT64_MAX. This limits the
533 * maximum timeout from 584 years to 292 years - likely not a big deal.
534 */
535 int64_t timeout = MIN2(_timeout, INT64_MAX);
536
537 VkResult result = VK_SUCCESS;
538 uint32_t pending_fences = fenceCount;
539 while (pending_fences) {
540 pending_fences = 0;
541 bool signaled_fences = false;
542 for (uint32_t i = 0; i < fenceCount; i++) {
543 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
544
545 /* This function assumes that all fences are BO fences and that they
546 * have no temporary state. Since BO fences will never be exported,
547 * this should be a safe assumption.
548 */
549 assert(fence->permanent.type == ANV_FENCE_TYPE_BO);
550 assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
551 struct anv_fence_impl *impl = &fence->permanent;
552
553 switch (impl->bo.state) {
554 case ANV_BO_FENCE_STATE_RESET:
555 /* This fence hasn't been submitted yet, we'll catch it the next
556 * time around. Yes, this may mean we dead-loop but, short of
557 * lots of locking and a condition variable, there's not much that
558 * we can do about that.
559 */
560 pending_fences++;
561 continue;
562
563 case ANV_BO_FENCE_STATE_SIGNALED:
564 /* This fence is not pending. If waitAll isn't set, we can return
565 * early. Otherwise, we have to keep going.
566 */
567 if (!waitAll) {
568 result = VK_SUCCESS;
569 goto done;
570 }
571 continue;
572
573 case ANV_BO_FENCE_STATE_SUBMITTED:
574 /* These are the fences we really care about. Go ahead and wait
575 * on it until we hit a timeout.
576 */
577 result = anv_device_wait(device, &impl->bo.bo, timeout);
578 switch (result) {
579 case VK_SUCCESS:
580 impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
581 signaled_fences = true;
582 if (!waitAll)
583 goto done;
584 break;
585
586 case VK_TIMEOUT:
587 goto done;
588
589 default:
590 return result;
591 }
592 }
593 }
594
595 if (pending_fences && !signaled_fences) {
596 /* If we've hit this then someone decided to vkWaitForFences before
597 * they've actually submitted any of them to a queue. This is a
598 * fairly pessimal case, so it's ok to lock here and use a standard
599 * pthreads condition variable.
600 */
601 pthread_mutex_lock(&device->mutex);
602
603 /* It's possible that some of the fences have changed state since the
604 * last time we checked. Now that we have the lock, check for
605 * pending fences again and don't wait if it's changed.
606 */
607 uint32_t now_pending_fences = 0;
608 for (uint32_t i = 0; i < fenceCount; i++) {
609 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
610 if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
611 now_pending_fences++;
612 }
613 assert(now_pending_fences <= pending_fences);
614
615 if (now_pending_fences == pending_fences) {
616 struct timespec before;
617 clock_gettime(CLOCK_MONOTONIC, &before);
618
619 uint32_t abs_nsec = before.tv_nsec + timeout % NSEC_PER_SEC;
620 uint64_t abs_sec = before.tv_sec + (abs_nsec / NSEC_PER_SEC) +
621 (timeout / NSEC_PER_SEC);
622 abs_nsec %= NSEC_PER_SEC;
623
624 /* Avoid roll-over in tv_sec on 32-bit systems if the user
625 * provided timeout is UINT64_MAX
626 */
627 struct timespec abstime;
628 abstime.tv_nsec = abs_nsec;
629 abstime.tv_sec = MIN2(abs_sec, INT_TYPE_MAX(abstime.tv_sec));
630
631 ret = pthread_cond_timedwait(&device->queue_submit,
632 &device->mutex, &abstime);
633 assert(ret != EINVAL);
634
635 struct timespec after;
636 clock_gettime(CLOCK_MONOTONIC, &after);
637 uint64_t time_elapsed =
638 ((uint64_t)after.tv_sec * NSEC_PER_SEC + after.tv_nsec) -
639 ((uint64_t)before.tv_sec * NSEC_PER_SEC + before.tv_nsec);
640
641 if (time_elapsed >= timeout) {
642 pthread_mutex_unlock(&device->mutex);
643 result = VK_TIMEOUT;
644 goto done;
645 }
646
647 timeout -= time_elapsed;
648 }
649
650 pthread_mutex_unlock(&device->mutex);
651 }
652 }
653
654 done:
655 if (unlikely(device->lost))
656 return VK_ERROR_DEVICE_LOST;
657
658 return result;
659 }
660
661 VkResult anv_WaitForFences(
662 VkDevice _device,
663 uint32_t fenceCount,
664 const VkFence* pFences,
665 VkBool32 waitAll,
666 uint64_t timeout)
667 {
668 ANV_FROM_HANDLE(anv_device, device, _device);
669
670 if (unlikely(device->lost))
671 return VK_ERROR_DEVICE_LOST;
672
673 if (device->instance->physicalDevice.has_syncobj_wait) {
674 return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
675 waitAll, timeout);
676 } else {
677 return anv_wait_for_bo_fences(device, fenceCount, pFences,
678 waitAll, timeout);
679 }
680 }
681
682 void anv_GetPhysicalDeviceExternalFencePropertiesKHR(
683 VkPhysicalDevice physicalDevice,
684 const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo,
685 VkExternalFencePropertiesKHR* pExternalFenceProperties)
686 {
687 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
688
689 switch (pExternalFenceInfo->handleType) {
690 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
691 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
692 if (device->has_syncobj_wait) {
693 pExternalFenceProperties->exportFromImportedHandleTypes =
694 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR |
695 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
696 pExternalFenceProperties->compatibleHandleTypes =
697 VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR |
698 VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
699 pExternalFenceProperties->externalFenceFeatures =
700 VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR |
701 VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR;
702 return;
703 }
704 break;
705
706 default:
707 break;
708 }
709
710 pExternalFenceProperties->exportFromImportedHandleTypes = 0;
711 pExternalFenceProperties->compatibleHandleTypes = 0;
712 pExternalFenceProperties->externalFenceFeatures = 0;
713 }
714
715 VkResult anv_ImportFenceFdKHR(
716 VkDevice _device,
717 const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
718 {
719 ANV_FROM_HANDLE(anv_device, device, _device);
720 ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
721 int fd = pImportFenceFdInfo->fd;
722
723 assert(pImportFenceFdInfo->sType ==
724 VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
725
726 struct anv_fence_impl new_impl = {
727 .type = ANV_FENCE_TYPE_NONE,
728 };
729
730 switch (pImportFenceFdInfo->handleType) {
731 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
732 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
733
734 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
735 if (!new_impl.syncobj)
736 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
737
738 break;
739
740 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
741 /* Sync files are a bit tricky. Because we want to continue using the
742 * syncobj implementation of WaitForFences, we don't use the sync file
743 * directly but instead import it into a syncobj.
744 */
745 new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
746
747 new_impl.syncobj = anv_gem_syncobj_create(device, 0);
748 if (!new_impl.syncobj)
749 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
750
751 if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
752 anv_gem_syncobj_destroy(device, new_impl.syncobj);
753 return vk_errorf(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR,
754 "syncobj sync file import failed: %m");
755 }
756 break;
757
758 default:
759 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
760 }
761
762 /* From the Vulkan 1.0.53 spec:
763 *
764 * "Importing a fence payload from a file descriptor transfers
765 * ownership of the file descriptor from the application to the
766 * Vulkan implementation. The application must not perform any
767 * operations on the file descriptor after a successful import."
768 *
769 * If the import fails, we leave the file descriptor open.
770 */
771 close(fd);
772
773 if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT_KHR) {
774 anv_fence_impl_cleanup(device, &fence->temporary);
775 fence->temporary = new_impl;
776 } else {
777 anv_fence_impl_cleanup(device, &fence->permanent);
778 fence->permanent = new_impl;
779 }
780
781 return VK_SUCCESS;
782 }
783
784 VkResult anv_GetFenceFdKHR(
785 VkDevice _device,
786 const VkFenceGetFdInfoKHR* pGetFdInfo,
787 int* pFd)
788 {
789 ANV_FROM_HANDLE(anv_device, device, _device);
790 ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
791
792 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
793
794 struct anv_fence_impl *impl =
795 fence->temporary.type != ANV_FENCE_TYPE_NONE ?
796 &fence->temporary : &fence->permanent;
797
798 assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
799 switch (pGetFdInfo->handleType) {
800 case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR: {
801 int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
802 if (fd < 0)
803 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
804
805 *pFd = fd;
806 break;
807 }
808
809 case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR: {
810 int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
811 if (fd < 0)
812 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
813
814 *pFd = fd;
815 break;
816 }
817
818 default:
819 unreachable("Invalid fence export handle type");
820 }
821
822 /* From the Vulkan 1.0.53 spec:
823 *
824 * "Export operations have the same transference as the specified handle
825 * type’s import operations. [...] If the fence was using a
826 * temporarily imported payload, the fence’s prior permanent payload
827 * will be restored.
828 */
829 if (impl == &fence->temporary)
830 anv_fence_impl_cleanup(device, impl);
831
832 return VK_SUCCESS;
833 }
834
835 // Queue semaphore functions
836
837 VkResult anv_CreateSemaphore(
838 VkDevice _device,
839 const VkSemaphoreCreateInfo* pCreateInfo,
840 const VkAllocationCallbacks* pAllocator,
841 VkSemaphore* pSemaphore)
842 {
843 ANV_FROM_HANDLE(anv_device, device, _device);
844 struct anv_semaphore *semaphore;
845
846 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
847
848 semaphore = vk_alloc2(&device->alloc, pAllocator, sizeof(*semaphore), 8,
849 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
850 if (semaphore == NULL)
851 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
852
853 const VkExportSemaphoreCreateInfoKHR *export =
854 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO_KHR);
855 VkExternalSemaphoreHandleTypeFlagsKHR handleTypes =
856 export ? export->handleTypes : 0;
857
858 if (handleTypes == 0) {
859 /* The DRM execbuffer ioctl always execute in-oder so long as you stay
860 * on the same ring. Since we don't expose the blit engine as a DMA
861 * queue, a dummy no-op semaphore is a perfectly valid implementation.
862 */
863 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY;
864 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR) {
865 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR);
866 if (device->instance->physicalDevice.has_syncobj) {
867 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
868 semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
869 if (!semaphore->permanent.syncobj) {
870 vk_free2(&device->alloc, pAllocator, semaphore);
871 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
872 }
873 } else {
874 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
875 VkResult result = anv_bo_cache_alloc(device, &device->bo_cache,
876 4096, &semaphore->permanent.bo);
877 if (result != VK_SUCCESS) {
878 vk_free2(&device->alloc, pAllocator, semaphore);
879 return result;
880 }
881
882 /* If we're going to use this as a fence, we need to *not* have the
883 * EXEC_OBJECT_ASYNC bit set.
884 */
885 assert(!(semaphore->permanent.bo->flags & EXEC_OBJECT_ASYNC));
886 }
887 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR) {
888 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR);
889
890 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
891 semaphore->permanent.fd = -1;
892 } else {
893 assert(!"Unknown handle type");
894 vk_free2(&device->alloc, pAllocator, semaphore);
895 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
896 }
897
898 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
899
900 *pSemaphore = anv_semaphore_to_handle(semaphore);
901
902 return VK_SUCCESS;
903 }
904
905 static void
906 anv_semaphore_impl_cleanup(struct anv_device *device,
907 struct anv_semaphore_impl *impl)
908 {
909 switch (impl->type) {
910 case ANV_SEMAPHORE_TYPE_NONE:
911 case ANV_SEMAPHORE_TYPE_DUMMY:
912 /* Dummy. Nothing to do */
913 return;
914
915 case ANV_SEMAPHORE_TYPE_BO:
916 anv_bo_cache_release(device, &device->bo_cache, impl->bo);
917 return;
918
919 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
920 close(impl->fd);
921 return;
922
923 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
924 anv_gem_syncobj_destroy(device, impl->syncobj);
925 return;
926 }
927
928 unreachable("Invalid semaphore type");
929 }
930
931 void
932 anv_semaphore_reset_temporary(struct anv_device *device,
933 struct anv_semaphore *semaphore)
934 {
935 if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
936 return;
937
938 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
939 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
940 }
941
942 void anv_DestroySemaphore(
943 VkDevice _device,
944 VkSemaphore _semaphore,
945 const VkAllocationCallbacks* pAllocator)
946 {
947 ANV_FROM_HANDLE(anv_device, device, _device);
948 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
949
950 if (semaphore == NULL)
951 return;
952
953 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
954 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
955
956 vk_free2(&device->alloc, pAllocator, semaphore);
957 }
958
959 void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHR(
960 VkPhysicalDevice physicalDevice,
961 const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
962 VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties)
963 {
964 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
965
966 switch (pExternalSemaphoreInfo->handleType) {
967 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
968 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
969 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
970 pExternalSemaphoreProperties->compatibleHandleTypes =
971 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
972 pExternalSemaphoreProperties->externalSemaphoreFeatures =
973 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
974 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
975 return;
976
977 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
978 if (device->has_exec_fence) {
979 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
980 pExternalSemaphoreProperties->compatibleHandleTypes =
981 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
982 pExternalSemaphoreProperties->externalSemaphoreFeatures =
983 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
984 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
985 return;
986 }
987 break;
988
989 default:
990 break;
991 }
992
993 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
994 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
995 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
996 }
997
998 VkResult anv_ImportSemaphoreFdKHR(
999 VkDevice _device,
1000 const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
1001 {
1002 ANV_FROM_HANDLE(anv_device, device, _device);
1003 ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
1004 int fd = pImportSemaphoreFdInfo->fd;
1005
1006 struct anv_semaphore_impl new_impl = {
1007 .type = ANV_SEMAPHORE_TYPE_NONE,
1008 };
1009
1010 switch (pImportSemaphoreFdInfo->handleType) {
1011 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
1012 if (device->instance->physicalDevice.has_syncobj) {
1013 new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
1014
1015 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
1016 if (!new_impl.syncobj)
1017 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
1018
1019 /* From the Vulkan spec:
1020 *
1021 * "Importing semaphore state from a file descriptor transfers
1022 * ownership of the file descriptor from the application to the
1023 * Vulkan implementation. The application must not perform any
1024 * operations on the file descriptor after a successful import."
1025 *
1026 * If the import fails, we leave the file descriptor open.
1027 */
1028 close(pImportSemaphoreFdInfo->fd);
1029 } else {
1030 new_impl.type = ANV_SEMAPHORE_TYPE_BO;
1031
1032 VkResult result = anv_bo_cache_import(device, &device->bo_cache,
1033 fd, 4096, &new_impl.bo);
1034 if (result != VK_SUCCESS)
1035 return result;
1036
1037 /* If we're going to use this as a fence, we need to *not* have the
1038 * EXEC_OBJECT_ASYNC bit set.
1039 */
1040 assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
1041 }
1042 break;
1043
1044 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
1045 new_impl = (struct anv_semaphore_impl) {
1046 .type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
1047 .fd = fd,
1048 };
1049 break;
1050
1051 default:
1052 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
1053 }
1054
1055 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR) {
1056 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
1057 semaphore->temporary = new_impl;
1058 } else {
1059 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
1060 semaphore->permanent = new_impl;
1061 }
1062
1063 return VK_SUCCESS;
1064 }
1065
1066 VkResult anv_GetSemaphoreFdKHR(
1067 VkDevice _device,
1068 const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
1069 int* pFd)
1070 {
1071 ANV_FROM_HANDLE(anv_device, device, _device);
1072 ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
1073 VkResult result;
1074 int fd;
1075
1076 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
1077
1078 struct anv_semaphore_impl *impl =
1079 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
1080 &semaphore->temporary : &semaphore->permanent;
1081
1082 switch (impl->type) {
1083 case ANV_SEMAPHORE_TYPE_BO:
1084 result = anv_bo_cache_export(device, &device->bo_cache, impl->bo, pFd);
1085 if (result != VK_SUCCESS)
1086 return result;
1087 break;
1088
1089 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
1090 /* There are two reasons why this could happen:
1091 *
1092 * 1) The user is trying to export without submitting something that
1093 * signals the semaphore. If this is the case, it's their bug so
1094 * what we return here doesn't matter.
1095 *
1096 * 2) The kernel didn't give us a file descriptor. The most likely
1097 * reason for this is running out of file descriptors.
1098 */
1099 if (impl->fd < 0)
1100 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1101
1102 *pFd = impl->fd;
1103
1104 /* From the Vulkan 1.0.53 spec:
1105 *
1106 * "...exporting a semaphore payload to a handle with copy
1107 * transference has the same side effects on the source
1108 * semaphore’s payload as executing a semaphore wait operation."
1109 *
1110 * In other words, it may still be a SYNC_FD semaphore, but it's now
1111 * considered to have been waited on and no longer has a sync file
1112 * attached.
1113 */
1114 impl->fd = -1;
1115 return VK_SUCCESS;
1116
1117 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
1118 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
1119 if (fd < 0)
1120 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
1121 *pFd = fd;
1122 break;
1123
1124 default:
1125 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
1126 }
1127
1128 /* From the Vulkan 1.0.53 spec:
1129 *
1130 * "Export operations have the same transference as the specified handle
1131 * type’s import operations. [...] If the semaphore was using a
1132 * temporarily imported payload, the semaphore’s prior permanent payload
1133 * will be restored.
1134 */
1135 if (impl == &semaphore->temporary)
1136 anv_semaphore_impl_cleanup(device, impl);
1137
1138 return VK_SUCCESS;
1139 }