anv: Use DRM sync objects for external semaphores when available
[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 ANV_FROM_HANDLE(anv_fence, fence, _fence);
121 struct anv_device *device = queue->device;
122
123 /* Query for device status prior to submitting. Technically, we don't need
124 * to do this. However, if we have a client that's submitting piles of
125 * garbage, we would rather break as early as possible to keep the GPU
126 * hanging contained. If we don't check here, we'll either be waiting for
127 * the kernel to kick us or we'll have to wait until the client waits on a
128 * fence before we actually know whether or not we've hung.
129 */
130 VkResult result = anv_device_query_status(device);
131 if (result != VK_SUCCESS)
132 return result;
133
134 /* We lock around QueueSubmit for three main reasons:
135 *
136 * 1) When a block pool is resized, we create a new gem handle with a
137 * different size and, in the case of surface states, possibly a
138 * different center offset but we re-use the same anv_bo struct when
139 * we do so. If this happens in the middle of setting up an execbuf,
140 * we could end up with our list of BOs out of sync with our list of
141 * gem handles.
142 *
143 * 2) The algorithm we use for building the list of unique buffers isn't
144 * thread-safe. While the client is supposed to syncronize around
145 * QueueSubmit, this would be extremely difficult to debug if it ever
146 * came up in the wild due to a broken app. It's better to play it
147 * safe and just lock around QueueSubmit.
148 *
149 * 3) The anv_cmd_buffer_execbuf function may perform relocations in
150 * userspace. Due to the fact that the surface state buffer is shared
151 * between batches, we can't afford to have that happen from multiple
152 * threads at the same time. Even though the user is supposed to
153 * ensure this doesn't happen, we play it safe as in (2) above.
154 *
155 * Since the only other things that ever take the device lock such as block
156 * pool resize only rarely happen, this will almost never be contended so
157 * taking a lock isn't really an expensive operation in this case.
158 */
159 pthread_mutex_lock(&device->mutex);
160
161 for (uint32_t i = 0; i < submitCount; i++) {
162 if (pSubmits[i].commandBufferCount == 0) {
163 /* If we don't have any command buffers, we need to submit a dummy
164 * batch to give GEM something to wait on. We could, potentially,
165 * come up with something more efficient but this shouldn't be a
166 * common case.
167 */
168 result = anv_cmd_buffer_execbuf(device, NULL,
169 pSubmits[i].pWaitSemaphores,
170 pSubmits[i].waitSemaphoreCount,
171 pSubmits[i].pSignalSemaphores,
172 pSubmits[i].signalSemaphoreCount);
173 if (result != VK_SUCCESS)
174 goto out;
175
176 continue;
177 }
178
179 for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
180 ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
181 pSubmits[i].pCommandBuffers[j]);
182 assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
183 assert(!anv_batch_has_error(&cmd_buffer->batch));
184
185 const VkSemaphore *in_semaphores = NULL, *out_semaphores = NULL;
186 uint32_t num_in_semaphores = 0, num_out_semaphores = 0;
187 if (j == 0) {
188 /* Only the first batch gets the in semaphores */
189 in_semaphores = pSubmits[i].pWaitSemaphores;
190 num_in_semaphores = pSubmits[i].waitSemaphoreCount;
191 }
192
193 if (j == pSubmits[i].commandBufferCount - 1) {
194 /* Only the last batch gets the out semaphores */
195 out_semaphores = pSubmits[i].pSignalSemaphores;
196 num_out_semaphores = pSubmits[i].signalSemaphoreCount;
197 }
198
199 result = anv_cmd_buffer_execbuf(device, cmd_buffer,
200 in_semaphores, num_in_semaphores,
201 out_semaphores, num_out_semaphores);
202 if (result != VK_SUCCESS)
203 goto out;
204 }
205 }
206
207 if (fence) {
208 struct anv_bo *fence_bo = &fence->bo;
209 result = anv_device_execbuf(device, &fence->execbuf, &fence_bo);
210 if (result != VK_SUCCESS)
211 goto out;
212
213 /* Update the fence and wake up any waiters */
214 assert(fence->state == ANV_FENCE_STATE_RESET);
215 fence->state = ANV_FENCE_STATE_SUBMITTED;
216 pthread_cond_broadcast(&device->queue_submit);
217 }
218
219 out:
220 if (result != VK_SUCCESS) {
221 /* In the case that something has gone wrong we may end up with an
222 * inconsistent state from which it may not be trivial to recover.
223 * For example, we might have computed address relocations and
224 * any future attempt to re-submit this job will need to know about
225 * this and avoid computing relocation addresses again.
226 *
227 * To avoid this sort of issues, we assume that if something was
228 * wrong during submission we must already be in a really bad situation
229 * anyway (such us being out of memory) and return
230 * VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
231 * submit the same job again to this device.
232 */
233 result = vk_errorf(VK_ERROR_DEVICE_LOST, "vkQueueSubmit() failed");
234 device->lost = true;
235
236 /* If we return VK_ERROR_DEVICE LOST here, we need to ensure that
237 * vkWaitForFences() and vkGetFenceStatus() return a valid result
238 * (VK_SUCCESS or VK_ERROR_DEVICE_LOST) in a finite amount of time.
239 * Setting the fence status to SIGNALED ensures this will happen in
240 * any case.
241 */
242 if (fence)
243 fence->state = ANV_FENCE_STATE_SIGNALED;
244 }
245
246 pthread_mutex_unlock(&device->mutex);
247
248 return result;
249 }
250
251 VkResult anv_QueueWaitIdle(
252 VkQueue _queue)
253 {
254 ANV_FROM_HANDLE(anv_queue, queue, _queue);
255
256 return anv_DeviceWaitIdle(anv_device_to_handle(queue->device));
257 }
258
259 VkResult anv_CreateFence(
260 VkDevice _device,
261 const VkFenceCreateInfo* pCreateInfo,
262 const VkAllocationCallbacks* pAllocator,
263 VkFence* pFence)
264 {
265 ANV_FROM_HANDLE(anv_device, device, _device);
266 struct anv_bo fence_bo;
267 struct anv_fence *fence;
268 struct anv_batch batch;
269 VkResult result;
270
271 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
272
273 result = anv_bo_pool_alloc(&device->batch_bo_pool, &fence_bo, 4096);
274 if (result != VK_SUCCESS)
275 return result;
276
277 /* Fences are small. Just store the CPU data structure in the BO. */
278 fence = fence_bo.map;
279 fence->bo = fence_bo;
280
281 /* Place the batch after the CPU data but on its own cache line. */
282 const uint32_t batch_offset = align_u32(sizeof(*fence), CACHELINE_SIZE);
283 batch.next = batch.start = fence->bo.map + batch_offset;
284 batch.end = fence->bo.map + fence->bo.size;
285 anv_batch_emit(&batch, GEN7_MI_BATCH_BUFFER_END, bbe);
286 anv_batch_emit(&batch, GEN7_MI_NOOP, noop);
287
288 if (!device->info.has_llc) {
289 assert(((uintptr_t) batch.start & CACHELINE_MASK) == 0);
290 assert(batch.next - batch.start <= CACHELINE_SIZE);
291 __builtin_ia32_mfence();
292 __builtin_ia32_clflush(batch.start);
293 }
294
295 fence->exec2_objects[0].handle = fence->bo.gem_handle;
296 fence->exec2_objects[0].relocation_count = 0;
297 fence->exec2_objects[0].relocs_ptr = 0;
298 fence->exec2_objects[0].alignment = 0;
299 fence->exec2_objects[0].offset = fence->bo.offset;
300 fence->exec2_objects[0].flags = 0;
301 fence->exec2_objects[0].rsvd1 = 0;
302 fence->exec2_objects[0].rsvd2 = 0;
303
304 fence->execbuf.buffers_ptr = (uintptr_t) fence->exec2_objects;
305 fence->execbuf.buffer_count = 1;
306 fence->execbuf.batch_start_offset = batch.start - fence->bo.map;
307 fence->execbuf.batch_len = batch.next - batch.start;
308 fence->execbuf.cliprects_ptr = 0;
309 fence->execbuf.num_cliprects = 0;
310 fence->execbuf.DR1 = 0;
311 fence->execbuf.DR4 = 0;
312
313 fence->execbuf.flags =
314 I915_EXEC_HANDLE_LUT | I915_EXEC_NO_RELOC | I915_EXEC_RENDER;
315 fence->execbuf.rsvd1 = device->context_id;
316 fence->execbuf.rsvd2 = 0;
317
318 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
319 fence->state = ANV_FENCE_STATE_SIGNALED;
320 } else {
321 fence->state = ANV_FENCE_STATE_RESET;
322 }
323
324 *pFence = anv_fence_to_handle(fence);
325
326 return VK_SUCCESS;
327 }
328
329 void anv_DestroyFence(
330 VkDevice _device,
331 VkFence _fence,
332 const VkAllocationCallbacks* pAllocator)
333 {
334 ANV_FROM_HANDLE(anv_device, device, _device);
335 ANV_FROM_HANDLE(anv_fence, fence, _fence);
336
337 if (!fence)
338 return;
339
340 assert(fence->bo.map == fence);
341 anv_bo_pool_free(&device->batch_bo_pool, &fence->bo);
342 }
343
344 VkResult anv_ResetFences(
345 VkDevice _device,
346 uint32_t fenceCount,
347 const VkFence* pFences)
348 {
349 for (uint32_t i = 0; i < fenceCount; i++) {
350 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
351 fence->state = ANV_FENCE_STATE_RESET;
352 }
353
354 return VK_SUCCESS;
355 }
356
357 VkResult anv_GetFenceStatus(
358 VkDevice _device,
359 VkFence _fence)
360 {
361 ANV_FROM_HANDLE(anv_device, device, _device);
362 ANV_FROM_HANDLE(anv_fence, fence, _fence);
363
364 if (unlikely(device->lost))
365 return VK_ERROR_DEVICE_LOST;
366
367 switch (fence->state) {
368 case ANV_FENCE_STATE_RESET:
369 /* If it hasn't even been sent off to the GPU yet, it's not ready */
370 return VK_NOT_READY;
371
372 case ANV_FENCE_STATE_SIGNALED:
373 /* It's been signaled, return success */
374 return VK_SUCCESS;
375
376 case ANV_FENCE_STATE_SUBMITTED: {
377 VkResult result = anv_device_bo_busy(device, &fence->bo);
378 if (result == VK_SUCCESS) {
379 fence->state = ANV_FENCE_STATE_SIGNALED;
380 return VK_SUCCESS;
381 } else {
382 return result;
383 }
384 }
385 default:
386 unreachable("Invalid fence status");
387 }
388 }
389
390 #define NSEC_PER_SEC 1000000000
391 #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)
392
393 VkResult anv_WaitForFences(
394 VkDevice _device,
395 uint32_t fenceCount,
396 const VkFence* pFences,
397 VkBool32 waitAll,
398 uint64_t _timeout)
399 {
400 ANV_FROM_HANDLE(anv_device, device, _device);
401 int ret;
402
403 if (unlikely(device->lost))
404 return VK_ERROR_DEVICE_LOST;
405
406 /* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is supposed
407 * to block indefinitely timeouts <= 0. Unfortunately, this was broken
408 * for a couple of kernel releases. Since there's no way to know
409 * whether or not the kernel we're using is one of the broken ones, the
410 * best we can do is to clamp the timeout to INT64_MAX. This limits the
411 * maximum timeout from 584 years to 292 years - likely not a big deal.
412 */
413 int64_t timeout = MIN2(_timeout, INT64_MAX);
414
415 VkResult result = VK_SUCCESS;
416 uint32_t pending_fences = fenceCount;
417 while (pending_fences) {
418 pending_fences = 0;
419 bool signaled_fences = false;
420 for (uint32_t i = 0; i < fenceCount; i++) {
421 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
422 switch (fence->state) {
423 case ANV_FENCE_STATE_RESET:
424 /* This fence hasn't been submitted yet, we'll catch it the next
425 * time around. Yes, this may mean we dead-loop but, short of
426 * lots of locking and a condition variable, there's not much that
427 * we can do about that.
428 */
429 pending_fences++;
430 continue;
431
432 case ANV_FENCE_STATE_SIGNALED:
433 /* This fence is not pending. If waitAll isn't set, we can return
434 * early. Otherwise, we have to keep going.
435 */
436 if (!waitAll) {
437 result = VK_SUCCESS;
438 goto done;
439 }
440 continue;
441
442 case ANV_FENCE_STATE_SUBMITTED:
443 /* These are the fences we really care about. Go ahead and wait
444 * on it until we hit a timeout.
445 */
446 result = anv_device_wait(device, &fence->bo, timeout);
447 switch (result) {
448 case VK_SUCCESS:
449 fence->state = ANV_FENCE_STATE_SIGNALED;
450 signaled_fences = true;
451 if (!waitAll)
452 goto done;
453 break;
454
455 case VK_TIMEOUT:
456 goto done;
457
458 default:
459 return result;
460 }
461 }
462 }
463
464 if (pending_fences && !signaled_fences) {
465 /* If we've hit this then someone decided to vkWaitForFences before
466 * they've actually submitted any of them to a queue. This is a
467 * fairly pessimal case, so it's ok to lock here and use a standard
468 * pthreads condition variable.
469 */
470 pthread_mutex_lock(&device->mutex);
471
472 /* It's possible that some of the fences have changed state since the
473 * last time we checked. Now that we have the lock, check for
474 * pending fences again and don't wait if it's changed.
475 */
476 uint32_t now_pending_fences = 0;
477 for (uint32_t i = 0; i < fenceCount; i++) {
478 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
479 if (fence->state == ANV_FENCE_STATE_RESET)
480 now_pending_fences++;
481 }
482 assert(now_pending_fences <= pending_fences);
483
484 if (now_pending_fences == pending_fences) {
485 struct timespec before;
486 clock_gettime(CLOCK_MONOTONIC, &before);
487
488 uint32_t abs_nsec = before.tv_nsec + timeout % NSEC_PER_SEC;
489 uint64_t abs_sec = before.tv_sec + (abs_nsec / NSEC_PER_SEC) +
490 (timeout / NSEC_PER_SEC);
491 abs_nsec %= NSEC_PER_SEC;
492
493 /* Avoid roll-over in tv_sec on 32-bit systems if the user
494 * provided timeout is UINT64_MAX
495 */
496 struct timespec abstime;
497 abstime.tv_nsec = abs_nsec;
498 abstime.tv_sec = MIN2(abs_sec, INT_TYPE_MAX(abstime.tv_sec));
499
500 ret = pthread_cond_timedwait(&device->queue_submit,
501 &device->mutex, &abstime);
502 assert(ret != EINVAL);
503
504 struct timespec after;
505 clock_gettime(CLOCK_MONOTONIC, &after);
506 uint64_t time_elapsed =
507 ((uint64_t)after.tv_sec * NSEC_PER_SEC + after.tv_nsec) -
508 ((uint64_t)before.tv_sec * NSEC_PER_SEC + before.tv_nsec);
509
510 if (time_elapsed >= timeout) {
511 pthread_mutex_unlock(&device->mutex);
512 result = VK_TIMEOUT;
513 goto done;
514 }
515
516 timeout -= time_elapsed;
517 }
518
519 pthread_mutex_unlock(&device->mutex);
520 }
521 }
522
523 done:
524 if (unlikely(device->lost))
525 return VK_ERROR_DEVICE_LOST;
526
527 return result;
528 }
529
530 // Queue semaphore functions
531
532 VkResult anv_CreateSemaphore(
533 VkDevice _device,
534 const VkSemaphoreCreateInfo* pCreateInfo,
535 const VkAllocationCallbacks* pAllocator,
536 VkSemaphore* pSemaphore)
537 {
538 ANV_FROM_HANDLE(anv_device, device, _device);
539 struct anv_semaphore *semaphore;
540
541 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
542
543 semaphore = vk_alloc2(&device->alloc, pAllocator, sizeof(*semaphore), 8,
544 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
545 if (semaphore == NULL)
546 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
547
548 const VkExportSemaphoreCreateInfoKHR *export =
549 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO_KHR);
550 VkExternalSemaphoreHandleTypeFlagsKHR handleTypes =
551 export ? export->handleTypes : 0;
552
553 if (handleTypes == 0) {
554 /* The DRM execbuffer ioctl always execute in-oder so long as you stay
555 * on the same ring. Since we don't expose the blit engine as a DMA
556 * queue, a dummy no-op semaphore is a perfectly valid implementation.
557 */
558 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY;
559 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR) {
560 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR);
561 if (device->instance->physicalDevice.has_syncobj) {
562 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
563 semaphore->permanent.syncobj = anv_gem_syncobj_create(device);
564 if (!semaphore->permanent.syncobj) {
565 vk_free2(&device->alloc, pAllocator, semaphore);
566 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
567 }
568 } else {
569 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
570 VkResult result = anv_bo_cache_alloc(device, &device->bo_cache,
571 4096, &semaphore->permanent.bo);
572 if (result != VK_SUCCESS) {
573 vk_free2(&device->alloc, pAllocator, semaphore);
574 return result;
575 }
576
577 /* If we're going to use this as a fence, we need to *not* have the
578 * EXEC_OBJECT_ASYNC bit set.
579 */
580 assert(!(semaphore->permanent.bo->flags & EXEC_OBJECT_ASYNC));
581 }
582 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR) {
583 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR);
584
585 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
586 semaphore->permanent.fd = -1;
587 } else {
588 assert(!"Unknown handle type");
589 vk_free2(&device->alloc, pAllocator, semaphore);
590 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
591 }
592
593 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
594
595 *pSemaphore = anv_semaphore_to_handle(semaphore);
596
597 return VK_SUCCESS;
598 }
599
600 static void
601 anv_semaphore_impl_cleanup(struct anv_device *device,
602 struct anv_semaphore_impl *impl)
603 {
604 switch (impl->type) {
605 case ANV_SEMAPHORE_TYPE_NONE:
606 case ANV_SEMAPHORE_TYPE_DUMMY:
607 /* Dummy. Nothing to do */
608 return;
609
610 case ANV_SEMAPHORE_TYPE_BO:
611 anv_bo_cache_release(device, &device->bo_cache, impl->bo);
612 return;
613
614 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
615 close(impl->fd);
616 return;
617
618 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
619 anv_gem_syncobj_destroy(device, impl->syncobj);
620 return;
621 }
622
623 unreachable("Invalid semaphore type");
624 }
625
626 void
627 anv_semaphore_reset_temporary(struct anv_device *device,
628 struct anv_semaphore *semaphore)
629 {
630 if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
631 return;
632
633 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
634 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
635 }
636
637 void anv_DestroySemaphore(
638 VkDevice _device,
639 VkSemaphore _semaphore,
640 const VkAllocationCallbacks* pAllocator)
641 {
642 ANV_FROM_HANDLE(anv_device, device, _device);
643 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
644
645 if (semaphore == NULL)
646 return;
647
648 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
649 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
650
651 vk_free2(&device->alloc, pAllocator, semaphore);
652 }
653
654 void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHR(
655 VkPhysicalDevice physicalDevice,
656 const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
657 VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties)
658 {
659 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
660
661 switch (pExternalSemaphoreInfo->handleType) {
662 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
663 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
664 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
665 pExternalSemaphoreProperties->compatibleHandleTypes =
666 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
667 pExternalSemaphoreProperties->externalSemaphoreFeatures =
668 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
669 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
670 return;
671
672 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
673 if (device->has_exec_fence) {
674 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
675 pExternalSemaphoreProperties->compatibleHandleTypes =
676 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
677 pExternalSemaphoreProperties->externalSemaphoreFeatures =
678 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
679 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
680 return;
681 }
682 break;
683
684 default:
685 break;
686 }
687
688 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
689 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
690 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
691 }
692
693 VkResult anv_ImportSemaphoreFdKHR(
694 VkDevice _device,
695 const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
696 {
697 ANV_FROM_HANDLE(anv_device, device, _device);
698 ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
699 int fd = pImportSemaphoreFdInfo->fd;
700
701 struct anv_semaphore_impl new_impl = {
702 .type = ANV_SEMAPHORE_TYPE_NONE,
703 };
704
705 switch (pImportSemaphoreFdInfo->handleType) {
706 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
707 if (device->instance->physicalDevice.has_syncobj) {
708 new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
709
710 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
711 if (!new_impl.syncobj)
712 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
713
714 /* From the Vulkan spec:
715 *
716 * "Importing semaphore state from a file descriptor transfers
717 * ownership of the file descriptor from the application to the
718 * Vulkan implementation. The application must not perform any
719 * operations on the file descriptor after a successful import."
720 *
721 * If the import fails, we leave the file descriptor open.
722 */
723 close(pImportSemaphoreFdInfo->fd);
724 } else {
725 new_impl.type = ANV_SEMAPHORE_TYPE_BO;
726
727 VkResult result = anv_bo_cache_import(device, &device->bo_cache,
728 fd, 4096, &new_impl.bo);
729 if (result != VK_SUCCESS)
730 return result;
731
732 /* If we're going to use this as a fence, we need to *not* have the
733 * EXEC_OBJECT_ASYNC bit set.
734 */
735 assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
736 }
737 break;
738
739 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
740 new_impl = (struct anv_semaphore_impl) {
741 .type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
742 .fd = fd,
743 };
744 break;
745
746 default:
747 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
748 }
749
750 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR) {
751 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
752 semaphore->temporary = new_impl;
753 } else {
754 /* SYNC_FILE must be a temporary import */
755 assert(new_impl.type != ANV_SEMAPHORE_TYPE_SYNC_FILE);
756
757 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
758 semaphore->permanent = new_impl;
759 }
760
761 return VK_SUCCESS;
762 }
763
764 VkResult anv_GetSemaphoreFdKHR(
765 VkDevice _device,
766 const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
767 int* pFd)
768 {
769 ANV_FROM_HANDLE(anv_device, device, _device);
770 ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
771 VkResult result;
772 int fd;
773
774 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
775
776 struct anv_semaphore_impl *impl =
777 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
778 &semaphore->temporary : &semaphore->permanent;
779
780 switch (impl->type) {
781 case ANV_SEMAPHORE_TYPE_BO:
782 result = anv_bo_cache_export(device, &device->bo_cache, impl->bo, pFd);
783 if (result != VK_SUCCESS)
784 return result;
785 break;
786
787 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
788 /* There are two reasons why this could happen:
789 *
790 * 1) The user is trying to export without submitting something that
791 * signals the semaphore. If this is the case, it's their bug so
792 * what we return here doesn't matter.
793 *
794 * 2) The kernel didn't give us a file descriptor. The most likely
795 * reason for this is running out of file descriptors.
796 */
797 if (impl->fd < 0)
798 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
799
800 *pFd = impl->fd;
801
802 /* From the Vulkan 1.0.53 spec:
803 *
804 * "...exporting a semaphore payload to a handle with copy
805 * transference has the same side effects on the source
806 * semaphore’s payload as executing a semaphore wait operation."
807 *
808 * In other words, it may still be a SYNC_FD semaphore, but it's now
809 * considered to have been waited on and no longer has a sync file
810 * attached.
811 */
812 impl->fd = -1;
813 return VK_SUCCESS;
814
815 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
816 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
817 if (fd < 0)
818 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
819 *pFd = fd;
820 break;
821
822 default:
823 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
824 }
825
826 /* From the Vulkan 1.0.53 spec:
827 *
828 * "Export operations have the same transference as the specified handle
829 * type’s import operations. [...] If the semaphore was using a
830 * temporarily imported payload, the semaphore’s prior permanent payload
831 * will be restored.
832 */
833 if (impl == &semaphore->temporary)
834 anv_semaphore_impl_cleanup(device, impl);
835
836 return VK_SUCCESS;
837 }