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