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