Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/intel/vulkan/anv_queue.c
4547 views
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 <errno.h>
29
#include <fcntl.h>
30
#include <unistd.h>
31
32
#include "util/os_file.h"
33
34
#include "anv_private.h"
35
#include "anv_measure.h"
36
#include "vk_util.h"
37
38
#include "genxml/gen7_pack.h"
39
40
uint64_t anv_gettime_ns(void)
41
{
42
struct timespec current;
43
clock_gettime(CLOCK_MONOTONIC, &current);
44
return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
45
}
46
47
uint64_t anv_get_absolute_timeout(uint64_t timeout)
48
{
49
if (timeout == 0)
50
return 0;
51
uint64_t current_time = anv_gettime_ns();
52
uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;
53
54
timeout = MIN2(max_timeout, timeout);
55
56
return (current_time + timeout);
57
}
58
59
static int64_t anv_get_relative_timeout(uint64_t abs_timeout)
60
{
61
uint64_t now = anv_gettime_ns();
62
63
/* We don't want negative timeouts.
64
*
65
* DRM_IOCTL_I915_GEM_WAIT uses a signed 64 bit timeout and is
66
* supposed to block indefinitely timeouts < 0. Unfortunately,
67
* this was broken for a couple of kernel releases. Since there's
68
* no way to know whether or not the kernel we're using is one of
69
* the broken ones, the best we can do is to clamp the timeout to
70
* INT64_MAX. This limits the maximum timeout from 584 years to
71
* 292 years - likely not a big deal.
72
*/
73
if (abs_timeout < now)
74
return 0;
75
76
uint64_t rel_timeout = abs_timeout - now;
77
if (rel_timeout > (uint64_t) INT64_MAX)
78
rel_timeout = INT64_MAX;
79
80
return rel_timeout;
81
}
82
83
static struct anv_semaphore *anv_semaphore_ref(struct anv_semaphore *semaphore);
84
static void anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore);
85
static void anv_semaphore_impl_cleanup(struct anv_device *device,
86
struct anv_semaphore_impl *impl);
87
88
static void
89
anv_queue_submit_free(struct anv_device *device,
90
struct anv_queue_submit *submit)
91
{
92
const VkAllocationCallbacks *alloc = submit->alloc;
93
94
for (uint32_t i = 0; i < submit->temporary_semaphore_count; i++)
95
anv_semaphore_impl_cleanup(device, &submit->temporary_semaphores[i]);
96
for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++)
97
anv_semaphore_unref(device, submit->sync_fd_semaphores[i]);
98
/* Execbuf does not consume the in_fence. It's our job to close it. */
99
if (submit->in_fence != -1) {
100
assert(!device->has_thread_submit);
101
close(submit->in_fence);
102
}
103
if (submit->out_fence != -1) {
104
assert(!device->has_thread_submit);
105
close(submit->out_fence);
106
}
107
vk_free(alloc, submit->fences);
108
vk_free(alloc, submit->fence_values);
109
vk_free(alloc, submit->temporary_semaphores);
110
vk_free(alloc, submit->wait_timelines);
111
vk_free(alloc, submit->wait_timeline_values);
112
vk_free(alloc, submit->signal_timelines);
113
vk_free(alloc, submit->signal_timeline_values);
114
vk_free(alloc, submit->fence_bos);
115
vk_free(alloc, submit->cmd_buffers);
116
vk_free(alloc, submit);
117
}
118
119
static bool
120
anv_queue_submit_ready_locked(struct anv_queue_submit *submit)
121
{
122
for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
123
if (submit->wait_timeline_values[i] > submit->wait_timelines[i]->highest_pending)
124
return false;
125
}
126
127
return true;
128
}
129
130
static VkResult
131
anv_timeline_init(struct anv_device *device,
132
struct anv_timeline *timeline,
133
uint64_t initial_value)
134
{
135
timeline->highest_past =
136
timeline->highest_pending = initial_value;
137
list_inithead(&timeline->points);
138
list_inithead(&timeline->free_points);
139
140
return VK_SUCCESS;
141
}
142
143
static void
144
anv_timeline_finish(struct anv_device *device,
145
struct anv_timeline *timeline)
146
{
147
list_for_each_entry_safe(struct anv_timeline_point, point,
148
&timeline->free_points, link) {
149
list_del(&point->link);
150
anv_device_release_bo(device, point->bo);
151
vk_free(&device->vk.alloc, point);
152
}
153
list_for_each_entry_safe(struct anv_timeline_point, point,
154
&timeline->points, link) {
155
list_del(&point->link);
156
anv_device_release_bo(device, point->bo);
157
vk_free(&device->vk.alloc, point);
158
}
159
}
160
161
static VkResult
162
anv_timeline_add_point_locked(struct anv_device *device,
163
struct anv_timeline *timeline,
164
uint64_t value,
165
struct anv_timeline_point **point)
166
{
167
VkResult result = VK_SUCCESS;
168
169
if (list_is_empty(&timeline->free_points)) {
170
*point =
171
vk_zalloc(&device->vk.alloc, sizeof(**point),
172
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
173
if (!(*point))
174
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
175
if (result == VK_SUCCESS) {
176
result = anv_device_alloc_bo(device, "timeline-semaphore", 4096,
177
ANV_BO_ALLOC_EXTERNAL |
178
ANV_BO_ALLOC_IMPLICIT_SYNC,
179
0 /* explicit_address */,
180
&(*point)->bo);
181
if (result != VK_SUCCESS)
182
vk_free(&device->vk.alloc, *point);
183
}
184
} else {
185
*point = list_first_entry(&timeline->free_points,
186
struct anv_timeline_point, link);
187
list_del(&(*point)->link);
188
}
189
190
if (result == VK_SUCCESS) {
191
(*point)->serial = value;
192
list_addtail(&(*point)->link, &timeline->points);
193
}
194
195
return result;
196
}
197
198
static VkResult
199
anv_timeline_gc_locked(struct anv_device *device,
200
struct anv_timeline *timeline)
201
{
202
list_for_each_entry_safe(struct anv_timeline_point, point,
203
&timeline->points, link) {
204
/* timeline->higest_pending is only incremented once submission has
205
* happened. If this point has a greater serial, it means the point
206
* hasn't been submitted yet.
207
*/
208
if (point->serial > timeline->highest_pending)
209
return VK_SUCCESS;
210
211
/* If someone is waiting on this time point, consider it busy and don't
212
* try to recycle it. There's a slim possibility that it's no longer
213
* busy by the time we look at it but we would be recycling it out from
214
* under a waiter and that can lead to weird races.
215
*
216
* We walk the list in-order so if this time point is still busy so is
217
* every following time point
218
*/
219
assert(point->waiting >= 0);
220
if (point->waiting)
221
return VK_SUCCESS;
222
223
/* Garbage collect any signaled point. */
224
VkResult result = anv_device_bo_busy(device, point->bo);
225
if (result == VK_NOT_READY) {
226
/* We walk the list in-order so if this time point is still busy so
227
* is every following time point
228
*/
229
return VK_SUCCESS;
230
} else if (result != VK_SUCCESS) {
231
return result;
232
}
233
234
assert(timeline->highest_past < point->serial);
235
timeline->highest_past = point->serial;
236
237
list_del(&point->link);
238
list_add(&point->link, &timeline->free_points);
239
}
240
241
return VK_SUCCESS;
242
}
243
244
static VkResult anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,
245
struct anv_bo *bo,
246
bool signal);
247
248
static VkResult
249
anv_queue_submit_timeline_locked(struct anv_queue *queue,
250
struct anv_queue_submit *submit)
251
{
252
VkResult result;
253
254
for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
255
struct anv_timeline *timeline = submit->wait_timelines[i];
256
uint64_t wait_value = submit->wait_timeline_values[i];
257
258
if (timeline->highest_past >= wait_value)
259
continue;
260
261
list_for_each_entry(struct anv_timeline_point, point, &timeline->points, link) {
262
if (point->serial < wait_value)
263
continue;
264
result = anv_queue_submit_add_fence_bo(submit, point->bo, false);
265
if (result != VK_SUCCESS)
266
return result;
267
break;
268
}
269
}
270
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
271
struct anv_timeline *timeline = submit->signal_timelines[i];
272
uint64_t signal_value = submit->signal_timeline_values[i];
273
struct anv_timeline_point *point;
274
275
result = anv_timeline_add_point_locked(queue->device, timeline,
276
signal_value, &point);
277
if (result != VK_SUCCESS)
278
return result;
279
280
result = anv_queue_submit_add_fence_bo(submit, point->bo, true);
281
if (result != VK_SUCCESS)
282
return result;
283
}
284
285
result = anv_queue_execbuf_locked(queue, submit);
286
287
if (result == VK_SUCCESS) {
288
/* Update the pending values in the timeline objects. */
289
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
290
struct anv_timeline *timeline = submit->signal_timelines[i];
291
uint64_t signal_value = submit->signal_timeline_values[i];
292
293
assert(signal_value > timeline->highest_pending);
294
timeline->highest_pending = signal_value;
295
}
296
297
/* Update signaled semaphores backed by syncfd. */
298
for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {
299
struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];
300
/* Out fences can't have temporary state because that would imply
301
* that we imported a sync file and are trying to signal it.
302
*/
303
assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
304
struct anv_semaphore_impl *impl = &semaphore->permanent;
305
306
assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);
307
impl->fd = os_dupfd_cloexec(submit->out_fence);
308
}
309
} else {
310
/* Unblock any waiter by signaling the points, the application will get
311
* a device lost error code.
312
*/
313
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
314
struct anv_timeline *timeline = submit->signal_timelines[i];
315
uint64_t signal_value = submit->signal_timeline_values[i];
316
317
assert(signal_value > timeline->highest_pending);
318
timeline->highest_past = timeline->highest_pending = signal_value;
319
}
320
}
321
322
return result;
323
}
324
325
static VkResult
326
anv_queue_submit_deferred_locked(struct anv_queue *queue, uint32_t *advance)
327
{
328
VkResult result = VK_SUCCESS;
329
330
/* Go through all the queued submissions and submit then until we find one
331
* that's waiting on a point that hasn't materialized yet.
332
*/
333
list_for_each_entry_safe(struct anv_queue_submit, submit,
334
&queue->queued_submits, link) {
335
if (!anv_queue_submit_ready_locked(submit))
336
break;
337
338
(*advance)++;
339
list_del(&submit->link);
340
341
result = anv_queue_submit_timeline_locked(queue, submit);
342
343
anv_queue_submit_free(queue->device, submit);
344
345
if (result != VK_SUCCESS)
346
break;
347
}
348
349
return result;
350
}
351
352
static VkResult
353
anv_device_submit_deferred_locked(struct anv_device *device)
354
{
355
VkResult result = VK_SUCCESS;
356
357
uint32_t advance;
358
do {
359
advance = 0;
360
for (uint32_t i = 0; i < device->queue_count; i++) {
361
struct anv_queue *queue = &device->queues[i];
362
VkResult qres = anv_queue_submit_deferred_locked(queue, &advance);
363
if (qres != VK_SUCCESS)
364
result = qres;
365
}
366
} while (advance);
367
368
return result;
369
}
370
371
static void
372
anv_queue_submit_signal_fences(struct anv_device *device,
373
struct anv_queue_submit *submit)
374
{
375
for (uint32_t i = 0; i < submit->fence_count; i++) {
376
if (submit->fences[i].flags & I915_EXEC_FENCE_SIGNAL) {
377
anv_gem_syncobj_timeline_signal(device, &submit->fences[i].handle,
378
&submit->fence_values[i], 1);
379
}
380
}
381
}
382
383
static void *
384
anv_queue_task(void *_queue)
385
{
386
struct anv_queue *queue = _queue;
387
388
pthread_mutex_lock(&queue->mutex);
389
390
while (!queue->quit) {
391
while (!list_is_empty(&queue->queued_submits)) {
392
struct anv_queue_submit *submit =
393
list_first_entry(&queue->queued_submits, struct anv_queue_submit, link);
394
list_del(&submit->link);
395
396
pthread_mutex_unlock(&queue->mutex);
397
398
VkResult result = VK_ERROR_DEVICE_LOST;
399
400
/* Wait for timeline points to materialize before submitting. We need
401
* to do this because we're using threads to do the submit to i915.
402
* We could end up in a situation where the application submits to 2
403
* queues with the first submit creating the dma-fence for the
404
* second. But because the scheduling of the submission threads might
405
* wakeup the second queue thread first, this would make that execbuf
406
* fail because the dma-fence it depends on hasn't materialized yet.
407
*/
408
if (!queue->lost && submit->wait_timeline_count > 0) {
409
int ret = queue->device->no_hw ? 0 :
410
anv_gem_syncobj_timeline_wait(
411
queue->device, submit->wait_timeline_syncobjs,
412
submit->wait_timeline_values, submit->wait_timeline_count,
413
anv_get_absolute_timeout(UINT64_MAX) /* wait forever */,
414
true /* wait for all */, true /* wait for materialize */);
415
if (ret) {
416
result = anv_queue_set_lost(queue, "timeline timeout: %s",
417
strerror(errno));
418
}
419
}
420
421
/* Now submit */
422
if (!queue->lost) {
423
pthread_mutex_lock(&queue->device->mutex);
424
result = anv_queue_execbuf_locked(queue, submit);
425
pthread_mutex_unlock(&queue->device->mutex);
426
}
427
428
for (uint32_t i = 0; i < submit->sync_fd_semaphore_count; i++) {
429
struct anv_semaphore *semaphore = submit->sync_fd_semaphores[i];
430
/* Out fences can't have temporary state because that would imply
431
* that we imported a sync file and are trying to signal it.
432
*/
433
assert(semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE);
434
struct anv_semaphore_impl *impl = &semaphore->permanent;
435
436
assert(impl->type == ANV_SEMAPHORE_TYPE_SYNC_FILE);
437
impl->fd = dup(submit->out_fence);
438
}
439
440
if (result != VK_SUCCESS) {
441
/* vkQueueSubmit or some other entry point will report the
442
* DEVICE_LOST error at some point, but until we have emptied our
443
* list of execbufs we need to wake up all potential the waiters
444
* until one of them spots the error.
445
*/
446
anv_queue_submit_signal_fences(queue->device, submit);
447
}
448
449
anv_queue_submit_free(queue->device, submit);
450
451
pthread_mutex_lock(&queue->mutex);
452
}
453
454
if (!queue->quit)
455
pthread_cond_wait(&queue->cond, &queue->mutex);
456
}
457
458
pthread_mutex_unlock(&queue->mutex);
459
460
return NULL;
461
}
462
463
static VkResult
464
anv_queue_submit_post(struct anv_queue *queue,
465
struct anv_queue_submit **_submit,
466
bool flush_queue)
467
{
468
struct anv_queue_submit *submit = *_submit;
469
470
/* Wait before signal behavior means we might keep alive the
471
* anv_queue_submit object a bit longer, so transfer the ownership to the
472
* anv_queue.
473
*/
474
*_submit = NULL;
475
if (queue->device->has_thread_submit) {
476
pthread_mutex_lock(&queue->mutex);
477
pthread_cond_broadcast(&queue->cond);
478
list_addtail(&submit->link, &queue->queued_submits);
479
pthread_mutex_unlock(&queue->mutex);
480
return VK_SUCCESS;
481
} else {
482
pthread_mutex_lock(&queue->device->mutex);
483
list_addtail(&submit->link, &queue->queued_submits);
484
VkResult result = anv_device_submit_deferred_locked(queue->device);
485
if (flush_queue) {
486
while (result == VK_SUCCESS && !list_is_empty(&queue->queued_submits)) {
487
int ret = pthread_cond_wait(&queue->device->queue_submit,
488
&queue->device->mutex);
489
if (ret != 0) {
490
result = anv_device_set_lost(queue->device, "wait timeout");
491
break;
492
}
493
494
result = anv_device_submit_deferred_locked(queue->device);
495
}
496
}
497
pthread_mutex_unlock(&queue->device->mutex);
498
return result;
499
}
500
}
501
502
VkResult
503
anv_queue_init(struct anv_device *device, struct anv_queue *queue,
504
uint32_t exec_flags,
505
const VkDeviceQueueCreateInfo *pCreateInfo)
506
{
507
struct anv_physical_device *pdevice = device->physical;
508
VkResult result;
509
510
queue->device = device;
511
queue->flags = pCreateInfo->flags;
512
513
assert(pCreateInfo->queueFamilyIndex < pdevice->queue.family_count);
514
queue->family = &pdevice->queue.families[pCreateInfo->queueFamilyIndex];
515
516
queue->exec_flags = exec_flags;
517
queue->lost = false;
518
queue->quit = false;
519
520
list_inithead(&queue->queued_submits);
521
522
/* We only need those additional thread/mutex when using a thread for
523
* submission.
524
*/
525
if (device->has_thread_submit) {
526
if (pthread_mutex_init(&queue->mutex, NULL) != 0)
527
return vk_error(VK_ERROR_INITIALIZATION_FAILED);
528
529
if (pthread_cond_init(&queue->cond, NULL) != 0) {
530
result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
531
goto fail_mutex;
532
}
533
if (pthread_create(&queue->thread, NULL, anv_queue_task, queue)) {
534
result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
535
goto fail_cond;
536
}
537
}
538
539
vk_object_base_init(&device->vk, &queue->base, VK_OBJECT_TYPE_QUEUE);
540
541
return VK_SUCCESS;
542
543
fail_cond:
544
pthread_cond_destroy(&queue->cond);
545
fail_mutex:
546
pthread_mutex_destroy(&queue->mutex);
547
548
return result;
549
}
550
551
void
552
anv_queue_finish(struct anv_queue *queue)
553
{
554
if (queue->device->has_thread_submit) {
555
pthread_mutex_lock(&queue->mutex);
556
pthread_cond_broadcast(&queue->cond);
557
queue->quit = true;
558
pthread_mutex_unlock(&queue->mutex);
559
560
void *ret;
561
pthread_join(queue->thread, &ret);
562
563
pthread_cond_destroy(&queue->cond);
564
pthread_mutex_destroy(&queue->mutex);
565
}
566
567
vk_object_base_finish(&queue->base);
568
}
569
570
static VkResult
571
anv_queue_submit_add_fence_bo(struct anv_queue_submit *submit,
572
struct anv_bo *bo,
573
bool signal)
574
{
575
if (submit->fence_bo_count >= submit->fence_bo_array_length) {
576
uint32_t new_len = MAX2(submit->fence_bo_array_length * 2, 64);
577
uintptr_t *new_fence_bos =
578
vk_realloc(submit->alloc,
579
submit->fence_bos, new_len * sizeof(*submit->fence_bos),
580
8, submit->alloc_scope);
581
if (new_fence_bos == NULL)
582
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
583
584
submit->fence_bos = new_fence_bos;
585
submit->fence_bo_array_length = new_len;
586
}
587
588
/* Take advantage that anv_bo are allocated at 8 byte alignement so we can
589
* use the lowest bit to store whether this is a BO we need to signal.
590
*/
591
submit->fence_bos[submit->fence_bo_count++] = anv_pack_ptr(bo, 1, signal);
592
593
return VK_SUCCESS;
594
}
595
596
static VkResult
597
anv_queue_submit_add_syncobj(struct anv_queue_submit* submit,
598
struct anv_device *device,
599
uint32_t handle, uint32_t flags,
600
uint64_t value)
601
{
602
assert(flags != 0);
603
604
if (device->has_thread_submit && (flags & I915_EXEC_FENCE_WAIT)) {
605
if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
606
uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
607
608
uint32_t *new_wait_timeline_syncobjs =
609
vk_realloc(submit->alloc,
610
submit->wait_timeline_syncobjs,
611
new_len * sizeof(*submit->wait_timeline_syncobjs),
612
8, submit->alloc_scope);
613
if (new_wait_timeline_syncobjs == NULL)
614
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
615
616
submit->wait_timeline_syncobjs = new_wait_timeline_syncobjs;
617
618
uint64_t *new_wait_timeline_values =
619
vk_realloc(submit->alloc,
620
submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),
621
8, submit->alloc_scope);
622
if (new_wait_timeline_values == NULL)
623
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
624
625
submit->wait_timeline_values = new_wait_timeline_values;
626
submit->wait_timeline_array_length = new_len;
627
}
628
629
submit->wait_timeline_syncobjs[submit->wait_timeline_count] = handle;
630
submit->wait_timeline_values[submit->wait_timeline_count] = value;
631
632
submit->wait_timeline_count++;
633
}
634
635
if (submit->fence_count >= submit->fence_array_length) {
636
uint32_t new_len = MAX2(submit->fence_array_length * 2, 64);
637
struct drm_i915_gem_exec_fence *new_fences =
638
vk_realloc(submit->alloc,
639
submit->fences, new_len * sizeof(*submit->fences),
640
8, submit->alloc_scope);
641
if (new_fences == NULL)
642
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
643
644
submit->fences = new_fences;
645
646
uint64_t *new_fence_values =
647
vk_realloc(submit->alloc,
648
submit->fence_values, new_len * sizeof(*submit->fence_values),
649
8, submit->alloc_scope);
650
if (new_fence_values == NULL)
651
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
652
653
submit->fence_values = new_fence_values;
654
submit->fence_array_length = new_len;
655
}
656
657
submit->fences[submit->fence_count] = (struct drm_i915_gem_exec_fence) {
658
.handle = handle,
659
.flags = flags,
660
};
661
submit->fence_values[submit->fence_count] = value;
662
submit->fence_count++;
663
664
return VK_SUCCESS;
665
}
666
667
static VkResult
668
anv_queue_submit_add_sync_fd_fence(struct anv_queue_submit *submit,
669
struct anv_semaphore *semaphore)
670
{
671
if (submit->sync_fd_semaphore_count >= submit->sync_fd_semaphore_array_length) {
672
uint32_t new_len = MAX2(submit->sync_fd_semaphore_array_length * 2, 64);
673
struct anv_semaphore **new_semaphores =
674
vk_realloc(submit->alloc, submit->sync_fd_semaphores,
675
new_len * sizeof(*submit->sync_fd_semaphores), 8,
676
submit->alloc_scope);
677
if (new_semaphores == NULL)
678
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
679
680
submit->sync_fd_semaphores = new_semaphores;
681
}
682
683
submit->sync_fd_semaphores[submit->sync_fd_semaphore_count++] =
684
anv_semaphore_ref(semaphore);
685
submit->need_out_fence = true;
686
687
return VK_SUCCESS;
688
}
689
690
static VkResult
691
anv_queue_submit_add_timeline_wait(struct anv_queue_submit* submit,
692
struct anv_device *device,
693
struct anv_timeline *timeline,
694
uint64_t value)
695
{
696
if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
697
uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
698
struct anv_timeline **new_wait_timelines =
699
vk_realloc(submit->alloc,
700
submit->wait_timelines, new_len * sizeof(*submit->wait_timelines),
701
8, submit->alloc_scope);
702
if (new_wait_timelines == NULL)
703
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
704
705
submit->wait_timelines = new_wait_timelines;
706
707
uint64_t *new_wait_timeline_values =
708
vk_realloc(submit->alloc,
709
submit->wait_timeline_values, new_len * sizeof(*submit->wait_timeline_values),
710
8, submit->alloc_scope);
711
if (new_wait_timeline_values == NULL)
712
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
713
714
submit->wait_timeline_values = new_wait_timeline_values;
715
716
submit->wait_timeline_array_length = new_len;
717
}
718
719
submit->wait_timelines[submit->wait_timeline_count] = timeline;
720
submit->wait_timeline_values[submit->wait_timeline_count] = value;
721
722
submit->wait_timeline_count++;
723
724
return VK_SUCCESS;
725
}
726
727
static VkResult
728
anv_queue_submit_add_timeline_signal(struct anv_queue_submit* submit,
729
struct anv_device *device,
730
struct anv_timeline *timeline,
731
uint64_t value)
732
{
733
assert(timeline->highest_pending < value);
734
735
if (submit->signal_timeline_count >= submit->signal_timeline_array_length) {
736
uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 64);
737
struct anv_timeline **new_signal_timelines =
738
vk_realloc(submit->alloc,
739
submit->signal_timelines, new_len * sizeof(*submit->signal_timelines),
740
8, submit->alloc_scope);
741
if (new_signal_timelines == NULL)
742
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
743
744
submit->signal_timelines = new_signal_timelines;
745
746
uint64_t *new_signal_timeline_values =
747
vk_realloc(submit->alloc,
748
submit->signal_timeline_values, new_len * sizeof(*submit->signal_timeline_values),
749
8, submit->alloc_scope);
750
if (new_signal_timeline_values == NULL)
751
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
752
753
submit->signal_timeline_values = new_signal_timeline_values;
754
755
submit->signal_timeline_array_length = new_len;
756
}
757
758
submit->signal_timelines[submit->signal_timeline_count] = timeline;
759
submit->signal_timeline_values[submit->signal_timeline_count] = value;
760
761
submit->signal_timeline_count++;
762
763
return VK_SUCCESS;
764
}
765
766
static struct anv_queue_submit *
767
anv_queue_submit_alloc(struct anv_device *device)
768
{
769
const VkAllocationCallbacks *alloc = &device->vk.alloc;
770
VkSystemAllocationScope alloc_scope = VK_SYSTEM_ALLOCATION_SCOPE_DEVICE;
771
772
struct anv_queue_submit *submit = vk_zalloc(alloc, sizeof(*submit), 8, alloc_scope);
773
if (!submit)
774
return NULL;
775
776
submit->alloc = alloc;
777
submit->alloc_scope = alloc_scope;
778
submit->in_fence = -1;
779
submit->out_fence = -1;
780
submit->perf_query_pass = -1;
781
782
return submit;
783
}
784
785
VkResult
786
anv_queue_submit_simple_batch(struct anv_queue *queue,
787
struct anv_batch *batch)
788
{
789
if (queue->device->no_hw)
790
return VK_SUCCESS;
791
792
struct anv_device *device = queue->device;
793
struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
794
if (!submit)
795
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
796
797
bool has_syncobj_wait = device->physical->has_syncobj_wait;
798
VkResult result;
799
uint32_t syncobj;
800
struct anv_bo *batch_bo, *sync_bo;
801
802
if (has_syncobj_wait) {
803
syncobj = anv_gem_syncobj_create(device, 0);
804
if (!syncobj) {
805
result = vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
806
goto err_free_submit;
807
}
808
809
result = anv_queue_submit_add_syncobj(submit, device, syncobj,
810
I915_EXEC_FENCE_SIGNAL, 0);
811
} else {
812
result = anv_device_alloc_bo(device, "simple-batch-sync", 4096,
813
ANV_BO_ALLOC_EXTERNAL |
814
ANV_BO_ALLOC_IMPLICIT_SYNC,
815
0 /* explicit_address */,
816
&sync_bo);
817
if (result != VK_SUCCESS)
818
goto err_free_submit;
819
820
result = anv_queue_submit_add_fence_bo(submit, sync_bo, true /* signal */);
821
}
822
823
if (result != VK_SUCCESS)
824
goto err_destroy_sync_primitive;
825
826
if (batch) {
827
uint32_t size = align_u32(batch->next - batch->start, 8);
828
result = anv_bo_pool_alloc(&device->batch_bo_pool, size, &batch_bo);
829
if (result != VK_SUCCESS)
830
goto err_destroy_sync_primitive;
831
832
memcpy(batch_bo->map, batch->start, size);
833
if (!device->info.has_llc)
834
intel_flush_range(batch_bo->map, size);
835
836
submit->simple_bo = batch_bo;
837
submit->simple_bo_size = size;
838
}
839
840
result = anv_queue_submit_post(queue, &submit, true);
841
842
if (result == VK_SUCCESS) {
843
if (has_syncobj_wait) {
844
if (anv_gem_syncobj_wait(device, &syncobj, 1,
845
anv_get_absolute_timeout(INT64_MAX), true))
846
result = anv_device_set_lost(device, "anv_gem_syncobj_wait failed: %m");
847
anv_gem_syncobj_destroy(device, syncobj);
848
} else {
849
result = anv_device_wait(device, sync_bo,
850
anv_get_relative_timeout(INT64_MAX));
851
anv_device_release_bo(device, sync_bo);
852
}
853
}
854
855
if (batch)
856
anv_bo_pool_free(&device->batch_bo_pool, batch_bo);
857
858
if (submit)
859
anv_queue_submit_free(device, submit);
860
861
return result;
862
863
err_destroy_sync_primitive:
864
if (has_syncobj_wait)
865
anv_gem_syncobj_destroy(device, syncobj);
866
else
867
anv_device_release_bo(device, sync_bo);
868
err_free_submit:
869
if (submit)
870
anv_queue_submit_free(device, submit);
871
872
return result;
873
}
874
875
/* Transfer ownership of temporary semaphores from the VkSemaphore object to
876
* the anv_queue_submit object. Those temporary semaphores are then freed in
877
* anv_queue_submit_free() once the driver is finished with them.
878
*/
879
static VkResult
880
maybe_transfer_temporary_semaphore(struct anv_queue_submit *submit,
881
struct anv_semaphore *semaphore,
882
struct anv_semaphore_impl **out_impl)
883
{
884
struct anv_semaphore_impl *impl = &semaphore->temporary;
885
886
if (impl->type == ANV_SEMAPHORE_TYPE_NONE) {
887
*out_impl = &semaphore->permanent;
888
return VK_SUCCESS;
889
}
890
891
/* BO backed timeline semaphores cannot be temporary. */
892
assert(impl->type != ANV_SEMAPHORE_TYPE_TIMELINE);
893
894
/*
895
* There is a requirement to reset semaphore to their permanent state after
896
* submission. From the Vulkan 1.0.53 spec:
897
*
898
* "If the import is temporary, the implementation must restore the
899
* semaphore to its prior permanent state after submitting the next
900
* semaphore wait operation."
901
*
902
* In the case we defer the actual submission to a thread because of the
903
* wait-before-submit behavior required for timeline semaphores, we need to
904
* make copies of the temporary syncobj to ensure they stay alive until we
905
* do the actual execbuffer ioctl.
906
*/
907
if (submit->temporary_semaphore_count >= submit->temporary_semaphore_array_length) {
908
uint32_t new_len = MAX2(submit->temporary_semaphore_array_length * 2, 8);
909
/* Make sure that if the realloc fails, we still have the old semaphore
910
* array around to properly clean things up on failure.
911
*/
912
struct anv_semaphore_impl *new_array =
913
vk_realloc(submit->alloc,
914
submit->temporary_semaphores,
915
new_len * sizeof(*submit->temporary_semaphores),
916
8, submit->alloc_scope);
917
if (new_array == NULL)
918
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
919
920
submit->temporary_semaphores = new_array;
921
submit->temporary_semaphore_array_length = new_len;
922
}
923
924
/* Copy anv_semaphore_impl into anv_queue_submit. */
925
submit->temporary_semaphores[submit->temporary_semaphore_count++] = *impl;
926
*out_impl = &submit->temporary_semaphores[submit->temporary_semaphore_count - 1];
927
928
/* Clear the incoming semaphore */
929
impl->type = ANV_SEMAPHORE_TYPE_NONE;
930
931
return VK_SUCCESS;
932
}
933
934
static VkResult
935
anv_queue_submit_add_in_semaphores(struct anv_queue_submit *submit,
936
struct anv_device *device,
937
const VkSemaphore *in_semaphores,
938
const uint64_t *in_values,
939
uint32_t num_in_semaphores)
940
{
941
ASSERTED struct anv_physical_device *pdevice = device->physical;
942
VkResult result;
943
944
for (uint32_t i = 0; i < num_in_semaphores; i++) {
945
ANV_FROM_HANDLE(anv_semaphore, semaphore, in_semaphores[i]);
946
struct anv_semaphore_impl *impl;
947
948
result = maybe_transfer_temporary_semaphore(submit, semaphore, &impl);
949
if (result != VK_SUCCESS)
950
return result;
951
952
switch (impl->type) {
953
case ANV_SEMAPHORE_TYPE_BO:
954
assert(!pdevice->has_syncobj);
955
result = anv_queue_submit_add_fence_bo(submit, impl->bo, false /* signal */);
956
if (result != VK_SUCCESS)
957
return result;
958
break;
959
960
case ANV_SEMAPHORE_TYPE_WSI_BO:
961
/* When using a window-system buffer as a semaphore, always enable
962
* EXEC_OBJECT_WRITE. This gives us a WaR hazard with the display or
963
* compositor's read of the buffer and enforces that we don't start
964
* rendering until they are finished. This is exactly the
965
* synchronization we want with vkAcquireNextImage.
966
*/
967
result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
968
if (result != VK_SUCCESS)
969
return result;
970
break;
971
972
case ANV_SEMAPHORE_TYPE_SYNC_FILE:
973
assert(!pdevice->has_syncobj);
974
if (submit->in_fence == -1) {
975
submit->in_fence = impl->fd;
976
if (submit->in_fence == -1)
977
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
978
impl->fd = -1;
979
} else {
980
int merge = anv_gem_sync_file_merge(device, submit->in_fence, impl->fd);
981
if (merge == -1)
982
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
983
close(impl->fd);
984
close(submit->in_fence);
985
impl->fd = -1;
986
submit->in_fence = merge;
987
}
988
break;
989
990
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
991
result = anv_queue_submit_add_syncobj(submit, device,
992
impl->syncobj,
993
I915_EXEC_FENCE_WAIT,
994
0);
995
if (result != VK_SUCCESS)
996
return result;
997
break;
998
}
999
1000
case ANV_SEMAPHORE_TYPE_TIMELINE:
1001
assert(in_values);
1002
if (in_values[i] == 0)
1003
break;
1004
result = anv_queue_submit_add_timeline_wait(submit, device,
1005
&impl->timeline,
1006
in_values[i]);
1007
if (result != VK_SUCCESS)
1008
return result;
1009
break;
1010
1011
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
1012
assert(in_values);
1013
if (in_values[i] == 0)
1014
break;
1015
result = anv_queue_submit_add_syncobj(submit, device,
1016
impl->syncobj,
1017
I915_EXEC_FENCE_WAIT,
1018
in_values[i]);
1019
if (result != VK_SUCCESS)
1020
return result;
1021
break;
1022
1023
default:
1024
break;
1025
}
1026
}
1027
1028
return VK_SUCCESS;
1029
}
1030
1031
static VkResult
1032
anv_queue_submit_add_out_semaphores(struct anv_queue_submit *submit,
1033
struct anv_device *device,
1034
const VkSemaphore *out_semaphores,
1035
const uint64_t *out_values,
1036
uint32_t num_out_semaphores)
1037
{
1038
ASSERTED struct anv_physical_device *pdevice = device->physical;
1039
VkResult result;
1040
1041
for (uint32_t i = 0; i < num_out_semaphores; i++) {
1042
ANV_FROM_HANDLE(anv_semaphore, semaphore, out_semaphores[i]);
1043
1044
/* Under most circumstances, out fences won't be temporary. However,
1045
* the spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
1046
*
1047
* "If the import is temporary, the implementation must restore the
1048
* semaphore to its prior permanent state after submitting the next
1049
* semaphore wait operation."
1050
*
1051
* The spec says nothing whatsoever about signal operations on
1052
* temporarily imported semaphores so it appears they are allowed.
1053
* There are also CTS tests that require this to work.
1054
*/
1055
struct anv_semaphore_impl *impl =
1056
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
1057
&semaphore->temporary : &semaphore->permanent;
1058
1059
switch (impl->type) {
1060
case ANV_SEMAPHORE_TYPE_BO:
1061
assert(!pdevice->has_syncobj);
1062
result = anv_queue_submit_add_fence_bo(submit, impl->bo, true /* signal */);
1063
if (result != VK_SUCCESS)
1064
return result;
1065
break;
1066
1067
case ANV_SEMAPHORE_TYPE_SYNC_FILE:
1068
assert(!pdevice->has_syncobj);
1069
result = anv_queue_submit_add_sync_fd_fence(submit, semaphore);
1070
if (result != VK_SUCCESS)
1071
return result;
1072
break;
1073
1074
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ: {
1075
/*
1076
* Reset the content of the syncobj so it doesn't contain a
1077
* previously signaled dma-fence, until one is added by EXECBUFFER by
1078
* the submission thread.
1079
*/
1080
anv_gem_syncobj_reset(device, impl->syncobj);
1081
1082
result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
1083
I915_EXEC_FENCE_SIGNAL,
1084
0);
1085
if (result != VK_SUCCESS)
1086
return result;
1087
break;
1088
}
1089
1090
case ANV_SEMAPHORE_TYPE_TIMELINE:
1091
assert(out_values);
1092
if (out_values[i] == 0)
1093
break;
1094
result = anv_queue_submit_add_timeline_signal(submit, device,
1095
&impl->timeline,
1096
out_values[i]);
1097
if (result != VK_SUCCESS)
1098
return result;
1099
break;
1100
1101
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
1102
assert(out_values);
1103
if (out_values[i] == 0)
1104
break;
1105
result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
1106
I915_EXEC_FENCE_SIGNAL,
1107
out_values[i]);
1108
if (result != VK_SUCCESS)
1109
return result;
1110
break;
1111
1112
default:
1113
break;
1114
}
1115
}
1116
1117
return VK_SUCCESS;
1118
}
1119
1120
static VkResult
1121
anv_queue_submit_add_fence(struct anv_queue_submit *submit,
1122
struct anv_device *device,
1123
struct anv_fence *fence)
1124
{
1125
/* Under most circumstances, out fences won't be temporary. However, the
1126
* spec does allow it for opaque_fd. From the Vulkan 1.0.53 spec:
1127
*
1128
* "If the import is temporary, the implementation must restore the
1129
* semaphore to its prior permanent state after submitting the next
1130
* semaphore wait operation."
1131
*
1132
* The spec says nothing whatsoever about signal operations on temporarily
1133
* imported semaphores so it appears they are allowed. There are also CTS
1134
* tests that require this to work.
1135
*/
1136
struct anv_fence_impl *impl =
1137
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1138
&fence->temporary : &fence->permanent;
1139
1140
VkResult result;
1141
1142
switch (impl->type) {
1143
case ANV_FENCE_TYPE_BO:
1144
assert(!device->has_thread_submit);
1145
result = anv_queue_submit_add_fence_bo(submit, impl->bo.bo, true /* signal */);
1146
if (result != VK_SUCCESS)
1147
return result;
1148
break;
1149
1150
case ANV_FENCE_TYPE_SYNCOBJ: {
1151
/*
1152
* For the same reason we reset the signaled binary syncobj above, also
1153
* reset the fence's syncobj so that they don't contain a signaled
1154
* dma-fence.
1155
*/
1156
anv_gem_syncobj_reset(device, impl->syncobj);
1157
1158
result = anv_queue_submit_add_syncobj(submit, device, impl->syncobj,
1159
I915_EXEC_FENCE_SIGNAL,
1160
0);
1161
if (result != VK_SUCCESS)
1162
return result;
1163
break;
1164
}
1165
1166
default:
1167
unreachable("Invalid fence type");
1168
}
1169
1170
return VK_SUCCESS;
1171
}
1172
1173
static void
1174
anv_post_queue_fence_update(struct anv_device *device, struct anv_fence *fence)
1175
{
1176
if (fence->permanent.type == ANV_FENCE_TYPE_BO) {
1177
assert(!device->has_thread_submit);
1178
/* If we have permanent BO fence, the only type of temporary possible
1179
* would be BO_WSI (because BO fences are not shareable). The Vulkan spec
1180
* also requires that the fence passed to vkQueueSubmit() be :
1181
*
1182
* * unsignaled
1183
* * not be associated with any other queue command that has not yet
1184
* completed execution on that queue
1185
*
1186
* So the only acceptable type for the temporary is NONE.
1187
*/
1188
assert(fence->temporary.type == ANV_FENCE_TYPE_NONE);
1189
1190
/* Once the execbuf has returned, we need to set the fence state to
1191
* SUBMITTED. We can't do this before calling execbuf because
1192
* anv_GetFenceStatus does take the global device lock before checking
1193
* fence->state.
1194
*
1195
* We set the fence state to SUBMITTED regardless of whether or not the
1196
* execbuf succeeds because we need to ensure that vkWaitForFences() and
1197
* vkGetFenceStatus() return a valid result (VK_ERROR_DEVICE_LOST or
1198
* VK_SUCCESS) in a finite amount of time even if execbuf fails.
1199
*/
1200
fence->permanent.bo.state = ANV_BO_FENCE_STATE_SUBMITTED;
1201
}
1202
}
1203
1204
static VkResult
1205
anv_queue_submit_add_cmd_buffer(struct anv_queue_submit *submit,
1206
struct anv_cmd_buffer *cmd_buffer,
1207
int perf_pass)
1208
{
1209
if (submit->cmd_buffer_count >= submit->cmd_buffer_array_length) {
1210
uint32_t new_len = MAX2(submit->cmd_buffer_array_length * 2, 4);
1211
struct anv_cmd_buffer **new_cmd_buffers =
1212
vk_realloc(submit->alloc,
1213
submit->cmd_buffers, new_len * sizeof(*submit->cmd_buffers),
1214
8, submit->alloc_scope);
1215
if (new_cmd_buffers == NULL)
1216
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1217
1218
submit->cmd_buffers = new_cmd_buffers;
1219
submit->cmd_buffer_array_length = new_len;
1220
}
1221
1222
submit->cmd_buffers[submit->cmd_buffer_count++] = cmd_buffer;
1223
/* Only update the perf_query_pool if there is one. We can decide to batch
1224
* 2 command buffers if the second one doesn't use a query pool, but we
1225
* can't drop the already chosen one.
1226
*/
1227
if (cmd_buffer->perf_query_pool)
1228
submit->perf_query_pool = cmd_buffer->perf_query_pool;
1229
submit->perf_query_pass = perf_pass;
1230
1231
return VK_SUCCESS;
1232
}
1233
1234
static bool
1235
anv_queue_submit_can_add_cmd_buffer(const struct anv_queue_submit *submit,
1236
const struct anv_cmd_buffer *cmd_buffer,
1237
int perf_pass)
1238
{
1239
/* If first command buffer, no problem. */
1240
if (submit->cmd_buffer_count == 0)
1241
return true;
1242
1243
/* Can we chain the last buffer into the next one? */
1244
if (!anv_cmd_buffer_is_chainable(submit->cmd_buffers[submit->cmd_buffer_count - 1]))
1245
return false;
1246
1247
/* A change of perf query pools between VkSubmitInfo elements means we
1248
* can't batch things up.
1249
*/
1250
if (cmd_buffer->perf_query_pool &&
1251
submit->perf_query_pool &&
1252
submit->perf_query_pool != cmd_buffer->perf_query_pool)
1253
return false;
1254
1255
/* A change of perf pass also prevents batching things up.
1256
*/
1257
if (submit->perf_query_pass != -1 &&
1258
submit->perf_query_pass != perf_pass)
1259
return false;
1260
1261
return true;
1262
}
1263
1264
static bool
1265
anv_queue_submit_can_add_submit(const struct anv_queue_submit *submit,
1266
uint32_t n_wait_semaphores,
1267
uint32_t n_signal_semaphores,
1268
int perf_pass)
1269
{
1270
/* We can add to an empty anv_queue_submit. */
1271
if (submit->cmd_buffer_count == 0 &&
1272
submit->fence_count == 0 &&
1273
submit->sync_fd_semaphore_count == 0 &&
1274
submit->wait_timeline_count == 0 &&
1275
submit->signal_timeline_count == 0 &&
1276
submit->fence_bo_count == 0)
1277
return true;
1278
1279
/* Different perf passes will require different EXECBUF ioctls. */
1280
if (perf_pass != submit->perf_query_pass)
1281
return false;
1282
1283
/* If the current submit is signaling anything, we can't add anything. */
1284
if (submit->signal_timeline_count ||
1285
submit->sync_fd_semaphore_count)
1286
return false;
1287
1288
/* If a submit is waiting on anything, anything that happened before needs
1289
* to be submitted.
1290
*/
1291
if (n_wait_semaphores)
1292
return false;
1293
1294
return true;
1295
}
1296
1297
static VkResult
1298
anv_queue_submit_post_and_alloc_new(struct anv_queue *queue,
1299
struct anv_queue_submit **submit)
1300
{
1301
VkResult result = anv_queue_submit_post(queue, submit, false);
1302
if (result != VK_SUCCESS)
1303
return result;
1304
1305
*submit = anv_queue_submit_alloc(queue->device);
1306
if (!*submit)
1307
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1308
return VK_SUCCESS;
1309
}
1310
1311
VkResult anv_QueueSubmit(
1312
VkQueue _queue,
1313
uint32_t submitCount,
1314
const VkSubmitInfo* pSubmits,
1315
VkFence _fence)
1316
{
1317
ANV_FROM_HANDLE(anv_queue, queue, _queue);
1318
ANV_FROM_HANDLE(anv_fence, fence, _fence);
1319
struct anv_device *device = queue->device;
1320
1321
if (device->no_hw)
1322
return VK_SUCCESS;
1323
1324
/* Query for device status prior to submitting. Technically, we don't need
1325
* to do this. However, if we have a client that's submitting piles of
1326
* garbage, we would rather break as early as possible to keep the GPU
1327
* hanging contained. If we don't check here, we'll either be waiting for
1328
* the kernel to kick us or we'll have to wait until the client waits on a
1329
* fence before we actually know whether or not we've hung.
1330
*/
1331
VkResult result = anv_device_query_status(device);
1332
if (result != VK_SUCCESS)
1333
return result;
1334
1335
struct anv_queue_submit *submit = anv_queue_submit_alloc(device);
1336
if (!submit)
1337
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1338
1339
for (uint32_t i = 0; i < submitCount; i++) {
1340
const struct wsi_memory_signal_submit_info *mem_signal_info =
1341
vk_find_struct_const(pSubmits[i].pNext,
1342
WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA);
1343
struct anv_bo *wsi_signal_bo =
1344
mem_signal_info && mem_signal_info->memory != VK_NULL_HANDLE ?
1345
anv_device_memory_from_handle(mem_signal_info->memory)->bo : NULL;
1346
1347
const VkTimelineSemaphoreSubmitInfoKHR *timeline_info =
1348
vk_find_struct_const(pSubmits[i].pNext,
1349
TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR);
1350
const VkPerformanceQuerySubmitInfoKHR *perf_info =
1351
vk_find_struct_const(pSubmits[i].pNext,
1352
PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
1353
const int perf_pass = perf_info ? perf_info->counterPassIndex : 0;
1354
const uint64_t *wait_values =
1355
timeline_info && timeline_info->waitSemaphoreValueCount ?
1356
timeline_info->pWaitSemaphoreValues : NULL;
1357
const uint64_t *signal_values =
1358
timeline_info && timeline_info->signalSemaphoreValueCount ?
1359
timeline_info->pSignalSemaphoreValues : NULL;
1360
1361
if (!anv_queue_submit_can_add_submit(submit,
1362
pSubmits[i].waitSemaphoreCount,
1363
pSubmits[i].signalSemaphoreCount,
1364
perf_pass)) {
1365
result = anv_queue_submit_post_and_alloc_new(queue, &submit);
1366
if (result != VK_SUCCESS)
1367
goto out;
1368
}
1369
1370
/* Wait semaphores */
1371
result = anv_queue_submit_add_in_semaphores(submit,
1372
device,
1373
pSubmits[i].pWaitSemaphores,
1374
wait_values,
1375
pSubmits[i].waitSemaphoreCount);
1376
if (result != VK_SUCCESS)
1377
goto out;
1378
1379
/* Command buffers */
1380
for (uint32_t j = 0; j < pSubmits[i].commandBufferCount; j++) {
1381
ANV_FROM_HANDLE(anv_cmd_buffer, cmd_buffer,
1382
pSubmits[i].pCommandBuffers[j]);
1383
assert(cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY);
1384
assert(!anv_batch_has_error(&cmd_buffer->batch));
1385
anv_measure_submit(cmd_buffer);
1386
1387
/* If we can't add an additional command buffer to the existing
1388
* anv_queue_submit, post it and create a new one.
1389
*/
1390
if (!anv_queue_submit_can_add_cmd_buffer(submit, cmd_buffer, perf_pass)) {
1391
result = anv_queue_submit_post_and_alloc_new(queue, &submit);
1392
if (result != VK_SUCCESS)
1393
goto out;
1394
}
1395
1396
result = anv_queue_submit_add_cmd_buffer(submit, cmd_buffer, perf_pass);
1397
if (result != VK_SUCCESS)
1398
goto out;
1399
}
1400
1401
/* Signal semaphores */
1402
result = anv_queue_submit_add_out_semaphores(submit,
1403
device,
1404
pSubmits[i].pSignalSemaphores,
1405
signal_values,
1406
pSubmits[i].signalSemaphoreCount);
1407
if (result != VK_SUCCESS)
1408
goto out;
1409
1410
/* WSI BO */
1411
if (wsi_signal_bo) {
1412
result = anv_queue_submit_add_fence_bo(submit, wsi_signal_bo,
1413
true /* signal */);
1414
if (result != VK_SUCCESS)
1415
goto out;
1416
}
1417
}
1418
1419
if (fence) {
1420
result = anv_queue_submit_add_fence(submit, device, fence);
1421
if (result != VK_SUCCESS)
1422
goto out;
1423
}
1424
1425
result = anv_queue_submit_post(queue, &submit, false);
1426
if (result != VK_SUCCESS)
1427
goto out;
1428
1429
if (fence)
1430
anv_post_queue_fence_update(device, fence);
1431
1432
out:
1433
if (submit)
1434
anv_queue_submit_free(device, submit);
1435
1436
if (result != VK_SUCCESS && result != VK_ERROR_DEVICE_LOST) {
1437
/* In the case that something has gone wrong we may end up with an
1438
* inconsistent state from which it may not be trivial to recover.
1439
* For example, we might have computed address relocations and
1440
* any future attempt to re-submit this job will need to know about
1441
* this and avoid computing relocation addresses again.
1442
*
1443
* To avoid this sort of issues, we assume that if something was
1444
* wrong during submission we must already be in a really bad situation
1445
* anyway (such us being out of memory) and return
1446
* VK_ERROR_DEVICE_LOST to ensure that clients do not attempt to
1447
* submit the same job again to this device.
1448
*
1449
* We skip doing this on VK_ERROR_DEVICE_LOST because
1450
* anv_device_set_lost() would have been called already by a callee of
1451
* anv_queue_submit().
1452
*/
1453
result = anv_device_set_lost(device, "vkQueueSubmit() failed");
1454
}
1455
1456
return result;
1457
}
1458
1459
VkResult anv_QueueWaitIdle(
1460
VkQueue _queue)
1461
{
1462
ANV_FROM_HANDLE(anv_queue, queue, _queue);
1463
1464
if (anv_device_is_lost(queue->device))
1465
return VK_ERROR_DEVICE_LOST;
1466
1467
return anv_queue_submit_simple_batch(queue, NULL);
1468
}
1469
1470
VkResult anv_CreateFence(
1471
VkDevice _device,
1472
const VkFenceCreateInfo* pCreateInfo,
1473
const VkAllocationCallbacks* pAllocator,
1474
VkFence* pFence)
1475
{
1476
ANV_FROM_HANDLE(anv_device, device, _device);
1477
struct anv_fence *fence;
1478
1479
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO);
1480
1481
fence = vk_object_zalloc(&device->vk, pAllocator, sizeof(*fence),
1482
VK_OBJECT_TYPE_FENCE);
1483
if (fence == NULL)
1484
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1485
1486
if (device->physical->has_syncobj_wait) {
1487
fence->permanent.type = ANV_FENCE_TYPE_SYNCOBJ;
1488
1489
uint32_t create_flags = 0;
1490
if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)
1491
create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
1492
1493
fence->permanent.syncobj = anv_gem_syncobj_create(device, create_flags);
1494
if (!fence->permanent.syncobj)
1495
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1496
} else {
1497
fence->permanent.type = ANV_FENCE_TYPE_BO;
1498
1499
VkResult result = anv_bo_pool_alloc(&device->batch_bo_pool, 4096,
1500
&fence->permanent.bo.bo);
1501
if (result != VK_SUCCESS)
1502
return result;
1503
1504
if (pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT) {
1505
fence->permanent.bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1506
} else {
1507
fence->permanent.bo.state = ANV_BO_FENCE_STATE_RESET;
1508
}
1509
}
1510
1511
*pFence = anv_fence_to_handle(fence);
1512
1513
return VK_SUCCESS;
1514
}
1515
1516
static void
1517
anv_fence_impl_cleanup(struct anv_device *device,
1518
struct anv_fence_impl *impl)
1519
{
1520
switch (impl->type) {
1521
case ANV_FENCE_TYPE_NONE:
1522
/* Dummy. Nothing to do */
1523
break;
1524
1525
case ANV_FENCE_TYPE_BO:
1526
anv_bo_pool_free(&device->batch_bo_pool, impl->bo.bo);
1527
break;
1528
1529
case ANV_FENCE_TYPE_WSI_BO:
1530
anv_device_release_bo(device, impl->bo.bo);
1531
break;
1532
1533
case ANV_FENCE_TYPE_SYNCOBJ:
1534
anv_gem_syncobj_destroy(device, impl->syncobj);
1535
break;
1536
1537
case ANV_FENCE_TYPE_WSI:
1538
impl->fence_wsi->destroy(impl->fence_wsi);
1539
break;
1540
1541
default:
1542
unreachable("Invalid fence type");
1543
}
1544
1545
impl->type = ANV_FENCE_TYPE_NONE;
1546
}
1547
1548
void
1549
anv_fence_reset_temporary(struct anv_device *device,
1550
struct anv_fence *fence)
1551
{
1552
if (fence->temporary.type == ANV_FENCE_TYPE_NONE)
1553
return;
1554
1555
anv_fence_impl_cleanup(device, &fence->temporary);
1556
}
1557
1558
void anv_DestroyFence(
1559
VkDevice _device,
1560
VkFence _fence,
1561
const VkAllocationCallbacks* pAllocator)
1562
{
1563
ANV_FROM_HANDLE(anv_device, device, _device);
1564
ANV_FROM_HANDLE(anv_fence, fence, _fence);
1565
1566
if (!fence)
1567
return;
1568
1569
anv_fence_impl_cleanup(device, &fence->temporary);
1570
anv_fence_impl_cleanup(device, &fence->permanent);
1571
1572
vk_object_free(&device->vk, pAllocator, fence);
1573
}
1574
1575
VkResult anv_ResetFences(
1576
VkDevice _device,
1577
uint32_t fenceCount,
1578
const VkFence* pFences)
1579
{
1580
ANV_FROM_HANDLE(anv_device, device, _device);
1581
1582
for (uint32_t i = 0; i < fenceCount; i++) {
1583
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1584
1585
/* From the Vulkan 1.0.53 spec:
1586
*
1587
* "If any member of pFences currently has its payload imported with
1588
* temporary permanence, that fence’s prior permanent payload is
1589
* first restored. The remaining operations described therefore
1590
* operate on the restored payload.
1591
*/
1592
anv_fence_reset_temporary(device, fence);
1593
1594
struct anv_fence_impl *impl = &fence->permanent;
1595
1596
switch (impl->type) {
1597
case ANV_FENCE_TYPE_BO:
1598
impl->bo.state = ANV_BO_FENCE_STATE_RESET;
1599
break;
1600
1601
case ANV_FENCE_TYPE_SYNCOBJ:
1602
anv_gem_syncobj_reset(device, impl->syncobj);
1603
break;
1604
1605
default:
1606
unreachable("Invalid fence type");
1607
}
1608
}
1609
1610
return VK_SUCCESS;
1611
}
1612
1613
VkResult anv_GetFenceStatus(
1614
VkDevice _device,
1615
VkFence _fence)
1616
{
1617
ANV_FROM_HANDLE(anv_device, device, _device);
1618
ANV_FROM_HANDLE(anv_fence, fence, _fence);
1619
1620
if (anv_device_is_lost(device))
1621
return VK_ERROR_DEVICE_LOST;
1622
1623
struct anv_fence_impl *impl =
1624
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1625
&fence->temporary : &fence->permanent;
1626
1627
switch (impl->type) {
1628
case ANV_FENCE_TYPE_BO:
1629
case ANV_FENCE_TYPE_WSI_BO:
1630
switch (impl->bo.state) {
1631
case ANV_BO_FENCE_STATE_RESET:
1632
/* If it hasn't even been sent off to the GPU yet, it's not ready */
1633
return VK_NOT_READY;
1634
1635
case ANV_BO_FENCE_STATE_SIGNALED:
1636
/* It's been signaled, return success */
1637
return VK_SUCCESS;
1638
1639
case ANV_BO_FENCE_STATE_SUBMITTED: {
1640
VkResult result = anv_device_bo_busy(device, impl->bo.bo);
1641
if (result == VK_SUCCESS) {
1642
impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1643
return VK_SUCCESS;
1644
} else {
1645
return result;
1646
}
1647
}
1648
default:
1649
unreachable("Invalid fence status");
1650
}
1651
1652
case ANV_FENCE_TYPE_SYNCOBJ: {
1653
if (device->has_thread_submit) {
1654
uint64_t binary_value = 0;
1655
int ret = anv_gem_syncobj_timeline_wait(device, &impl->syncobj,
1656
&binary_value, 1, 0,
1657
true /* wait_all */,
1658
false /* wait_materialize */);
1659
if (ret == -1) {
1660
if (errno == ETIME) {
1661
return VK_NOT_READY;
1662
} else {
1663
/* We don't know the real error. */
1664
return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1665
}
1666
} else {
1667
return VK_SUCCESS;
1668
}
1669
} else {
1670
int ret = anv_gem_syncobj_wait(device, &impl->syncobj, 1, 0, false);
1671
if (ret == -1) {
1672
if (errno == ETIME) {
1673
return VK_NOT_READY;
1674
} else {
1675
/* We don't know the real error. */
1676
return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1677
}
1678
} else {
1679
return VK_SUCCESS;
1680
}
1681
}
1682
}
1683
1684
default:
1685
unreachable("Invalid fence type");
1686
}
1687
}
1688
1689
static VkResult
1690
anv_wait_for_syncobj_fences(struct anv_device *device,
1691
uint32_t fenceCount,
1692
const VkFence *pFences,
1693
bool waitAll,
1694
uint64_t abs_timeout_ns)
1695
{
1696
uint32_t *syncobjs = vk_zalloc(&device->vk.alloc,
1697
sizeof(*syncobjs) * fenceCount, 8,
1698
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
1699
if (!syncobjs)
1700
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
1701
1702
for (uint32_t i = 0; i < fenceCount; i++) {
1703
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1704
assert(fence->permanent.type == ANV_FENCE_TYPE_SYNCOBJ);
1705
1706
struct anv_fence_impl *impl =
1707
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1708
&fence->temporary : &fence->permanent;
1709
1710
assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
1711
syncobjs[i] = impl->syncobj;
1712
}
1713
1714
int ret = 0;
1715
/* The gem_syncobj_wait ioctl may return early due to an inherent
1716
* limitation in the way it computes timeouts. Loop until we've actually
1717
* passed the timeout.
1718
*/
1719
do {
1720
ret = anv_gem_syncobj_wait(device, syncobjs, fenceCount,
1721
abs_timeout_ns, waitAll);
1722
} while (ret == -1 && errno == ETIME && anv_gettime_ns() < abs_timeout_ns);
1723
1724
vk_free(&device->vk.alloc, syncobjs);
1725
1726
if (ret == -1) {
1727
if (errno == ETIME) {
1728
return VK_TIMEOUT;
1729
} else {
1730
/* We don't know the real error. */
1731
return anv_device_set_lost(device, "drm_syncobj_wait failed: %m");
1732
}
1733
} else {
1734
return VK_SUCCESS;
1735
}
1736
}
1737
1738
static VkResult
1739
anv_wait_for_bo_fences(struct anv_device *device,
1740
uint32_t fenceCount,
1741
const VkFence *pFences,
1742
bool waitAll,
1743
uint64_t abs_timeout_ns)
1744
{
1745
VkResult result = VK_SUCCESS;
1746
uint32_t pending_fences = fenceCount;
1747
while (pending_fences) {
1748
pending_fences = 0;
1749
bool signaled_fences = false;
1750
for (uint32_t i = 0; i < fenceCount; i++) {
1751
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1752
1753
struct anv_fence_impl *impl =
1754
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1755
&fence->temporary : &fence->permanent;
1756
assert(impl->type == ANV_FENCE_TYPE_BO ||
1757
impl->type == ANV_FENCE_TYPE_WSI_BO);
1758
1759
switch (impl->bo.state) {
1760
case ANV_BO_FENCE_STATE_RESET:
1761
/* This fence hasn't been submitted yet, we'll catch it the next
1762
* time around. Yes, this may mean we dead-loop but, short of
1763
* lots of locking and a condition variable, there's not much that
1764
* we can do about that.
1765
*/
1766
pending_fences++;
1767
continue;
1768
1769
case ANV_BO_FENCE_STATE_SIGNALED:
1770
/* This fence is not pending. If waitAll isn't set, we can return
1771
* early. Otherwise, we have to keep going.
1772
*/
1773
if (!waitAll) {
1774
result = VK_SUCCESS;
1775
goto done;
1776
}
1777
continue;
1778
1779
case ANV_BO_FENCE_STATE_SUBMITTED:
1780
/* These are the fences we really care about. Go ahead and wait
1781
* on it until we hit a timeout.
1782
*/
1783
result = anv_device_wait(device, impl->bo.bo,
1784
anv_get_relative_timeout(abs_timeout_ns));
1785
switch (result) {
1786
case VK_SUCCESS:
1787
impl->bo.state = ANV_BO_FENCE_STATE_SIGNALED;
1788
signaled_fences = true;
1789
if (!waitAll)
1790
goto done;
1791
break;
1792
1793
case VK_TIMEOUT:
1794
goto done;
1795
1796
default:
1797
return result;
1798
}
1799
}
1800
}
1801
1802
if (pending_fences && !signaled_fences) {
1803
/* If we've hit this then someone decided to vkWaitForFences before
1804
* they've actually submitted any of them to a queue. This is a
1805
* fairly pessimal case, so it's ok to lock here and use a standard
1806
* pthreads condition variable.
1807
*/
1808
pthread_mutex_lock(&device->mutex);
1809
1810
/* It's possible that some of the fences have changed state since the
1811
* last time we checked. Now that we have the lock, check for
1812
* pending fences again and don't wait if it's changed.
1813
*/
1814
uint32_t now_pending_fences = 0;
1815
for (uint32_t i = 0; i < fenceCount; i++) {
1816
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1817
if (fence->permanent.bo.state == ANV_BO_FENCE_STATE_RESET)
1818
now_pending_fences++;
1819
}
1820
assert(now_pending_fences <= pending_fences);
1821
1822
if (now_pending_fences == pending_fences) {
1823
struct timespec abstime = {
1824
.tv_sec = abs_timeout_ns / NSEC_PER_SEC,
1825
.tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
1826
};
1827
1828
ASSERTED int ret;
1829
ret = pthread_cond_timedwait(&device->queue_submit,
1830
&device->mutex, &abstime);
1831
assert(ret != EINVAL);
1832
if (anv_gettime_ns() >= abs_timeout_ns) {
1833
pthread_mutex_unlock(&device->mutex);
1834
result = VK_TIMEOUT;
1835
goto done;
1836
}
1837
}
1838
1839
pthread_mutex_unlock(&device->mutex);
1840
}
1841
}
1842
1843
done:
1844
if (anv_device_is_lost(device))
1845
return VK_ERROR_DEVICE_LOST;
1846
1847
return result;
1848
}
1849
1850
static VkResult
1851
anv_wait_for_wsi_fence(struct anv_device *device,
1852
struct anv_fence_impl *impl,
1853
uint64_t abs_timeout)
1854
{
1855
return impl->fence_wsi->wait(impl->fence_wsi, abs_timeout);
1856
}
1857
1858
static VkResult
1859
anv_wait_for_fences(struct anv_device *device,
1860
uint32_t fenceCount,
1861
const VkFence *pFences,
1862
bool waitAll,
1863
uint64_t abs_timeout)
1864
{
1865
VkResult result = VK_SUCCESS;
1866
1867
if (fenceCount <= 1 || waitAll) {
1868
for (uint32_t i = 0; i < fenceCount; i++) {
1869
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1870
struct anv_fence_impl *impl =
1871
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1872
&fence->temporary : &fence->permanent;
1873
1874
switch (impl->type) {
1875
case ANV_FENCE_TYPE_BO:
1876
assert(!device->physical->has_syncobj_wait);
1877
FALLTHROUGH;
1878
case ANV_FENCE_TYPE_WSI_BO:
1879
result = anv_wait_for_bo_fences(device, 1, &pFences[i],
1880
true, abs_timeout);
1881
break;
1882
case ANV_FENCE_TYPE_SYNCOBJ:
1883
result = anv_wait_for_syncobj_fences(device, 1, &pFences[i],
1884
true, abs_timeout);
1885
break;
1886
case ANV_FENCE_TYPE_WSI:
1887
result = anv_wait_for_wsi_fence(device, impl, abs_timeout);
1888
break;
1889
case ANV_FENCE_TYPE_NONE:
1890
result = VK_SUCCESS;
1891
break;
1892
}
1893
if (result != VK_SUCCESS)
1894
return result;
1895
}
1896
} else {
1897
do {
1898
for (uint32_t i = 0; i < fenceCount; i++) {
1899
if (anv_wait_for_fences(device, 1, &pFences[i], true, 0) == VK_SUCCESS)
1900
return VK_SUCCESS;
1901
}
1902
} while (anv_gettime_ns() < abs_timeout);
1903
result = VK_TIMEOUT;
1904
}
1905
return result;
1906
}
1907
1908
static bool anv_all_fences_syncobj(uint32_t fenceCount, const VkFence *pFences)
1909
{
1910
for (uint32_t i = 0; i < fenceCount; ++i) {
1911
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1912
struct anv_fence_impl *impl =
1913
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1914
&fence->temporary : &fence->permanent;
1915
if (impl->type != ANV_FENCE_TYPE_SYNCOBJ)
1916
return false;
1917
}
1918
return true;
1919
}
1920
1921
static bool anv_all_fences_bo(uint32_t fenceCount, const VkFence *pFences)
1922
{
1923
for (uint32_t i = 0; i < fenceCount; ++i) {
1924
ANV_FROM_HANDLE(anv_fence, fence, pFences[i]);
1925
struct anv_fence_impl *impl =
1926
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
1927
&fence->temporary : &fence->permanent;
1928
if (impl->type != ANV_FENCE_TYPE_BO &&
1929
impl->type != ANV_FENCE_TYPE_WSI_BO)
1930
return false;
1931
}
1932
return true;
1933
}
1934
1935
VkResult anv_WaitForFences(
1936
VkDevice _device,
1937
uint32_t fenceCount,
1938
const VkFence* pFences,
1939
VkBool32 waitAll,
1940
uint64_t timeout)
1941
{
1942
ANV_FROM_HANDLE(anv_device, device, _device);
1943
1944
if (device->no_hw)
1945
return VK_SUCCESS;
1946
1947
if (anv_device_is_lost(device))
1948
return VK_ERROR_DEVICE_LOST;
1949
1950
uint64_t abs_timeout = anv_get_absolute_timeout(timeout);
1951
if (anv_all_fences_syncobj(fenceCount, pFences)) {
1952
return anv_wait_for_syncobj_fences(device, fenceCount, pFences,
1953
waitAll, abs_timeout);
1954
} else if (anv_all_fences_bo(fenceCount, pFences)) {
1955
return anv_wait_for_bo_fences(device, fenceCount, pFences,
1956
waitAll, abs_timeout);
1957
} else {
1958
return anv_wait_for_fences(device, fenceCount, pFences,
1959
waitAll, abs_timeout);
1960
}
1961
}
1962
1963
void anv_GetPhysicalDeviceExternalFenceProperties(
1964
VkPhysicalDevice physicalDevice,
1965
const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
1966
VkExternalFenceProperties* pExternalFenceProperties)
1967
{
1968
ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
1969
1970
switch (pExternalFenceInfo->handleType) {
1971
case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
1972
case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT:
1973
if (device->has_syncobj_wait) {
1974
pExternalFenceProperties->exportFromImportedHandleTypes =
1975
VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1976
VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1977
pExternalFenceProperties->compatibleHandleTypes =
1978
VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT |
1979
VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
1980
pExternalFenceProperties->externalFenceFeatures =
1981
VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT |
1982
VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT;
1983
return;
1984
}
1985
break;
1986
1987
default:
1988
break;
1989
}
1990
1991
pExternalFenceProperties->exportFromImportedHandleTypes = 0;
1992
pExternalFenceProperties->compatibleHandleTypes = 0;
1993
pExternalFenceProperties->externalFenceFeatures = 0;
1994
}
1995
1996
VkResult anv_ImportFenceFdKHR(
1997
VkDevice _device,
1998
const VkImportFenceFdInfoKHR* pImportFenceFdInfo)
1999
{
2000
ANV_FROM_HANDLE(anv_device, device, _device);
2001
ANV_FROM_HANDLE(anv_fence, fence, pImportFenceFdInfo->fence);
2002
int fd = pImportFenceFdInfo->fd;
2003
2004
assert(pImportFenceFdInfo->sType ==
2005
VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR);
2006
2007
struct anv_fence_impl new_impl = {
2008
.type = ANV_FENCE_TYPE_NONE,
2009
};
2010
2011
switch (pImportFenceFdInfo->handleType) {
2012
case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT:
2013
new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
2014
2015
new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
2016
if (!new_impl.syncobj)
2017
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2018
2019
break;
2020
2021
case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
2022
/* Sync files are a bit tricky. Because we want to continue using the
2023
* syncobj implementation of WaitForFences, we don't use the sync file
2024
* directly but instead import it into a syncobj.
2025
*/
2026
new_impl.type = ANV_FENCE_TYPE_SYNCOBJ;
2027
2028
/* "If handleType is VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, the
2029
* special value -1 for fd is treated like a valid sync file descriptor
2030
* referring to an object that has already signaled. The import
2031
* operation will succeed and the VkFence will have a temporarily
2032
* imported payload as if a valid file descriptor had been provided."
2033
*/
2034
uint32_t create_flags = 0;
2035
if (fd == -1)
2036
create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
2037
2038
new_impl.syncobj = anv_gem_syncobj_create(device, create_flags);
2039
if (!new_impl.syncobj)
2040
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2041
2042
if (fd != -1 &&
2043
anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
2044
anv_gem_syncobj_destroy(device, new_impl.syncobj);
2045
return vk_errorf(device, NULL, VK_ERROR_INVALID_EXTERNAL_HANDLE,
2046
"syncobj sync file import failed: %m");
2047
}
2048
break;
2049
}
2050
2051
default:
2052
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2053
}
2054
2055
/* From the Vulkan 1.0.53 spec:
2056
*
2057
* "Importing a fence payload from a file descriptor transfers
2058
* ownership of the file descriptor from the application to the
2059
* Vulkan implementation. The application must not perform any
2060
* operations on the file descriptor after a successful import."
2061
*
2062
* If the import fails, we leave the file descriptor open.
2063
*/
2064
if (fd != -1)
2065
close(fd);
2066
2067
if (pImportFenceFdInfo->flags & VK_FENCE_IMPORT_TEMPORARY_BIT) {
2068
anv_fence_impl_cleanup(device, &fence->temporary);
2069
fence->temporary = new_impl;
2070
} else {
2071
anv_fence_impl_cleanup(device, &fence->permanent);
2072
fence->permanent = new_impl;
2073
}
2074
2075
return VK_SUCCESS;
2076
}
2077
2078
/* The sideband payload of the DRM syncobj was incremented when the
2079
* application called vkQueueSubmit(). Here we wait for a fence with the same
2080
* value to materialize so that we can exporting (typically as a SyncFD).
2081
*/
2082
static VkResult
2083
wait_syncobj_materialize(struct anv_device *device,
2084
uint32_t syncobj,
2085
int *fd)
2086
{
2087
if (!device->has_thread_submit)
2088
return VK_SUCCESS;
2089
2090
uint64_t binary_value = 0;
2091
/* We might need to wait until the fence materializes before we can
2092
* export to a sync FD when we use a thread for submission.
2093
*/
2094
if (anv_gem_syncobj_timeline_wait(device, &syncobj, &binary_value, 1,
2095
anv_get_absolute_timeout(5ull * NSEC_PER_SEC),
2096
true /* wait_all */,
2097
true /* wait_materialize */))
2098
return anv_device_set_lost(device, "anv_gem_syncobj_timeline_wait failed: %m");
2099
2100
return VK_SUCCESS;
2101
}
2102
2103
VkResult anv_GetFenceFdKHR(
2104
VkDevice _device,
2105
const VkFenceGetFdInfoKHR* pGetFdInfo,
2106
int* pFd)
2107
{
2108
ANV_FROM_HANDLE(anv_device, device, _device);
2109
ANV_FROM_HANDLE(anv_fence, fence, pGetFdInfo->fence);
2110
2111
assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR);
2112
2113
struct anv_fence_impl *impl =
2114
fence->temporary.type != ANV_FENCE_TYPE_NONE ?
2115
&fence->temporary : &fence->permanent;
2116
2117
assert(impl->type == ANV_FENCE_TYPE_SYNCOBJ);
2118
switch (pGetFdInfo->handleType) {
2119
case VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT: {
2120
int fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
2121
if (fd < 0)
2122
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2123
2124
*pFd = fd;
2125
break;
2126
}
2127
2128
case VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT: {
2129
VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);
2130
if (result != VK_SUCCESS)
2131
return result;
2132
2133
int fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
2134
if (fd < 0)
2135
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2136
2137
*pFd = fd;
2138
break;
2139
}
2140
2141
default:
2142
unreachable("Invalid fence export handle type");
2143
}
2144
2145
/* From the Vulkan 1.0.53 spec:
2146
*
2147
* "Export operations have the same transference as the specified handle
2148
* type’s import operations. [...] If the fence was using a
2149
* temporarily imported payload, the fence’s prior permanent payload
2150
* will be restored.
2151
*/
2152
if (impl == &fence->temporary)
2153
anv_fence_impl_cleanup(device, impl);
2154
2155
return VK_SUCCESS;
2156
}
2157
2158
// Queue semaphore functions
2159
2160
static VkSemaphoreTypeKHR
2161
get_semaphore_type(const void *pNext, uint64_t *initial_value)
2162
{
2163
const VkSemaphoreTypeCreateInfoKHR *type_info =
2164
vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);
2165
2166
if (!type_info)
2167
return VK_SEMAPHORE_TYPE_BINARY_KHR;
2168
2169
if (initial_value)
2170
*initial_value = type_info->initialValue;
2171
return type_info->semaphoreType;
2172
}
2173
2174
static VkResult
2175
binary_semaphore_create(struct anv_device *device,
2176
struct anv_semaphore_impl *impl,
2177
bool exportable)
2178
{
2179
if (device->physical->has_syncobj) {
2180
impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
2181
impl->syncobj = anv_gem_syncobj_create(device, 0);
2182
if (!impl->syncobj)
2183
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2184
return VK_SUCCESS;
2185
} else {
2186
impl->type = ANV_SEMAPHORE_TYPE_BO;
2187
VkResult result =
2188
anv_device_alloc_bo(device, "binary-semaphore", 4096,
2189
ANV_BO_ALLOC_EXTERNAL |
2190
ANV_BO_ALLOC_IMPLICIT_SYNC,
2191
0 /* explicit_address */,
2192
&impl->bo);
2193
/* If we're going to use this as a fence, we need to *not* have the
2194
* EXEC_OBJECT_ASYNC bit set.
2195
*/
2196
assert(!(impl->bo->flags & EXEC_OBJECT_ASYNC));
2197
return result;
2198
}
2199
}
2200
2201
static VkResult
2202
timeline_semaphore_create(struct anv_device *device,
2203
struct anv_semaphore_impl *impl,
2204
uint64_t initial_value)
2205
{
2206
if (device->has_thread_submit) {
2207
impl->type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE;
2208
impl->syncobj = anv_gem_syncobj_create(device, 0);
2209
if (!impl->syncobj)
2210
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2211
if (initial_value) {
2212
if (anv_gem_syncobj_timeline_signal(device,
2213
&impl->syncobj,
2214
&initial_value, 1)) {
2215
anv_gem_syncobj_destroy(device, impl->syncobj);
2216
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2217
}
2218
}
2219
} else {
2220
impl->type = ANV_SEMAPHORE_TYPE_TIMELINE;
2221
anv_timeline_init(device, &impl->timeline, initial_value);
2222
}
2223
2224
return VK_SUCCESS;
2225
}
2226
2227
VkResult anv_CreateSemaphore(
2228
VkDevice _device,
2229
const VkSemaphoreCreateInfo* pCreateInfo,
2230
const VkAllocationCallbacks* pAllocator,
2231
VkSemaphore* pSemaphore)
2232
{
2233
ANV_FROM_HANDLE(anv_device, device, _device);
2234
struct anv_semaphore *semaphore;
2235
2236
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
2237
2238
uint64_t timeline_value = 0;
2239
VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);
2240
2241
semaphore = vk_object_alloc(&device->vk, NULL, sizeof(*semaphore),
2242
VK_OBJECT_TYPE_SEMAPHORE);
2243
if (semaphore == NULL)
2244
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2245
2246
p_atomic_set(&semaphore->refcount, 1);
2247
2248
const VkExportSemaphoreCreateInfo *export =
2249
vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
2250
VkExternalSemaphoreHandleTypeFlags handleTypes =
2251
export ? export->handleTypes : 0;
2252
VkResult result;
2253
2254
if (handleTypes == 0) {
2255
if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
2256
result = binary_semaphore_create(device, &semaphore->permanent, false);
2257
else
2258
result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
2259
if (result != VK_SUCCESS) {
2260
vk_object_free(&device->vk, pAllocator, semaphore);
2261
return result;
2262
}
2263
} else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) {
2264
assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
2265
if (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR)
2266
result = binary_semaphore_create(device, &semaphore->permanent, true);
2267
else
2268
result = timeline_semaphore_create(device, &semaphore->permanent, timeline_value);
2269
if (result != VK_SUCCESS) {
2270
vk_object_free(&device->vk, pAllocator, semaphore);
2271
return result;
2272
}
2273
} else if (handleTypes & VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
2274
assert(handleTypes == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT);
2275
assert(sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR);
2276
if (device->physical->has_syncobj) {
2277
semaphore->permanent.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
2278
semaphore->permanent.syncobj = anv_gem_syncobj_create(device, 0);
2279
if (!semaphore->permanent.syncobj) {
2280
vk_object_free(&device->vk, pAllocator, semaphore);
2281
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2282
}
2283
} else {
2284
semaphore->permanent.type = ANV_SEMAPHORE_TYPE_SYNC_FILE;
2285
semaphore->permanent.fd = -1;
2286
}
2287
} else {
2288
assert(!"Unknown handle type");
2289
vk_object_free(&device->vk, pAllocator, semaphore);
2290
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2291
}
2292
2293
semaphore->temporary.type = ANV_SEMAPHORE_TYPE_NONE;
2294
2295
*pSemaphore = anv_semaphore_to_handle(semaphore);
2296
2297
return VK_SUCCESS;
2298
}
2299
2300
static void
2301
anv_semaphore_impl_cleanup(struct anv_device *device,
2302
struct anv_semaphore_impl *impl)
2303
{
2304
switch (impl->type) {
2305
case ANV_SEMAPHORE_TYPE_NONE:
2306
case ANV_SEMAPHORE_TYPE_DUMMY:
2307
/* Dummy. Nothing to do */
2308
break;
2309
2310
case ANV_SEMAPHORE_TYPE_BO:
2311
case ANV_SEMAPHORE_TYPE_WSI_BO:
2312
anv_device_release_bo(device, impl->bo);
2313
break;
2314
2315
case ANV_SEMAPHORE_TYPE_SYNC_FILE:
2316
if (impl->fd >= 0)
2317
close(impl->fd);
2318
break;
2319
2320
case ANV_SEMAPHORE_TYPE_TIMELINE:
2321
anv_timeline_finish(device, &impl->timeline);
2322
break;
2323
2324
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
2325
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
2326
anv_gem_syncobj_destroy(device, impl->syncobj);
2327
break;
2328
2329
default:
2330
unreachable("Invalid semaphore type");
2331
}
2332
2333
impl->type = ANV_SEMAPHORE_TYPE_NONE;
2334
}
2335
2336
void
2337
anv_semaphore_reset_temporary(struct anv_device *device,
2338
struct anv_semaphore *semaphore)
2339
{
2340
if (semaphore->temporary.type == ANV_SEMAPHORE_TYPE_NONE)
2341
return;
2342
2343
anv_semaphore_impl_cleanup(device, &semaphore->temporary);
2344
}
2345
2346
static struct anv_semaphore *
2347
anv_semaphore_ref(struct anv_semaphore *semaphore)
2348
{
2349
assert(semaphore->refcount);
2350
p_atomic_inc(&semaphore->refcount);
2351
return semaphore;
2352
}
2353
2354
static void
2355
anv_semaphore_unref(struct anv_device *device, struct anv_semaphore *semaphore)
2356
{
2357
if (!p_atomic_dec_zero(&semaphore->refcount))
2358
return;
2359
2360
anv_semaphore_impl_cleanup(device, &semaphore->temporary);
2361
anv_semaphore_impl_cleanup(device, &semaphore->permanent);
2362
2363
vk_object_free(&device->vk, NULL, semaphore);
2364
}
2365
2366
void anv_DestroySemaphore(
2367
VkDevice _device,
2368
VkSemaphore _semaphore,
2369
const VkAllocationCallbacks* pAllocator)
2370
{
2371
ANV_FROM_HANDLE(anv_device, device, _device);
2372
ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
2373
2374
if (semaphore == NULL)
2375
return;
2376
2377
anv_semaphore_unref(device, semaphore);
2378
}
2379
2380
void anv_GetPhysicalDeviceExternalSemaphoreProperties(
2381
VkPhysicalDevice physicalDevice,
2382
const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
2383
VkExternalSemaphoreProperties* pExternalSemaphoreProperties)
2384
{
2385
ANV_FROM_HANDLE(anv_physical_device, device, physicalDevice);
2386
2387
VkSemaphoreTypeKHR sem_type =
2388
get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
2389
2390
switch (pExternalSemaphoreInfo->handleType) {
2391
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
2392
/* Timeline semaphores are not exportable, unless we have threaded
2393
* submission.
2394
*/
2395
if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR && !device->has_thread_submit)
2396
break;
2397
pExternalSemaphoreProperties->exportFromImportedHandleTypes =
2398
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2399
pExternalSemaphoreProperties->compatibleHandleTypes =
2400
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
2401
pExternalSemaphoreProperties->externalSemaphoreFeatures =
2402
VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
2403
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
2404
return;
2405
2406
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
2407
if (sem_type == VK_SEMAPHORE_TYPE_TIMELINE_KHR)
2408
break;
2409
if (!device->has_exec_fence)
2410
break;
2411
pExternalSemaphoreProperties->exportFromImportedHandleTypes =
2412
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
2413
pExternalSemaphoreProperties->compatibleHandleTypes =
2414
VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
2415
pExternalSemaphoreProperties->externalSemaphoreFeatures =
2416
VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
2417
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
2418
return;
2419
2420
default:
2421
break;
2422
}
2423
2424
pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
2425
pExternalSemaphoreProperties->compatibleHandleTypes = 0;
2426
pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
2427
}
2428
2429
VkResult anv_ImportSemaphoreFdKHR(
2430
VkDevice _device,
2431
const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo)
2432
{
2433
ANV_FROM_HANDLE(anv_device, device, _device);
2434
ANV_FROM_HANDLE(anv_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
2435
int fd = pImportSemaphoreFdInfo->fd;
2436
2437
struct anv_semaphore_impl new_impl = {
2438
.type = ANV_SEMAPHORE_TYPE_NONE,
2439
};
2440
2441
switch (pImportSemaphoreFdInfo->handleType) {
2442
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
2443
if (device->physical->has_syncobj) {
2444
/* When importing non temporarily, reuse the semaphore's existing
2445
* type. The Linux/DRM implementation allows to interchangeably use
2446
* binary & timeline semaphores and we have no way to differenciate
2447
* them.
2448
*/
2449
if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT)
2450
new_impl.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ;
2451
else
2452
new_impl.type = semaphore->permanent.type;
2453
2454
new_impl.syncobj = anv_gem_syncobj_fd_to_handle(device, fd);
2455
if (!new_impl.syncobj)
2456
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2457
} else {
2458
new_impl.type = ANV_SEMAPHORE_TYPE_BO;
2459
2460
VkResult result = anv_device_import_bo(device, fd,
2461
ANV_BO_ALLOC_EXTERNAL |
2462
ANV_BO_ALLOC_IMPLICIT_SYNC,
2463
0 /* client_address */,
2464
&new_impl.bo);
2465
if (result != VK_SUCCESS)
2466
return result;
2467
2468
if (new_impl.bo->size < 4096) {
2469
anv_device_release_bo(device, new_impl.bo);
2470
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2471
}
2472
2473
/* If we're going to use this as a fence, we need to *not* have the
2474
* EXEC_OBJECT_ASYNC bit set.
2475
*/
2476
assert(!(new_impl.bo->flags & EXEC_OBJECT_ASYNC));
2477
}
2478
2479
/* From the Vulkan spec:
2480
*
2481
* "Importing semaphore state from a file descriptor transfers
2482
* ownership of the file descriptor from the application to the
2483
* Vulkan implementation. The application must not perform any
2484
* operations on the file descriptor after a successful import."
2485
*
2486
* If the import fails, we leave the file descriptor open.
2487
*/
2488
close(fd);
2489
break;
2490
2491
case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
2492
if (device->physical->has_syncobj) {
2493
uint32_t create_flags = 0;
2494
2495
if (fd == -1)
2496
create_flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
2497
2498
new_impl = (struct anv_semaphore_impl) {
2499
.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ,
2500
.syncobj = anv_gem_syncobj_create(device, create_flags),
2501
};
2502
2503
if (!new_impl.syncobj)
2504
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2505
2506
if (fd != -1) {
2507
if (anv_gem_syncobj_import_sync_file(device, new_impl.syncobj, fd)) {
2508
anv_gem_syncobj_destroy(device, new_impl.syncobj);
2509
return vk_errorf(device, NULL, VK_ERROR_INVALID_EXTERNAL_HANDLE,
2510
"syncobj sync file import failed: %m");
2511
}
2512
/* Ownership of the FD is transfered to Anv. Since we don't need it
2513
* anymore because the associated fence has been put into a syncobj,
2514
* we must close the FD.
2515
*/
2516
close(fd);
2517
}
2518
} else {
2519
new_impl = (struct anv_semaphore_impl) {
2520
.type = ANV_SEMAPHORE_TYPE_SYNC_FILE,
2521
.fd = fd,
2522
};
2523
}
2524
break;
2525
2526
default:
2527
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2528
}
2529
2530
if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
2531
anv_semaphore_impl_cleanup(device, &semaphore->temporary);
2532
semaphore->temporary = new_impl;
2533
} else {
2534
anv_semaphore_impl_cleanup(device, &semaphore->permanent);
2535
semaphore->permanent = new_impl;
2536
}
2537
2538
return VK_SUCCESS;
2539
}
2540
2541
VkResult anv_GetSemaphoreFdKHR(
2542
VkDevice _device,
2543
const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
2544
int* pFd)
2545
{
2546
ANV_FROM_HANDLE(anv_device, device, _device);
2547
ANV_FROM_HANDLE(anv_semaphore, semaphore, pGetFdInfo->semaphore);
2548
VkResult result;
2549
int fd;
2550
2551
assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
2552
2553
struct anv_semaphore_impl *impl =
2554
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2555
&semaphore->temporary : &semaphore->permanent;
2556
2557
switch (impl->type) {
2558
case ANV_SEMAPHORE_TYPE_BO:
2559
result = anv_device_export_bo(device, impl->bo, pFd);
2560
if (result != VK_SUCCESS)
2561
return result;
2562
break;
2563
2564
case ANV_SEMAPHORE_TYPE_SYNC_FILE: {
2565
/* There's a potential race here with vkQueueSubmit if you are trying
2566
* to export a semaphore Fd while the queue submit is still happening.
2567
* This can happen if we see all dependencies get resolved via timeline
2568
* semaphore waits completing before the execbuf completes and we
2569
* process the resulting out fence. To work around this, take a lock
2570
* around grabbing the fd.
2571
*/
2572
pthread_mutex_lock(&device->mutex);
2573
2574
/* From the Vulkan 1.0.53 spec:
2575
*
2576
* "...exporting a semaphore payload to a handle with copy
2577
* transference has the same side effects on the source
2578
* semaphore’s payload as executing a semaphore wait operation."
2579
*
2580
* In other words, it may still be a SYNC_FD semaphore, but it's now
2581
* considered to have been waited on and no longer has a sync file
2582
* attached.
2583
*/
2584
int fd = impl->fd;
2585
impl->fd = -1;
2586
2587
pthread_mutex_unlock(&device->mutex);
2588
2589
/* There are two reasons why this could happen:
2590
*
2591
* 1) The user is trying to export without submitting something that
2592
* signals the semaphore. If this is the case, it's their bug so
2593
* what we return here doesn't matter.
2594
*
2595
* 2) The kernel didn't give us a file descriptor. The most likely
2596
* reason for this is running out of file descriptors.
2597
*/
2598
if (fd < 0)
2599
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2600
2601
*pFd = fd;
2602
return VK_SUCCESS;
2603
}
2604
2605
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ:
2606
if (pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT) {
2607
VkResult result = wait_syncobj_materialize(device, impl->syncobj, pFd);
2608
if (result != VK_SUCCESS)
2609
return result;
2610
2611
fd = anv_gem_syncobj_export_sync_file(device, impl->syncobj);
2612
} else {
2613
assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
2614
fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
2615
}
2616
if (fd < 0)
2617
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2618
*pFd = fd;
2619
break;
2620
2621
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE:
2622
assert(pGetFdInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
2623
fd = anv_gem_syncobj_handle_to_fd(device, impl->syncobj);
2624
if (fd < 0)
2625
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
2626
*pFd = fd;
2627
break;
2628
2629
default:
2630
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE);
2631
}
2632
2633
/* From the Vulkan 1.0.53 spec:
2634
*
2635
* "Export operations have the same transference as the specified handle
2636
* type’s import operations. [...] If the semaphore was using a
2637
* temporarily imported payload, the semaphore’s prior permanent payload
2638
* will be restored.
2639
*/
2640
if (impl == &semaphore->temporary)
2641
anv_semaphore_impl_cleanup(device, impl);
2642
2643
return VK_SUCCESS;
2644
}
2645
2646
VkResult anv_GetSemaphoreCounterValue(
2647
VkDevice _device,
2648
VkSemaphore _semaphore,
2649
uint64_t* pValue)
2650
{
2651
ANV_FROM_HANDLE(anv_device, device, _device);
2652
ANV_FROM_HANDLE(anv_semaphore, semaphore, _semaphore);
2653
2654
struct anv_semaphore_impl *impl =
2655
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2656
&semaphore->temporary : &semaphore->permanent;
2657
2658
switch (impl->type) {
2659
case ANV_SEMAPHORE_TYPE_TIMELINE: {
2660
pthread_mutex_lock(&device->mutex);
2661
anv_timeline_gc_locked(device, &impl->timeline);
2662
*pValue = impl->timeline.highest_past;
2663
pthread_mutex_unlock(&device->mutex);
2664
return VK_SUCCESS;
2665
}
2666
2667
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {
2668
int ret = anv_gem_syncobj_timeline_query(device, &impl->syncobj, pValue, 1);
2669
2670
if (ret != 0)
2671
return anv_device_set_lost(device, "unable to query timeline syncobj");
2672
2673
return VK_SUCCESS;
2674
}
2675
2676
default:
2677
unreachable("Invalid semaphore type");
2678
}
2679
}
2680
2681
static VkResult
2682
anv_timeline_wait_locked(struct anv_device *device,
2683
struct anv_timeline *timeline,
2684
uint64_t serial, uint64_t abs_timeout_ns)
2685
{
2686
/* Wait on the queue_submit condition variable until the timeline has a
2687
* time point pending that's at least as high as serial.
2688
*/
2689
while (timeline->highest_pending < serial) {
2690
struct timespec abstime = {
2691
.tv_sec = abs_timeout_ns / NSEC_PER_SEC,
2692
.tv_nsec = abs_timeout_ns % NSEC_PER_SEC,
2693
};
2694
2695
UNUSED int ret = pthread_cond_timedwait(&device->queue_submit,
2696
&device->mutex, &abstime);
2697
assert(ret != EINVAL);
2698
if (anv_gettime_ns() >= abs_timeout_ns &&
2699
timeline->highest_pending < serial)
2700
return VK_TIMEOUT;
2701
}
2702
2703
while (1) {
2704
VkResult result = anv_timeline_gc_locked(device, timeline);
2705
if (result != VK_SUCCESS)
2706
return result;
2707
2708
if (timeline->highest_past >= serial)
2709
return VK_SUCCESS;
2710
2711
/* If we got here, our earliest time point has a busy BO */
2712
struct anv_timeline_point *point =
2713
list_first_entry(&timeline->points,
2714
struct anv_timeline_point, link);
2715
2716
/* Drop the lock while we wait. */
2717
point->waiting++;
2718
pthread_mutex_unlock(&device->mutex);
2719
2720
result = anv_device_wait(device, point->bo,
2721
anv_get_relative_timeout(abs_timeout_ns));
2722
2723
/* Pick the mutex back up */
2724
pthread_mutex_lock(&device->mutex);
2725
point->waiting--;
2726
2727
/* This covers both VK_TIMEOUT and VK_ERROR_DEVICE_LOST */
2728
if (result != VK_SUCCESS)
2729
return result;
2730
}
2731
}
2732
2733
static VkResult
2734
anv_timelines_wait(struct anv_device *device,
2735
struct anv_timeline **timelines,
2736
const uint64_t *serials,
2737
uint32_t n_timelines,
2738
bool wait_all,
2739
uint64_t abs_timeout_ns)
2740
{
2741
if (!wait_all && n_timelines > 1) {
2742
pthread_mutex_lock(&device->mutex);
2743
2744
while (1) {
2745
VkResult result;
2746
for (uint32_t i = 0; i < n_timelines; i++) {
2747
result =
2748
anv_timeline_wait_locked(device, timelines[i], serials[i], 0);
2749
if (result != VK_TIMEOUT)
2750
break;
2751
}
2752
2753
if (result != VK_TIMEOUT ||
2754
anv_gettime_ns() >= abs_timeout_ns) {
2755
pthread_mutex_unlock(&device->mutex);
2756
return result;
2757
}
2758
2759
/* If none of them are ready do a short wait so we don't completely
2760
* spin while holding the lock. The 10us is completely arbitrary.
2761
*/
2762
uint64_t abs_short_wait_ns =
2763
anv_get_absolute_timeout(
2764
MIN2((anv_gettime_ns() - abs_timeout_ns) / 10, 10 * 1000));
2765
struct timespec abstime = {
2766
.tv_sec = abs_short_wait_ns / NSEC_PER_SEC,
2767
.tv_nsec = abs_short_wait_ns % NSEC_PER_SEC,
2768
};
2769
ASSERTED int ret;
2770
ret = pthread_cond_timedwait(&device->queue_submit,
2771
&device->mutex, &abstime);
2772
assert(ret != EINVAL);
2773
}
2774
} else {
2775
VkResult result = VK_SUCCESS;
2776
pthread_mutex_lock(&device->mutex);
2777
for (uint32_t i = 0; i < n_timelines; i++) {
2778
result =
2779
anv_timeline_wait_locked(device, timelines[i],
2780
serials[i], abs_timeout_ns);
2781
if (result != VK_SUCCESS)
2782
break;
2783
}
2784
pthread_mutex_unlock(&device->mutex);
2785
return result;
2786
}
2787
}
2788
2789
VkResult anv_WaitSemaphores(
2790
VkDevice _device,
2791
const VkSemaphoreWaitInfoKHR* pWaitInfo,
2792
uint64_t timeout)
2793
{
2794
ANV_FROM_HANDLE(anv_device, device, _device);
2795
uint32_t *handles;
2796
struct anv_timeline **timelines;
2797
2798
VK_MULTIALLOC(ma);
2799
2800
VK_MULTIALLOC_DECL(&ma, uint64_t, values, pWaitInfo->semaphoreCount);
2801
if (device->has_thread_submit) {
2802
vk_multialloc_add(&ma, &handles, uint32_t, pWaitInfo->semaphoreCount);
2803
} else {
2804
vk_multialloc_add(&ma, &timelines, struct anv_timeline *,
2805
pWaitInfo->semaphoreCount);
2806
}
2807
2808
if (!vk_multialloc_alloc(&ma, &device->vk.alloc,
2809
VK_SYSTEM_ALLOCATION_SCOPE_COMMAND))
2810
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
2811
2812
uint32_t handle_count = 0;
2813
for (uint32_t i = 0; i < pWaitInfo->semaphoreCount; i++) {
2814
ANV_FROM_HANDLE(anv_semaphore, semaphore, pWaitInfo->pSemaphores[i]);
2815
struct anv_semaphore_impl *impl =
2816
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2817
&semaphore->temporary : &semaphore->permanent;
2818
2819
if (pWaitInfo->pValues[i] == 0)
2820
continue;
2821
2822
if (device->has_thread_submit) {
2823
assert(impl->type == ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE);
2824
handles[handle_count] = impl->syncobj;
2825
} else {
2826
assert(impl->type == ANV_SEMAPHORE_TYPE_TIMELINE);
2827
timelines[handle_count] = &impl->timeline;
2828
}
2829
values[handle_count] = pWaitInfo->pValues[i];
2830
handle_count++;
2831
}
2832
2833
VkResult result = VK_SUCCESS;
2834
if (handle_count > 0) {
2835
if (device->has_thread_submit) {
2836
int ret =
2837
anv_gem_syncobj_timeline_wait(device,
2838
handles, values, handle_count,
2839
anv_get_absolute_timeout(timeout),
2840
!(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
2841
false);
2842
if (ret != 0)
2843
result = errno == ETIME ? VK_TIMEOUT :
2844
anv_device_set_lost(device, "unable to wait on timeline syncobj");
2845
} else {
2846
result =
2847
anv_timelines_wait(device, timelines, values, handle_count,
2848
!(pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR),
2849
anv_get_absolute_timeout(timeout));
2850
}
2851
}
2852
2853
vk_free(&device->vk.alloc, values);
2854
2855
return result;
2856
}
2857
2858
VkResult anv_SignalSemaphore(
2859
VkDevice _device,
2860
const VkSemaphoreSignalInfoKHR* pSignalInfo)
2861
{
2862
ANV_FROM_HANDLE(anv_device, device, _device);
2863
ANV_FROM_HANDLE(anv_semaphore, semaphore, pSignalInfo->semaphore);
2864
2865
struct anv_semaphore_impl *impl =
2866
semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE ?
2867
&semaphore->temporary : &semaphore->permanent;
2868
2869
switch (impl->type) {
2870
case ANV_SEMAPHORE_TYPE_TIMELINE: {
2871
pthread_mutex_lock(&device->mutex);
2872
2873
VkResult result = anv_timeline_gc_locked(device, &impl->timeline);
2874
2875
assert(pSignalInfo->value > impl->timeline.highest_pending);
2876
2877
impl->timeline.highest_pending = impl->timeline.highest_past = pSignalInfo->value;
2878
2879
if (result == VK_SUCCESS)
2880
result = anv_device_submit_deferred_locked(device);
2881
2882
pthread_cond_broadcast(&device->queue_submit);
2883
pthread_mutex_unlock(&device->mutex);
2884
return result;
2885
}
2886
2887
case ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ_TIMELINE: {
2888
/* Timeline semaphores are created with a value of 0, so signaling on 0
2889
* is a waste of time.
2890
*/
2891
if (pSignalInfo->value == 0)
2892
return VK_SUCCESS;
2893
2894
int ret = anv_gem_syncobj_timeline_signal(device, &impl->syncobj,
2895
&pSignalInfo->value, 1);
2896
2897
return ret == 0 ? VK_SUCCESS :
2898
anv_device_set_lost(device, "unable to signal timeline syncobj");
2899
}
2900
2901
default:
2902
unreachable("Invalid semaphore type");
2903
}
2904
}
2905
2906