1 /*
2 * Copyright © 2020 Google, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "tu_private.h"
25
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <stdint.h>
29 #include <sys/ioctl.h>
30 #include <sys/mman.h>
31
32 #include "msm_kgsl.h"
33 #include "vk_util.h"
34
35 struct tu_syncobj {
36 struct vk_object_base base;
37 uint32_t timestamp;
38 bool timestamp_valid;
39 };
40
41 static int
safe_ioctl(int fd,unsigned long request,void * arg)42 safe_ioctl(int fd, unsigned long request, void *arg)
43 {
44 int ret;
45
46 do {
47 ret = ioctl(fd, request, arg);
48 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
49
50 return ret;
51 }
52
53 int
tu_drm_submitqueue_new(const struct tu_device * dev,int priority,uint32_t * queue_id)54 tu_drm_submitqueue_new(const struct tu_device *dev,
55 int priority,
56 uint32_t *queue_id)
57 {
58 struct kgsl_drawctxt_create req = {
59 .flags = KGSL_CONTEXT_SAVE_GMEM |
60 KGSL_CONTEXT_NO_GMEM_ALLOC |
61 KGSL_CONTEXT_PREAMBLE,
62 };
63
64 int ret = safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_DRAWCTXT_CREATE, &req);
65 if (ret)
66 return ret;
67
68 *queue_id = req.drawctxt_id;
69
70 return 0;
71 }
72
73 void
tu_drm_submitqueue_close(const struct tu_device * dev,uint32_t queue_id)74 tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)
75 {
76 struct kgsl_drawctxt_destroy req = {
77 .drawctxt_id = queue_id,
78 };
79
80 safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &req);
81 }
82
83 VkResult
tu_bo_init_new(struct tu_device * dev,struct tu_bo * bo,uint64_t size,enum tu_bo_alloc_flags flags)84 tu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size,
85 enum tu_bo_alloc_flags flags)
86 {
87 struct kgsl_gpumem_alloc_id req = {
88 .size = size,
89 };
90
91 if (flags & TU_BO_ALLOC_GPU_READ_ONLY)
92 req.flags |= KGSL_MEMFLAGS_GPUREADONLY;
93
94 int ret;
95
96 ret = safe_ioctl(dev->physical_device->local_fd,
97 IOCTL_KGSL_GPUMEM_ALLOC_ID, &req);
98 if (ret) {
99 return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
100 "GPUMEM_ALLOC_ID failed (%s)", strerror(errno));
101 }
102
103 *bo = (struct tu_bo) {
104 .gem_handle = req.id,
105 .size = req.mmapsize,
106 .iova = req.gpuaddr,
107 };
108
109 return VK_SUCCESS;
110 }
111
112 VkResult
tu_bo_init_dmabuf(struct tu_device * dev,struct tu_bo * bo,uint64_t size,int fd)113 tu_bo_init_dmabuf(struct tu_device *dev,
114 struct tu_bo *bo,
115 uint64_t size,
116 int fd)
117 {
118 struct kgsl_gpuobj_import_dma_buf import_dmabuf = {
119 .fd = fd,
120 };
121 struct kgsl_gpuobj_import req = {
122 .priv = (uintptr_t)&import_dmabuf,
123 .priv_len = sizeof(import_dmabuf),
124 .flags = 0,
125 .type = KGSL_USER_MEM_TYPE_DMABUF,
126 };
127 int ret;
128
129 ret = safe_ioctl(dev->physical_device->local_fd,
130 IOCTL_KGSL_GPUOBJ_IMPORT, &req);
131 if (ret)
132 return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
133 "Failed to import dma-buf (%s)\n", strerror(errno));
134
135 struct kgsl_gpuobj_info info_req = {
136 .id = req.id,
137 };
138
139 ret = safe_ioctl(dev->physical_device->local_fd,
140 IOCTL_KGSL_GPUOBJ_INFO, &info_req);
141 if (ret)
142 return vk_errorf(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY,
143 "Failed to get dma-buf info (%s)\n", strerror(errno));
144
145 *bo = (struct tu_bo) {
146 .gem_handle = req.id,
147 .size = info_req.size,
148 .iova = info_req.gpuaddr,
149 };
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 (bo->map)
185 munmap(bo->map, bo->size);
186
187 struct kgsl_gpumem_free_id req = {
188 .id = bo->gem_handle
189 };
190
191 safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_GPUMEM_FREE_ID, &req);
192 }
193
194 static VkResult
get_kgsl_prop(int fd,unsigned int type,void * value,size_t size)195 get_kgsl_prop(int fd, unsigned int type, void *value, size_t size)
196 {
197 struct kgsl_device_getproperty getprop = {
198 .type = type,
199 .value = value,
200 .sizebytes = size,
201 };
202
203 return safe_ioctl(fd, IOCTL_KGSL_DEVICE_GETPROPERTY, &getprop);
204 }
205
206 VkResult
tu_enumerate_devices(struct tu_instance * instance)207 tu_enumerate_devices(struct tu_instance *instance)
208 {
209 static const char path[] = "/dev/kgsl-3d0";
210 int fd;
211
212 struct tu_physical_device *device = &instance->physical_devices[0];
213
214 if (instance->vk.enabled_extensions.KHR_display)
215 return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
216 "I can't KHR_display");
217
218 fd = open(path, O_RDWR | O_CLOEXEC);
219 if (fd < 0) {
220 instance->physical_device_count = 0;
221 return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
222 "failed to open device %s", path);
223 }
224
225 struct kgsl_devinfo info;
226 if (get_kgsl_prop(fd, KGSL_PROP_DEVICE_INFO, &info, sizeof(info)))
227 goto fail;
228
229 uint64_t gmem_iova;
230 if (get_kgsl_prop(fd, KGSL_PROP_UCHE_GMEM_VADDR, &gmem_iova, sizeof(gmem_iova)))
231 goto fail;
232
233 /* kgsl version check? */
234
235 if (instance->debug_flags & TU_DEBUG_STARTUP)
236 mesa_logi("Found compatible device '%s'.", path);
237
238 device->instance = instance;
239 device->master_fd = -1;
240 device->local_fd = fd;
241
242 device->dev_id.gpu_id =
243 ((info.chip_id >> 24) & 0xff) * 100 +
244 ((info.chip_id >> 16) & 0xff) * 10 +
245 ((info.chip_id >> 8) & 0xff);
246 device->dev_id.chip_id = info.chip_id;
247 device->gmem_size = info.gmem_sizebytes;
248 device->gmem_base = gmem_iova;
249
250 device->heap.size = tu_get_system_heap_size();
251 device->heap.used = 0u;
252 device->heap.flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
253
254 if (tu_physical_device_init(device, instance) != VK_SUCCESS)
255 goto fail;
256
257 instance->physical_device_count = 1;
258
259 return VK_SUCCESS;
260
261 fail:
262 close(fd);
263 return VK_ERROR_INITIALIZATION_FAILED;
264 }
265
266 static int
timestamp_to_fd(struct tu_queue * queue,uint32_t timestamp)267 timestamp_to_fd(struct tu_queue *queue, uint32_t timestamp)
268 {
269 int fd;
270 struct kgsl_timestamp_event event = {
271 .type = KGSL_TIMESTAMP_EVENT_FENCE,
272 .context_id = queue->msm_queue_id,
273 .timestamp = timestamp,
274 .priv = &fd,
275 .len = sizeof(fd),
276 };
277
278 int ret = safe_ioctl(queue->device->fd, IOCTL_KGSL_TIMESTAMP_EVENT, &event);
279 if (ret)
280 return -1;
281
282 return fd;
283 }
284
285 /* return true if timestamp a is greater (more recent) then b
286 * this relies on timestamps never having a difference > (1<<31)
287 */
288 static inline bool
timestamp_cmp(uint32_t a,uint32_t b)289 timestamp_cmp(uint32_t a, uint32_t b)
290 {
291 return (int32_t) (a - b) >= 0;
292 }
293
294 static uint32_t
max_ts(uint32_t a,uint32_t b)295 max_ts(uint32_t a, uint32_t b)
296 {
297 return timestamp_cmp(a, b) ? a : b;
298 }
299
300 static uint32_t
min_ts(uint32_t a,uint32_t b)301 min_ts(uint32_t a, uint32_t b)
302 {
303 return timestamp_cmp(a, b) ? b : a;
304 }
305
306 static struct tu_syncobj
sync_merge(const VkSemaphore * syncobjs,uint32_t count,bool wait_all,bool reset)307 sync_merge(const VkSemaphore *syncobjs, uint32_t count, bool wait_all, bool reset)
308 {
309 struct tu_syncobj ret;
310
311 ret.timestamp_valid = false;
312
313 for (uint32_t i = 0; i < count; ++i) {
314 TU_FROM_HANDLE(tu_syncobj, sync, syncobjs[i]);
315
316 /* TODO: this means the fence is unsignaled and will never become signaled */
317 if (!sync->timestamp_valid)
318 continue;
319
320 if (!ret.timestamp_valid)
321 ret.timestamp = sync->timestamp;
322 else if (wait_all)
323 ret.timestamp = max_ts(ret.timestamp, sync->timestamp);
324 else
325 ret.timestamp = min_ts(ret.timestamp, sync->timestamp);
326
327 ret.timestamp_valid = true;
328 if (reset)
329 sync->timestamp_valid = false;
330
331 }
332 return ret;
333 }
334
335 VKAPI_ATTR VkResult VKAPI_CALL
tu_QueueSubmit(VkQueue _queue,uint32_t submitCount,const VkSubmitInfo * pSubmits,VkFence _fence)336 tu_QueueSubmit(VkQueue _queue,
337 uint32_t submitCount,
338 const VkSubmitInfo *pSubmits,
339 VkFence _fence)
340 {
341 TU_FROM_HANDLE(tu_queue, queue, _queue);
342 TU_FROM_HANDLE(tu_syncobj, fence, _fence);
343 VkResult result = VK_SUCCESS;
344
345 uint32_t max_entry_count = 0;
346 for (uint32_t i = 0; i < submitCount; ++i) {
347 const VkSubmitInfo *submit = pSubmits + i;
348
349 const VkPerformanceQuerySubmitInfoKHR *perf_info =
350 vk_find_struct_const(pSubmits[i].pNext,
351 PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
352
353 uint32_t entry_count = 0;
354 for (uint32_t j = 0; j < submit->commandBufferCount; ++j) {
355 TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);
356 entry_count += cmdbuf->cs.entry_count;
357 if (perf_info)
358 entry_count++;
359 }
360
361 max_entry_count = MAX2(max_entry_count, entry_count);
362 }
363
364 struct kgsl_command_object *cmds =
365 vk_alloc(&queue->device->vk.alloc,
366 sizeof(cmds[0]) * max_entry_count, 8,
367 VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);
368 if (cmds == NULL)
369 return vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
370
371 for (uint32_t i = 0; i < submitCount; ++i) {
372 const VkSubmitInfo *submit = pSubmits + i;
373 uint32_t entry_idx = 0;
374 const VkPerformanceQuerySubmitInfoKHR *perf_info =
375 vk_find_struct_const(pSubmits[i].pNext,
376 PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
377
378
379 for (uint32_t j = 0; j < submit->commandBufferCount; j++) {
380 TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);
381 struct tu_cs *cs = &cmdbuf->cs;
382
383 if (perf_info) {
384 struct tu_cs_entry *perf_cs_entry =
385 &cmdbuf->device->perfcntrs_pass_cs_entries[perf_info->counterPassIndex];
386
387 cmds[entry_idx++] = (struct kgsl_command_object) {
388 .offset = perf_cs_entry->offset,
389 .gpuaddr = perf_cs_entry->bo->iova,
390 .size = perf_cs_entry->size,
391 .flags = KGSL_CMDLIST_IB,
392 .id = perf_cs_entry->bo->gem_handle,
393 };
394 }
395
396 for (unsigned k = 0; k < cs->entry_count; k++) {
397 cmds[entry_idx++] = (struct kgsl_command_object) {
398 .offset = cs->entries[k].offset,
399 .gpuaddr = cs->entries[k].bo->iova,
400 .size = cs->entries[k].size,
401 .flags = KGSL_CMDLIST_IB,
402 .id = cs->entries[k].bo->gem_handle,
403 };
404 }
405 }
406
407 struct tu_syncobj s = sync_merge(submit->pWaitSemaphores,
408 submit->waitSemaphoreCount,
409 true, true);
410
411 struct kgsl_cmd_syncpoint_timestamp ts = {
412 .context_id = queue->msm_queue_id,
413 .timestamp = s.timestamp,
414 };
415 struct kgsl_command_syncpoint sync = {
416 .type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP,
417 .size = sizeof(ts),
418 .priv = (uintptr_t) &ts,
419 };
420
421 struct kgsl_gpu_command req = {
422 .flags = KGSL_CMDBATCH_SUBMIT_IB_LIST,
423 .context_id = queue->msm_queue_id,
424 .cmdlist = (uint64_t) (uintptr_t) cmds,
425 .numcmds = entry_idx,
426 .cmdsize = sizeof(struct kgsl_command_object),
427 .synclist = (uintptr_t) &sync,
428 .syncsize = sizeof(struct kgsl_command_syncpoint),
429 .numsyncs = s.timestamp_valid ? 1 : 0,
430 };
431
432 int ret = safe_ioctl(queue->device->physical_device->local_fd,
433 IOCTL_KGSL_GPU_COMMAND, &req);
434 if (ret) {
435 result = tu_device_set_lost(queue->device,
436 "submit failed: %s\n", strerror(errno));
437 goto fail;
438 }
439
440 for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) {
441 TU_FROM_HANDLE(tu_syncobj, sem, submit->pSignalSemaphores[i]);
442 sem->timestamp = req.timestamp;
443 sem->timestamp_valid = true;
444 }
445
446 /* no need to merge fences as queue execution is serialized */
447 if (i == submitCount - 1) {
448 int fd = timestamp_to_fd(queue, req.timestamp);
449 if (fd < 0) {
450 result = tu_device_set_lost(queue->device,
451 "Failed to create sync file for timestamp: %s\n",
452 strerror(errno));
453 goto fail;
454 }
455
456 if (queue->fence >= 0)
457 close(queue->fence);
458 queue->fence = fd;
459
460 if (fence) {
461 fence->timestamp = req.timestamp;
462 fence->timestamp_valid = true;
463 }
464 }
465 }
466 fail:
467 vk_free(&queue->device->vk.alloc, cmds);
468
469 return result;
470 }
471
472 static VkResult
sync_create(VkDevice _device,bool signaled,bool fence,const VkAllocationCallbacks * pAllocator,void ** p_sync)473 sync_create(VkDevice _device,
474 bool signaled,
475 bool fence,
476 const VkAllocationCallbacks *pAllocator,
477 void **p_sync)
478 {
479 TU_FROM_HANDLE(tu_device, device, _device);
480
481 struct tu_syncobj *sync =
482 vk_object_alloc(&device->vk, pAllocator, sizeof(*sync),
483 fence ? VK_OBJECT_TYPE_FENCE : VK_OBJECT_TYPE_SEMAPHORE);
484 if (!sync)
485 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
486
487 if (signaled)
488 tu_finishme("CREATE FENCE SIGNALED");
489
490 sync->timestamp_valid = false;
491 *p_sync = sync;
492
493 return VK_SUCCESS;
494 }
495
496 VKAPI_ATTR VkResult VKAPI_CALL
tu_ImportSemaphoreFdKHR(VkDevice _device,const VkImportSemaphoreFdInfoKHR * pImportSemaphoreFdInfo)497 tu_ImportSemaphoreFdKHR(VkDevice _device,
498 const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
499 {
500 tu_finishme("ImportSemaphoreFdKHR");
501 return VK_SUCCESS;
502 }
503
504 VKAPI_ATTR VkResult VKAPI_CALL
tu_GetSemaphoreFdKHR(VkDevice _device,const VkSemaphoreGetFdInfoKHR * pGetFdInfo,int * pFd)505 tu_GetSemaphoreFdKHR(VkDevice _device,
506 const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
507 int *pFd)
508 {
509 tu_finishme("GetSemaphoreFdKHR");
510 return VK_SUCCESS;
511 }
512
513 VKAPI_ATTR VkResult VKAPI_CALL
tu_CreateSemaphore(VkDevice device,const VkSemaphoreCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSemaphore * pSemaphore)514 tu_CreateSemaphore(VkDevice device,
515 const VkSemaphoreCreateInfo *pCreateInfo,
516 const VkAllocationCallbacks *pAllocator,
517 VkSemaphore *pSemaphore)
518 {
519 return sync_create(device, false, false, pAllocator, (void**) pSemaphore);
520 }
521
522 VKAPI_ATTR void VKAPI_CALL
tu_DestroySemaphore(VkDevice _device,VkSemaphore semaphore,const VkAllocationCallbacks * pAllocator)523 tu_DestroySemaphore(VkDevice _device,
524 VkSemaphore semaphore,
525 const VkAllocationCallbacks *pAllocator)
526 {
527 TU_FROM_HANDLE(tu_device, device, _device);
528 TU_FROM_HANDLE(tu_syncobj, sync, semaphore);
529
530 if (!sync)
531 return;
532
533 vk_object_free(&device->vk, pAllocator, sync);
534 }
535
536 VKAPI_ATTR VkResult VKAPI_CALL
tu_ImportFenceFdKHR(VkDevice _device,const VkImportFenceFdInfoKHR * pImportFenceFdInfo)537 tu_ImportFenceFdKHR(VkDevice _device,
538 const VkImportFenceFdInfoKHR *pImportFenceFdInfo)
539 {
540 tu_stub();
541
542 return VK_SUCCESS;
543 }
544
545 VKAPI_ATTR VkResult VKAPI_CALL
tu_GetFenceFdKHR(VkDevice _device,const VkFenceGetFdInfoKHR * pGetFdInfo,int * pFd)546 tu_GetFenceFdKHR(VkDevice _device,
547 const VkFenceGetFdInfoKHR *pGetFdInfo,
548 int *pFd)
549 {
550 tu_stub();
551
552 return VK_SUCCESS;
553 }
554
555 VKAPI_ATTR VkResult VKAPI_CALL
tu_CreateFence(VkDevice device,const VkFenceCreateInfo * info,const VkAllocationCallbacks * pAllocator,VkFence * pFence)556 tu_CreateFence(VkDevice device,
557 const VkFenceCreateInfo *info,
558 const VkAllocationCallbacks *pAllocator,
559 VkFence *pFence)
560 {
561 return sync_create(device, info->flags & VK_FENCE_CREATE_SIGNALED_BIT, true,
562 pAllocator, (void**) pFence);
563 }
564
565 VKAPI_ATTR void VKAPI_CALL
tu_DestroyFence(VkDevice _device,VkFence fence,const VkAllocationCallbacks * pAllocator)566 tu_DestroyFence(VkDevice _device, VkFence fence, const VkAllocationCallbacks *pAllocator)
567 {
568 TU_FROM_HANDLE(tu_device, device, _device);
569 TU_FROM_HANDLE(tu_syncobj, sync, fence);
570
571 if (!sync)
572 return;
573
574 vk_object_free(&device->vk, pAllocator, sync);
575 }
576
577 VKAPI_ATTR VkResult VKAPI_CALL
tu_WaitForFences(VkDevice _device,uint32_t count,const VkFence * pFences,VkBool32 waitAll,uint64_t timeout)578 tu_WaitForFences(VkDevice _device,
579 uint32_t count,
580 const VkFence *pFences,
581 VkBool32 waitAll,
582 uint64_t timeout)
583 {
584 TU_FROM_HANDLE(tu_device, device, _device);
585 struct tu_syncobj s = sync_merge((const VkSemaphore*) pFences, count, waitAll, false);
586
587 if (!s.timestamp_valid)
588 return VK_SUCCESS;
589
590 int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
591 &(struct kgsl_device_waittimestamp_ctxtid) {
592 .context_id = device->queues[0]->msm_queue_id,
593 .timestamp = s.timestamp,
594 .timeout = timeout / 1000000,
595 });
596 if (ret) {
597 assert(errno == ETIME);
598 return VK_TIMEOUT;
599 }
600
601 return VK_SUCCESS;
602 }
603
604 VKAPI_ATTR VkResult VKAPI_CALL
tu_ResetFences(VkDevice _device,uint32_t count,const VkFence * pFences)605 tu_ResetFences(VkDevice _device, uint32_t count, const VkFence *pFences)
606 {
607 for (uint32_t i = 0; i < count; i++) {
608 TU_FROM_HANDLE(tu_syncobj, sync, pFences[i]);
609 sync->timestamp_valid = false;
610 }
611 return VK_SUCCESS;
612 }
613
614 VKAPI_ATTR VkResult VKAPI_CALL
tu_GetFenceStatus(VkDevice _device,VkFence _fence)615 tu_GetFenceStatus(VkDevice _device, VkFence _fence)
616 {
617 TU_FROM_HANDLE(tu_device, device, _device);
618 TU_FROM_HANDLE(tu_syncobj, sync, _fence);
619
620 if (!sync->timestamp_valid)
621 return VK_NOT_READY;
622
623 int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
624 &(struct kgsl_device_waittimestamp_ctxtid) {
625 .context_id = device->queues[0]->msm_queue_id,
626 .timestamp = sync->timestamp,
627 .timeout = 0,
628 });
629 if (ret) {
630 assert(errno == ETIME);
631 return VK_NOT_READY;
632 }
633
634 return VK_SUCCESS;
635 }
636
637 int
tu_signal_fences(struct tu_device * device,struct tu_syncobj * fence1,struct tu_syncobj * fence2)638 tu_signal_fences(struct tu_device *device, struct tu_syncobj *fence1, struct tu_syncobj *fence2)
639 {
640 tu_finishme("tu_signal_fences");
641 return 0;
642 }
643
644 int
tu_syncobj_to_fd(struct tu_device * device,struct tu_syncobj * sync)645 tu_syncobj_to_fd(struct tu_device *device, struct tu_syncobj *sync)
646 {
647 tu_finishme("tu_syncobj_to_fd");
648 return -1;
649 }
650
651 VkResult
tu_device_submit_deferred_locked(struct tu_device * dev)652 tu_device_submit_deferred_locked(struct tu_device *dev)
653 {
654 tu_finishme("tu_device_submit_deferred_locked");
655
656 return VK_SUCCESS;
657 }
658
659 VkResult
tu_device_wait_u_trace(struct tu_device * dev,struct tu_u_trace_syncobj * syncobj)660 tu_device_wait_u_trace(struct tu_device *dev, struct tu_u_trace_syncobj *syncobj)
661 {
662 tu_finishme("tu_device_wait_u_trace");
663 return VK_SUCCESS;
664 }
665
666 int
tu_drm_get_timestamp(struct tu_physical_device * device,uint64_t * ts)667 tu_drm_get_timestamp(struct tu_physical_device *device, uint64_t *ts)
668 {
669 tu_finishme("tu_drm_get_timestamp");
670 return 0;
671 }
672
673 #ifdef ANDROID
674 VKAPI_ATTR VkResult VKAPI_CALL
tu_QueueSignalReleaseImageANDROID(VkQueue _queue,uint32_t waitSemaphoreCount,const VkSemaphore * pWaitSemaphores,VkImage image,int * pNativeFenceFd)675 tu_QueueSignalReleaseImageANDROID(VkQueue _queue,
676 uint32_t waitSemaphoreCount,
677 const VkSemaphore *pWaitSemaphores,
678 VkImage image,
679 int *pNativeFenceFd)
680 {
681 TU_FROM_HANDLE(tu_queue, queue, _queue);
682 if (!pNativeFenceFd)
683 return VK_SUCCESS;
684
685 struct tu_syncobj s = sync_merge(pWaitSemaphores, waitSemaphoreCount, true, true);
686
687 if (!s.timestamp_valid) {
688 *pNativeFenceFd = -1;
689 return VK_SUCCESS;
690 }
691
692 *pNativeFenceFd = timestamp_to_fd(queue, s.timestamp);
693
694 return VK_SUCCESS;
695 }
696 #endif
697