5023172250a44dbc89a5597ee2d7dfa433525754
[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_bo fence_bo;
266 struct anv_fence *fence;
267
268 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
269
270 VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, &fence_bo, 4096);
271 if (result != VK_SUCCESS)
272 return result;
273
274 /* Fences are small. Just store the CPU data structure in the BO. */
275 fence = fence_bo.map;
276 fence->bo = fence_bo;
277
278 if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
279 fence->state = ANV_FENCE_STATE_SIGNALED;
280 } else {
281 fence->state = ANV_FENCE_STATE_RESET;
282 }
283
284 *pFence = anv_fence_to_handle(fence);
285
286 return VK_SUCCESS;
287 }
288
289 void anv_DestroyFence(
290 VkDevice _device,
291 VkFence _fence,
292 const VkAllocationCallbacks* pAllocator)
293 {
294 ANV_FROM_HANDLE(anv_device, device, _device);
295 ANV_FROM_HANDLE(anv_fence, fence, _fence);
296
297 if (!fence)
298 return;
299
300 assert(fence->bo.map == fence);
301 anv_bo_pool_free(&device->batch_bo_pool, &fence->bo);
302 }
303
304 VkResult anv_ResetFences(
305 VkDevice _device,
306 uint32_t fenceCount,
307 const VkFence* pFences)
308 {
309 for (uint32_t i = 0; i < fenceCount; i++) {
310 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
311 fence->state = ANV_FENCE_STATE_RESET;
312 }
313
314 return VK_SUCCESS;
315 }
316
317 VkResult anv_GetFenceStatus(
318 VkDevice _device,
319 VkFence _fence)
320 {
321 ANV_FROM_HANDLE(anv_device, device, _device);
322 ANV_FROM_HANDLE(anv_fence, fence, _fence);
323
324 if (unlikely(device->lost))
325 return VK_ERROR_DEVICE_LOST;
326
327 switch (fence->state) {
328 case ANV_FENCE_STATE_RESET:
329 /* If it hasn't even been sent off to the GPU yet, it's not ready */
330 return VK_NOT_READY;
331
332 case ANV_FENCE_STATE_SIGNALED:
333 /* It's been signaled, return success */
334 return VK_SUCCESS;
335
336 case ANV_FENCE_STATE_SUBMITTED: {
337 VkResult result = anv_device_bo_busy(device, &fence->bo);
338 if (result == VK_SUCCESS) {
339 fence->state = ANV_FENCE_STATE_SIGNALED;
340 return VK_SUCCESS;
341 } else {
342 return result;
343 }
344 }
345 default:
346 unreachable("Invalid fence status");
347 }
348 }
349
350 #define NSEC_PER_SEC 1000000000
351 #define INT_TYPE_MAX(type) ((1ull << (sizeof(type) * 8 - 1)) - 1)
352
353 VkResult anv_WaitForFences(
354 VkDevice _device,
355 uint32_t fenceCount,
356 const VkFence* pFences,
357 VkBool32 waitAll,
358 uint64_t _timeout)
359 {
360 ANV_FROM_HANDLE(anv_device, device, _device);
361 int ret;
362
363 if (unlikely(device->lost))
364 return VK_ERROR_DEVICE_LOST;
365
366 /* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is supposed
367 * to block indefinitely timeouts <= 0. Unfortunately, this was broken
368 * for a couple of kernel releases. Since there's no way to know
369 * whether or not the kernel we're using is one of the broken ones, the
370 * best we can do is to clamp the timeout to INT64_MAX. This limits the
371 * maximum timeout from 584 years to 292 years - likely not a big deal.
372 */
373 int64_t timeout = MIN2(_timeout, INT64_MAX);
374
375 VkResult result = VK_SUCCESS;
376 uint32_t pending_fences = fenceCount;
377 while (pending_fences) {
378 pending_fences = 0;
379 bool signaled_fences = false;
380 for (uint32_t i = 0; i < fenceCount; i++) {
381 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
382 switch (fence->state) {
383 case ANV_FENCE_STATE_RESET:
384 /* This fence hasn't been submitted yet, we'll catch it the next
385 * time around. Yes, this may mean we dead-loop but, short of
386 * lots of locking and a condition variable, there's not much that
387 * we can do about that.
388 */
389 pending_fences++;
390 continue;
391
392 case ANV_FENCE_STATE_SIGNALED:
393 /* This fence is not pending. If waitAll isn't set, we can return
394 * early. Otherwise, we have to keep going.
395 */
396 if (!waitAll) {
397 result = VK_SUCCESS;
398 goto done;
399 }
400 continue;
401
402 case ANV_FENCE_STATE_SUBMITTED:
403 /* These are the fences we really care about. Go ahead and wait
404 * on it until we hit a timeout.
405 */
406 result = anv_device_wait(device, &fence->bo, timeout);
407 switch (result) {
408 case VK_SUCCESS:
409 fence->state = ANV_FENCE_STATE_SIGNALED;
410 signaled_fences = true;
411 if (!waitAll)
412 goto done;
413 break;
414
415 case VK_TIMEOUT:
416 goto done;
417
418 default:
419 return result;
420 }
421 }
422 }
423
424 if (pending_fences && !signaled_fences) {
425 /* If we've hit this then someone decided to vkWaitForFences before
426 * they've actually submitted any of them to a queue. This is a
427 * fairly pessimal case, so it's ok to lock here and use a standard
428 * pthreads condition variable.
429 */
430 pthread_mutex_lock(&device->mutex);
431
432 /* It's possible that some of the fences have changed state since the
433 * last time we checked. Now that we have the lock, check for
434 * pending fences again and don't wait if it's changed.
435 */
436 uint32_t now_pending_fences = 0;
437 for (uint32_t i = 0; i < fenceCount; i++) {
438 ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
439 if (fence->state == ANV_FENCE_STATE_RESET)
440 now_pending_fences++;
441 }
442 assert(now_pending_fences <= pending_fences);
443
444 if (now_pending_fences == pending_fences) {
445 struct timespec before;
446 clock_gettime(CLOCK_MONOTONIC, &before);
447
448 uint32_t abs_nsec = before.tv_nsec + timeout % NSEC_PER_SEC;
449 uint64_t abs_sec = before.tv_sec + (abs_nsec / NSEC_PER_SEC) +
450 (timeout / NSEC_PER_SEC);
451 abs_nsec %= NSEC_PER_SEC;
452
453 /* Avoid roll-over in tv_sec on 32-bit systems if the user
454 * provided timeout is UINT64_MAX
455 */
456 struct timespec abstime;
457 abstime.tv_nsec = abs_nsec;
458 abstime.tv_sec = MIN2(abs_sec, INT_TYPE_MAX(abstime.tv_sec));
459
460 ret = pthread_cond_timedwait(&device->queue_submit,
461 &device->mutex, &abstime);
462 assert(ret != EINVAL);
463
464 struct timespec after;
465 clock_gettime(CLOCK_MONOTONIC, &after);
466 uint64_t time_elapsed =
467 ((uint64_t)after.tv_sec * NSEC_PER_SEC + after.tv_nsec) -
468 ((uint64_t)before.tv_sec * NSEC_PER_SEC + before.tv_nsec);
469
470 if (time_elapsed >= timeout) {
471 pthread_mutex_unlock(&device->mutex);
472 result = VK_TIMEOUT;
473 goto done;
474 }
475
476 timeout -= time_elapsed;
477 }
478
479 pthread_mutex_unlock(&device->mutex);
480 }
481 }
482
483 done:
484 if (unlikely(device->lost))
485 return VK_ERROR_DEVICE_LOST;
486
487 return result;
488 }
489
490 // Queue semaphore functions
491
492 VkResult anv_CreateSemaphore(
493 VkDevice _device,
494 const VkSemaphoreCreateInfo* pCreateInfo,
495 const VkAllocationCallbacks* pAllocator,
496 VkSemaphore* pSemaphore)
497 {
498 ANV_FROM_HANDLE(anv_device, device, _device);
499 struct anv_semaphore *semaphore;
500
501 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
502
503 semaphore = vk_alloc2(&device->alloc, pAllocator, sizeof(*semaphore), 8,
504 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
505 if (semaphore == NULL)
506 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
507
508 const VkExportSemaphoreCreateInfoKHR *export =
509 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO_KHR);
510 VkExternalSemaphoreHandleTypeFlagsKHR handleTypes =
511 export ? export->handleTypes : 0;
512
513 if (handleTypes == 0) {
514 /* The DRM execbuffer ioctl always execute in-oder so long as you stay
515 * on the same ring. Since we don't expose the blit engine as a DMA
516 * queue, a dummy no-op semaphore is a perfectly valid implementation.
517 */
518 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DUMMY;
519 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR) {
520 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR);
521 if (device->instance->physicalDevice.has_syncobj) {
522 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
523 semaphore->permanent.syncobj = anv_gem_syncobj_create(device);
524 if (!semaphore->permanent.syncobj) {
525 vk_free2(&device->alloc, pAllocator, semaphore);
526 return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
527 }
528 } else {
529 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_BO;
530 VkResult result = anv_bo_cache_alloc(device, &device->bo_cache,
531 4096, &semaphore->permanent.bo);
532 if (result != VK_SUCCESS) {
533 vk_free2(&device->alloc, pAllocator, semaphore);
534 return result;
535 }
536
537 /* If we're going to use this as a fence, we need to *not* have the
538 * EXEC_OBJECT_ASYNC bit set.
539 */
540 assert(!(semaphore->permanent.bo->flags & EXEC_OBJECT_ASYNC));
541 }
542 } else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR) {
543 assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR);
544
545 semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
546 semaphore->permanent.fd = -1;
547 } else {
548 assert(!"Unknown handle type");
549 vk_free2(&device->alloc, pAllocator, semaphore);
550 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
551 }
552
553 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
554
555 *pSemaphore = anv_semaphore_to_handle(semaphore);
556
557 return VK_SUCCESS;
558 }
559
560 static void
561 anv_semaphore_impl_cleanup(struct anv_device *device,
562 struct anv_semaphore_impl *impl)
563 {
564 switch (impl->type) {
565 case ANV_SEMAPHORE_TYPE_NONE:
566 case ANV_SEMAPHORE_TYPE_DUMMY:
567 /* Dummy. Nothing to do */
568 return;
569
570 case ANV_SEMAPHORE_TYPE_BO:
571 anv_bo_cache_release(device, &device->bo_cache, impl->bo);
572 return;
573
574 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
575 close(impl->fd);
576 return;
577
578 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
579 anv_gem_syncobj_destroy(device, impl->syncobj);
580 return;
581 }
582
583 unreachable("Invalid semaphore type");
584 }
585
586 void
587 anv_semaphore_reset_temporary(struct anv_device *device,
588 struct anv_semaphore *semaphore)
589 {
590 if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
591 return;
592
593 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
594 semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
595 }
596
597 void anv_DestroySemaphore(
598 VkDevice _device,
599 VkSemaphore _semaphore,
600 const VkAllocationCallbacks* pAllocator)
601 {
602 ANV_FROM_HANDLE(anv_device, device, _device);
603 ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
604
605 if (semaphore == NULL)
606 return;
607
608 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
609 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
610
611 vk_free2(&device->alloc, pAllocator, semaphore);
612 }
613
614 void anv_GetPhysicalDeviceExternalSemaphorePropertiesKHR(
615 VkPhysicalDevice physicalDevice,
616 const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
617 VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties)
618 {
619 ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
620
621 switch (pExternalSemaphoreInfo->handleType) {
622 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
623 pExternalSemaphoreProperties->exportFromImportedHandleTypes =
624 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
625 pExternalSemaphoreProperties->compatibleHandleTypes =
626 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
627 pExternalSemaphoreProperties->externalSemaphoreFeatures =
628 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
629 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
630 return;
631
632 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
633 if (device->has_exec_fence) {
634 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
635 pExternalSemaphoreProperties->compatibleHandleTypes =
636 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR;
637 pExternalSemaphoreProperties->externalSemaphoreFeatures =
638 VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR |
639 VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR;
640 return;
641 }
642 break;
643
644 default:
645 break;
646 }
647
648 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
649 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
650 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
651 }
652
653 VkResult anv_ImportSemaphoreFdKHR(
654 VkDevice _device,
655 const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
656 {
657 ANV_FROM_HANDLE(anv_device, device, _device);
658 ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
659 int fd = pImportSemaphoreFdInfo->fd;
660
661 struct anv_semaphore_impl new_impl = {
662 .type = ANV_SEMAPHORE_TYPE_NONE,
663 };
664
665 switch (pImportSemaphoreFdInfo->handleType) {
666 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR:
667 if (device->instance->physicalDevice.has_syncobj) {
668 new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
669
670 new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
671 if (!new_impl.syncobj)
672 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
673
674 /* From the Vulkan spec:
675 *
676 * "Importing semaphore state from a file descriptor transfers
677 * ownership of the file descriptor from the application to the
678 * Vulkan implementation. The application must not perform any
679 * operations on the file descriptor after a successful import."
680 *
681 * If the import fails, we leave the file descriptor open.
682 */
683 close(pImportSemaphoreFdInfo->fd);
684 } else {
685 new_impl.type = ANV_SEMAPHORE_TYPE_BO;
686
687 VkResult result = anv_bo_cache_import(device, &device->bo_cache,
688 fd, 4096, &new_impl.bo);
689 if (result != VK_SUCCESS)
690 return result;
691
692 /* If we're going to use this as a fence, we need to *not* have the
693 * EXEC_OBJECT_ASYNC bit set.
694 */
695 assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
696 }
697 break;
698
699 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT_KHR:
700 new_impl = (struct anv_semaphore_impl) {
701 .type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
702 .fd = fd,
703 };
704 break;
705
706 default:
707 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
708 }
709
710 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR) {
711 anv_semaphore_impl_cleanup(device, &semaphore->temporary);
712 semaphore->temporary = new_impl;
713 } else {
714 anv_semaphore_impl_cleanup(device, &semaphore->permanent);
715 semaphore->permanent = new_impl;
716 }
717
718 return VK_SUCCESS;
719 }
720
721 VkResult anv_GetSemaphoreFdKHR(
722 VkDevice _device,
723 const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
724 int* pFd)
725 {
726 ANV_FROM_HANDLE(anv_device, device, _device);
727 ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
728 VkResult result;
729 int fd;
730
731 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
732
733 struct anv_semaphore_impl *impl =
734 semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
735 &semaphore->temporary : &semaphore->permanent;
736
737 switch (impl->type) {
738 case ANV_SEMAPHORE_TYPE_BO:
739 result = anv_bo_cache_export(device, &device->bo_cache, impl->bo, pFd);
740 if (result != VK_SUCCESS)
741 return result;
742 break;
743
744 case ANV_SEMAPHORE_TYPE_SYNC_FILE:
745 /* There are two reasons why this could happen:
746 *
747 * 1) The user is trying to export without submitting something that
748 * signals the semaphore. If this is the case, it's their bug so
749 * what we return here doesn't matter.
750 *
751 * 2) The kernel didn't give us a file descriptor. The most likely
752 * reason for this is running out of file descriptors.
753 */
754 if (impl->fd < 0)
755 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
756
757 *pFd = impl->fd;
758
759 /* From the Vulkan 1.0.53 spec:
760 *
761 * "...exporting a semaphore payload to a handle with copy
762 * transference has the same side effects on the source
763 * semaphore’s payload as executing a semaphore wait operation."
764 *
765 * In other words, it may still be a SYNC_FD semaphore, but it's now
766 * considered to have been waited on and no longer has a sync file
767 * attached.
768 */
769 impl->fd = -1;
770 return VK_SUCCESS;
771
772 case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
773 fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
774 if (fd < 0)
775 return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
776 *pFd = fd;
777 break;
778
779 default:
780 return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
781 }
782
783 /* From the Vulkan 1.0.53 spec:
784 *
785 * "Export operations have the same transference as the specified handle
786 * type’s import operations. [...] If the semaphore was using a
787 * temporarily imported payload, the semaphore’s prior permanent payload
788 * will be restored.
789 */
790 if (impl == &semaphore->temporary)
791 anv_semaphore_impl_cleanup(device, impl);
792
793 return VK_SUCCESS;
794 }