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