Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/freedreno/vulkan/tu_drm.c
4565 views
1
/*
2
* Copyright © 2018 Google, Inc.
3
* Copyright © 2015 Intel Corporation
4
*
5
* Permission is hereby granted, free of charge, to any person obtaining a
6
* copy of this software and associated documentation files (the "Software"),
7
* to deal in the Software without restriction, including without limitation
8
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
* and/or sell copies of the Software, and to permit persons to whom the
10
* Software is furnished to do so, subject to the following conditions:
11
*
12
* The above copyright notice and this permission notice (including the next
13
* paragraph) shall be included in all copies or substantial portions of the
14
* Software.
15
*
16
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
* DEALINGS IN THE SOFTWARE.
23
*/
24
25
#include <errno.h>
26
#include <fcntl.h>
27
#include <stdint.h>
28
#include <sys/ioctl.h>
29
#include <sys/mman.h>
30
#include <xf86drm.h>
31
32
#include "vk_util.h"
33
34
#include "drm-uapi/msm_drm.h"
35
#include "util/timespec.h"
36
#include "util/os_time.h"
37
38
#include "tu_private.h"
39
40
struct tu_binary_syncobj {
41
uint32_t permanent, temporary;
42
};
43
44
struct tu_timeline_point {
45
struct list_head link;
46
47
uint64_t value;
48
uint32_t syncobj;
49
uint32_t wait_count;
50
};
51
52
struct tu_timeline {
53
uint64_t highest_submitted;
54
uint64_t highest_signaled;
55
56
/* A timeline can have multiple timeline points */
57
struct list_head points;
58
59
/* A list containing points that has been already submited.
60
* A point will be moved to 'points' when new point is required
61
* at submit time.
62
*/
63
struct list_head free_points;
64
};
65
66
typedef enum {
67
TU_SEMAPHORE_BINARY,
68
TU_SEMAPHORE_TIMELINE,
69
} tu_semaphore_type;
70
71
72
struct tu_syncobj {
73
struct vk_object_base base;
74
75
tu_semaphore_type type;
76
union {
77
struct tu_binary_syncobj binary;
78
struct tu_timeline timeline;
79
};
80
};
81
82
struct tu_queue_submit
83
{
84
struct list_head link;
85
86
VkCommandBuffer *cmd_buffers;
87
uint32_t cmd_buffer_count;
88
89
struct tu_syncobj **wait_semaphores;
90
uint32_t wait_semaphore_count;
91
struct tu_syncobj **signal_semaphores;
92
uint32_t signal_semaphore_count;
93
94
struct tu_syncobj **wait_timelines;
95
uint64_t *wait_timeline_values;
96
uint32_t wait_timeline_count;
97
uint32_t wait_timeline_array_length;
98
99
struct tu_syncobj **signal_timelines;
100
uint64_t *signal_timeline_values;
101
uint32_t signal_timeline_count;
102
uint32_t signal_timeline_array_length;
103
104
struct drm_msm_gem_submit_cmd *cmds;
105
struct drm_msm_gem_submit_syncobj *in_syncobjs;
106
uint32_t nr_in_syncobjs;
107
struct drm_msm_gem_submit_syncobj *out_syncobjs;
108
uint32_t nr_out_syncobjs;
109
110
bool last_submit;
111
uint32_t entry_count;
112
uint32_t counter_pass_index;
113
};
114
115
static int
116
tu_drm_get_param(const struct tu_physical_device *dev,
117
uint32_t param,
118
uint64_t *value)
119
{
120
/* Technically this requires a pipe, but the kernel only supports one pipe
121
* anyway at the time of writing and most of these are clearly pipe
122
* independent. */
123
struct drm_msm_param req = {
124
.pipe = MSM_PIPE_3D0,
125
.param = param,
126
};
127
128
int ret = drmCommandWriteRead(dev->local_fd, DRM_MSM_GET_PARAM, &req,
129
sizeof(req));
130
if (ret)
131
return ret;
132
133
*value = req.value;
134
135
return 0;
136
}
137
138
static int
139
tu_drm_get_gpu_id(const struct tu_physical_device *dev, uint32_t *id)
140
{
141
uint64_t value;
142
int ret = tu_drm_get_param(dev, MSM_PARAM_GPU_ID, &value);
143
if (ret)
144
return ret;
145
146
*id = value;
147
return 0;
148
}
149
150
static int
151
tu_drm_get_gmem_size(const struct tu_physical_device *dev, uint32_t *size)
152
{
153
uint64_t value;
154
int ret = tu_drm_get_param(dev, MSM_PARAM_GMEM_SIZE, &value);
155
if (ret)
156
return ret;
157
158
*size = value;
159
return 0;
160
}
161
162
static int
163
tu_drm_get_gmem_base(const struct tu_physical_device *dev, uint64_t *base)
164
{
165
return tu_drm_get_param(dev, MSM_PARAM_GMEM_BASE, base);
166
}
167
168
int
169
tu_drm_submitqueue_new(const struct tu_device *dev,
170
int priority,
171
uint32_t *queue_id)
172
{
173
struct drm_msm_submitqueue req = {
174
.flags = 0,
175
.prio = priority,
176
};
177
178
int ret = drmCommandWriteRead(dev->fd,
179
DRM_MSM_SUBMITQUEUE_NEW, &req, sizeof(req));
180
if (ret)
181
return ret;
182
183
*queue_id = req.id;
184
return 0;
185
}
186
187
void
188
tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)
189
{
190
drmCommandWrite(dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE,
191
&queue_id, sizeof(uint32_t));
192
}
193
194
static void
195
tu_gem_close(const struct tu_device *dev, uint32_t gem_handle)
196
{
197
struct drm_gem_close req = {
198
.handle = gem_handle,
199
};
200
201
drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
202
}
203
204
/** Helper for DRM_MSM_GEM_INFO, returns 0 on error. */
205
static uint64_t
206
tu_gem_info(const struct tu_device *dev, uint32_t gem_handle, uint32_t info)
207
{
208
struct drm_msm_gem_info req = {
209
.handle = gem_handle,
210
.info = info,
211
};
212
213
int ret = drmCommandWriteRead(dev->fd,
214
DRM_MSM_GEM_INFO, &req, sizeof(req));
215
if (ret < 0)
216
return 0;
217
218
return req.value;
219
}
220
221
static VkResult
222
tu_bo_init(struct tu_device *dev,
223
struct tu_bo *bo,
224
uint32_t gem_handle,
225
uint64_t size,
226
bool dump)
227
{
228
uint64_t iova = tu_gem_info(dev, gem_handle, MSM_INFO_GET_IOVA);
229
if (!iova) {
230
tu_gem_close(dev, gem_handle);
231
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
232
}
233
234
*bo = (struct tu_bo) {
235
.gem_handle = gem_handle,
236
.size = size,
237
.iova = iova,
238
};
239
240
mtx_lock(&dev->bo_mutex);
241
uint32_t idx = dev->bo_count++;
242
243
/* grow the bo list if needed */
244
if (idx >= dev->bo_list_size) {
245
uint32_t new_len = idx + 64;
246
struct drm_msm_gem_submit_bo *new_ptr =
247
vk_realloc(&dev->vk.alloc, dev->bo_list, new_len * sizeof(*dev->bo_list),
248
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
249
if (!new_ptr) {
250
tu_gem_close(dev, gem_handle);
251
return VK_ERROR_OUT_OF_HOST_MEMORY;
252
}
253
254
dev->bo_list = new_ptr;
255
dev->bo_list_size = new_len;
256
}
257
258
/* grow the "bo idx" list (maps gem handles to index in the bo list) */
259
if (bo->gem_handle >= dev->bo_idx_size) {
260
uint32_t new_len = bo->gem_handle + 256;
261
uint32_t *new_ptr =
262
vk_realloc(&dev->vk.alloc, dev->bo_idx, new_len * sizeof(*dev->bo_idx),
263
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
264
if (!new_ptr) {
265
tu_gem_close(dev, gem_handle);
266
return VK_ERROR_OUT_OF_HOST_MEMORY;
267
}
268
269
dev->bo_idx = new_ptr;
270
dev->bo_idx_size = new_len;
271
}
272
273
dev->bo_idx[bo->gem_handle] = idx;
274
dev->bo_list[idx] = (struct drm_msm_gem_submit_bo) {
275
.flags = MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE |
276
COND(dump, MSM_SUBMIT_BO_DUMP),
277
.handle = gem_handle,
278
.presumed = iova,
279
};
280
mtx_unlock(&dev->bo_mutex);
281
282
return VK_SUCCESS;
283
}
284
285
VkResult
286
tu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size,
287
enum tu_bo_alloc_flags flags)
288
{
289
/* TODO: Choose better flags. As of 2018-11-12, freedreno/drm/msm_bo.c
290
* always sets `flags = MSM_BO_WC`, and we copy that behavior here.
291
*/
292
struct drm_msm_gem_new req = {
293
.size = size,
294
.flags = MSM_BO_WC
295
};
296
297
if (flags & TU_BO_ALLOC_GPU_READ_ONLY)
298
req.flags |= MSM_BO_GPU_READONLY;
299
300
int ret = drmCommandWriteRead(dev->fd,
301
DRM_MSM_GEM_NEW, &req, sizeof(req));
302
if (ret)
303
return vk_error(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);
304
305
return tu_bo_init(dev, bo, req.handle, size, flags & TU_BO_ALLOC_ALLOW_DUMP);
306
}
307
308
VkResult
309
tu_bo_init_dmabuf(struct tu_device *dev,
310
struct tu_bo *bo,
311
uint64_t size,
312
int prime_fd)
313
{
314
/* lseek() to get the real size */
315
off_t real_size = lseek(prime_fd, 0, SEEK_END);
316
lseek(prime_fd, 0, SEEK_SET);
317
if (real_size < 0 || (uint64_t) real_size < size)
318
return vk_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
319
320
uint32_t gem_handle;
321
int ret = drmPrimeFDToHandle(dev->fd, prime_fd,
322
&gem_handle);
323
if (ret)
324
return vk_error(dev->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
325
326
return tu_bo_init(dev, bo, gem_handle, size, false);
327
}
328
329
int
330
tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)
331
{
332
int prime_fd;
333
int ret = drmPrimeHandleToFD(dev->fd, bo->gem_handle,
334
DRM_CLOEXEC, &prime_fd);
335
336
return ret == 0 ? prime_fd : -1;
337
}
338
339
VkResult
340
tu_bo_map(struct tu_device *dev, struct tu_bo *bo)
341
{
342
if (bo->map)
343
return VK_SUCCESS;
344
345
uint64_t offset = tu_gem_info(dev, bo->gem_handle, MSM_INFO_GET_OFFSET);
346
if (!offset)
347
return vk_error(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY);
348
349
/* TODO: Should we use the wrapper os_mmap() like Freedreno does? */
350
void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
351
dev->fd, offset);
352
if (map == MAP_FAILED)
353
return vk_error(dev->instance, VK_ERROR_MEMORY_MAP_FAILED);
354
355
bo->map = map;
356
return VK_SUCCESS;
357
}
358
359
void
360
tu_bo_finish(struct tu_device *dev, struct tu_bo *bo)
361
{
362
assert(bo->gem_handle);
363
364
if (bo->map)
365
munmap(bo->map, bo->size);
366
367
mtx_lock(&dev->bo_mutex);
368
uint32_t idx = dev->bo_idx[bo->gem_handle];
369
dev->bo_count--;
370
dev->bo_list[idx] = dev->bo_list[dev->bo_count];
371
dev->bo_idx[dev->bo_list[idx].handle] = idx;
372
mtx_unlock(&dev->bo_mutex);
373
374
tu_gem_close(dev, bo->gem_handle);
375
}
376
377
static VkResult
378
tu_drm_device_init(struct tu_physical_device *device,
379
struct tu_instance *instance,
380
drmDevicePtr drm_device)
381
{
382
const char *path = drm_device->nodes[DRM_NODE_RENDER];
383
VkResult result = VK_SUCCESS;
384
drmVersionPtr version;
385
int fd;
386
int master_fd = -1;
387
388
fd = open(path, O_RDWR | O_CLOEXEC);
389
if (fd < 0) {
390
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
391
"failed to open device %s", path);
392
}
393
394
/* Version 1.6 added SYNCOBJ support. */
395
const int min_version_major = 1;
396
const int min_version_minor = 6;
397
398
version = drmGetVersion(fd);
399
if (!version) {
400
close(fd);
401
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
402
"failed to query kernel driver version for device %s",
403
path);
404
}
405
406
if (strcmp(version->name, "msm")) {
407
drmFreeVersion(version);
408
close(fd);
409
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
410
"device %s does not use the msm kernel driver",
411
path);
412
}
413
414
if (version->version_major != min_version_major ||
415
version->version_minor < min_version_minor) {
416
result = vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
417
"kernel driver for device %s has version %d.%d, "
418
"but Vulkan requires version >= %d.%d",
419
path,
420
version->version_major, version->version_minor,
421
min_version_major, min_version_minor);
422
drmFreeVersion(version);
423
close(fd);
424
return result;
425
}
426
427
device->msm_major_version = version->version_major;
428
device->msm_minor_version = version->version_minor;
429
430
drmFreeVersion(version);
431
432
if (instance->debug_flags & TU_DEBUG_STARTUP)
433
mesa_logi("Found compatible device '%s'.", path);
434
435
device->instance = instance;
436
437
if (instance->vk.enabled_extensions.KHR_display) {
438
master_fd =
439
open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC);
440
if (master_fd >= 0) {
441
/* TODO: free master_fd is accel is not working? */
442
}
443
}
444
445
device->master_fd = master_fd;
446
device->local_fd = fd;
447
448
if (tu_drm_get_gpu_id(device, &device->gpu_id)) {
449
result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
450
"could not get GPU ID");
451
goto fail;
452
}
453
454
if (tu_drm_get_gmem_size(device, &device->gmem_size)) {
455
result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
456
"could not get GMEM size");
457
goto fail;
458
}
459
460
if (tu_drm_get_gmem_base(device, &device->gmem_base)) {
461
result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
462
"could not get GMEM size");
463
goto fail;
464
}
465
466
device->heap.size = tu_get_system_heap_size();
467
device->heap.used = 0u;
468
device->heap.flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
469
470
result = tu_physical_device_init(device, instance);
471
if (result == VK_SUCCESS)
472
return result;
473
474
fail:
475
close(fd);
476
if (master_fd != -1)
477
close(master_fd);
478
return result;
479
}
480
481
VkResult
482
tu_enumerate_devices(struct tu_instance *instance)
483
{
484
/* TODO: Check for more devices ? */
485
drmDevicePtr devices[8];
486
VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
487
int max_devices;
488
489
instance->physical_device_count = 0;
490
491
max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
492
493
if (instance->debug_flags & TU_DEBUG_STARTUP) {
494
if (max_devices < 0)
495
mesa_logi("drmGetDevices2 returned error: %s\n", strerror(max_devices));
496
else
497
mesa_logi("Found %d drm nodes", max_devices);
498
}
499
500
if (max_devices < 1)
501
return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
502
"No DRM devices found");
503
504
for (unsigned i = 0; i < (unsigned) max_devices; i++) {
505
if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
506
devices[i]->bustype == DRM_BUS_PLATFORM) {
507
508
result = tu_drm_device_init(
509
instance->physical_devices + instance->physical_device_count,
510
instance, devices[i]);
511
if (result == VK_SUCCESS)
512
++instance->physical_device_count;
513
else if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
514
break;
515
}
516
}
517
drmFreeDevices(devices, max_devices);
518
519
return result;
520
}
521
522
static void
523
tu_timeline_finish(struct tu_device *device,
524
struct tu_timeline *timeline)
525
{
526
list_for_each_entry_safe(struct tu_timeline_point, point,
527
&timeline->free_points, link) {
528
list_del(&point->link);
529
drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
530
&(struct drm_syncobj_destroy) { .handle = point->syncobj });
531
532
vk_free(&device->vk.alloc, point);
533
}
534
list_for_each_entry_safe(struct tu_timeline_point, point,
535
&timeline->points, link) {
536
list_del(&point->link);
537
drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
538
&(struct drm_syncobj_destroy) { .handle = point->syncobj });
539
vk_free(&device->vk.alloc, point);
540
}
541
}
542
543
static VkResult
544
sync_create(VkDevice _device,
545
bool signaled,
546
bool fence,
547
bool binary,
548
uint64_t timeline_value,
549
const VkAllocationCallbacks *pAllocator,
550
void **p_sync)
551
{
552
TU_FROM_HANDLE(tu_device, device, _device);
553
554
struct tu_syncobj *sync =
555
vk_object_alloc(&device->vk, pAllocator, sizeof(*sync),
556
fence ? VK_OBJECT_TYPE_FENCE : VK_OBJECT_TYPE_SEMAPHORE);
557
if (!sync)
558
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
559
560
if (binary) {
561
struct drm_syncobj_create create = {};
562
if (signaled)
563
create.flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
564
565
int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
566
if (ret) {
567
vk_free2(&device->vk.alloc, pAllocator, sync);
568
return VK_ERROR_OUT_OF_HOST_MEMORY;
569
}
570
571
sync->binary.permanent = create.handle;
572
sync->binary.temporary = 0;
573
sync->type = TU_SEMAPHORE_BINARY;
574
} else {
575
sync->type = TU_SEMAPHORE_TIMELINE;
576
sync->timeline.highest_signaled = sync->timeline.highest_submitted =
577
timeline_value;
578
list_inithead(&sync->timeline.points);
579
list_inithead(&sync->timeline.free_points);
580
}
581
582
*p_sync = sync;
583
584
return VK_SUCCESS;
585
}
586
587
static void
588
sync_set_temporary(struct tu_device *device, struct tu_syncobj *sync, uint32_t syncobj)
589
{
590
if (sync->binary.temporary) {
591
drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
592
&(struct drm_syncobj_destroy) { .handle = sync->binary.temporary });
593
}
594
sync->binary.temporary = syncobj;
595
}
596
597
static void
598
sync_destroy(VkDevice _device, struct tu_syncobj *sync, const VkAllocationCallbacks *pAllocator)
599
{
600
TU_FROM_HANDLE(tu_device, device, _device);
601
602
if (!sync)
603
return;
604
605
if (sync->type == TU_SEMAPHORE_BINARY) {
606
sync_set_temporary(device, sync, 0);
607
drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
608
&(struct drm_syncobj_destroy) { .handle = sync->binary.permanent });
609
} else {
610
tu_timeline_finish(device, &sync->timeline);
611
}
612
613
vk_object_free(&device->vk, pAllocator, sync);
614
}
615
616
static VkResult
617
sync_import(VkDevice _device, struct tu_syncobj *sync, bool temporary, bool sync_fd, int fd)
618
{
619
TU_FROM_HANDLE(tu_device, device, _device);
620
int ret;
621
622
if (!sync_fd) {
623
uint32_t *dst = temporary ? &sync->binary.temporary : &sync->binary.permanent;
624
625
struct drm_syncobj_handle handle = { .fd = fd };
626
ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &handle);
627
if (ret)
628
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
629
630
if (*dst) {
631
drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
632
&(struct drm_syncobj_destroy) { .handle = *dst });
633
}
634
*dst = handle.handle;
635
close(fd);
636
} else {
637
assert(temporary);
638
639
struct drm_syncobj_create create = {};
640
641
if (fd == -1)
642
create.flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
643
644
ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
645
if (ret)
646
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
647
648
if (fd != -1) {
649
ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &(struct drm_syncobj_handle) {
650
.fd = fd,
651
.handle = create.handle,
652
.flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE,
653
});
654
if (ret) {
655
drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
656
&(struct drm_syncobj_destroy) { .handle = create.handle });
657
return VK_ERROR_INVALID_EXTERNAL_HANDLE;
658
}
659
close(fd);
660
}
661
662
sync_set_temporary(device, sync, create.handle);
663
}
664
665
return VK_SUCCESS;
666
}
667
668
static VkResult
669
sync_export(VkDevice _device, struct tu_syncobj *sync, bool sync_fd, int *p_fd)
670
{
671
TU_FROM_HANDLE(tu_device, device, _device);
672
673
struct drm_syncobj_handle handle = {
674
.handle = sync->binary.temporary ?: sync->binary.permanent,
675
.flags = COND(sync_fd, DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE),
676
.fd = -1,
677
};
678
int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
679
if (ret)
680
return vk_error(device->instance, VK_ERROR_INVALID_EXTERNAL_HANDLE);
681
682
/* restore permanent payload on export */
683
sync_set_temporary(device, sync, 0);
684
685
*p_fd = handle.fd;
686
return VK_SUCCESS;
687
}
688
689
static VkSemaphoreTypeKHR
690
get_semaphore_type(const void *pNext, uint64_t *initial_value)
691
{
692
const VkSemaphoreTypeCreateInfoKHR *type_info =
693
vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);
694
695
if (!type_info)
696
return VK_SEMAPHORE_TYPE_BINARY_KHR;
697
698
if (initial_value)
699
*initial_value = type_info->initialValue;
700
return type_info->semaphoreType;
701
}
702
703
VKAPI_ATTR VkResult VKAPI_CALL
704
tu_CreateSemaphore(VkDevice device,
705
const VkSemaphoreCreateInfo *pCreateInfo,
706
const VkAllocationCallbacks *pAllocator,
707
VkSemaphore *pSemaphore)
708
{
709
uint64_t timeline_value = 0;
710
VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);
711
712
return sync_create(device, false, false, (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR),
713
timeline_value, pAllocator, (void**) pSemaphore);
714
}
715
716
VKAPI_ATTR void VKAPI_CALL
717
tu_DestroySemaphore(VkDevice device, VkSemaphore sem, const VkAllocationCallbacks *pAllocator)
718
{
719
TU_FROM_HANDLE(tu_syncobj, sync, sem);
720
sync_destroy(device, sync, pAllocator);
721
}
722
723
VKAPI_ATTR VkResult VKAPI_CALL
724
tu_ImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR *info)
725
{
726
TU_FROM_HANDLE(tu_syncobj, sync, info->semaphore);
727
return sync_import(device, sync, info->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
728
info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, info->fd);
729
}
730
731
VKAPI_ATTR VkResult VKAPI_CALL
732
tu_GetSemaphoreFdKHR(VkDevice device, const VkSemaphoreGetFdInfoKHR *info, int *pFd)
733
{
734
TU_FROM_HANDLE(tu_syncobj, sync, info->semaphore);
735
return sync_export(device, sync,
736
info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, pFd);
737
}
738
739
VKAPI_ATTR void VKAPI_CALL
740
tu_GetPhysicalDeviceExternalSemaphoreProperties(
741
VkPhysicalDevice physicalDevice,
742
const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
743
VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
744
{
745
VkSemaphoreTypeKHR type = get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
746
747
if (type != VK_SEMAPHORE_TYPE_TIMELINE &&
748
(pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT ||
749
pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT )) {
750
pExternalSemaphoreProperties->exportFromImportedHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
751
pExternalSemaphoreProperties->compatibleHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
752
pExternalSemaphoreProperties->externalSemaphoreFeatures = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
753
VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
754
} else {
755
pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
756
pExternalSemaphoreProperties->compatibleHandleTypes = 0;
757
pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
758
}
759
}
760
761
static VkResult
762
tu_queue_submit_add_timeline_wait_locked(struct tu_queue_submit* submit,
763
struct tu_device *device,
764
struct tu_syncobj *timeline,
765
uint64_t value)
766
{
767
if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
768
uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
769
770
submit->wait_timelines = vk_realloc(&device->vk.alloc,
771
submit->wait_timelines,
772
new_len * sizeof(*submit->wait_timelines),
773
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
774
775
if (submit->wait_timelines == NULL)
776
return VK_ERROR_OUT_OF_HOST_MEMORY;
777
778
submit->wait_timeline_values = vk_realloc(&device->vk.alloc,
779
submit->wait_timeline_values,
780
new_len * sizeof(*submit->wait_timeline_values),
781
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
782
783
if (submit->wait_timeline_values == NULL) {
784
vk_free(&device->vk.alloc, submit->wait_timelines);
785
return VK_ERROR_OUT_OF_HOST_MEMORY;
786
}
787
788
submit->wait_timeline_array_length = new_len;
789
}
790
791
submit->wait_timelines[submit->wait_timeline_count] = timeline;
792
submit->wait_timeline_values[submit->wait_timeline_count] = value;
793
794
submit->wait_timeline_count++;
795
796
return VK_SUCCESS;
797
}
798
799
static VkResult
800
tu_queue_submit_add_timeline_signal_locked(struct tu_queue_submit* submit,
801
struct tu_device *device,
802
struct tu_syncobj *timeline,
803
uint64_t value)
804
{
805
if (submit->signal_timeline_count >= submit->signal_timeline_array_length) {
806
uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 32);
807
808
submit->signal_timelines = vk_realloc(&device->vk.alloc,
809
submit->signal_timelines,
810
new_len * sizeof(*submit->signal_timelines),
811
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
812
813
if (submit->signal_timelines == NULL)
814
return VK_ERROR_OUT_OF_HOST_MEMORY;
815
816
submit->signal_timeline_values = vk_realloc(&device->vk.alloc,
817
submit->signal_timeline_values,
818
new_len * sizeof(*submit->signal_timeline_values),
819
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
820
821
if (submit->signal_timeline_values == NULL) {
822
vk_free(&device->vk.alloc, submit->signal_timelines);
823
return VK_ERROR_OUT_OF_HOST_MEMORY;
824
}
825
826
submit->signal_timeline_array_length = new_len;
827
}
828
829
submit->signal_timelines[submit->signal_timeline_count] = timeline;
830
submit->signal_timeline_values[submit->signal_timeline_count] = value;
831
832
submit->signal_timeline_count++;
833
834
return VK_SUCCESS;
835
}
836
837
static VkResult
838
tu_queue_submit_create_locked(struct tu_queue *queue,
839
const VkSubmitInfo *submit_info,
840
const uint32_t nr_in_syncobjs,
841
const uint32_t nr_out_syncobjs,
842
const bool last_submit,
843
const VkPerformanceQuerySubmitInfoKHR *perf_info,
844
struct tu_queue_submit **submit)
845
{
846
VkResult result;
847
848
const VkTimelineSemaphoreSubmitInfoKHR *timeline_info =
849
vk_find_struct_const(submit_info->pNext,
850
TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR);
851
852
const uint32_t wait_values_count =
853
timeline_info ? timeline_info->waitSemaphoreValueCount : 0;
854
const uint32_t signal_values_count =
855
timeline_info ? timeline_info->signalSemaphoreValueCount : 0;
856
857
const uint64_t *wait_values =
858
wait_values_count ? timeline_info->pWaitSemaphoreValues : NULL;
859
const uint64_t *signal_values =
860
signal_values_count ? timeline_info->pSignalSemaphoreValues : NULL;
861
862
struct tu_queue_submit *new_submit = vk_zalloc(&queue->device->vk.alloc,
863
sizeof(*new_submit), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
864
865
new_submit->cmd_buffer_count = submit_info->commandBufferCount;
866
new_submit->cmd_buffers = vk_zalloc(&queue->device->vk.alloc,
867
new_submit->cmd_buffer_count * sizeof(*new_submit->cmd_buffers), 8,
868
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
869
870
if (new_submit->cmd_buffers == NULL) {
871
result = vk_error(queue->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY)
872
goto fail_cmd_buffers;
873
}
874
875
memcpy(new_submit->cmd_buffers, submit_info->pCommandBuffers,
876
new_submit->cmd_buffer_count * sizeof(*new_submit->cmd_buffers));
877
878
new_submit->wait_semaphores = vk_zalloc(&queue->device->vk.alloc,
879
submit_info->waitSemaphoreCount * sizeof(*new_submit->wait_semaphores),
880
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
881
if (new_submit->wait_semaphores == NULL) {
882
result = vk_error(queue->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY)
883
goto fail_wait_semaphores;
884
}
885
new_submit->wait_semaphore_count = submit_info->waitSemaphoreCount;
886
887
new_submit->signal_semaphores = vk_zalloc(&queue->device->vk.alloc,
888
submit_info->signalSemaphoreCount *sizeof(*new_submit->signal_semaphores),
889
8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
890
if (new_submit->signal_semaphores == NULL) {
891
result = vk_error(queue->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY)
892
goto fail_signal_semaphores;
893
}
894
new_submit->signal_semaphore_count = submit_info->signalSemaphoreCount;
895
896
for (uint32_t i = 0; i < submit_info->waitSemaphoreCount; i++) {
897
TU_FROM_HANDLE(tu_syncobj, sem, submit_info->pWaitSemaphores[i]);
898
new_submit->wait_semaphores[i] = sem;
899
900
if (sem->type == TU_SEMAPHORE_TIMELINE) {
901
result = tu_queue_submit_add_timeline_wait_locked(new_submit,
902
queue->device, sem, wait_values[i]);
903
if (result != VK_SUCCESS)
904
goto fail_wait_timelines;
905
}
906
}
907
908
for (uint32_t i = 0; i < submit_info->signalSemaphoreCount; i++) {
909
TU_FROM_HANDLE(tu_syncobj, sem, submit_info->pSignalSemaphores[i]);
910
new_submit->signal_semaphores[i] = sem;
911
912
if (sem->type == TU_SEMAPHORE_TIMELINE) {
913
result = tu_queue_submit_add_timeline_signal_locked(new_submit,
914
queue->device, sem, signal_values[i]);
915
if (result != VK_SUCCESS)
916
goto fail_signal_timelines;
917
}
918
}
919
920
uint32_t entry_count = 0;
921
for (uint32_t j = 0; j < new_submit->cmd_buffer_count; ++j) {
922
TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, new_submit->cmd_buffers[j]);
923
924
if (perf_info)
925
entry_count++;
926
927
entry_count += cmdbuf->cs.entry_count;
928
}
929
930
new_submit->cmds = vk_zalloc(&queue->device->vk.alloc,
931
entry_count * sizeof(*new_submit->cmds), 8,
932
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
933
934
if (new_submit->cmds == NULL) {
935
result = vk_error(queue->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY)
936
goto fail_cmds;
937
}
938
939
/* Allocate without wait timeline semaphores */
940
new_submit->in_syncobjs = vk_zalloc(&queue->device->vk.alloc,
941
(nr_in_syncobjs - new_submit->wait_timeline_count) *
942
sizeof(*new_submit->in_syncobjs), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
943
944
if (new_submit->in_syncobjs == NULL) {
945
result = vk_error(queue->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY)
946
goto fail_in_syncobjs;
947
}
948
949
/* Allocate with signal timeline semaphores considered */
950
new_submit->out_syncobjs = vk_zalloc(&queue->device->vk.alloc,
951
nr_out_syncobjs * sizeof(*new_submit->out_syncobjs), 8,
952
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
953
954
if (new_submit->out_syncobjs == NULL) {
955
result = vk_error(queue->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY)
956
goto fail_out_syncobjs;
957
}
958
959
new_submit->entry_count = entry_count;
960
new_submit->nr_in_syncobjs = nr_in_syncobjs;
961
new_submit->nr_out_syncobjs = nr_out_syncobjs;
962
new_submit->last_submit = last_submit;
963
new_submit->counter_pass_index = perf_info ? perf_info->counterPassIndex : ~0;
964
965
list_inithead(&new_submit->link);
966
967
*submit = new_submit;
968
969
return VK_SUCCESS;
970
971
fail_out_syncobjs:
972
vk_free(&queue->device->vk.alloc, new_submit->in_syncobjs);
973
fail_in_syncobjs:
974
vk_free(&queue->device->vk.alloc, new_submit->cmds);
975
fail_cmds:
976
fail_signal_timelines:
977
fail_wait_timelines:
978
vk_free(&queue->device->vk.alloc, new_submit->signal_semaphores);
979
fail_signal_semaphores:
980
vk_free(&queue->device->vk.alloc, new_submit->wait_semaphores);
981
fail_wait_semaphores:
982
vk_free(&queue->device->vk.alloc, new_submit->cmd_buffers);
983
fail_cmd_buffers:
984
return result;
985
}
986
987
static void
988
tu_queue_submit_free(struct tu_queue *queue, struct tu_queue_submit *submit)
989
{
990
vk_free(&queue->device->vk.alloc, submit->wait_semaphores);
991
vk_free(&queue->device->vk.alloc, submit->signal_semaphores);
992
993
vk_free(&queue->device->vk.alloc, submit->wait_timelines);
994
vk_free(&queue->device->vk.alloc, submit->wait_timeline_values);
995
vk_free(&queue->device->vk.alloc, submit->signal_timelines);
996
vk_free(&queue->device->vk.alloc, submit->signal_timeline_values);
997
998
vk_free(&queue->device->vk.alloc, submit->cmds);
999
vk_free(&queue->device->vk.alloc, submit->in_syncobjs);
1000
vk_free(&queue->device->vk.alloc, submit->out_syncobjs);
1001
vk_free(&queue->device->vk.alloc, submit->cmd_buffers);
1002
vk_free(&queue->device->vk.alloc, submit);
1003
}
1004
1005
static void
1006
tu_queue_build_msm_gem_submit_cmds(struct tu_queue *queue,
1007
struct tu_queue_submit *submit)
1008
{
1009
struct drm_msm_gem_submit_cmd *cmds = submit->cmds;
1010
1011
uint32_t entry_idx = 0;
1012
for (uint32_t j = 0; j < submit->cmd_buffer_count; ++j) {
1013
TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->cmd_buffers[j]);
1014
struct tu_cs *cs = &cmdbuf->cs;
1015
struct tu_device *dev = queue->device;
1016
1017
if (submit->counter_pass_index != ~0) {
1018
struct tu_cs_entry *perf_cs_entry =
1019
&dev->perfcntrs_pass_cs_entries[submit->counter_pass_index];
1020
1021
cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
1022
cmds[entry_idx].submit_idx =
1023
dev->bo_idx[perf_cs_entry->bo->gem_handle];
1024
cmds[entry_idx].submit_offset = perf_cs_entry->offset;
1025
cmds[entry_idx].size = perf_cs_entry->size;
1026
cmds[entry_idx].pad = 0;
1027
cmds[entry_idx].nr_relocs = 0;
1028
cmds[entry_idx++].relocs = 0;
1029
}
1030
1031
for (unsigned i = 0; i < cs->entry_count; ++i, ++entry_idx) {
1032
cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
1033
cmds[entry_idx].submit_idx =
1034
dev->bo_idx[cs->entries[i].bo->gem_handle];
1035
cmds[entry_idx].submit_offset = cs->entries[i].offset;
1036
cmds[entry_idx].size = cs->entries[i].size;
1037
cmds[entry_idx].pad = 0;
1038
cmds[entry_idx].nr_relocs = 0;
1039
cmds[entry_idx].relocs = 0;
1040
}
1041
}
1042
}
1043
1044
static VkResult
1045
tu_queue_submit_locked(struct tu_queue *queue, struct tu_queue_submit *submit)
1046
{
1047
uint32_t flags = MSM_PIPE_3D0;
1048
1049
if (submit->nr_in_syncobjs)
1050
flags |= MSM_SUBMIT_SYNCOBJ_IN;
1051
1052
if (submit->nr_out_syncobjs)
1053
flags |= MSM_SUBMIT_SYNCOBJ_OUT;
1054
1055
if (submit->last_submit)
1056
flags |= MSM_SUBMIT_FENCE_FD_OUT;
1057
1058
mtx_lock(&queue->device->bo_mutex);
1059
1060
/* drm_msm_gem_submit_cmd requires index of bo which could change at any
1061
* time when bo_mutex is not locked. So we build submit cmds here the real
1062
* place to submit.
1063
*/
1064
tu_queue_build_msm_gem_submit_cmds(queue, submit);
1065
1066
struct drm_msm_gem_submit req = {
1067
.flags = flags,
1068
.queueid = queue->msm_queue_id,
1069
.bos = (uint64_t)(uintptr_t) queue->device->bo_list,
1070
.nr_bos = queue->device->bo_count,
1071
.cmds = (uint64_t)(uintptr_t)submit->cmds,
1072
.nr_cmds = submit->entry_count,
1073
.in_syncobjs = (uint64_t)(uintptr_t)submit->in_syncobjs,
1074
.out_syncobjs = (uint64_t)(uintptr_t)submit->out_syncobjs,
1075
.nr_in_syncobjs = submit->nr_in_syncobjs - submit->wait_timeline_count,
1076
.nr_out_syncobjs = submit->nr_out_syncobjs,
1077
.syncobj_stride = sizeof(struct drm_msm_gem_submit_syncobj),
1078
};
1079
1080
int ret = drmCommandWriteRead(queue->device->fd,
1081
DRM_MSM_GEM_SUBMIT,
1082
&req, sizeof(req));
1083
1084
mtx_unlock(&queue->device->bo_mutex);
1085
1086
if (ret)
1087
return tu_device_set_lost(queue->device, "submit failed: %s\n",
1088
strerror(errno));
1089
1090
/* restore permanent payload on wait */
1091
for (uint32_t i = 0; i < submit->wait_semaphore_count; i++) {
1092
TU_FROM_HANDLE(tu_syncobj, sem, submit->wait_semaphores[i]);
1093
if(sem->type == TU_SEMAPHORE_BINARY)
1094
sync_set_temporary(queue->device, sem, 0);
1095
}
1096
1097
if (submit->last_submit) {
1098
if (queue->fence >= 0)
1099
close(queue->fence);
1100
queue->fence = req.fence_fd;
1101
}
1102
1103
/* Update highest_submitted values in the timeline. */
1104
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
1105
struct tu_syncobj *sem = submit->signal_timelines[i];
1106
uint64_t signal_value = submit->signal_timeline_values[i];
1107
1108
assert(signal_value > sem->timeline.highest_submitted);
1109
1110
sem->timeline.highest_submitted = signal_value;
1111
}
1112
1113
pthread_cond_broadcast(&queue->device->timeline_cond);
1114
1115
return VK_SUCCESS;
1116
}
1117
1118
1119
static bool
1120
tu_queue_submit_ready_locked(struct tu_queue_submit *submit)
1121
{
1122
for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
1123
if (submit->wait_timeline_values[i] >
1124
submit->wait_timelines[i]->timeline.highest_submitted) {
1125
return false;
1126
}
1127
}
1128
1129
return true;
1130
}
1131
1132
static VkResult
1133
tu_timeline_add_point_locked(struct tu_device *device,
1134
struct tu_timeline *timeline,
1135
uint64_t value,
1136
struct tu_timeline_point **point)
1137
{
1138
1139
if (list_is_empty(&timeline->free_points)) {
1140
*point = vk_zalloc(&device->vk.alloc, sizeof(**point), 8,
1141
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
1142
1143
if (!(*point))
1144
return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);
1145
1146
struct drm_syncobj_create create = {};
1147
1148
int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
1149
if (ret) {
1150
vk_free(&device->vk.alloc, *point);
1151
return vk_error(device->instance, VK_ERROR_DEVICE_LOST);
1152
}
1153
1154
(*point)->syncobj = create.handle;
1155
1156
} else {
1157
*point = list_first_entry(&timeline->free_points,
1158
struct tu_timeline_point, link);
1159
list_del(&(*point)->link);
1160
}
1161
1162
(*point)->value = value;
1163
list_addtail(&(*point)->link, &timeline->points);
1164
1165
return VK_SUCCESS;
1166
}
1167
1168
static VkResult
1169
tu_queue_submit_timeline_locked(struct tu_queue *queue,
1170
struct tu_queue_submit *submit)
1171
{
1172
VkResult result;
1173
uint32_t timeline_idx =
1174
submit->nr_out_syncobjs - submit->signal_timeline_count;
1175
1176
for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
1177
struct tu_timeline *timeline = &submit->signal_timelines[i]->timeline;
1178
uint64_t signal_value = submit->signal_timeline_values[i];
1179
struct tu_timeline_point *point;
1180
1181
result = tu_timeline_add_point_locked(queue->device, timeline,
1182
signal_value, &point);
1183
if (result != VK_SUCCESS)
1184
return result;
1185
1186
submit->out_syncobjs[timeline_idx + i] =
1187
(struct drm_msm_gem_submit_syncobj) {
1188
.handle = point->syncobj,
1189
.flags = 0,
1190
};
1191
}
1192
1193
return tu_queue_submit_locked(queue, submit);
1194
}
1195
1196
static VkResult
1197
tu_queue_submit_deferred_locked(struct tu_queue *queue, uint32_t *advance)
1198
{
1199
VkResult result = VK_SUCCESS;
1200
1201
list_for_each_entry_safe(struct tu_queue_submit, submit,
1202
&queue->queued_submits, link) {
1203
if (!tu_queue_submit_ready_locked(submit))
1204
break;
1205
1206
(*advance)++;
1207
1208
result = tu_queue_submit_timeline_locked(queue, submit);
1209
1210
list_del(&submit->link);
1211
tu_queue_submit_free(queue, submit);
1212
1213
if (result != VK_SUCCESS)
1214
break;
1215
}
1216
1217
return result;
1218
}
1219
1220
VkResult
1221
tu_device_submit_deferred_locked(struct tu_device *dev)
1222
{
1223
VkResult result = VK_SUCCESS;
1224
1225
uint32_t advance = 0;
1226
do {
1227
advance = 0;
1228
for (uint32_t i = 0; i < dev->queue_count[0]; i++) {
1229
/* Try again if there's signaled submission. */
1230
result = tu_queue_submit_deferred_locked(&dev->queues[0][i],
1231
&advance);
1232
if (result != VK_SUCCESS)
1233
return result;
1234
}
1235
1236
} while(advance);
1237
1238
return result;
1239
}
1240
1241
VKAPI_ATTR VkResult VKAPI_CALL
1242
tu_QueueSubmit(VkQueue _queue,
1243
uint32_t submitCount,
1244
const VkSubmitInfo *pSubmits,
1245
VkFence _fence)
1246
{
1247
TU_FROM_HANDLE(tu_queue, queue, _queue);
1248
TU_FROM_HANDLE(tu_syncobj, fence, _fence);
1249
1250
for (uint32_t i = 0; i < submitCount; ++i) {
1251
const VkSubmitInfo *submit = pSubmits + i;
1252
const bool last_submit = (i == submitCount - 1);
1253
uint32_t out_syncobjs_size = submit->signalSemaphoreCount;
1254
1255
const VkPerformanceQuerySubmitInfoKHR *perf_info =
1256
vk_find_struct_const(pSubmits[i].pNext,
1257
PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
1258
1259
if (last_submit && fence)
1260
out_syncobjs_size += 1;
1261
1262
pthread_mutex_lock(&queue->device->submit_mutex);
1263
struct tu_queue_submit *submit_req = NULL;
1264
1265
VkResult ret = tu_queue_submit_create_locked(queue, submit,
1266
submit->waitSemaphoreCount, out_syncobjs_size,
1267
last_submit, perf_info, &submit_req);
1268
1269
if (ret != VK_SUCCESS) {
1270
pthread_mutex_unlock(&queue->device->submit_mutex);
1271
return ret;
1272
}
1273
1274
/* note: assuming there won't be any very large semaphore counts */
1275
struct drm_msm_gem_submit_syncobj *in_syncobjs = submit_req->in_syncobjs;
1276
struct drm_msm_gem_submit_syncobj *out_syncobjs = submit_req->out_syncobjs;
1277
uint32_t nr_in_syncobjs = 0, nr_out_syncobjs = 0;
1278
1279
for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) {
1280
TU_FROM_HANDLE(tu_syncobj, sem, submit->pWaitSemaphores[i]);
1281
if (sem->type == TU_SEMAPHORE_TIMELINE)
1282
continue;
1283
1284
in_syncobjs[nr_in_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
1285
.handle = sem->binary.temporary ?: sem->binary.permanent,
1286
.flags = MSM_SUBMIT_SYNCOBJ_RESET,
1287
};
1288
}
1289
1290
for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) {
1291
TU_FROM_HANDLE(tu_syncobj, sem, submit->pSignalSemaphores[i]);
1292
1293
/* In case of timeline semaphores, we can defer the creation of syncobj
1294
* and adding it at real submit time.
1295
*/
1296
if (sem->type == TU_SEMAPHORE_TIMELINE)
1297
continue;
1298
1299
out_syncobjs[nr_out_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
1300
.handle = sem->binary.temporary ?: sem->binary.permanent,
1301
.flags = 0,
1302
};
1303
}
1304
1305
if (last_submit && fence) {
1306
out_syncobjs[nr_out_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
1307
.handle = fence->binary.temporary ?: fence->binary.permanent,
1308
.flags = 0,
1309
};
1310
}
1311
1312
/* Queue the current submit */
1313
list_addtail(&submit_req->link, &queue->queued_submits);
1314
ret = tu_device_submit_deferred_locked(queue->device);
1315
1316
pthread_mutex_unlock(&queue->device->submit_mutex);
1317
if (ret != VK_SUCCESS)
1318
return ret;
1319
}
1320
1321
if (!submitCount && fence) {
1322
/* signal fence imemediately since we don't have a submit to do it */
1323
drmIoctl(queue->device->fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &(struct drm_syncobj_array) {
1324
.handles = (uintptr_t) (uint32_t[]) { fence->binary.temporary ?: fence->binary.permanent },
1325
.count_handles = 1,
1326
});
1327
}
1328
1329
return VK_SUCCESS;
1330
}
1331
1332
VKAPI_ATTR VkResult VKAPI_CALL
1333
tu_CreateFence(VkDevice device,
1334
const VkFenceCreateInfo *info,
1335
const VkAllocationCallbacks *pAllocator,
1336
VkFence *pFence)
1337
{
1338
return sync_create(device, info->flags & VK_FENCE_CREATE_SIGNALED_BIT, true, true, 0,
1339
pAllocator, (void**) pFence);
1340
}
1341
1342
VKAPI_ATTR void VKAPI_CALL
1343
tu_DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator)
1344
{
1345
TU_FROM_HANDLE(tu_syncobj, sync, fence);
1346
sync_destroy(device, sync, pAllocator);
1347
}
1348
1349
VKAPI_ATTR VkResult VKAPI_CALL
1350
tu_ImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR *info)
1351
{
1352
TU_FROM_HANDLE(tu_syncobj, sync, info->fence);
1353
return sync_import(device, sync, info->flags & VK_FENCE_IMPORT_TEMPORARY_BIT,
1354
info->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, info->fd);
1355
}
1356
1357
VKAPI_ATTR VkResult VKAPI_CALL
1358
tu_GetFenceFdKHR(VkDevice device, const VkFenceGetFdInfoKHR *info, int *pFd)
1359
{
1360
TU_FROM_HANDLE(tu_syncobj, sync, info->fence);
1361
return sync_export(device, sync,
1362
info->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, pFd);
1363
}
1364
1365
static VkResult
1366
drm_syncobj_wait(struct tu_device *device,
1367
const uint32_t *handles, uint32_t count_handles,
1368
int64_t timeout_nsec, bool wait_all)
1369
{
1370
int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_WAIT, &(struct drm_syncobj_wait) {
1371
.handles = (uint64_t) (uintptr_t) handles,
1372
.count_handles = count_handles,
1373
.timeout_nsec = timeout_nsec,
1374
.flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
1375
COND(wait_all, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)
1376
});
1377
if (ret) {
1378
if (errno == ETIME)
1379
return VK_TIMEOUT;
1380
1381
assert(0);
1382
return VK_ERROR_DEVICE_LOST; /* TODO */
1383
}
1384
return VK_SUCCESS;
1385
}
1386
1387
static uint64_t
1388
gettime_ns(void)
1389
{
1390
struct timespec current;
1391
clock_gettime(CLOCK_MONOTONIC, &current);
1392
return (uint64_t)current.tv_sec * 1000000000 + current.tv_nsec;
1393
}
1394
1395
/* and the kernel converts it right back to relative timeout - very smart UAPI */
1396
static uint64_t
1397
absolute_timeout(uint64_t timeout)
1398
{
1399
if (timeout == 0)
1400
return 0;
1401
uint64_t current_time = gettime_ns();
1402
uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;
1403
1404
timeout = MIN2(max_timeout, timeout);
1405
1406
return (current_time + timeout);
1407
}
1408
1409
VKAPI_ATTR VkResult VKAPI_CALL
1410
tu_WaitForFences(VkDevice _device,
1411
uint32_t fenceCount,
1412
const VkFence *pFences,
1413
VkBool32 waitAll,
1414
uint64_t timeout)
1415
{
1416
TU_FROM_HANDLE(tu_device, device, _device);
1417
1418
if (tu_device_is_lost(device))
1419
return VK_ERROR_DEVICE_LOST;
1420
1421
uint32_t handles[fenceCount];
1422
for (unsigned i = 0; i < fenceCount; ++i) {
1423
TU_FROM_HANDLE(tu_syncobj, fence, pFences[i]);
1424
handles[i] = fence->binary.temporary ?: fence->binary.permanent;
1425
}
1426
1427
return drm_syncobj_wait(device, handles, fenceCount, absolute_timeout(timeout), waitAll);
1428
}
1429
1430
VKAPI_ATTR VkResult VKAPI_CALL
1431
tu_ResetFences(VkDevice _device, uint32_t fenceCount, const VkFence *pFences)
1432
{
1433
TU_FROM_HANDLE(tu_device, device, _device);
1434
int ret;
1435
1436
uint32_t handles[fenceCount];
1437
for (unsigned i = 0; i < fenceCount; ++i) {
1438
TU_FROM_HANDLE(tu_syncobj, fence, pFences[i]);
1439
sync_set_temporary(device, fence, 0);
1440
handles[i] = fence->binary.permanent;
1441
}
1442
1443
ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_RESET, &(struct drm_syncobj_array) {
1444
.handles = (uint64_t) (uintptr_t) handles,
1445
.count_handles = fenceCount,
1446
});
1447
if (ret) {
1448
tu_device_set_lost(device, "DRM_IOCTL_SYNCOBJ_RESET failure: %s",
1449
strerror(errno));
1450
}
1451
1452
return VK_SUCCESS;
1453
}
1454
1455
VKAPI_ATTR VkResult VKAPI_CALL
1456
tu_GetFenceStatus(VkDevice _device, VkFence _fence)
1457
{
1458
TU_FROM_HANDLE(tu_device, device, _device);
1459
TU_FROM_HANDLE(tu_syncobj, fence, _fence);
1460
VkResult result;
1461
1462
result = drm_syncobj_wait(device, (uint32_t[]){fence->binary.temporary ?: fence->binary.permanent}, 1, 0, false);
1463
if (result == VK_TIMEOUT)
1464
result = VK_NOT_READY;
1465
return result;
1466
}
1467
1468
int
1469
tu_signal_fences(struct tu_device *device, struct tu_syncobj *fence1, struct tu_syncobj *fence2)
1470
{
1471
uint32_t handles[2], count = 0;
1472
if (fence1)
1473
handles[count++] = fence1->binary.temporary ?: fence1->binary.permanent;
1474
1475
if (fence2)
1476
handles[count++] = fence2->binary.temporary ?: fence2->binary.permanent;
1477
1478
if (!count)
1479
return 0;
1480
1481
return drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &(struct drm_syncobj_array) {
1482
.handles = (uintptr_t) handles,
1483
.count_handles = count
1484
});
1485
}
1486
1487
int
1488
tu_syncobj_to_fd(struct tu_device *device, struct tu_syncobj *sync)
1489
{
1490
struct drm_syncobj_handle handle = { .handle = sync->binary.permanent };
1491
int ret;
1492
1493
ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
1494
1495
return ret ? -1 : handle.fd;
1496
}
1497
1498
static VkResult
1499
tu_timeline_gc_locked(struct tu_device *dev, struct tu_timeline *timeline)
1500
{
1501
VkResult result = VK_SUCCESS;
1502
1503
/* Go through every point in the timeline and check if any signaled point */
1504
list_for_each_entry_safe(struct tu_timeline_point, point,
1505
&timeline->points, link) {
1506
1507
/* If the value of the point is higher than highest_submitted,
1508
* the point has not been submited yet.
1509
*/
1510
if (point->wait_count || point->value > timeline->highest_submitted)
1511
return VK_SUCCESS;
1512
1513
result = drm_syncobj_wait(dev, (uint32_t[]){point->syncobj}, 1, 0, true);
1514
1515
if (result == VK_TIMEOUT) {
1516
/* This means the syncobj is still busy and it should wait
1517
* with timeout specified by users via vkWaitSemaphores.
1518
*/
1519
result = VK_SUCCESS;
1520
} else {
1521
timeline->highest_signaled =
1522
MAX2(timeline->highest_signaled, point->value);
1523
list_del(&point->link);
1524
list_add(&point->link, &timeline->free_points);
1525
}
1526
}
1527
1528
return result;
1529
}
1530
1531
1532
static VkResult
1533
tu_timeline_wait_locked(struct tu_device *device,
1534
struct tu_timeline *timeline,
1535
uint64_t value,
1536
uint64_t abs_timeout)
1537
{
1538
VkResult result;
1539
1540
while(timeline->highest_submitted < value) {
1541
struct timespec abstime;
1542
timespec_from_nsec(&abstime, abs_timeout);
1543
1544
pthread_cond_timedwait(&device->timeline_cond, &device->submit_mutex,
1545
&abstime);
1546
1547
if (os_time_get_nano() >= abs_timeout &&
1548
timeline->highest_submitted < value)
1549
return VK_TIMEOUT;
1550
}
1551
1552
/* Visit every point in the timeline and wait until
1553
* the highest_signaled reaches the value.
1554
*/
1555
while (1) {
1556
result = tu_timeline_gc_locked(device, timeline);
1557
if (result != VK_SUCCESS)
1558
return result;
1559
1560
if (timeline->highest_signaled >= value)
1561
return VK_SUCCESS;
1562
1563
struct tu_timeline_point *point =
1564
list_first_entry(&timeline->points,
1565
struct tu_timeline_point, link);
1566
1567
point->wait_count++;
1568
pthread_mutex_unlock(&device->submit_mutex);
1569
result = drm_syncobj_wait(device, (uint32_t[]){point->syncobj}, 1,
1570
abs_timeout, true);
1571
1572
pthread_mutex_lock(&device->submit_mutex);
1573
point->wait_count--;
1574
1575
if (result != VK_SUCCESS)
1576
return result;
1577
}
1578
1579
return result;
1580
}
1581
1582
static VkResult
1583
tu_wait_timelines(struct tu_device *device,
1584
const VkSemaphoreWaitInfoKHR* pWaitInfo,
1585
uint64_t abs_timeout)
1586
{
1587
if ((pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR) &&
1588
pWaitInfo->semaphoreCount > 1) {
1589
pthread_mutex_lock(&device->submit_mutex);
1590
1591
/* Visit every timline semaphore in the queue until timeout */
1592
while (1) {
1593
for(uint32_t i = 0; i < pWaitInfo->semaphoreCount; ++i) {
1594
TU_FROM_HANDLE(tu_syncobj, semaphore, pWaitInfo->pSemaphores[i]);
1595
VkResult result = tu_timeline_wait_locked(device,
1596
&semaphore->timeline, pWaitInfo->pValues[i], 0);
1597
1598
/* Returns result values including VK_SUCCESS except for VK_TIMEOUT */
1599
if (result != VK_TIMEOUT) {
1600
pthread_mutex_unlock(&device->submit_mutex);
1601
return result;
1602
}
1603
}
1604
1605
if (os_time_get_nano() > abs_timeout) {
1606
pthread_mutex_unlock(&device->submit_mutex);
1607
return VK_TIMEOUT;
1608
}
1609
}
1610
} else {
1611
VkResult result = VK_SUCCESS;
1612
1613
pthread_mutex_lock(&device->submit_mutex);
1614
for(uint32_t i = 0; i < pWaitInfo->semaphoreCount; ++i) {
1615
TU_FROM_HANDLE(tu_syncobj, semaphore, pWaitInfo->pSemaphores[i]);
1616
assert(semaphore->type == TU_SEMAPHORE_TIMELINE);
1617
1618
result = tu_timeline_wait_locked(device, &semaphore->timeline,
1619
pWaitInfo->pValues[i], abs_timeout);
1620
if (result != VK_SUCCESS)
1621
break;
1622
}
1623
pthread_mutex_unlock(&device->submit_mutex);
1624
1625
return result;
1626
}
1627
}
1628
1629
1630
VKAPI_ATTR VkResult VKAPI_CALL
1631
tu_GetSemaphoreCounterValue(VkDevice _device,
1632
VkSemaphore _semaphore,
1633
uint64_t* pValue)
1634
{
1635
TU_FROM_HANDLE(tu_device, device, _device);
1636
TU_FROM_HANDLE(tu_syncobj, semaphore, _semaphore);
1637
1638
assert(semaphore->type == TU_SEMAPHORE_TIMELINE);
1639
1640
VkResult result;
1641
1642
pthread_mutex_lock(&device->submit_mutex);
1643
1644
result = tu_timeline_gc_locked(device, &semaphore->timeline);
1645
*pValue = semaphore->timeline.highest_signaled;
1646
1647
pthread_mutex_unlock(&device->submit_mutex);
1648
1649
return result;
1650
}
1651
1652
1653
VKAPI_ATTR VkResult VKAPI_CALL
1654
tu_WaitSemaphores(VkDevice _device,
1655
const VkSemaphoreWaitInfoKHR* pWaitInfo,
1656
uint64_t timeout)
1657
{
1658
TU_FROM_HANDLE(tu_device, device, _device);
1659
1660
return tu_wait_timelines(device, pWaitInfo, absolute_timeout(timeout));
1661
}
1662
1663
VKAPI_ATTR VkResult VKAPI_CALL
1664
tu_SignalSemaphore(VkDevice _device,
1665
const VkSemaphoreSignalInfoKHR* pSignalInfo)
1666
{
1667
TU_FROM_HANDLE(tu_device, device, _device);
1668
TU_FROM_HANDLE(tu_syncobj, semaphore, pSignalInfo->semaphore);
1669
VkResult result;
1670
1671
assert(semaphore->type == TU_SEMAPHORE_TIMELINE);
1672
1673
pthread_mutex_lock(&device->submit_mutex);
1674
1675
result = tu_timeline_gc_locked(device, &semaphore->timeline);
1676
if (result != VK_SUCCESS) {
1677
pthread_mutex_unlock(&device->submit_mutex);
1678
return result;
1679
}
1680
1681
semaphore->timeline.highest_submitted = pSignalInfo->value;
1682
semaphore->timeline.highest_signaled = pSignalInfo->value;
1683
1684
result = tu_device_submit_deferred_locked(device);
1685
1686
pthread_cond_broadcast(&device->timeline_cond);
1687
pthread_mutex_unlock(&device->submit_mutex);
1688
1689
return result;
1690
}
1691
1692
#ifdef ANDROID
1693
#include <libsync.h>
1694
1695
VKAPI_ATTR VkResult VKAPI_CALL
1696
tu_QueueSignalReleaseImageANDROID(VkQueue _queue,
1697
uint32_t waitSemaphoreCount,
1698
const VkSemaphore *pWaitSemaphores,
1699
VkImage image,
1700
int *pNativeFenceFd)
1701
{
1702
TU_FROM_HANDLE(tu_queue, queue, _queue);
1703
VkResult result = VK_SUCCESS;
1704
1705
if (waitSemaphoreCount == 0) {
1706
if (pNativeFenceFd)
1707
*pNativeFenceFd = -1;
1708
return VK_SUCCESS;
1709
}
1710
1711
int fd = -1;
1712
1713
for (uint32_t i = 0; i < waitSemaphoreCount; ++i) {
1714
int tmp_fd;
1715
result = tu_GetSemaphoreFdKHR(
1716
tu_device_to_handle(queue->device),
1717
&(VkSemaphoreGetFdInfoKHR) {
1718
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
1719
.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
1720
.semaphore = pWaitSemaphores[i],
1721
},
1722
&tmp_fd);
1723
if (result != VK_SUCCESS) {
1724
if (fd >= 0)
1725
close(fd);
1726
return result;
1727
}
1728
1729
if (fd < 0)
1730
fd = tmp_fd;
1731
else if (tmp_fd >= 0) {
1732
sync_accumulate("tu", &fd, tmp_fd);
1733
close(tmp_fd);
1734
}
1735
}
1736
1737
if (pNativeFenceFd) {
1738
*pNativeFenceFd = fd;
1739
} else if (fd >= 0) {
1740
close(fd);
1741
/* We still need to do the exports, to reset the semaphores, but
1742
* otherwise we don't wait on them. */
1743
}
1744
return VK_SUCCESS;
1745
}
1746
#endif
1747
1748