1 /*
2 * Copyright © 2020 Google, Inc.
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "tu_drm.h"
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <sys/ioctl.h>
11 #include <sys/mman.h>
12
13 #include "msm_kgsl.h"
14 #include "vk_util.h"
15
16 #include "util/debug.h"
17
18 #include "tu_cmd_buffer.h"
19 #include "tu_cs.h"
20 #include "tu_device.h"
21 #include "tu_dynamic_rendering.h"
22
23 struct tu_syncobj {
24 struct vk_object_base base;
25 uint32_t timestamp;
26 bool timestamp_valid;
27 };
28
29 static int
safe_ioctl(int fd, unsigned long request, void *arg)30 safe_ioctl(int fd, unsigned long request, void *arg)
31 {
32 int ret;
33
34 do {
35 ret = ioctl(fd, request, arg);
36 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
37
38 return ret;
39 }
40
41 int
tu_drm_submitqueue_new(const struct tu_device *dev, int priority, uint32_t *queue_id)42 tu_drm_submitqueue_new(const struct tu_device *dev,
43 int priority,
44 uint32_t *queue_id)
45 {
46 struct kgsl_drawctxt_create req = {
47 .flags = KGSL_CONTEXT_SAVE_GMEM |
48 KGSL_CONTEXT_NO_GMEM_ALLOC |
49 KGSL_CONTEXT_PREAMBLE,
50 };
51
52 int ret = safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_DRAWCTXT_CREATE, &req);
53 if (ret)
54 return ret;
55
56 *queue_id = req.drawctxt_id;
57
58 return 0;
59 }
60
61 void
tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)62 tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)
63 {
64 struct kgsl_drawctxt_destroy req = {
65 .drawctxt_id = queue_id,
66 };
67
68 safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &req);
69 }
70
71 VkResult
tu_bo_init_new(struct tu_device *dev, struct tu_bo **out_bo, uint64_t size, enum tu_bo_alloc_flags flags)72 tu_bo_init_new(struct tu_device *dev, struct tu_bo **out_bo, uint64_t size,
73 enum tu_bo_alloc_flags flags)
74 {
75 struct kgsl_gpumem_alloc_id req = {
76 .size = size,
77 };
78
79 if (flags & TU_BO_ALLOC_GPU_READ_ONLY)
80 req.flags |= KGSL_MEMFLAGS_GPUREADONLY;
81
82 int ret;
83
84 ret = safe_ioctl(dev->physical_device->local_fd,
85 IOCTL_KGSL_GPUMEM_ALLOC_ID, &req);
86 if (ret) {
87 return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
88 "GPUMEM_ALLOC_ID failed (%s)", strerror(errno));
89 }
90
91 struct tu_bo* bo = tu_device_lookup_bo(dev, req.id);
92 assert(bo && bo->gem_handle == 0);
93
94 *bo = (struct tu_bo) {
95 .gem_handle = req.id,
96 .size = req.mmapsize,
97 .iova = req.gpuaddr,
98 .refcnt = 1,
99 };
100
101 *out_bo = bo;
102
103 return VK_SUCCESS;
104 }
105
106 VkResult
tu_bo_init_dmabuf(struct tu_device *dev, struct tu_bo **out_bo, uint64_t size, int fd)107 tu_bo_init_dmabuf(struct tu_device *dev,
108 struct tu_bo **out_bo,
109 uint64_t size,
110 int fd)
111 {
112 struct kgsl_gpuobj_import_dma_buf import_dmabuf = {
113 .fd = fd,
114 };
115 struct kgsl_gpuobj_import req = {
116 .priv = (uintptr_t)&import_dmabuf,
117 .priv_len = sizeof(import_dmabuf),
118 .flags = 0,
119 .type = KGSL_USER_MEM_TYPE_DMABUF,
120 };
121 int ret;
122
123 ret = safe_ioctl(dev->physical_device->local_fd,
124 IOCTL_KGSL_GPUOBJ_IMPORT, &req);
125 if (ret)
126 return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
127 "Failed to import dma-buf (%s)\n", strerror(errno));
128
129 struct kgsl_gpuobj_info info_req = {
130 .id = req.id,
131 };
132
133 ret = safe_ioctl(dev->physical_device->local_fd,
134 IOCTL_KGSL_GPUOBJ_INFO, &info_req);
135 if (ret)
136 return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
137 "Failed to get dma-buf info (%s)\n", strerror(errno));
138
139 struct tu_bo* bo = tu_device_lookup_bo(dev, req.id);
140 assert(bo && bo->gem_handle == 0);
141
142 *bo = (struct tu_bo) {
143 .gem_handle = req.id,
144 .size = info_req.size,
145 .iova = info_req.gpuaddr,
146 .refcnt = 1,
147 };
148
149 *out_bo = bo;
150
151 return VK_SUCCESS;
152 }
153
154 int
tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)155 tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)
156 {
157 tu_stub();
158
159 return -1;
160 }
161
162 VkResult
tu_bo_map(struct tu_device *dev, struct tu_bo *bo)163 tu_bo_map(struct tu_device *dev, struct tu_bo *bo)
164 {
165 if (bo->map)
166 return VK_SUCCESS;
167
168 uint64_t offset = bo->gem_handle << 12;
169 void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
170 dev->physical_device->local_fd, offset);
171 if (map == MAP_FAILED)
172 return vk_error(dev, VK_ERROR_MEMORY_MAP_FAILED);
173
174 bo->map = map;
175
176 return VK_SUCCESS;
177 }
178
179 void
tu_bo_finish(struct tu_device *dev, struct tu_bo *bo)180 tu_bo_finish(struct tu_device *dev, struct tu_bo *bo)
181 {
182 assert(bo->gem_handle);
183
184 if (!p_atomic_dec_zero(&bo->refcnt))
185 return;
186
187 if (bo->map)
188 munmap(bo->map, bo->size);
189
190 struct kgsl_gpumem_free_id req = {
191 .id = bo->gem_handle
192 };
193
194 /* Tell sparse array that entry is free */
195 memset(bo, 0, sizeof(*bo));
196
197 safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_GPUMEM_FREE_ID, &req);
198 }
199
200 static VkResult
get_kgsl_prop(int fd, unsigned int type, void *value, size_t size)201 get_kgsl_prop(int fd, unsigned int type, void *value, size_t size)
202 {
203 struct kgsl_device_getproperty getprop = {
204 .type = type,
205 .value = value,
206 .sizebytes = size,
207 };
208
209 return safe_ioctl(fd, IOCTL_KGSL_DEVICE_GETPROPERTY, &getprop);
210 }
211
212 VkResult
tu_enumerate_devices(struct tu_instance *instance)213 tu_enumerate_devices(struct tu_instance *instance)
214 {
215 static const char path[] = "/dev/kgsl-3d0";
216 int fd;
217
218 struct tu_physical_device *device = &instance->physical_devices[0];
219
220 if (instance->vk.enabled_extensions.KHR_display)
221 return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
222 "I can't KHR_display");
223
224 fd = open(path, O_RDWR | O_CLOEXEC);
225 if (fd < 0) {
226 instance->physical_device_count = 0;
227 return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
228 "failed to open device %s", path);
229 }
230
231 struct kgsl_devinfo info;
232 if (get_kgsl_prop(fd, KGSL_PROP_DEVICE_INFO, &info, sizeof(info)))
233 goto fail;
234
235 uint64_t gmem_iova;
236 if (get_kgsl_prop(fd, KGSL_PROP_UCHE_GMEM_VADDR, &gmem_iova, sizeof(gmem_iova)))
237 goto fail;
238
239 /* kgsl version check? */
240
241 if (instance->debug_flags & TU_DEBUG_STARTUP)
242 mesa_logi("Found compatible device '%s'.", path);
243
244 device->instance = instance;
245 device->master_fd = -1;
246 device->local_fd = fd;
247
248 device->dev_id.gpu_id =
249 ((info.chip_id >> 24) & 0xff) * 100 +
250 ((info.chip_id >> 16) & 0xff) * 10 +
251 ((info.chip_id >> 8) & 0xff);
252 device->dev_id.chip_id = info.chip_id;
253 device->gmem_size = env_var_as_unsigned("TU_GMEM", info.gmem_sizebytes);
254 device->gmem_base = gmem_iova;
255
256 device->heap.size = tu_get_system_heap_size();
257 device->heap.used = 0u;
258 device->heap.flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
259
260 if (tu_physical_device_init(device, instance) != VK_SUCCESS)
261 goto fail;
262
263 instance->physical_device_count = 1;
264
265 return VK_SUCCESS;
266
267 fail:
268 close(fd);
269 return VK_ERROR_INITIALIZATION_FAILED;
270 }
271
272 static int
timestamp_to_fd(struct tu_queue *queue, uint32_t timestamp)273 timestamp_to_fd(struct tu_queue *queue, uint32_t timestamp)
274 {
275 int fd;
276 struct kgsl_timestamp_event event = {
277 .type = KGSL_TIMESTAMP_EVENT_FENCE,
278 .context_id = queue->msm_queue_id,
279 .timestamp = timestamp,
280 .priv = &fd,
281 .len = sizeof(fd),
282 };
283
284 int ret = safe_ioctl(queue->device->fd, IOCTL_KGSL_TIMESTAMP_EVENT, &event);
285 if (ret)
286 return -1;
287
288 return fd;
289 }
290
291 /* return true if timestamp a is greater (more recent) then b
292 * this relies on timestamps never having a difference > (1<<31)
293 */
294 static inline bool
timestamp_cmp(uint32_t a, uint32_t b)295 timestamp_cmp(uint32_t a, uint32_t b)
296 {
297 return (int32_t) (a - b) >= 0;
298 }
299
300 static uint32_t
max_ts(uint32_t a, uint32_t b)301 max_ts(uint32_t a, uint32_t b)
302 {
303 return timestamp_cmp(a, b) ? a : b;
304 }
305
306 static uint32_t
min_ts(uint32_t a, uint32_t b)307 min_ts(uint32_t a, uint32_t b)
308 {
309 return timestamp_cmp(a, b) ? b : a;
310 }
311
312 static struct tu_syncobj
sync_merge(const VkSemaphore *syncobjs, uint32_t count, bool wait_all, bool reset)313 sync_merge(const VkSemaphore *syncobjs, uint32_t count, bool wait_all, bool reset)
314 {
315 struct tu_syncobj ret;
316
317 ret.timestamp_valid = false;
318
319 for (uint32_t i = 0; i < count; ++i) {
320 TU_FROM_HANDLE(tu_syncobj, sync, syncobjs[i]);
321
322 /* TODO: this means the fence is unsignaled and will never become signaled */
323 if (!sync->timestamp_valid)
324 continue;
325
326 if (!ret.timestamp_valid)
327 ret.timestamp = sync->timestamp;
328 else if (wait_all)
329 ret.timestamp = max_ts(ret.timestamp, sync->timestamp);
330 else
331 ret.timestamp = min_ts(ret.timestamp, sync->timestamp);
332
333 ret.timestamp_valid = true;
334 if (reset)
335 sync->timestamp_valid = false;
336
337 }
338 return ret;
339 }
340
341 VKAPI_ATTR VkResult VKAPI_CALL
tu_QueueSubmit2(VkQueue _queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence _fence)342 tu_QueueSubmit2(VkQueue _queue,
343 uint32_t submitCount,
344 const VkSubmitInfo2 *pSubmits,
345 VkFence _fence)
346 {
347 TU_FROM_HANDLE(tu_queue, queue, _queue);
348 TU_FROM_HANDLE(tu_syncobj, fence, _fence);
349 VkResult result = VK_SUCCESS;
350
351 if (unlikely(queue->device->physical_device->instance->debug_flags &
352 TU_DEBUG_LOG_SKIP_GMEM_OPS)) {
353 tu_dbg_log_gmem_load_store_skips(queue->device);
354 }
355
356 struct tu_cmd_buffer **submit_cmd_buffers[submitCount];
357 uint32_t submit_cmd_buffer_count[submitCount];
358
359 uint32_t max_entry_count = 0;
360 for (uint32_t i = 0; i < submitCount; ++i) {
361 const VkSubmitInfo2 *submit = pSubmits + i;
362
363 const VkPerformanceQuerySubmitInfoKHR *perf_info =
364 vk_find_struct_const(pSubmits[i].pNext,
365 PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
366
367 struct tu_cmd_buffer *old_cmd_buffers[submit->commandBufferInfoCount];
368 uint32_t cmdbuf_count = submit->commandBufferInfoCount;
369 for (uint32_t j = 0; j < cmdbuf_count; ++j) {
370 TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBufferInfos[j].commandBuffer);
371 old_cmd_buffers[j] = cmdbuf;
372 }
373
374 struct tu_cmd_buffer **cmd_buffers = old_cmd_buffers;
375 tu_insert_dynamic_cmdbufs(queue->device, &cmd_buffers, &cmdbuf_count);
376 if (cmd_buffers == old_cmd_buffers) {
377 cmd_buffers =
378 vk_alloc(&queue->device->vk.alloc,
379 sizeof(*cmd_buffers) * cmdbuf_count, 8,
380 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
381 memcpy(cmd_buffers, old_cmd_buffers,
382 sizeof(*cmd_buffers) * cmdbuf_count);
383 }
384 submit_cmd_buffers[i] = cmd_buffers;
385 submit_cmd_buffer_count[i] = cmdbuf_count;
386
387 uint32_t entry_count = 0;
388 for (uint32_t j = 0; j < cmdbuf_count; ++j) {
389 entry_count += cmd_buffers[i]->cs.entry_count;
390 if (perf_info)
391 entry_count++;
392 }
393
394 if (tu_autotune_submit_requires_fence(cmd_buffers, cmdbuf_count))
395 entry_count++;
396
397 max_entry_count = MAX2(max_entry_count, entry_count);
398 }
399
400 struct kgsl_command_object *cmds =
401 vk_alloc(&queue->device->vk.alloc,
402 sizeof(cmds[0]) * max_entry_count, 8,
403 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
404 if (cmds == NULL)
405 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
406
407 for (uint32_t i = 0; i < submitCount; ++i) {
408 const VkSubmitInfo2 *submit = pSubmits + i;
409 uint32_t entry_idx = 0;
410 const VkPerformanceQuerySubmitInfoKHR *perf_info =
411 vk_find_struct_const(pSubmits[i].pNext,
412 PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
413
414
415 struct tu_cmd_buffer **cmd_buffers = submit_cmd_buffers[i];
416 uint32_t cmdbuf_count = submit_cmd_buffer_count[i];
417 for (uint32_t j = 0; j < cmdbuf_count; j++) {
418 struct tu_cmd_buffer *cmdbuf = cmd_buffers[j];
419 struct tu_cs *cs = &cmdbuf->cs;
420
421 if (perf_info) {
422 struct tu_cs_entry *perf_cs_entry =
423 &cmdbuf->device->perfcntrs_pass_cs_entries[perf_info->counterPassIndex];
424
425 cmds[entry_idx++] = (struct kgsl_command_object) {
426 .offset = perf_cs_entry->offset,
427 .gpuaddr = perf_cs_entry->bo->iova,
428 .size = perf_cs_entry->size,
429 .flags = KGSL_CMDLIST_IB,
430 .id = perf_cs_entry->bo->gem_handle,
431 };
432 }
433
434 for (unsigned k = 0; k < cs->entry_count; k++) {
435 cmds[entry_idx++] = (struct kgsl_command_object) {
436 .offset = cs->entries[k].offset,
437 .gpuaddr = cs->entries[k].bo->iova,
438 .size = cs->entries[k].size,
439 .flags = KGSL_CMDLIST_IB,
440 .id = cs->entries[k].bo->gem_handle,
441 };
442 }
443 }
444
445 if (tu_autotune_submit_requires_fence(cmd_buffers, cmdbuf_count)) {
446 struct tu_cs *autotune_cs =
447 tu_autotune_on_submit(queue->device,
448 &queue->device->autotune,
449 cmd_buffers,
450 cmdbuf_count);
451 cmds[entry_idx++] = (struct kgsl_command_object) {
452 .offset = autotune_cs->entries[0].offset,
453 .gpuaddr = autotune_cs->entries[0].bo->iova,
454 .size = autotune_cs->entries[0].size,
455 .flags = KGSL_CMDLIST_IB,
456 .id = autotune_cs->entries[0].bo->gem_handle,
457 };
458 }
459
460 VkSemaphore wait_semaphores[submit->waitSemaphoreInfoCount];
461 for (uint32_t j = 0; j < submit->waitSemaphoreInfoCount; j++) {
462 wait_semaphores[j] = submit->pWaitSemaphoreInfos[j].semaphore;
463 }
464
465 struct tu_syncobj s = sync_merge(wait_semaphores,
466 submit->waitSemaphoreInfoCount,
467 true, true);
468
469 struct kgsl_cmd_syncpoint_timestamp ts = {
470 .context_id = queue->msm_queue_id,
471 .timestamp = s.timestamp,
472 };
473 struct kgsl_command_syncpoint sync = {
474 .type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP,
475 .size = sizeof(ts),
476 .priv = (uintptr_t) &ts,
477 };
478
479 struct kgsl_gpu_command req = {
480 .flags = KGSL_CMDBATCH_SUBMIT_IB_LIST,
481 .context_id = queue->msm_queue_id,
482 .cmdlist = (uint64_t) (uintptr_t) cmds,
483 .numcmds = entry_idx,
484 .cmdsize = sizeof(struct kgsl_command_object),
485 .synclist = (uintptr_t) &sync,
486 .syncsize = sizeof(struct kgsl_command_syncpoint),
487 .numsyncs = s.timestamp_valid ? 1 : 0,
488 };
489
490 int ret = safe_ioctl(queue->device->physical_device->local_fd,
491 IOCTL_KGSL_GPU_COMMAND, &req);
492 if (ret) {
493 result = vk_device_set_lost(&queue->device->vk,
494 "submit failed: %s\n", strerror(errno));
495 goto fail;
496 }
497
498 for (uint32_t i = 0; i < submit->signalSemaphoreInfoCount; i++) {
499 TU_FROM_HANDLE(tu_syncobj, sem, submit->pSignalSemaphoreInfos[i].semaphore);
500 sem->timestamp = req.timestamp;
501 sem->timestamp_valid = true;
502 }
503
504 /* no need to merge fences as queue execution is serialized */
505 if (i == submitCount - 1) {
506 int fd = timestamp_to_fd(queue, req.timestamp);
507 if (fd < 0) {
508 result = vk_device_set_lost(&queue->device->vk,
509 "Failed to create sync file for timestamp: %s\n",
510 strerror(errno));
511 goto fail;
512 }
513
514 if (queue->fence >= 0)
515 close(queue->fence);
516 queue->fence = fd;
517
518 if (fence) {
519 fence->timestamp = req.timestamp;
520 fence->timestamp_valid = true;
521 }
522 }
523 }
524 fail:
525 vk_free(&queue->device->vk.alloc, cmds);
526
527 return result;
528 }
529
530 static VkResult
sync_create(VkDevice _device, bool signaled, bool fence, const VkAllocationCallbacks *pAllocator, void **p_sync)531 sync_create(VkDevice _device,
532 bool signaled,
533 bool fence,
534 const VkAllocationCallbacks *pAllocator,
535 void **p_sync)
536 {
537 TU_FROM_HANDLE(tu_device, device, _device);
538
539 struct tu_syncobj *sync =
540 vk_object_alloc(&device->vk, pAllocator, sizeof(*sync),
541 fence ? VK_OBJECT_TYPE_FENCE : VK_OBJECT_TYPE_SEMAPHORE);
542 if (!sync)
543 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
544
545 if (signaled)
546 tu_finishme("CREATE FENCE SIGNALED");
547
548 sync->timestamp_valid = false;
549 *p_sync = sync;
550
551 return VK_SUCCESS;
552 }
553
554 VKAPI_ATTR VkResult VKAPI_CALL
tu_ImportSemaphoreFdKHR(VkDevice _device, const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)555 tu_ImportSemaphoreFdKHR(VkDevice _device,
556 const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
557 {
558 tu_finishme("ImportSemaphoreFdKHR");
559 return VK_SUCCESS;
560 }
561
562 VKAPI_ATTR VkResult VKAPI_CALL
tu_GetSemaphoreFdKHR(VkDevice _device, const VkSemaphoreGetFdInfoKHR *pGetFdInfo, int *pFd)563 tu_GetSemaphoreFdKHR(VkDevice _device,
564 const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
565 int *pFd)
566 {
567 tu_finishme("GetSemaphoreFdKHR");
568 return VK_SUCCESS;
569 }
570
571 VKAPI_ATTR VkResult VKAPI_CALL
tu_CreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore)572 tu_CreateSemaphore(VkDevice device,
573 const VkSemaphoreCreateInfo *pCreateInfo,
574 const VkAllocationCallbacks *pAllocator,
575 VkSemaphore *pSemaphore)
576 {
577 return sync_create(device, false, false, pAllocator, (void**) pSemaphore);
578 }
579
580 VKAPI_ATTR void VKAPI_CALL
tu_DestroySemaphore(VkDevice _device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator)581 tu_DestroySemaphore(VkDevice _device,
582 VkSemaphore semaphore,
583 const VkAllocationCallbacks *pAllocator)
584 {
585 TU_FROM_HANDLE(tu_device, device, _device);
586 TU_FROM_HANDLE(tu_syncobj, sync, semaphore);
587
588 if (!sync)
589 return;
590
591 vk_object_free(&device->vk, pAllocator, sync);
592 }
593
594 VKAPI_ATTR VkResult VKAPI_CALL
tu_ImportFenceFdKHR(VkDevice _device, const VkImportFenceFdInfoKHR *pImportFenceFdInfo)595 tu_ImportFenceFdKHR(VkDevice _device,
596 const VkImportFenceFdInfoKHR *pImportFenceFdInfo)
597 {
598 tu_stub();
599
600 return VK_SUCCESS;
601 }
602
603 VKAPI_ATTR VkResult VKAPI_CALL
tu_GetFenceFdKHR(VkDevice _device, const VkFenceGetFdInfoKHR *pGetFdInfo, int *pFd)604 tu_GetFenceFdKHR(VkDevice _device,
605 const VkFenceGetFdInfoKHR *pGetFdInfo,
606 int *pFd)
607 {
608 tu_stub();
609
610 return VK_SUCCESS;
611 }
612
613 VKAPI_ATTR VkResult VKAPI_CALL
tu_CreateFence(VkDevice device, const VkFenceCreateInfo *info, const VkAllocationCallbacks *pAllocator, VkFence *pFence)614 tu_CreateFence(VkDevice device,
615 const VkFenceCreateInfo *info,
616 const VkAllocationCallbacks *pAllocator,
617 VkFence *pFence)
618 {
619 return sync_create(device, info->flags & VK_FENCE_CREATE_SIGNALED_BIT, true,
620 pAllocator, (void**) pFence);
621 }
622
623 VKAPI_ATTR void VKAPI_CALL
tu_DestroyFence(VkDevice _device, VkFence fence, const VkAllocationCallbacks *pAllocator)624 tu_DestroyFence(VkDevice _device, VkFence fence, const VkAllocationCallbacks *pAllocator)
625 {
626 TU_FROM_HANDLE(tu_device, device, _device);
627 TU_FROM_HANDLE(tu_syncobj, sync, fence);
628
629 if (!sync)
630 return;
631
632 vk_object_free(&device->vk, pAllocator, sync);
633 }
634
635 VKAPI_ATTR VkResult VKAPI_CALL
tu_WaitForFences(VkDevice _device, uint32_t count, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout)636 tu_WaitForFences(VkDevice _device,
637 uint32_t count,
638 const VkFence *pFences,
639 VkBool32 waitAll,
640 uint64_t timeout)
641 {
642 TU_FROM_HANDLE(tu_device, device, _device);
643 struct tu_syncobj s = sync_merge((const VkSemaphore*) pFences, count, waitAll, false);
644
645 if (!s.timestamp_valid)
646 return VK_SUCCESS;
647
648 int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
649 &(struct kgsl_device_waittimestamp_ctxtid) {
650 .context_id = device->queues[0]->msm_queue_id,
651 .timestamp = s.timestamp,
652 .timeout = timeout / 1000000,
653 });
654 if (ret) {
655 assert(errno == ETIME);
656 return VK_TIMEOUT;
657 }
658
659 return VK_SUCCESS;
660 }
661
662 VKAPI_ATTR VkResult VKAPI_CALL
tu_ResetFences(VkDevice _device, uint32_t count, const VkFence *pFences)663 tu_ResetFences(VkDevice _device, uint32_t count, const VkFence *pFences)
664 {
665 for (uint32_t i = 0; i < count; i++) {
666 TU_FROM_HANDLE(tu_syncobj, sync, pFences[i]);
667 sync->timestamp_valid = false;
668 }
669 return VK_SUCCESS;
670 }
671
672 VKAPI_ATTR VkResult VKAPI_CALL
tu_GetFenceStatus(VkDevice _device, VkFence _fence)673 tu_GetFenceStatus(VkDevice _device, VkFence _fence)
674 {
675 TU_FROM_HANDLE(tu_device, device, _device);
676 TU_FROM_HANDLE(tu_syncobj, sync, _fence);
677
678 if (!sync->timestamp_valid)
679 return VK_NOT_READY;
680
681 int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
682 &(struct kgsl_device_waittimestamp_ctxtid) {
683 .context_id = device->queues[0]->msm_queue_id,
684 .timestamp = sync->timestamp,
685 .timeout = 0,
686 });
687 if (ret) {
688 assert(errno == ETIME);
689 return VK_NOT_READY;
690 }
691
692 return VK_SUCCESS;
693 }
694
695 int
tu_syncobj_to_fd(struct tu_device *device, struct vk_sync *sync)696 tu_syncobj_to_fd(struct tu_device *device, struct vk_sync *sync)
697 {
698 tu_finishme("tu_syncobj_to_fd");
699 return -1;
700 }
701
702 VkResult
tu_device_wait_u_trace(struct tu_device *dev, struct tu_u_trace_syncobj *syncobj)703 tu_device_wait_u_trace(struct tu_device *dev, struct tu_u_trace_syncobj *syncobj)
704 {
705 tu_finishme("tu_device_wait_u_trace");
706 return VK_SUCCESS;
707 }
708
709 int
tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts)710 tu_device_get_gpu_timestamp(struct tu_device *dev, uint64_t *ts)
711 {
712 tu_finishme("tu_device_get_gpu_timestamp");
713 return 0;
714 }
715
716 int
tu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count)717 tu_device_get_suspend_count(struct tu_device *dev, uint64_t *suspend_count)
718 {
719 /* kgsl doesn't have a way to get it */
720 *suspend_count = 0;
721 return 0;
722 }
723
724 VkResult
tu_device_check_status(struct vk_device *vk_device)725 tu_device_check_status(struct vk_device *vk_device)
726 {
727 struct tu_device *device = container_of(vk_device, struct tu_device, vk);
728
729 for (unsigned i = 0; i < TU_MAX_QUEUE_FAMILIES; i++) {
730 for (unsigned q = 0; q < device->queue_count[i]; q++) {
731 /* KGSL's KGSL_PROP_GPU_RESET_STAT takes the u32 msm_queue_id and returns a
732 * KGSL_CTX_STAT_* for the worst reset that happened since the last time it
733 * was queried on that queue.
734 */
735 uint32_t value = device->queues[i][q].msm_queue_id;
736 VkResult status = get_kgsl_prop(device->fd, KGSL_PROP_GPU_RESET_STAT,
737 &value, sizeof(value));
738 if (status != VK_SUCCESS)
739 return vk_device_set_lost(&device->vk, "Failed to get GPU reset status");
740
741 if (value != KGSL_CTX_STAT_NO_ERROR &&
742 value != KGSL_CTX_STAT_INNOCENT_CONTEXT_RESET_EXT) {
743 return vk_device_set_lost(&device->vk, "GPU faulted or hung");
744 }
745 }
746 }
747
748 return VK_SUCCESS;
749 }
750
751 #ifdef ANDROID
752 VKAPI_ATTR VkResult VKAPI_CALL
tu_QueueSignalReleaseImageANDROID(VkQueue _queue, uint32_t waitSemaphoreCount, const VkSemaphore *pWaitSemaphores, VkImage image, int *pNativeFenceFd)753 tu_QueueSignalReleaseImageANDROID(VkQueue _queue,
754 uint32_t waitSemaphoreCount,
755 const VkSemaphore *pWaitSemaphores,
756 VkImage image,
757 int *pNativeFenceFd)
758 {
759 TU_FROM_HANDLE(tu_queue, queue, _queue);
760 if (!pNativeFenceFd)
761 return VK_SUCCESS;
762
763 struct tu_syncobj s = sync_merge(pWaitSemaphores, waitSemaphoreCount, true, true);
764
765 if (!s.timestamp_valid) {
766 *pNativeFenceFd = -1;
767 return VK_SUCCESS;
768 }
769
770 *pNativeFenceFd = timestamp_to_fd(queue, s.timestamp);
771
772 return VK_SUCCESS;
773 }
774 #endif
775