2 * Copyright © 2015 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * This file implements VkQueue, VkFence, and VkSemaphore
30 #include <sys/eventfd.h>
32 #include "anv_private.h"
35 #include "genxml/gen7_pack.h"
38 anv_device_execbuf(struct anv_device
*device
,
39 struct drm_i915_gem_execbuffer2
*execbuf
,
40 struct anv_bo
**execbuf_bos
)
42 int ret
= anv_gem_execbuffer(device
, execbuf
);
44 /* We don't know the real error. */
46 return vk_errorf(VK_ERROR_DEVICE_LOST
, "execbuf2 failed: %m");
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
;
58 anv_device_submit_simple_batch(struct anv_device
*device
,
59 struct anv_batch
*batch
)
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
;
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
)
73 memcpy(bo
.map
, batch
->start
, size
);
74 if (!device
->info
.has_llc
)
75 gen_flush_range(bo
.map
, size
);
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;
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;
97 I915_EXEC_HANDLE_LUT
| I915_EXEC_NO_RELOC
| I915_EXEC_RENDER
;
98 execbuf
.rsvd1
= device
->context_id
;
101 result
= anv_device_execbuf(device
, &execbuf
, exec_bos
);
102 if (result
!= VK_SUCCESS
)
105 result
= anv_device_wait(device
, &bo
, INT64_MAX
);
108 anv_bo_pool_free(&device
->batch_bo_pool
, &bo
);
113 VkResult
anv_QueueSubmit(
115 uint32_t submitCount
,
116 const VkSubmitInfo
* pSubmits
,
119 ANV_FROM_HANDLE(anv_queue
, queue
, _queue
);
120 struct anv_device
*device
= queue
->device
;
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.
129 VkResult result
= anv_device_query_status(device
);
130 if (result
!= VK_SUCCESS
)
133 /* We lock around QueueSubmit for three main reasons:
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
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.
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.
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.
158 pthread_mutex_lock(&device
->mutex
);
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
166 result
= anv_cmd_buffer_execbuf(device
, NULL
, NULL
, 0, NULL
, 0, fence
);
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
;
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
180 result
= anv_cmd_buffer_execbuf(device
, NULL
,
181 pSubmits
[i
].pWaitSemaphores
,
182 pSubmits
[i
].waitSemaphoreCount
,
183 pSubmits
[i
].pSignalSemaphores
,
184 pSubmits
[i
].signalSemaphoreCount
,
186 if (result
!= VK_SUCCESS
)
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
));
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
;
202 const VkSemaphore
*in_semaphores
= NULL
, *out_semaphores
= NULL
;
203 uint32_t num_in_semaphores
= 0, num_out_semaphores
= 0;
205 /* Only the first batch gets the in semaphores */
206 in_semaphores
= pSubmits
[i
].pWaitSemaphores
;
207 num_in_semaphores
= pSubmits
[i
].waitSemaphoreCount
;
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
;
216 result
= anv_cmd_buffer_execbuf(device
, cmd_buffer
,
217 in_semaphores
, num_in_semaphores
,
218 out_semaphores
, num_out_semaphores
,
220 if (result
!= VK_SUCCESS
)
225 pthread_cond_broadcast(&device
->queue_submit
);
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.
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.
241 result
= vk_errorf(VK_ERROR_DEVICE_LOST
, "vkQueueSubmit() failed");
245 pthread_mutex_unlock(&device
->mutex
);
250 VkResult
anv_QueueWaitIdle(
253 ANV_FROM_HANDLE(anv_queue
, queue
, _queue
);
255 return anv_DeviceWaitIdle(anv_device_to_handle(queue
->device
));
258 VkResult
anv_CreateFence(
260 const VkFenceCreateInfo
* pCreateInfo
,
261 const VkAllocationCallbacks
* pAllocator
,
264 ANV_FROM_HANDLE(anv_device
, device
, _device
);
265 struct anv_fence
*fence
;
267 assert(pCreateInfo
->sType
== VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
);
269 fence
= vk_zalloc2(&device
->alloc
, pAllocator
, sizeof(*fence
), 8,
270 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
272 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
274 fence
->permanent
.type
= ANV_FENCE_TYPE_BO
;
276 VkResult result
= anv_bo_pool_alloc(&device
->batch_bo_pool
,
277 &fence
->permanent
.bo
.bo
, 4096);
278 if (result
!= VK_SUCCESS
)
281 if (pCreateInfo
->flags
& VK_FENCE_CREATE_SIGNALED_BIT
) {
282 fence
->permanent
.bo
.state
= ANV_FENCE_STATE_SIGNALED
;
284 fence
->permanent
.bo
.state
= ANV_FENCE_STATE_RESET
;
287 *pFence
= anv_fence_to_handle(fence
);
293 anv_fence_impl_cleanup(struct anv_device
*device
,
294 struct anv_fence_impl
*impl
)
296 switch (impl
->type
) {
297 case ANV_FENCE_TYPE_NONE
:
298 /* Dummy. Nothing to do */
301 case ANV_FENCE_TYPE_BO
:
302 anv_bo_pool_free(&device
->batch_bo_pool
, &impl
->bo
.bo
);
306 unreachable("Invalid fence type");
309 void anv_DestroyFence(
312 const VkAllocationCallbacks
* pAllocator
)
314 ANV_FROM_HANDLE(anv_device
, device
, _device
);
315 ANV_FROM_HANDLE(anv_fence
, fence
, _fence
);
320 anv_fence_impl_cleanup(device
, &fence
->temporary
);
321 anv_fence_impl_cleanup(device
, &fence
->permanent
);
323 vk_free2(&device
->alloc
, pAllocator
, fence
);
326 VkResult
anv_ResetFences(
329 const VkFence
* pFences
)
331 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
332 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
334 assert(fence
->temporary
.type
== ANV_FENCE_TYPE_NONE
);
335 struct anv_fence_impl
*impl
= &fence
->permanent
;
337 switch (impl
->type
) {
338 case ANV_FENCE_TYPE_BO
:
339 impl
->bo
.state
= ANV_FENCE_STATE_RESET
;
343 unreachable("Invalid fence type");
350 VkResult
anv_GetFenceStatus(
354 ANV_FROM_HANDLE(anv_device
, device
, _device
);
355 ANV_FROM_HANDLE(anv_fence
, fence
, _fence
);
357 if (unlikely(device
->lost
))
358 return VK_ERROR_DEVICE_LOST
;
360 assert(fence
->temporary
.type
== ANV_FENCE_TYPE_NONE
);
361 struct anv_fence_impl
*impl
= &fence
->permanent
;
363 switch (impl
->type
) {
364 case ANV_FENCE_TYPE_BO
:
365 switch (impl
->bo
.state
) {
366 case ANV_FENCE_STATE_RESET
:
367 /* If it hasn't even been sent off to the GPU yet, it's not ready */
370 case ANV_FENCE_STATE_SIGNALED
:
371 /* It's been signaled, return success */
374 case ANV_FENCE_STATE_SUBMITTED
: {
375 VkResult result
= anv_device_bo_busy(device
, &impl
->bo
.bo
);
376 if (result
== VK_SUCCESS
) {
377 impl
->bo
.state
= ANV_FENCE_STATE_SIGNALED
;
384 unreachable("Invalid fence status");
388 unreachable("Invalid fence type");
392 #define NSEC_PER_SEC 1000000000
393 #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)
396 anv_wait_for_bo_fences(struct anv_device
*device
,
398 const VkFence
*pFences
,
404 /* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is supposed
405 * to block indefinitely timeouts <= 0. Unfortunately, this was broken
406 * for a couple of kernel releases. Since there's no way to know
407 * whether or not the kernel we're using is one of the broken ones, the
408 * best we can do is to clamp the timeout to INT64_MAX. This limits the
409 * maximum timeout from 584 years to 292 years - likely not a big deal.
411 int64_t timeout
= MIN2(_timeout
, INT64_MAX
);
413 VkResult result
= VK_SUCCESS
;
414 uint32_t pending_fences
= fenceCount
;
415 while (pending_fences
) {
417 bool signaled_fences
= false;
418 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
419 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
421 /* This function assumes that all fences are BO fences and that they
422 * have no temporary state. Since BO fences will never be exported,
423 * this should be a safe assumption.
425 assert(fence
->permanent
.type
== ANV_FENCE_TYPE_BO
);
426 assert(fence
->temporary
.type
== ANV_FENCE_TYPE_NONE
);
427 struct anv_fence_impl
*impl
= &fence
->permanent
;
429 switch (impl
->bo
.state
) {
430 case ANV_FENCE_STATE_RESET
:
431 /* This fence hasn't been submitted yet, we'll catch it the next
432 * time around. Yes, this may mean we dead-loop but, short of
433 * lots of locking and a condition variable, there's not much that
434 * we can do about that.
439 case ANV_FENCE_STATE_SIGNALED
:
440 /* This fence is not pending. If waitAll isn't set, we can return
441 * early. Otherwise, we have to keep going.
449 case ANV_FENCE_STATE_SUBMITTED
:
450 /* These are the fences we really care about. Go ahead and wait
451 * on it until we hit a timeout.
453 result
= anv_device_wait(device
, &impl
->bo
.bo
, timeout
);
456 impl
->bo
.state
= ANV_FENCE_STATE_SIGNALED
;
457 signaled_fences
= true;
471 if (pending_fences
&& !signaled_fences
) {
472 /* If we've hit this then someone decided to vkWaitForFences before
473 * they've actually submitted any of them to a queue. This is a
474 * fairly pessimal case, so it's ok to lock here and use a standard
475 * pthreads condition variable.
477 pthread_mutex_lock(&device
->mutex
);
479 /* It's possible that some of the fences have changed state since the
480 * last time we checked. Now that we have the lock, check for
481 * pending fences again and don't wait if it's changed.
483 uint32_t now_pending_fences
= 0;
484 for (uint32_t i
= 0; i
< fenceCount
; i
++) {
485 ANV_FROM_HANDLE(anv_fence
, fence
, pFences
[i
]);
486 if (fence
->permanent
.bo
.state
== ANV_FENCE_STATE_RESET
)
487 now_pending_fences
++;
489 assert(now_pending_fences
<= pending_fences
);
491 if (now_pending_fences
== pending_fences
) {
492 struct timespec before
;
493 clock_gettime(CLOCK_MONOTONIC
, &before
);
495 uint32_t abs_nsec
= before
.tv_nsec
+ timeout
% NSEC_PER_SEC
;
496 uint64_t abs_sec
= before
.tv_sec
+ (abs_nsec
/ NSEC_PER_SEC
) +
497 (timeout
/ NSEC_PER_SEC
);
498 abs_nsec
%= NSEC_PER_SEC
;
500 /* Avoid roll-over in tv_sec on 32-bit systems if the user
501 * provided timeout is UINT64_MAX
503 struct timespec abstime
;
504 abstime
.tv_nsec
= abs_nsec
;
505 abstime
.tv_sec
= MIN2(abs_sec
, INT_TYPE_MAX(abstime
.tv_sec
));
507 ret
= pthread_cond_timedwait(&device
->queue_submit
,
508 &device
->mutex
, &abstime
);
509 assert(ret
!= EINVAL
);
511 struct timespec after
;
512 clock_gettime(CLOCK_MONOTONIC
, &after
);
513 uint64_t time_elapsed
=
514 ((uint64_t)after
.tv_sec
* NSEC_PER_SEC
+ after
.tv_nsec
) -
515 ((uint64_t)before
.tv_sec
* NSEC_PER_SEC
+ before
.tv_nsec
);
517 if (time_elapsed
>= timeout
) {
518 pthread_mutex_unlock(&device
->mutex
);
523 timeout
-= time_elapsed
;
526 pthread_mutex_unlock(&device
->mutex
);
531 if (unlikely(device
->lost
))
532 return VK_ERROR_DEVICE_LOST
;
537 VkResult
anv_WaitForFences(
540 const VkFence
* pFences
,
544 ANV_FROM_HANDLE(anv_device
, device
, _device
);
546 if (unlikely(device
->lost
))
547 return VK_ERROR_DEVICE_LOST
;
549 return anv_wait_for_bo_fences(device
, fenceCount
, pFences
, waitAll
, timeout
);
552 // Queue semaphore functions
554 VkResult
anv_CreateSemaphore(
556 const VkSemaphoreCreateInfo
* pCreateInfo
,
557 const VkAllocationCallbacks
* pAllocator
,
558 VkSemaphore
* pSemaphore
)
560 ANV_FROM_HANDLE(anv_device
, device
, _device
);
561 struct anv_semaphore
*semaphore
;
563 assert(pCreateInfo
->sType
== VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
);
565 semaphore
= vk_alloc2(&device
->alloc
, pAllocator
, sizeof(*semaphore
), 8,
566 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT
);
567 if (semaphore
== NULL
)
568 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
570 const VkExportSemaphoreCreateInfoKHR
*export
=
571 vk_find_struct_const(pCreateInfo
->pNext
, EXPORT_SEMAPHORE_CREATE_INFO_KHR
);
572 VkExternalSemaphoreHandleTypeFlagsKHR handleTypes
=
573 export
? export
->handleTypes
: 0;
575 if (handleTypes
== 0) {
576 /* The DRM execbuffer ioctl always execute in-oder so long as you stay
577 * on the same ring. Since we don't expose the blit engine as a DMA
578 * queue, a dummy no-op semaphore is a perfectly valid implementation.
580 semaphore
->permanent
.type
= ANV_SEMAPHORE_TYPE_DUMMY
;
581 } else if (handleTypes
& VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
) {
582 assert(handleTypes
== VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
);
583 if (device
->instance
->physicalDevice
.has_syncobj
) {
584 semaphore
->permanent
.type
= ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
;
585 semaphore
->permanent
.syncobj
= anv_gem_syncobj_create(device
);
586 if (!semaphore
->permanent
.syncobj
) {
587 vk_free2(&device
->alloc
, pAllocator
, semaphore
);
588 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY
);
591 semaphore
->permanent
.type
= ANV_SEMAPHORE_TYPE_BO
;
592 VkResult result
= anv_bo_cache_alloc(device
, &device
->bo_cache
,
593 4096, &semaphore
->permanent
.bo
);
594 if (result
!= VK_SUCCESS
) {
595 vk_free2(&device
->alloc
, pAllocator
, semaphore
);
599 /* If we're going to use this as a fence, we need to *not* have the
600 * EXEC_OBJECT_ASYNC bit set.
602 assert(!(semaphore
->permanent
.bo
->flags
& EXEC_OBJECT_ASYNC
));
604 } else if (handleTypes
& VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR
) {
605 assert(handleTypes
== VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR
);
607 semaphore
->permanent
.type
= ANV_SEMAPHORE_TYPE_SYNC_FILE
;
608 semaphore
->permanent
.fd
= -1;
610 assert(!"Unknown handle type");
611 vk_free2(&device
->alloc
, pAllocator
, semaphore
);
612 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR
);
615 semaphore
->temporary
.type
= ANV_SEMAPHORE_TYPE_NONE
;
617 *pSemaphore
= anv_semaphore_to_handle(semaphore
);
623 anv_semaphore_impl_cleanup(struct anv_device
*device
,
624 struct anv_semaphore_impl
*impl
)
626 switch (impl
->type
) {
627 case ANV_SEMAPHORE_TYPE_NONE
:
628 case ANV_SEMAPHORE_TYPE_DUMMY
:
629 /* Dummy. Nothing to do */
632 case ANV_SEMAPHORE_TYPE_BO
:
633 anv_bo_cache_release(device
, &device
->bo_cache
, impl
->bo
);
636 case ANV_SEMAPHORE_TYPE_SYNC_FILE
:
640 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
:
641 anv_gem_syncobj_destroy(device
, impl
->syncobj
);
645 unreachable("Invalid semaphore type");
649 anv_semaphore_reset_temporary(struct anv_device
*device
,
650 struct anv_semaphore
*semaphore
)
652 if (semaphore
->temporary
.type
== ANV_SEMAPHORE_TYPE_NONE
)
655 anv_semaphore_impl_cleanup(device
, &semaphore
->temporary
);
656 semaphore
->temporary
.type
= ANV_SEMAPHORE_TYPE_NONE
;
659 void anv_DestroySemaphore(
661 VkSemaphore _semaphore
,
662 const VkAllocationCallbacks
* pAllocator
)
664 ANV_FROM_HANDLE(anv_device
, device
, _device
);
665 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, _semaphore
);
667 if (semaphore
== NULL
)
670 anv_semaphore_impl_cleanup(device
, &semaphore
->temporary
);
671 anv_semaphore_impl_cleanup(device
, &semaphore
->permanent
);
673 vk_free2(&device
->alloc
, pAllocator
, semaphore
);
676 void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHR(
677 VkPhysicalDevice physicalDevice
,
678 const VkPhysicalDeviceExternalSemaphoreInfoKHR
* pExternalSemaphoreInfo
,
679 VkExternalSemaphorePropertiesKHR
* pExternalSemaphoreProperties
)
681 ANV_FROM_HANDLE(anv_physical_device
, device
, physicalDevice
);
683 switch (pExternalSemaphoreInfo
->handleType
) {
684 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
:
685 pExternalSemaphoreProperties
->exportFromImportedHandleTypes
=
686 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
;
687 pExternalSemaphoreProperties
->compatibleHandleTypes
=
688 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
;
689 pExternalSemaphoreProperties
->externalSemaphoreFeatures
=
690 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR
|
691 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR
;
694 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR
:
695 if (device
->has_exec_fence
) {
696 pExternalSemaphoreProperties
->exportFromImportedHandleTypes
= 0;
697 pExternalSemaphoreProperties
->compatibleHandleTypes
=
698 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR
;
699 pExternalSemaphoreProperties
->externalSemaphoreFeatures
=
700 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR
|
701 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR
;
710 pExternalSemaphoreProperties
->exportFromImportedHandleTypes
= 0;
711 pExternalSemaphoreProperties
->compatibleHandleTypes
= 0;
712 pExternalSemaphoreProperties
->externalSemaphoreFeatures
= 0;
715 VkResult
anv_ImportSemaphoreFdKHR(
717 const VkImportSemaphoreFdInfoKHR
* pImportSemaphoreFdInfo
)
719 ANV_FROM_HANDLE(anv_device
, device
, _device
);
720 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, pImportSemaphoreFdInfo
->semaphore
);
721 int fd
= pImportSemaphoreFdInfo
->fd
;
723 struct anv_semaphore_impl new_impl
= {
724 .type
= ANV_SEMAPHORE_TYPE_NONE
,
727 switch (pImportSemaphoreFdInfo
->handleType
) {
728 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR
:
729 if (device
->instance
->physicalDevice
.has_syncobj
) {
730 new_impl
.type
= ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
;
732 new_impl
.syncobj
= anv_gem_syncobj_fd_to_handle(device
, fd
);
733 if (!new_impl
.syncobj
)
734 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR
);
736 /* From the Vulkan spec:
738 * "Importing semaphore state from a file descriptor transfers
739 * ownership of the file descriptor from the application to the
740 * Vulkan implementation. The application must not perform any
741 * operations on the file descriptor after a successful import."
743 * If the import fails, we leave the file descriptor open.
745 close(pImportSemaphoreFdInfo
->fd
);
747 new_impl
.type
= ANV_SEMAPHORE_TYPE_BO
;
749 VkResult result
= anv_bo_cache_import(device
, &device
->bo_cache
,
750 fd
, 4096, &new_impl
.bo
);
751 if (result
!= VK_SUCCESS
)
754 /* If we're going to use this as a fence, we need to *not* have the
755 * EXEC_OBJECT_ASYNC bit set.
757 assert(!(new_impl
.bo
->flags
& EXEC_OBJECT_ASYNC
));
761 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR
:
762 new_impl
= (struct anv_semaphore_impl
) {
763 .type
= ANV_SEMAPHORE_TYPE_SYNC_FILE
,
769 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR
);
772 if (pImportSemaphoreFdInfo
->flags
& VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR
) {
773 anv_semaphore_impl_cleanup(device
, &semaphore
->temporary
);
774 semaphore
->temporary
= new_impl
;
776 anv_semaphore_impl_cleanup(device
, &semaphore
->permanent
);
777 semaphore
->permanent
= new_impl
;
783 VkResult
anv_GetSemaphoreFdKHR(
785 const VkSemaphoreGetFdInfoKHR
* pGetFdInfo
,
788 ANV_FROM_HANDLE(anv_device
, device
, _device
);
789 ANV_FROM_HANDLE(anv_semaphore
, semaphore
, pGetFdInfo
->semaphore
);
793 assert(pGetFdInfo
->sType
== VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR
);
795 struct anv_semaphore_impl
*impl
=
796 semaphore
->temporary
.type
!= ANV_SEMAPHORE_TYPE_NONE
?
797 &semaphore
->temporary
: &semaphore
->permanent
;
799 switch (impl
->type
) {
800 case ANV_SEMAPHORE_TYPE_BO
:
801 result
= anv_bo_cache_export(device
, &device
->bo_cache
, impl
->bo
, pFd
);
802 if (result
!= VK_SUCCESS
)
806 case ANV_SEMAPHORE_TYPE_SYNC_FILE
:
807 /* There are two reasons why this could happen:
809 * 1) The user is trying to export without submitting something that
810 * signals the semaphore. If this is the case, it's their bug so
811 * what we return here doesn't matter.
813 * 2) The kernel didn't give us a file descriptor. The most likely
814 * reason for this is running out of file descriptors.
817 return vk_error(VK_ERROR_TOO_MANY_OBJECTS
);
821 /* From the Vulkan 1.0.53 spec:
823 * "...exporting a semaphore payload to a handle with copy
824 * transference has the same side effects on the source
825 * semaphore’s payload as executing a semaphore wait operation."
827 * In other words, it may still be a SYNC_FD semaphore, but it's now
828 * considered to have been waited on and no longer has a sync file
834 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ
:
835 fd
= anv_gem_syncobj_handle_to_fd(device
, impl
->syncobj
);
837 return vk_error(VK_ERROR_TOO_MANY_OBJECTS
);
842 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR
);
845 /* From the Vulkan 1.0.53 spec:
847 * "Export operations have the same transference as the specified handle
848 * type’s import operations. [...] If the semaphore was using a
849 * temporarily imported payload, the semaphore’s prior permanent payload
852 if (impl
== &semaphore
->temporary
)
853 anv_semaphore_impl_cleanup(device
, impl
);