1361fc4cbSmaya/*
2361fc4cbSmaya * Copyright © 2018 Google, Inc.
3361fc4cbSmaya * Copyright © 2015 Intel Corporation
4361fc4cbSmaya *
5361fc4cbSmaya * Permission is hereby granted, free of charge, to any person obtaining a
6361fc4cbSmaya * copy of this software and associated documentation files (the "Software"),
7361fc4cbSmaya * to deal in the Software without restriction, including without limitation
8361fc4cbSmaya * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9361fc4cbSmaya * and/or sell copies of the Software, and to permit persons to whom the
10361fc4cbSmaya * Software is furnished to do so, subject to the following conditions:
11361fc4cbSmaya *
12361fc4cbSmaya * The above copyright notice and this permission notice (including the next
13361fc4cbSmaya * paragraph) shall be included in all copies or substantial portions of the
14361fc4cbSmaya * Software.
15361fc4cbSmaya *
16361fc4cbSmaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17361fc4cbSmaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18361fc4cbSmaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19361fc4cbSmaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20361fc4cbSmaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21361fc4cbSmaya * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22361fc4cbSmaya * DEALINGS IN THE SOFTWARE.
23361fc4cbSmaya */
24361fc4cbSmaya
25361fc4cbSmaya#include <errno.h>
26361fc4cbSmaya#include <fcntl.h>
27361fc4cbSmaya#include <stdint.h>
28361fc4cbSmaya#include <sys/ioctl.h>
297ec681f3Smrg#include <sys/mman.h>
30361fc4cbSmaya#include <xf86drm.h>
31361fc4cbSmaya
327ec681f3Smrg#include "vk_util.h"
337ec681f3Smrg
347ec681f3Smrg#include "drm-uapi/msm_drm.h"
357ec681f3Smrg#include "util/timespec.h"
367ec681f3Smrg#include "util/os_time.h"
377ec681f3Smrg#include "util/perf/u_trace.h"
387ec681f3Smrg
397ec681f3Smrg#include "tu_private.h"
407ec681f3Smrg
417ec681f3Smrg#include "tu_cs.h"
427ec681f3Smrg
437ec681f3Smrgstruct tu_binary_syncobj {
447ec681f3Smrg   uint32_t permanent, temporary;
457ec681f3Smrg};
467ec681f3Smrg
477ec681f3Smrgstruct tu_timeline_point {
487ec681f3Smrg   struct list_head link;
497ec681f3Smrg
507ec681f3Smrg   uint64_t value;
517ec681f3Smrg   uint32_t syncobj;
527ec681f3Smrg   uint32_t wait_count;
537ec681f3Smrg};
547ec681f3Smrg
557ec681f3Smrgstruct tu_timeline {
567ec681f3Smrg   uint64_t highest_submitted;
577ec681f3Smrg   uint64_t highest_signaled;
587ec681f3Smrg
597ec681f3Smrg   /* A timeline can have multiple timeline points */
607ec681f3Smrg   struct list_head points;
617ec681f3Smrg
627ec681f3Smrg   /* A list containing points that has been already submited.
637ec681f3Smrg    * A point will be moved to 'points' when new point is required
647ec681f3Smrg    * at submit time.
657ec681f3Smrg    */
667ec681f3Smrg   struct list_head free_points;
677ec681f3Smrg};
687ec681f3Smrg
697ec681f3Smrgtypedef enum {
707ec681f3Smrg   TU_SEMAPHORE_BINARY,
717ec681f3Smrg   TU_SEMAPHORE_TIMELINE,
727ec681f3Smrg} tu_semaphore_type;
737ec681f3Smrg
747ec681f3Smrg
757ec681f3Smrgstruct tu_syncobj {
767ec681f3Smrg   struct vk_object_base base;
777ec681f3Smrg
787ec681f3Smrg   tu_semaphore_type type;
797ec681f3Smrg   union {
807ec681f3Smrg      struct tu_binary_syncobj binary;
817ec681f3Smrg      struct tu_timeline timeline;
827ec681f3Smrg   };
837ec681f3Smrg};
847ec681f3Smrg
857ec681f3Smrgstruct tu_queue_submit
867ec681f3Smrg{
877ec681f3Smrg   struct   list_head link;
887ec681f3Smrg
897ec681f3Smrg   VkCommandBuffer *cmd_buffers;
907ec681f3Smrg   struct tu_u_trace_cmd_data *cmd_buffer_trace_data;
917ec681f3Smrg   uint32_t cmd_buffer_count;
927ec681f3Smrg
937ec681f3Smrg   struct   tu_syncobj **wait_semaphores;
947ec681f3Smrg   uint32_t wait_semaphore_count;
957ec681f3Smrg   struct   tu_syncobj **signal_semaphores;
967ec681f3Smrg   uint32_t signal_semaphore_count;
977ec681f3Smrg
987ec681f3Smrg   struct   tu_syncobj **wait_timelines;
997ec681f3Smrg   uint64_t *wait_timeline_values;
1007ec681f3Smrg   uint32_t wait_timeline_count;
1017ec681f3Smrg   uint32_t wait_timeline_array_length;
1027ec681f3Smrg
1037ec681f3Smrg   struct   tu_syncobj **signal_timelines;
1047ec681f3Smrg   uint64_t *signal_timeline_values;
1057ec681f3Smrg   uint32_t signal_timeline_count;
1067ec681f3Smrg   uint32_t signal_timeline_array_length;
1077ec681f3Smrg
1087ec681f3Smrg   struct   drm_msm_gem_submit_cmd *cmds;
1097ec681f3Smrg   struct   drm_msm_gem_submit_syncobj *in_syncobjs;
1107ec681f3Smrg   uint32_t nr_in_syncobjs;
1117ec681f3Smrg   struct   drm_msm_gem_submit_syncobj *out_syncobjs;
1127ec681f3Smrg   uint32_t nr_out_syncobjs;
1137ec681f3Smrg
1147ec681f3Smrg   bool     last_submit;
1157ec681f3Smrg   uint32_t entry_count;
1167ec681f3Smrg   uint32_t counter_pass_index;
1177ec681f3Smrg};
1187ec681f3Smrg
1197ec681f3Smrgstruct tu_u_trace_syncobj
1207ec681f3Smrg{
1217ec681f3Smrg   uint32_t msm_queue_id;
1227ec681f3Smrg   uint32_t fence;
1237ec681f3Smrg};
124361fc4cbSmaya
125361fc4cbSmayastatic int
126361fc4cbSmayatu_drm_get_param(const struct tu_physical_device *dev,
127361fc4cbSmaya                 uint32_t param,
128361fc4cbSmaya                 uint64_t *value)
129361fc4cbSmaya{
130361fc4cbSmaya   /* Technically this requires a pipe, but the kernel only supports one pipe
131361fc4cbSmaya    * anyway at the time of writing and most of these are clearly pipe
132361fc4cbSmaya    * independent. */
133361fc4cbSmaya   struct drm_msm_param req = {
134361fc4cbSmaya      .pipe = MSM_PIPE_3D0,
135361fc4cbSmaya      .param = param,
136361fc4cbSmaya   };
137361fc4cbSmaya
138361fc4cbSmaya   int ret = drmCommandWriteRead(dev->local_fd, DRM_MSM_GET_PARAM, &req,
139361fc4cbSmaya                                 sizeof(req));
140361fc4cbSmaya   if (ret)
141361fc4cbSmaya      return ret;
142361fc4cbSmaya
143361fc4cbSmaya   *value = req.value;
144361fc4cbSmaya
145361fc4cbSmaya   return 0;
146361fc4cbSmaya}
147361fc4cbSmaya
1487ec681f3Smrgstatic int
149361fc4cbSmayatu_drm_get_gpu_id(const struct tu_physical_device *dev, uint32_t *id)
150361fc4cbSmaya{
151361fc4cbSmaya   uint64_t value;
152361fc4cbSmaya   int ret = tu_drm_get_param(dev, MSM_PARAM_GPU_ID, &value);
153361fc4cbSmaya   if (ret)
154361fc4cbSmaya      return ret;
155361fc4cbSmaya
156361fc4cbSmaya   *id = value;
157361fc4cbSmaya   return 0;
158361fc4cbSmaya}
159361fc4cbSmaya
1607ec681f3Smrgstatic int
161361fc4cbSmayatu_drm_get_gmem_size(const struct tu_physical_device *dev, uint32_t *size)
162361fc4cbSmaya{
163361fc4cbSmaya   uint64_t value;
164361fc4cbSmaya   int ret = tu_drm_get_param(dev, MSM_PARAM_GMEM_SIZE, &value);
165361fc4cbSmaya   if (ret)
166361fc4cbSmaya      return ret;
167361fc4cbSmaya
168361fc4cbSmaya   *size = value;
169361fc4cbSmaya   return 0;
170361fc4cbSmaya}
171361fc4cbSmaya
1727ec681f3Smrgstatic int
1737ec681f3Smrgtu_drm_get_gmem_base(const struct tu_physical_device *dev, uint64_t *base)
1747ec681f3Smrg{
1757ec681f3Smrg   return tu_drm_get_param(dev, MSM_PARAM_GMEM_BASE, base);
1767ec681f3Smrg}
1777ec681f3Smrg
1787ec681f3Smrgint
1797ec681f3Smrgtu_drm_get_timestamp(struct tu_physical_device *device, uint64_t *ts)
1807ec681f3Smrg{
1817ec681f3Smrg   return tu_drm_get_param(device, MSM_PARAM_TIMESTAMP, ts);
1827ec681f3Smrg}
1837ec681f3Smrg
184361fc4cbSmayaint
185361fc4cbSmayatu_drm_submitqueue_new(const struct tu_device *dev,
186361fc4cbSmaya                       int priority,
187361fc4cbSmaya                       uint32_t *queue_id)
188361fc4cbSmaya{
189361fc4cbSmaya   struct drm_msm_submitqueue req = {
190361fc4cbSmaya      .flags = 0,
191361fc4cbSmaya      .prio = priority,
192361fc4cbSmaya   };
193361fc4cbSmaya
1947ec681f3Smrg   int ret = drmCommandWriteRead(dev->fd,
195361fc4cbSmaya                                 DRM_MSM_SUBMITQUEUE_NEW, &req, sizeof(req));
196361fc4cbSmaya   if (ret)
197361fc4cbSmaya      return ret;
198361fc4cbSmaya
199361fc4cbSmaya   *queue_id = req.id;
200361fc4cbSmaya   return 0;
201361fc4cbSmaya}
202361fc4cbSmaya
203361fc4cbSmayavoid
204361fc4cbSmayatu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)
205361fc4cbSmaya{
2067ec681f3Smrg   drmCommandWrite(dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE,
207361fc4cbSmaya                   &queue_id, sizeof(uint32_t));
208361fc4cbSmaya}
209361fc4cbSmaya
2107ec681f3Smrgstatic void
2117ec681f3Smrgtu_gem_close(const struct tu_device *dev, uint32_t gem_handle)
2127ec681f3Smrg{
2137ec681f3Smrg   struct drm_gem_close req = {
2147ec681f3Smrg      .handle = gem_handle,
2157ec681f3Smrg   };
2167ec681f3Smrg
2177ec681f3Smrg   drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
2187ec681f3Smrg}
2197ec681f3Smrg
2207ec681f3Smrg/** Helper for DRM_MSM_GEM_INFO, returns 0 on error. */
2217ec681f3Smrgstatic uint64_t
2227ec681f3Smrgtu_gem_info(const struct tu_device *dev, uint32_t gem_handle, uint32_t info)
223361fc4cbSmaya{
2247ec681f3Smrg   struct drm_msm_gem_info req = {
2257ec681f3Smrg      .handle = gem_handle,
2267ec681f3Smrg      .info = info,
2277ec681f3Smrg   };
2287ec681f3Smrg
2297ec681f3Smrg   int ret = drmCommandWriteRead(dev->fd,
2307ec681f3Smrg                                 DRM_MSM_GEM_INFO, &req, sizeof(req));
2317ec681f3Smrg   if (ret < 0)
2327ec681f3Smrg      return 0;
2337ec681f3Smrg
2347ec681f3Smrg   return req.value;
2357ec681f3Smrg}
2367ec681f3Smrg
2377ec681f3Smrgstatic VkResult
2387ec681f3Smrgtu_bo_init(struct tu_device *dev,
2397ec681f3Smrg           struct tu_bo *bo,
2407ec681f3Smrg           uint32_t gem_handle,
2417ec681f3Smrg           uint64_t size,
2427ec681f3Smrg           bool dump)
2437ec681f3Smrg{
2447ec681f3Smrg   uint64_t iova = tu_gem_info(dev, gem_handle, MSM_INFO_GET_IOVA);
2457ec681f3Smrg   if (!iova) {
2467ec681f3Smrg      tu_gem_close(dev, gem_handle);
2477ec681f3Smrg      return VK_ERROR_OUT_OF_DEVICE_MEMORY;
2487ec681f3Smrg   }
2497ec681f3Smrg
2507ec681f3Smrg   *bo = (struct tu_bo) {
2517ec681f3Smrg      .gem_handle = gem_handle,
2527ec681f3Smrg      .size = size,
2537ec681f3Smrg      .iova = iova,
2547ec681f3Smrg   };
2557ec681f3Smrg
2567ec681f3Smrg   mtx_lock(&dev->bo_mutex);
2577ec681f3Smrg   uint32_t idx = dev->bo_count++;
2587ec681f3Smrg
2597ec681f3Smrg   /* grow the bo list if needed */
2607ec681f3Smrg   if (idx >= dev->bo_list_size) {
2617ec681f3Smrg      uint32_t new_len = idx + 64;
2627ec681f3Smrg      struct drm_msm_gem_submit_bo *new_ptr =
2637ec681f3Smrg         vk_realloc(&dev->vk.alloc, dev->bo_list, new_len * sizeof(*dev->bo_list),
2647ec681f3Smrg                    8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
2657ec681f3Smrg      if (!new_ptr)
2667ec681f3Smrg         goto fail_bo_list;
2677ec681f3Smrg
2687ec681f3Smrg      dev->bo_list = new_ptr;
2697ec681f3Smrg      dev->bo_list_size = new_len;
2707ec681f3Smrg   }
2717ec681f3Smrg
2727ec681f3Smrg   /* grow the "bo idx" list (maps gem handles to index in the bo list) */
2737ec681f3Smrg   if (bo->gem_handle >= dev->bo_idx_size) {
2747ec681f3Smrg      uint32_t new_len = bo->gem_handle + 256;
2757ec681f3Smrg      uint32_t *new_ptr =
2767ec681f3Smrg         vk_realloc(&dev->vk.alloc, dev->bo_idx, new_len * sizeof(*dev->bo_idx),
2777ec681f3Smrg                    8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
2787ec681f3Smrg      if (!new_ptr)
2797ec681f3Smrg         goto fail_bo_idx;
2807ec681f3Smrg
2817ec681f3Smrg      dev->bo_idx = new_ptr;
2827ec681f3Smrg      dev->bo_idx_size = new_len;
2837ec681f3Smrg   }
2847ec681f3Smrg
2857ec681f3Smrg   dev->bo_idx[bo->gem_handle] = idx;
2867ec681f3Smrg   dev->bo_list[idx] = (struct drm_msm_gem_submit_bo) {
2877ec681f3Smrg      .flags = MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE |
2887ec681f3Smrg               COND(dump, MSM_SUBMIT_BO_DUMP),
2897ec681f3Smrg      .handle = gem_handle,
2907ec681f3Smrg      .presumed = iova,
2917ec681f3Smrg   };
2927ec681f3Smrg   mtx_unlock(&dev->bo_mutex);
2937ec681f3Smrg
2947ec681f3Smrg   return VK_SUCCESS;
2957ec681f3Smrg
2967ec681f3Smrgfail_bo_idx:
2977ec681f3Smrg   vk_free(&dev->vk.alloc, dev->bo_list);
2987ec681f3Smrgfail_bo_list:
2997ec681f3Smrg   tu_gem_close(dev, gem_handle);
3007ec681f3Smrg   return VK_ERROR_OUT_OF_HOST_MEMORY;
3017ec681f3Smrg}
3027ec681f3Smrg
3037ec681f3SmrgVkResult
3047ec681f3Smrgtu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size,
3057ec681f3Smrg               enum tu_bo_alloc_flags flags)
3067ec681f3Smrg{
3077ec681f3Smrg   /* TODO: Choose better flags. As of 2018-11-12, freedreno/drm/msm_bo.c
3087ec681f3Smrg    * always sets `flags = MSM_BO_WC`, and we copy that behavior here.
3097ec681f3Smrg    */
310361fc4cbSmaya   struct drm_msm_gem_new req = {
311361fc4cbSmaya      .size = size,
3127ec681f3Smrg      .flags = MSM_BO_WC
313361fc4cbSmaya   };
314361fc4cbSmaya
3157ec681f3Smrg   if (flags & TU_BO_ALLOC_GPU_READ_ONLY)
3167ec681f3Smrg      req.flags |= MSM_BO_GPU_READONLY;
3177ec681f3Smrg
3187ec681f3Smrg   int ret = drmCommandWriteRead(dev->fd,
319361fc4cbSmaya                                 DRM_MSM_GEM_NEW, &req, sizeof(req));
320361fc4cbSmaya   if (ret)
3217ec681f3Smrg      return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
322361fc4cbSmaya
3237ec681f3Smrg   return tu_bo_init(dev, bo, req.handle, size, flags & TU_BO_ALLOC_ALLOW_DUMP);
324361fc4cbSmaya}
325361fc4cbSmaya
3267ec681f3SmrgVkResult
3277ec681f3Smrgtu_bo_init_dmabuf(struct tu_device *dev,
3287ec681f3Smrg                  struct tu_bo *bo,
3297ec681f3Smrg                  uint64_t size,
3307ec681f3Smrg                  int prime_fd)
331361fc4cbSmaya{
332361fc4cbSmaya   /* lseek() to get the real size */
333361fc4cbSmaya   off_t real_size = lseek(prime_fd, 0, SEEK_END);
334361fc4cbSmaya   lseek(prime_fd, 0, SEEK_SET);
335361fc4cbSmaya   if (real_size < 0 || (uint64_t) real_size < size)
3367ec681f3Smrg      return vk_error(dev, VK_ERROR_INVALID_EXTERNAL_HANDLE);
337361fc4cbSmaya
338361fc4cbSmaya   uint32_t gem_handle;
3397ec681f3Smrg   int ret = drmPrimeFDToHandle(dev->fd, prime_fd,
340361fc4cbSmaya                                &gem_handle);
341361fc4cbSmaya   if (ret)
3427ec681f3Smrg      return vk_error(dev, VK_ERROR_INVALID_EXTERNAL_HANDLE);
343361fc4cbSmaya
3447ec681f3Smrg   return tu_bo_init(dev, bo, gem_handle, size, false);
345361fc4cbSmaya}
346361fc4cbSmaya
347361fc4cbSmayaint
3487ec681f3Smrgtu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)
349361fc4cbSmaya{
350361fc4cbSmaya   int prime_fd;
3517ec681f3Smrg   int ret = drmPrimeHandleToFD(dev->fd, bo->gem_handle,
352361fc4cbSmaya                                DRM_CLOEXEC, &prime_fd);
353361fc4cbSmaya
354361fc4cbSmaya   return ret == 0 ? prime_fd : -1;
355361fc4cbSmaya}
356361fc4cbSmaya
3577ec681f3SmrgVkResult
3587ec681f3Smrgtu_bo_map(struct tu_device *dev, struct tu_bo *bo)
3597ec681f3Smrg{
3607ec681f3Smrg   if (bo->map)
3617ec681f3Smrg      return VK_SUCCESS;
3627ec681f3Smrg
3637ec681f3Smrg   uint64_t offset = tu_gem_info(dev, bo->gem_handle, MSM_INFO_GET_OFFSET);
3647ec681f3Smrg   if (!offset)
3657ec681f3Smrg      return vk_error(dev, VK_ERROR_OUT_OF_DEVICE_MEMORY);
3667ec681f3Smrg
3677ec681f3Smrg   /* TODO: Should we use the wrapper os_mmap() like Freedreno does? */
3687ec681f3Smrg   void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
3697ec681f3Smrg                    dev->fd, offset);
3707ec681f3Smrg   if (map == MAP_FAILED)
3717ec681f3Smrg      return vk_error(dev, VK_ERROR_MEMORY_MAP_FAILED);
3727ec681f3Smrg
3737ec681f3Smrg   bo->map = map;
3747ec681f3Smrg   return VK_SUCCESS;
3757ec681f3Smrg}
3767ec681f3Smrg
377361fc4cbSmayavoid
3787ec681f3Smrgtu_bo_finish(struct tu_device *dev, struct tu_bo *bo)
379361fc4cbSmaya{
3807ec681f3Smrg   assert(bo->gem_handle);
3817ec681f3Smrg
3827ec681f3Smrg   if (bo->map)
3837ec681f3Smrg      munmap(bo->map, bo->size);
3847ec681f3Smrg
3857ec681f3Smrg   mtx_lock(&dev->bo_mutex);
3867ec681f3Smrg   uint32_t idx = dev->bo_idx[bo->gem_handle];
3877ec681f3Smrg   dev->bo_count--;
3887ec681f3Smrg   dev->bo_list[idx] = dev->bo_list[dev->bo_count];
3897ec681f3Smrg   dev->bo_idx[dev->bo_list[idx].handle] = idx;
3907ec681f3Smrg   mtx_unlock(&dev->bo_mutex);
3917ec681f3Smrg
3927ec681f3Smrg   tu_gem_close(dev, bo->gem_handle);
3937ec681f3Smrg}
3947ec681f3Smrg
3957ec681f3Smrgstatic VkResult
3967ec681f3Smrgtu_drm_device_init(struct tu_physical_device *device,
3977ec681f3Smrg                   struct tu_instance *instance,
3987ec681f3Smrg                   drmDevicePtr drm_device)
3997ec681f3Smrg{
4007ec681f3Smrg   const char *path = drm_device->nodes[DRM_NODE_RENDER];
4017ec681f3Smrg   VkResult result = VK_SUCCESS;
4027ec681f3Smrg   drmVersionPtr version;
4037ec681f3Smrg   int fd;
4047ec681f3Smrg   int master_fd = -1;
4057ec681f3Smrg
4067ec681f3Smrg   fd = open(path, O_RDWR | O_CLOEXEC);
4077ec681f3Smrg   if (fd < 0) {
4087ec681f3Smrg      return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
4097ec681f3Smrg                               "failed to open device %s", path);
4107ec681f3Smrg   }
4117ec681f3Smrg
4127ec681f3Smrg   /* Version 1.6 added SYNCOBJ support. */
4137ec681f3Smrg   const int min_version_major = 1;
4147ec681f3Smrg   const int min_version_minor = 6;
4157ec681f3Smrg
4167ec681f3Smrg   version = drmGetVersion(fd);
4177ec681f3Smrg   if (!version) {
4187ec681f3Smrg      close(fd);
4197ec681f3Smrg      return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
4207ec681f3Smrg                               "failed to query kernel driver version for device %s",
4217ec681f3Smrg                               path);
4227ec681f3Smrg   }
4237ec681f3Smrg
4247ec681f3Smrg   if (strcmp(version->name, "msm")) {
4257ec681f3Smrg      drmFreeVersion(version);
4267ec681f3Smrg      close(fd);
4277ec681f3Smrg      return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
4287ec681f3Smrg                               "device %s does not use the msm kernel driver",
4297ec681f3Smrg                               path);
4307ec681f3Smrg   }
4317ec681f3Smrg
4327ec681f3Smrg   if (version->version_major != min_version_major ||
4337ec681f3Smrg       version->version_minor < min_version_minor) {
4347ec681f3Smrg      result = vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
4357ec681f3Smrg                                 "kernel driver for device %s has version %d.%d, "
4367ec681f3Smrg                                 "but Vulkan requires version >= %d.%d",
4377ec681f3Smrg                                 path,
4387ec681f3Smrg                                 version->version_major, version->version_minor,
4397ec681f3Smrg                                 min_version_major, min_version_minor);
4407ec681f3Smrg      drmFreeVersion(version);
4417ec681f3Smrg      close(fd);
4427ec681f3Smrg      return result;
4437ec681f3Smrg   }
4447ec681f3Smrg
4457ec681f3Smrg   device->msm_major_version = version->version_major;
4467ec681f3Smrg   device->msm_minor_version = version->version_minor;
4477ec681f3Smrg
4487ec681f3Smrg   drmFreeVersion(version);
4497ec681f3Smrg
4507ec681f3Smrg   if (instance->debug_flags & TU_DEBUG_STARTUP)
4517ec681f3Smrg      mesa_logi("Found compatible device '%s'.", path);
4527ec681f3Smrg
4537ec681f3Smrg   device->instance = instance;
4547ec681f3Smrg
4557ec681f3Smrg   if (instance->vk.enabled_extensions.KHR_display) {
4567ec681f3Smrg      master_fd =
4577ec681f3Smrg         open(drm_device->nodes[DRM_NODE_PRIMARY], O_RDWR | O_CLOEXEC);
4587ec681f3Smrg      if (master_fd >= 0) {
4597ec681f3Smrg         /* TODO: free master_fd is accel is not working? */
4607ec681f3Smrg      }
4617ec681f3Smrg   }
4627ec681f3Smrg
4637ec681f3Smrg   device->master_fd = master_fd;
4647ec681f3Smrg   device->local_fd = fd;
4657ec681f3Smrg
4667ec681f3Smrg   if (tu_drm_get_gpu_id(device, &device->dev_id.gpu_id)) {
4677ec681f3Smrg      result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
4687ec681f3Smrg                                 "could not get GPU ID");
4697ec681f3Smrg      goto fail;
4707ec681f3Smrg   }
4717ec681f3Smrg
4727ec681f3Smrg   if (tu_drm_get_param(device, MSM_PARAM_CHIP_ID, &device->dev_id.chip_id)) {
4737ec681f3Smrg      result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
4747ec681f3Smrg                                 "could not get CHIP ID");
4757ec681f3Smrg      goto fail;
4767ec681f3Smrg   }
4777ec681f3Smrg
4787ec681f3Smrg   if (tu_drm_get_gmem_size(device, &device->gmem_size)) {
4797ec681f3Smrg      result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
4807ec681f3Smrg                                "could not get GMEM size");
4817ec681f3Smrg      goto fail;
4827ec681f3Smrg   }
4837ec681f3Smrg
4847ec681f3Smrg   if (tu_drm_get_gmem_base(device, &device->gmem_base)) {
4857ec681f3Smrg      result = vk_startup_errorf(instance, VK_ERROR_INITIALIZATION_FAILED,
4867ec681f3Smrg                                 "could not get GMEM size");
4877ec681f3Smrg      goto fail;
4887ec681f3Smrg   }
4897ec681f3Smrg
4907ec681f3Smrg   device->heap.size = tu_get_system_heap_size();
4917ec681f3Smrg   device->heap.used = 0u;
4927ec681f3Smrg   device->heap.flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;
4937ec681f3Smrg
4947ec681f3Smrg   result = tu_physical_device_init(device, instance);
4957ec681f3Smrg   if (result == VK_SUCCESS)
4967ec681f3Smrg       return result;
4977ec681f3Smrg
4987ec681f3Smrgfail:
4997ec681f3Smrg   close(fd);
5007ec681f3Smrg   if (master_fd != -1)
5017ec681f3Smrg      close(master_fd);
5027ec681f3Smrg   return result;
5037ec681f3Smrg}
5047ec681f3Smrg
5057ec681f3SmrgVkResult
5067ec681f3Smrgtu_enumerate_devices(struct tu_instance *instance)
5077ec681f3Smrg{
5087ec681f3Smrg   /* TODO: Check for more devices ? */
5097ec681f3Smrg   drmDevicePtr devices[8];
5107ec681f3Smrg   VkResult result = VK_ERROR_INCOMPATIBLE_DRIVER;
5117ec681f3Smrg   int max_devices;
5127ec681f3Smrg
5137ec681f3Smrg   instance->physical_device_count = 0;
5147ec681f3Smrg
5157ec681f3Smrg   max_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
5167ec681f3Smrg
5177ec681f3Smrg   if (instance->debug_flags & TU_DEBUG_STARTUP) {
5187ec681f3Smrg      if (max_devices < 0)
5197ec681f3Smrg         mesa_logi("drmGetDevices2 returned error: %s\n", strerror(max_devices));
5207ec681f3Smrg      else
5217ec681f3Smrg         mesa_logi("Found %d drm nodes", max_devices);
5227ec681f3Smrg   }
5237ec681f3Smrg
5247ec681f3Smrg   if (max_devices < 1)
5257ec681f3Smrg      return vk_startup_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,
5267ec681f3Smrg                               "No DRM devices found");
5277ec681f3Smrg
5287ec681f3Smrg   for (unsigned i = 0; i < (unsigned) max_devices; i++) {
5297ec681f3Smrg      if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
5307ec681f3Smrg          devices[i]->bustype == DRM_BUS_PLATFORM) {
5317ec681f3Smrg
5327ec681f3Smrg         result = tu_drm_device_init(
5337ec681f3Smrg            instance->physical_devices + instance->physical_device_count,
5347ec681f3Smrg            instance, devices[i]);
5357ec681f3Smrg         if (result == VK_SUCCESS)
5367ec681f3Smrg            ++instance->physical_device_count;
5377ec681f3Smrg         else if (result != VK_ERROR_INCOMPATIBLE_DRIVER)
5387ec681f3Smrg            break;
5397ec681f3Smrg      }
5407ec681f3Smrg   }
5417ec681f3Smrg   drmFreeDevices(devices, max_devices);
5427ec681f3Smrg
5437ec681f3Smrg   return result;
5447ec681f3Smrg}
5457ec681f3Smrg
5467ec681f3Smrgstatic void
5477ec681f3Smrgtu_timeline_finish(struct tu_device *device,
5487ec681f3Smrg                    struct tu_timeline *timeline)
5497ec681f3Smrg{
5507ec681f3Smrg   list_for_each_entry_safe(struct tu_timeline_point, point,
5517ec681f3Smrg                            &timeline->free_points, link) {
5527ec681f3Smrg      list_del(&point->link);
5537ec681f3Smrg      drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
5547ec681f3Smrg            &(struct drm_syncobj_destroy) { .handle = point->syncobj });
5557ec681f3Smrg
5567ec681f3Smrg      vk_free(&device->vk.alloc, point);
5577ec681f3Smrg   }
5587ec681f3Smrg   list_for_each_entry_safe(struct tu_timeline_point, point,
5597ec681f3Smrg                            &timeline->points, link) {
5607ec681f3Smrg      list_del(&point->link);
5617ec681f3Smrg      drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
5627ec681f3Smrg            &(struct drm_syncobj_destroy) { .handle = point->syncobj });
5637ec681f3Smrg      vk_free(&device->vk.alloc, point);
5647ec681f3Smrg   }
5657ec681f3Smrg}
5667ec681f3Smrg
5677ec681f3Smrgstatic VkResult
5687ec681f3Smrgsync_create(VkDevice _device,
5697ec681f3Smrg            bool signaled,
5707ec681f3Smrg            bool fence,
5717ec681f3Smrg            bool binary,
5727ec681f3Smrg            uint64_t timeline_value,
5737ec681f3Smrg            const VkAllocationCallbacks *pAllocator,
5747ec681f3Smrg            void **p_sync)
5757ec681f3Smrg{
5767ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
5777ec681f3Smrg
5787ec681f3Smrg   struct tu_syncobj *sync =
5797ec681f3Smrg         vk_object_alloc(&device->vk, pAllocator, sizeof(*sync),
5807ec681f3Smrg                         fence ? VK_OBJECT_TYPE_FENCE : VK_OBJECT_TYPE_SEMAPHORE);
5817ec681f3Smrg   if (!sync)
5827ec681f3Smrg      return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
5837ec681f3Smrg
5847ec681f3Smrg   if (binary) {
5857ec681f3Smrg      struct drm_syncobj_create create = {};
5867ec681f3Smrg      if (signaled)
5877ec681f3Smrg         create.flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
5887ec681f3Smrg
5897ec681f3Smrg      int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
5907ec681f3Smrg      if (ret) {
5917ec681f3Smrg         vk_free2(&device->vk.alloc, pAllocator, sync);
5927ec681f3Smrg         return VK_ERROR_OUT_OF_HOST_MEMORY;
5937ec681f3Smrg      }
5947ec681f3Smrg
5957ec681f3Smrg      sync->binary.permanent = create.handle;
5967ec681f3Smrg      sync->binary.temporary = 0;
5977ec681f3Smrg      sync->type = TU_SEMAPHORE_BINARY;
5987ec681f3Smrg   } else {
5997ec681f3Smrg      sync->type = TU_SEMAPHORE_TIMELINE;
6007ec681f3Smrg      sync->timeline.highest_signaled = sync->timeline.highest_submitted =
6017ec681f3Smrg             timeline_value;
6027ec681f3Smrg      list_inithead(&sync->timeline.points);
6037ec681f3Smrg      list_inithead(&sync->timeline.free_points);
6047ec681f3Smrg   }
6057ec681f3Smrg
6067ec681f3Smrg   *p_sync = sync;
6077ec681f3Smrg
6087ec681f3Smrg   return VK_SUCCESS;
6097ec681f3Smrg}
6107ec681f3Smrg
6117ec681f3Smrgstatic void
6127ec681f3Smrgsync_set_temporary(struct tu_device *device, struct tu_syncobj *sync, uint32_t syncobj)
6137ec681f3Smrg{
6147ec681f3Smrg   if (sync->binary.temporary) {
6157ec681f3Smrg      drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
6167ec681f3Smrg            &(struct drm_syncobj_destroy) { .handle = sync->binary.temporary });
6177ec681f3Smrg   }
6187ec681f3Smrg   sync->binary.temporary = syncobj;
6197ec681f3Smrg}
6207ec681f3Smrg
6217ec681f3Smrgstatic void
6227ec681f3Smrgsync_destroy(VkDevice _device, struct tu_syncobj *sync, const VkAllocationCallbacks *pAllocator)
6237ec681f3Smrg{
6247ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
6257ec681f3Smrg
6267ec681f3Smrg   if (!sync)
6277ec681f3Smrg      return;
6287ec681f3Smrg
6297ec681f3Smrg   if (sync->type == TU_SEMAPHORE_BINARY) {
6307ec681f3Smrg      sync_set_temporary(device, sync, 0);
6317ec681f3Smrg      drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
6327ec681f3Smrg            &(struct drm_syncobj_destroy) { .handle = sync->binary.permanent });
6337ec681f3Smrg   } else {
6347ec681f3Smrg      tu_timeline_finish(device, &sync->timeline);
6357ec681f3Smrg   }
6367ec681f3Smrg
6377ec681f3Smrg   vk_object_free(&device->vk, pAllocator, sync);
6387ec681f3Smrg}
6397ec681f3Smrg
6407ec681f3Smrgstatic VkResult
6417ec681f3Smrgsync_import(VkDevice _device, struct tu_syncobj *sync, bool temporary, bool sync_fd, int fd)
6427ec681f3Smrg{
6437ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
6447ec681f3Smrg   int ret;
6457ec681f3Smrg
6467ec681f3Smrg   if (!sync_fd) {
6477ec681f3Smrg      uint32_t *dst = temporary ? &sync->binary.temporary : &sync->binary.permanent;
6487ec681f3Smrg
6497ec681f3Smrg      struct drm_syncobj_handle handle = { .fd = fd };
6507ec681f3Smrg      ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &handle);
6517ec681f3Smrg      if (ret)
6527ec681f3Smrg         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
6537ec681f3Smrg
6547ec681f3Smrg      if (*dst) {
6557ec681f3Smrg         drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
6567ec681f3Smrg               &(struct drm_syncobj_destroy) { .handle = *dst });
6577ec681f3Smrg      }
6587ec681f3Smrg      *dst = handle.handle;
6597ec681f3Smrg      close(fd);
6607ec681f3Smrg   } else {
6617ec681f3Smrg      assert(temporary);
6627ec681f3Smrg
6637ec681f3Smrg      struct drm_syncobj_create create = {};
6647ec681f3Smrg
6657ec681f3Smrg      if (fd == -1)
6667ec681f3Smrg         create.flags |= DRM_SYNCOBJ_CREATE_SIGNALED;
6677ec681f3Smrg
6687ec681f3Smrg      ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
6697ec681f3Smrg      if (ret)
6707ec681f3Smrg         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
6717ec681f3Smrg
6727ec681f3Smrg      if (fd != -1) {
6737ec681f3Smrg         ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &(struct drm_syncobj_handle) {
6747ec681f3Smrg            .fd = fd,
6757ec681f3Smrg            .handle = create.handle,
6767ec681f3Smrg            .flags = DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE,
6777ec681f3Smrg         });
6787ec681f3Smrg         if (ret) {
6797ec681f3Smrg            drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_DESTROY,
6807ec681f3Smrg                  &(struct drm_syncobj_destroy) { .handle = create.handle });
6817ec681f3Smrg            return VK_ERROR_INVALID_EXTERNAL_HANDLE;
6827ec681f3Smrg         }
6837ec681f3Smrg         close(fd);
6847ec681f3Smrg      }
6857ec681f3Smrg
6867ec681f3Smrg      sync_set_temporary(device, sync, create.handle);
6877ec681f3Smrg   }
6887ec681f3Smrg
6897ec681f3Smrg   return VK_SUCCESS;
6907ec681f3Smrg}
6917ec681f3Smrg
6927ec681f3Smrgstatic VkResult
6937ec681f3Smrgsync_export(VkDevice _device, struct tu_syncobj *sync, bool sync_fd, int *p_fd)
6947ec681f3Smrg{
6957ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
6967ec681f3Smrg
6977ec681f3Smrg   struct drm_syncobj_handle handle = {
6987ec681f3Smrg      .handle = sync->binary.temporary ?: sync->binary.permanent,
6997ec681f3Smrg      .flags = COND(sync_fd, DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE),
7007ec681f3Smrg      .fd = -1,
701361fc4cbSmaya   };
7027ec681f3Smrg   int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
7037ec681f3Smrg   if (ret)
7047ec681f3Smrg      return vk_error(device, VK_ERROR_INVALID_EXTERNAL_HANDLE);
705361fc4cbSmaya
7067ec681f3Smrg   /* restore permanent payload on export */
7077ec681f3Smrg   sync_set_temporary(device, sync, 0);
7087ec681f3Smrg
7097ec681f3Smrg   *p_fd = handle.fd;
7107ec681f3Smrg   return VK_SUCCESS;
711361fc4cbSmaya}
712361fc4cbSmaya
7137ec681f3Smrgstatic VkSemaphoreTypeKHR
7147ec681f3Smrgget_semaphore_type(const void *pNext, uint64_t *initial_value)
715361fc4cbSmaya{
7167ec681f3Smrg   const VkSemaphoreTypeCreateInfoKHR *type_info =
7177ec681f3Smrg      vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO_KHR);
7187ec681f3Smrg
7197ec681f3Smrg   if (!type_info)
7207ec681f3Smrg      return VK_SEMAPHORE_TYPE_BINARY_KHR;
7217ec681f3Smrg
7227ec681f3Smrg   if (initial_value)
7237ec681f3Smrg      *initial_value = type_info->initialValue;
7247ec681f3Smrg   return type_info->semaphoreType;
7257ec681f3Smrg}
7267ec681f3Smrg
7277ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
7287ec681f3Smrgtu_CreateSemaphore(VkDevice device,
7297ec681f3Smrg                   const VkSemaphoreCreateInfo *pCreateInfo,
7307ec681f3Smrg                   const VkAllocationCallbacks *pAllocator,
7317ec681f3Smrg                   VkSemaphore *pSemaphore)
7327ec681f3Smrg{
7337ec681f3Smrg   uint64_t timeline_value = 0;
7347ec681f3Smrg   VkSemaphoreTypeKHR sem_type = get_semaphore_type(pCreateInfo->pNext, &timeline_value);
7357ec681f3Smrg
7367ec681f3Smrg   return sync_create(device, false, false, (sem_type == VK_SEMAPHORE_TYPE_BINARY_KHR),
7377ec681f3Smrg                      timeline_value, pAllocator, (void**) pSemaphore);
7387ec681f3Smrg}
7397ec681f3Smrg
7407ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
7417ec681f3Smrgtu_DestroySemaphore(VkDevice device, VkSemaphore sem, const VkAllocationCallbacks *pAllocator)
7427ec681f3Smrg{
7437ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, sync, sem);
7447ec681f3Smrg   sync_destroy(device, sync, pAllocator);
7457ec681f3Smrg}
7467ec681f3Smrg
7477ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
7487ec681f3Smrgtu_ImportSemaphoreFdKHR(VkDevice device, const VkImportSemaphoreFdInfoKHR *info)
7497ec681f3Smrg{
7507ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, sync, info->semaphore);
7517ec681f3Smrg   return sync_import(device, sync, info->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT,
7527ec681f3Smrg         info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, info->fd);
7537ec681f3Smrg}
7547ec681f3Smrg
7557ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
7567ec681f3Smrgtu_GetSemaphoreFdKHR(VkDevice device, const VkSemaphoreGetFdInfoKHR *info, int *pFd)
7577ec681f3Smrg{
7587ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, sync, info->semaphore);
7597ec681f3Smrg   return sync_export(device, sync,
7607ec681f3Smrg         info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT, pFd);
7617ec681f3Smrg}
7627ec681f3Smrg
7637ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
7647ec681f3Smrgtu_GetPhysicalDeviceExternalSemaphoreProperties(
7657ec681f3Smrg   VkPhysicalDevice physicalDevice,
7667ec681f3Smrg   const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
7677ec681f3Smrg   VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
7687ec681f3Smrg{
7697ec681f3Smrg   VkSemaphoreTypeKHR type = get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
7707ec681f3Smrg
7717ec681f3Smrg   if (type != VK_SEMAPHORE_TYPE_TIMELINE &&
7727ec681f3Smrg       (pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT ||
7737ec681f3Smrg       pExternalSemaphoreInfo->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT )) {
7747ec681f3Smrg      pExternalSemaphoreProperties->exportFromImportedHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
7757ec681f3Smrg      pExternalSemaphoreProperties->compatibleHandleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT | VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
7767ec681f3Smrg      pExternalSemaphoreProperties->externalSemaphoreFeatures = VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT |
7777ec681f3Smrg         VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
7787ec681f3Smrg   } else {
7797ec681f3Smrg      pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
7807ec681f3Smrg      pExternalSemaphoreProperties->compatibleHandleTypes = 0;
7817ec681f3Smrg      pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
7827ec681f3Smrg   }
7837ec681f3Smrg}
7847ec681f3Smrg
7857ec681f3Smrgstatic VkResult
7867ec681f3Smrgtu_queue_submit_add_timeline_wait_locked(struct tu_queue_submit* submit,
7877ec681f3Smrg                                         struct tu_device *device,
7887ec681f3Smrg                                         struct tu_syncobj *timeline,
7897ec681f3Smrg                                         uint64_t value)
7907ec681f3Smrg{
7917ec681f3Smrg   if (submit->wait_timeline_count >= submit->wait_timeline_array_length) {
7927ec681f3Smrg      uint32_t new_len = MAX2(submit->wait_timeline_array_length * 2, 64);
7937ec681f3Smrg
7947ec681f3Smrg      submit->wait_timelines = vk_realloc(&device->vk.alloc,
7957ec681f3Smrg            submit->wait_timelines,
7967ec681f3Smrg            new_len * sizeof(*submit->wait_timelines),
7977ec681f3Smrg            8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
7987ec681f3Smrg
7997ec681f3Smrg      if (submit->wait_timelines == NULL)
8007ec681f3Smrg         return VK_ERROR_OUT_OF_HOST_MEMORY;
8017ec681f3Smrg
8027ec681f3Smrg      submit->wait_timeline_values = vk_realloc(&device->vk.alloc,
8037ec681f3Smrg            submit->wait_timeline_values,
8047ec681f3Smrg            new_len * sizeof(*submit->wait_timeline_values),
8057ec681f3Smrg            8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
8067ec681f3Smrg
8077ec681f3Smrg      if (submit->wait_timeline_values == NULL) {
8087ec681f3Smrg         vk_free(&device->vk.alloc, submit->wait_timelines);
8097ec681f3Smrg         return VK_ERROR_OUT_OF_HOST_MEMORY;
8107ec681f3Smrg      }
8117ec681f3Smrg
8127ec681f3Smrg      submit->wait_timeline_array_length = new_len;
8137ec681f3Smrg   }
8147ec681f3Smrg
8157ec681f3Smrg   submit->wait_timelines[submit->wait_timeline_count] = timeline;
8167ec681f3Smrg   submit->wait_timeline_values[submit->wait_timeline_count] = value;
8177ec681f3Smrg
8187ec681f3Smrg   submit->wait_timeline_count++;
8197ec681f3Smrg
8207ec681f3Smrg   return VK_SUCCESS;
8217ec681f3Smrg}
8227ec681f3Smrg
8237ec681f3Smrgstatic VkResult
8247ec681f3Smrgtu_queue_submit_add_timeline_signal_locked(struct tu_queue_submit* submit,
8257ec681f3Smrg                                           struct tu_device *device,
8267ec681f3Smrg                                           struct tu_syncobj *timeline,
8277ec681f3Smrg                                           uint64_t value)
8287ec681f3Smrg{
8297ec681f3Smrg   if (submit->signal_timeline_count >= submit->signal_timeline_array_length) {
8307ec681f3Smrg      uint32_t new_len = MAX2(submit->signal_timeline_array_length * 2, 32);
8317ec681f3Smrg
8327ec681f3Smrg      submit->signal_timelines = vk_realloc(&device->vk.alloc,
8337ec681f3Smrg            submit->signal_timelines,
8347ec681f3Smrg            new_len * sizeof(*submit->signal_timelines),
8357ec681f3Smrg            8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
8367ec681f3Smrg
8377ec681f3Smrg      if (submit->signal_timelines == NULL)
8387ec681f3Smrg         return VK_ERROR_OUT_OF_HOST_MEMORY;
8397ec681f3Smrg
8407ec681f3Smrg      submit->signal_timeline_values = vk_realloc(&device->vk.alloc,
8417ec681f3Smrg            submit->signal_timeline_values,
8427ec681f3Smrg            new_len * sizeof(*submit->signal_timeline_values),
8437ec681f3Smrg            8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
8447ec681f3Smrg
8457ec681f3Smrg      if (submit->signal_timeline_values == NULL) {
8467ec681f3Smrg         vk_free(&device->vk.alloc, submit->signal_timelines);
8477ec681f3Smrg         return VK_ERROR_OUT_OF_HOST_MEMORY;
8487ec681f3Smrg      }
8497ec681f3Smrg
8507ec681f3Smrg      submit->signal_timeline_array_length = new_len;
8517ec681f3Smrg   }
8527ec681f3Smrg
8537ec681f3Smrg   submit->signal_timelines[submit->signal_timeline_count] = timeline;
8547ec681f3Smrg   submit->signal_timeline_values[submit->signal_timeline_count] = value;
8557ec681f3Smrg
8567ec681f3Smrg   submit->signal_timeline_count++;
8577ec681f3Smrg
8587ec681f3Smrg   return VK_SUCCESS;
8597ec681f3Smrg}
8607ec681f3Smrg
8617ec681f3Smrgstatic VkResult
8627ec681f3Smrgtu_queue_submit_create_locked(struct tu_queue *queue,
8637ec681f3Smrg                              const VkSubmitInfo *submit_info,
8647ec681f3Smrg                              const uint32_t nr_in_syncobjs,
8657ec681f3Smrg                              const uint32_t nr_out_syncobjs,
8667ec681f3Smrg                              const bool last_submit,
8677ec681f3Smrg                              const VkPerformanceQuerySubmitInfoKHR *perf_info,
8687ec681f3Smrg                              struct tu_queue_submit **submit)
8697ec681f3Smrg{
8707ec681f3Smrg   VkResult result;
8717ec681f3Smrg
8727ec681f3Smrg   const VkTimelineSemaphoreSubmitInfoKHR *timeline_info =
8737ec681f3Smrg         vk_find_struct_const(submit_info->pNext,
8747ec681f3Smrg                              TIMELINE_SEMAPHORE_SUBMIT_INFO_KHR);
8757ec681f3Smrg
8767ec681f3Smrg   const uint32_t wait_values_count =
8777ec681f3Smrg         timeline_info ? timeline_info->waitSemaphoreValueCount : 0;
8787ec681f3Smrg   const uint32_t signal_values_count =
8797ec681f3Smrg         timeline_info ? timeline_info->signalSemaphoreValueCount : 0;
8807ec681f3Smrg
8817ec681f3Smrg   const uint64_t *wait_values =
8827ec681f3Smrg         wait_values_count ? timeline_info->pWaitSemaphoreValues : NULL;
8837ec681f3Smrg   const uint64_t *signal_values =
8847ec681f3Smrg         signal_values_count ?  timeline_info->pSignalSemaphoreValues : NULL;
8857ec681f3Smrg
8867ec681f3Smrg   struct tu_queue_submit *new_submit = vk_zalloc(&queue->device->vk.alloc,
8877ec681f3Smrg               sizeof(*new_submit), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
8887ec681f3Smrg
8897ec681f3Smrg   new_submit->cmd_buffer_count = submit_info->commandBufferCount;
8907ec681f3Smrg   new_submit->cmd_buffers = vk_zalloc(&queue->device->vk.alloc,
8917ec681f3Smrg         new_submit->cmd_buffer_count * sizeof(*new_submit->cmd_buffers), 8,
8927ec681f3Smrg         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
8937ec681f3Smrg
8947ec681f3Smrg   if (new_submit->cmd_buffers == NULL) {
8957ec681f3Smrg      result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
8967ec681f3Smrg      goto fail_cmd_buffers;
8977ec681f3Smrg   }
8987ec681f3Smrg
8997ec681f3Smrg   memcpy(new_submit->cmd_buffers, submit_info->pCommandBuffers,
9007ec681f3Smrg          new_submit->cmd_buffer_count * sizeof(*new_submit->cmd_buffers));
9017ec681f3Smrg
9027ec681f3Smrg   new_submit->wait_semaphores = vk_zalloc(&queue->device->vk.alloc,
9037ec681f3Smrg         submit_info->waitSemaphoreCount * sizeof(*new_submit->wait_semaphores),
9047ec681f3Smrg         8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
9057ec681f3Smrg   if (new_submit->wait_semaphores == NULL) {
9067ec681f3Smrg      result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
9077ec681f3Smrg      goto fail_wait_semaphores;
9087ec681f3Smrg   }
9097ec681f3Smrg   new_submit->wait_semaphore_count = submit_info->waitSemaphoreCount;
9107ec681f3Smrg
9117ec681f3Smrg   new_submit->signal_semaphores = vk_zalloc(&queue->device->vk.alloc,
9127ec681f3Smrg         submit_info->signalSemaphoreCount *sizeof(*new_submit->signal_semaphores),
9137ec681f3Smrg         8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
9147ec681f3Smrg   if (new_submit->signal_semaphores == NULL) {
9157ec681f3Smrg      result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
9167ec681f3Smrg      goto fail_signal_semaphores;
9177ec681f3Smrg   }
9187ec681f3Smrg   new_submit->signal_semaphore_count = submit_info->signalSemaphoreCount;
9197ec681f3Smrg
9207ec681f3Smrg   for (uint32_t i = 0; i < submit_info->waitSemaphoreCount; i++) {
9217ec681f3Smrg      TU_FROM_HANDLE(tu_syncobj, sem, submit_info->pWaitSemaphores[i]);
9227ec681f3Smrg      new_submit->wait_semaphores[i] = sem;
9237ec681f3Smrg
9247ec681f3Smrg      if (sem->type == TU_SEMAPHORE_TIMELINE) {
9257ec681f3Smrg         result = tu_queue_submit_add_timeline_wait_locked(new_submit,
9267ec681f3Smrg               queue->device, sem, wait_values[i]);
9277ec681f3Smrg         if (result != VK_SUCCESS)
9287ec681f3Smrg            goto fail_wait_timelines;
9297ec681f3Smrg      }
9307ec681f3Smrg   }
9317ec681f3Smrg
9327ec681f3Smrg   for (uint32_t i = 0; i < submit_info->signalSemaphoreCount; i++) {
9337ec681f3Smrg      TU_FROM_HANDLE(tu_syncobj, sem, submit_info->pSignalSemaphores[i]);
9347ec681f3Smrg      new_submit->signal_semaphores[i] = sem;
9357ec681f3Smrg
9367ec681f3Smrg      if (sem->type == TU_SEMAPHORE_TIMELINE) {
9377ec681f3Smrg         result = tu_queue_submit_add_timeline_signal_locked(new_submit,
9387ec681f3Smrg               queue->device, sem, signal_values[i]);
9397ec681f3Smrg         if (result != VK_SUCCESS)
9407ec681f3Smrg            goto fail_signal_timelines;
9417ec681f3Smrg      }
9427ec681f3Smrg   }
9437ec681f3Smrg
9447ec681f3Smrg   bool u_trace_enabled = u_trace_context_tracing(&queue->device->trace_context);
9457ec681f3Smrg   bool has_trace_points = false;
9467ec681f3Smrg
9477ec681f3Smrg   uint32_t entry_count = 0;
9487ec681f3Smrg   for (uint32_t j = 0; j < new_submit->cmd_buffer_count; ++j) {
9497ec681f3Smrg      TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, new_submit->cmd_buffers[j]);
9507ec681f3Smrg
9517ec681f3Smrg      if (perf_info)
9527ec681f3Smrg         entry_count++;
9537ec681f3Smrg
9547ec681f3Smrg      entry_count += cmdbuf->cs.entry_count;
9557ec681f3Smrg
9567ec681f3Smrg      if (u_trace_enabled && u_trace_has_points(&cmdbuf->trace)) {
9577ec681f3Smrg         if (!(cmdbuf->usage_flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT))
9587ec681f3Smrg            entry_count++;
9597ec681f3Smrg
9607ec681f3Smrg         has_trace_points = true;
9617ec681f3Smrg      }
9627ec681f3Smrg   }
9637ec681f3Smrg
9647ec681f3Smrg   new_submit->cmds = vk_zalloc(&queue->device->vk.alloc,
9657ec681f3Smrg         entry_count * sizeof(*new_submit->cmds), 8,
9667ec681f3Smrg         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
9677ec681f3Smrg
9687ec681f3Smrg   if (new_submit->cmds == NULL) {
9697ec681f3Smrg      result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
9707ec681f3Smrg      goto fail_cmds;
9717ec681f3Smrg   }
9727ec681f3Smrg
9737ec681f3Smrg   if (has_trace_points) {
9747ec681f3Smrg      new_submit->cmd_buffer_trace_data = vk_zalloc(&queue->device->vk.alloc,
9757ec681f3Smrg            new_submit->cmd_buffer_count * sizeof(struct tu_u_trace_cmd_data), 8,
9767ec681f3Smrg            VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
9777ec681f3Smrg
9787ec681f3Smrg      if (new_submit->cmd_buffer_trace_data == NULL) {
9797ec681f3Smrg         result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
9807ec681f3Smrg         goto fail_cmd_trace_data;
9817ec681f3Smrg      }
9827ec681f3Smrg
9837ec681f3Smrg      for (uint32_t i = 0; i < new_submit->cmd_buffer_count; ++i) {
9847ec681f3Smrg         TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, new_submit->cmd_buffers[i]);
9857ec681f3Smrg
9867ec681f3Smrg         if (!(cmdbuf->usage_flags & VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT) &&
9877ec681f3Smrg             u_trace_has_points(&cmdbuf->trace)) {
9887ec681f3Smrg            /* A single command buffer could be submitted several times, but we
9897ec681f3Smrg             * already backed timestamp iova addresses and trace points are
9907ec681f3Smrg             * single-use. Therefor we have to copy trace points and create
9917ec681f3Smrg             * a new timestamp buffer on every submit of reusable command buffer.
9927ec681f3Smrg             */
9937ec681f3Smrg            if (tu_create_copy_timestamp_cs(cmdbuf,
9947ec681f3Smrg                  &new_submit->cmd_buffer_trace_data[i].timestamp_copy_cs,
9957ec681f3Smrg                  &new_submit->cmd_buffer_trace_data[i].trace) != VK_SUCCESS) {
9967ec681f3Smrg               result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
9977ec681f3Smrg               goto fail_copy_timestamp_cs;
9987ec681f3Smrg            }
9997ec681f3Smrg            assert(new_submit->cmd_buffer_trace_data[i].timestamp_copy_cs->entry_count == 1);
10007ec681f3Smrg         } else {
10017ec681f3Smrg            new_submit->cmd_buffer_trace_data[i].trace = &cmdbuf->trace;
10027ec681f3Smrg         }
10037ec681f3Smrg      }
10047ec681f3Smrg   }
10057ec681f3Smrg
10067ec681f3Smrg   /* Allocate without wait timeline semaphores */
10077ec681f3Smrg   new_submit->in_syncobjs = vk_zalloc(&queue->device->vk.alloc,
10087ec681f3Smrg         (nr_in_syncobjs - new_submit->wait_timeline_count) *
10097ec681f3Smrg         sizeof(*new_submit->in_syncobjs), 8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
10107ec681f3Smrg
10117ec681f3Smrg   if (new_submit->in_syncobjs == NULL) {
10127ec681f3Smrg      result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
10137ec681f3Smrg      goto fail_in_syncobjs;
10147ec681f3Smrg   }
10157ec681f3Smrg
10167ec681f3Smrg   /* Allocate with signal timeline semaphores considered */
10177ec681f3Smrg   new_submit->out_syncobjs = vk_zalloc(&queue->device->vk.alloc,
10187ec681f3Smrg         nr_out_syncobjs * sizeof(*new_submit->out_syncobjs), 8,
10197ec681f3Smrg         VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
10207ec681f3Smrg
10217ec681f3Smrg   if (new_submit->out_syncobjs == NULL) {
10227ec681f3Smrg      result = vk_error(queue, VK_ERROR_OUT_OF_HOST_MEMORY);
10237ec681f3Smrg      goto fail_out_syncobjs;
10247ec681f3Smrg   }
10257ec681f3Smrg
10267ec681f3Smrg   new_submit->entry_count = entry_count;
10277ec681f3Smrg   new_submit->nr_in_syncobjs = nr_in_syncobjs;
10287ec681f3Smrg   new_submit->nr_out_syncobjs = nr_out_syncobjs;
10297ec681f3Smrg   new_submit->last_submit = last_submit;
10307ec681f3Smrg   new_submit->counter_pass_index = perf_info ? perf_info->counterPassIndex : ~0;
10317ec681f3Smrg
10327ec681f3Smrg   list_inithead(&new_submit->link);
10337ec681f3Smrg
10347ec681f3Smrg   *submit = new_submit;
10357ec681f3Smrg
10367ec681f3Smrg   return VK_SUCCESS;
10377ec681f3Smrg
10387ec681f3Smrgfail_out_syncobjs:
10397ec681f3Smrg   vk_free(&queue->device->vk.alloc, new_submit->in_syncobjs);
10407ec681f3Smrgfail_in_syncobjs:
10417ec681f3Smrg   if (new_submit->cmd_buffer_trace_data)
10427ec681f3Smrg      tu_u_trace_cmd_data_finish(queue->device, new_submit->cmd_buffer_trace_data,
10437ec681f3Smrg                                 new_submit->cmd_buffer_count);
10447ec681f3Smrgfail_copy_timestamp_cs:
10457ec681f3Smrg   vk_free(&queue->device->vk.alloc, new_submit->cmd_buffer_trace_data);
10467ec681f3Smrgfail_cmd_trace_data:
10477ec681f3Smrg   vk_free(&queue->device->vk.alloc, new_submit->cmds);
10487ec681f3Smrgfail_cmds:
10497ec681f3Smrgfail_signal_timelines:
10507ec681f3Smrgfail_wait_timelines:
10517ec681f3Smrg   vk_free(&queue->device->vk.alloc, new_submit->signal_semaphores);
10527ec681f3Smrgfail_signal_semaphores:
10537ec681f3Smrg   vk_free(&queue->device->vk.alloc, new_submit->wait_semaphores);
10547ec681f3Smrgfail_wait_semaphores:
10557ec681f3Smrg   vk_free(&queue->device->vk.alloc, new_submit->cmd_buffers);
10567ec681f3Smrgfail_cmd_buffers:
10577ec681f3Smrg   return result;
10587ec681f3Smrg}
10597ec681f3Smrg
10607ec681f3Smrgstatic void
10617ec681f3Smrgtu_queue_submit_free(struct tu_queue *queue, struct tu_queue_submit *submit)
10627ec681f3Smrg{
10637ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->wait_semaphores);
10647ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->signal_semaphores);
10657ec681f3Smrg
10667ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->wait_timelines);
10677ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->wait_timeline_values);
10687ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->signal_timelines);
10697ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->signal_timeline_values);
10707ec681f3Smrg
10717ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->cmds);
10727ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->in_syncobjs);
10737ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->out_syncobjs);
10747ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit->cmd_buffers);
10757ec681f3Smrg   vk_free(&queue->device->vk.alloc, submit);
10767ec681f3Smrg}
10777ec681f3Smrg
10787ec681f3Smrgstatic void
10797ec681f3Smrgtu_queue_build_msm_gem_submit_cmds(struct tu_queue *queue,
10807ec681f3Smrg                                   struct tu_queue_submit *submit)
10817ec681f3Smrg{
10827ec681f3Smrg   struct drm_msm_gem_submit_cmd *cmds = submit->cmds;
10837ec681f3Smrg
10847ec681f3Smrg   uint32_t entry_idx = 0;
10857ec681f3Smrg   for (uint32_t j = 0; j < submit->cmd_buffer_count; ++j) {
10867ec681f3Smrg      TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->cmd_buffers[j]);
10877ec681f3Smrg      struct tu_cs *cs = &cmdbuf->cs;
10887ec681f3Smrg      struct tu_device *dev = queue->device;
10897ec681f3Smrg
10907ec681f3Smrg      if (submit->counter_pass_index != ~0) {
10917ec681f3Smrg         struct tu_cs_entry *perf_cs_entry =
10927ec681f3Smrg            &dev->perfcntrs_pass_cs_entries[submit->counter_pass_index];
10937ec681f3Smrg
10947ec681f3Smrg         cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
10957ec681f3Smrg         cmds[entry_idx].submit_idx =
10967ec681f3Smrg            dev->bo_idx[perf_cs_entry->bo->gem_handle];
10977ec681f3Smrg         cmds[entry_idx].submit_offset = perf_cs_entry->offset;
10987ec681f3Smrg         cmds[entry_idx].size = perf_cs_entry->size;
10997ec681f3Smrg         cmds[entry_idx].pad = 0;
11007ec681f3Smrg         cmds[entry_idx].nr_relocs = 0;
11017ec681f3Smrg         cmds[entry_idx++].relocs = 0;
11027ec681f3Smrg      }
11037ec681f3Smrg
11047ec681f3Smrg      for (unsigned i = 0; i < cs->entry_count; ++i, ++entry_idx) {
11057ec681f3Smrg         cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
11067ec681f3Smrg         cmds[entry_idx].submit_idx =
11077ec681f3Smrg            dev->bo_idx[cs->entries[i].bo->gem_handle];
11087ec681f3Smrg         cmds[entry_idx].submit_offset = cs->entries[i].offset;
11097ec681f3Smrg         cmds[entry_idx].size = cs->entries[i].size;
11107ec681f3Smrg         cmds[entry_idx].pad = 0;
11117ec681f3Smrg         cmds[entry_idx].nr_relocs = 0;
11127ec681f3Smrg         cmds[entry_idx].relocs = 0;
11137ec681f3Smrg      }
11147ec681f3Smrg
11157ec681f3Smrg      if (submit->cmd_buffer_trace_data) {
11167ec681f3Smrg         struct tu_cs *ts_cs = submit->cmd_buffer_trace_data[j].timestamp_copy_cs;
11177ec681f3Smrg         if (ts_cs) {
11187ec681f3Smrg            cmds[entry_idx].type = MSM_SUBMIT_CMD_BUF;
11197ec681f3Smrg            cmds[entry_idx].submit_idx =
11207ec681f3Smrg               queue->device->bo_idx[ts_cs->entries[0].bo->gem_handle];
11217ec681f3Smrg
11227ec681f3Smrg            assert(cmds[entry_idx].submit_idx < queue->device->bo_count);
11237ec681f3Smrg
11247ec681f3Smrg            cmds[entry_idx].submit_offset = ts_cs->entries[0].offset;
11257ec681f3Smrg            cmds[entry_idx].size = ts_cs->entries[0].size;
11267ec681f3Smrg            cmds[entry_idx].pad = 0;
11277ec681f3Smrg            cmds[entry_idx].nr_relocs = 0;
11287ec681f3Smrg            cmds[entry_idx++].relocs = 0;
11297ec681f3Smrg         }
11307ec681f3Smrg      }
11317ec681f3Smrg   }
11327ec681f3Smrg}
11337ec681f3Smrg
11347ec681f3Smrgstatic VkResult
11357ec681f3Smrgtu_queue_submit_locked(struct tu_queue *queue, struct tu_queue_submit *submit)
11367ec681f3Smrg{
11377ec681f3Smrg   queue->device->submit_count++;
11387ec681f3Smrg
11397ec681f3Smrg#if HAVE_PERFETTO
11407ec681f3Smrg   tu_perfetto_submit(queue->device, queue->device->submit_count);
11417ec681f3Smrg#endif
11427ec681f3Smrg
11437ec681f3Smrg   uint32_t flags = MSM_PIPE_3D0;
11447ec681f3Smrg
11457ec681f3Smrg   if (submit->nr_in_syncobjs)
11467ec681f3Smrg      flags |= MSM_SUBMIT_SYNCOBJ_IN;
11477ec681f3Smrg
11487ec681f3Smrg   if (submit->nr_out_syncobjs)
11497ec681f3Smrg      flags |= MSM_SUBMIT_SYNCOBJ_OUT;
11507ec681f3Smrg
11517ec681f3Smrg   if (submit->last_submit)
11527ec681f3Smrg      flags |= MSM_SUBMIT_FENCE_FD_OUT;
11537ec681f3Smrg
11547ec681f3Smrg   mtx_lock(&queue->device->bo_mutex);
11557ec681f3Smrg
11567ec681f3Smrg   /* drm_msm_gem_submit_cmd requires index of bo which could change at any
11577ec681f3Smrg    * time when bo_mutex is not locked. So we build submit cmds here the real
11587ec681f3Smrg    * place to submit.
11597ec681f3Smrg    */
11607ec681f3Smrg   tu_queue_build_msm_gem_submit_cmds(queue, submit);
11617ec681f3Smrg
11627ec681f3Smrg   struct drm_msm_gem_submit req = {
11637ec681f3Smrg      .flags = flags,
11647ec681f3Smrg      .queueid = queue->msm_queue_id,
11657ec681f3Smrg      .bos = (uint64_t)(uintptr_t) queue->device->bo_list,
11667ec681f3Smrg      .nr_bos = queue->device->bo_count,
11677ec681f3Smrg      .cmds = (uint64_t)(uintptr_t)submit->cmds,
11687ec681f3Smrg      .nr_cmds = submit->entry_count,
11697ec681f3Smrg      .in_syncobjs = (uint64_t)(uintptr_t)submit->in_syncobjs,
11707ec681f3Smrg      .out_syncobjs = (uint64_t)(uintptr_t)submit->out_syncobjs,
11717ec681f3Smrg      .nr_in_syncobjs = submit->nr_in_syncobjs - submit->wait_timeline_count,
11727ec681f3Smrg      .nr_out_syncobjs = submit->nr_out_syncobjs,
11737ec681f3Smrg      .syncobj_stride = sizeof(struct drm_msm_gem_submit_syncobj),
1174361fc4cbSmaya   };
1175361fc4cbSmaya
11767ec681f3Smrg   int ret = drmCommandWriteRead(queue->device->fd,
11777ec681f3Smrg                                 DRM_MSM_GEM_SUBMIT,
11787ec681f3Smrg                                 &req, sizeof(req));
1179361fc4cbSmaya
11807ec681f3Smrg   mtx_unlock(&queue->device->bo_mutex);
11817ec681f3Smrg
11827ec681f3Smrg   if (ret)
11837ec681f3Smrg      return tu_device_set_lost(queue->device, "submit failed: %s\n",
11847ec681f3Smrg                                strerror(errno));
11857ec681f3Smrg
11867ec681f3Smrg   /* restore permanent payload on wait */
11877ec681f3Smrg   for (uint32_t i = 0; i < submit->wait_semaphore_count; i++) {
11887ec681f3Smrg      TU_FROM_HANDLE(tu_syncobj, sem, submit->wait_semaphores[i]);
11897ec681f3Smrg      if(sem->type == TU_SEMAPHORE_BINARY)
11907ec681f3Smrg         sync_set_temporary(queue->device, sem, 0);
11917ec681f3Smrg   }
11927ec681f3Smrg
11937ec681f3Smrg   if (submit->last_submit) {
11947ec681f3Smrg      if (queue->fence >= 0)
11957ec681f3Smrg         close(queue->fence);
11967ec681f3Smrg      queue->fence = req.fence_fd;
11977ec681f3Smrg   }
11987ec681f3Smrg
11997ec681f3Smrg   /* Update highest_submitted values in the timeline. */
12007ec681f3Smrg   for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
12017ec681f3Smrg      struct tu_syncobj *sem = submit->signal_timelines[i];
12027ec681f3Smrg      uint64_t signal_value = submit->signal_timeline_values[i];
12037ec681f3Smrg
12047ec681f3Smrg      assert(signal_value > sem->timeline.highest_submitted);
12057ec681f3Smrg
12067ec681f3Smrg      sem->timeline.highest_submitted = signal_value;
12077ec681f3Smrg   }
12087ec681f3Smrg
12097ec681f3Smrg   if (submit->cmd_buffer_trace_data) {
12107ec681f3Smrg      struct tu_u_trace_flush_data *flush_data =
12117ec681f3Smrg         vk_alloc(&queue->device->vk.alloc, sizeof(struct tu_u_trace_flush_data),
12127ec681f3Smrg               8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
12137ec681f3Smrg      flush_data->submission_id = queue->device->submit_count;
12147ec681f3Smrg      flush_data->syncobj =
12157ec681f3Smrg         vk_alloc(&queue->device->vk.alloc, sizeof(struct tu_u_trace_syncobj),
12167ec681f3Smrg               8, VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
12177ec681f3Smrg      flush_data->syncobj->fence = req.fence;
12187ec681f3Smrg      flush_data->syncobj->msm_queue_id = queue->msm_queue_id;
12197ec681f3Smrg
12207ec681f3Smrg      flush_data->cmd_trace_data = submit->cmd_buffer_trace_data;
12217ec681f3Smrg      flush_data->trace_count = submit->cmd_buffer_count;
12227ec681f3Smrg      submit->cmd_buffer_trace_data = NULL;
12237ec681f3Smrg
12247ec681f3Smrg      for (uint32_t i = 0; i < submit->cmd_buffer_count; i++) {
12257ec681f3Smrg         bool free_data = i == (submit->cmd_buffer_count - 1);
12267ec681f3Smrg         u_trace_flush(flush_data->cmd_trace_data[i].trace, flush_data, free_data);
12277ec681f3Smrg      }
12287ec681f3Smrg   }
12297ec681f3Smrg
12307ec681f3Smrg   pthread_cond_broadcast(&queue->device->timeline_cond);
12317ec681f3Smrg
12327ec681f3Smrg   return VK_SUCCESS;
1233361fc4cbSmaya}
1234361fc4cbSmaya
12357ec681f3Smrg
12367ec681f3Smrgstatic bool
12377ec681f3Smrgtu_queue_submit_ready_locked(struct tu_queue_submit *submit)
1238361fc4cbSmaya{
12397ec681f3Smrg   for (uint32_t i = 0; i < submit->wait_timeline_count; i++) {
12407ec681f3Smrg      if (submit->wait_timeline_values[i] >
12417ec681f3Smrg            submit->wait_timelines[i]->timeline.highest_submitted) {
12427ec681f3Smrg         return false;
12437ec681f3Smrg      }
12447ec681f3Smrg   }
12457ec681f3Smrg
12467ec681f3Smrg   return true;
1247361fc4cbSmaya}
1248361fc4cbSmaya
12497ec681f3Smrgstatic VkResult
12507ec681f3Smrgtu_timeline_add_point_locked(struct tu_device *device,
12517ec681f3Smrg                             struct tu_timeline *timeline,
12527ec681f3Smrg                             uint64_t value,
12537ec681f3Smrg                             struct tu_timeline_point **point)
1254361fc4cbSmaya{
12557ec681f3Smrg
12567ec681f3Smrg   if (list_is_empty(&timeline->free_points)) {
12577ec681f3Smrg      *point = vk_zalloc(&device->vk.alloc, sizeof(**point), 8,
12587ec681f3Smrg            VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
12597ec681f3Smrg
12607ec681f3Smrg      if (!(*point))
12617ec681f3Smrg         return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
12627ec681f3Smrg
12637ec681f3Smrg      struct drm_syncobj_create create = {};
12647ec681f3Smrg
12657ec681f3Smrg      int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_CREATE, &create);
12667ec681f3Smrg      if (ret) {
12677ec681f3Smrg         vk_free(&device->vk.alloc, *point);
12687ec681f3Smrg         return vk_error(device, VK_ERROR_DEVICE_LOST);
12697ec681f3Smrg      }
12707ec681f3Smrg
12717ec681f3Smrg      (*point)->syncobj = create.handle;
12727ec681f3Smrg
12737ec681f3Smrg   } else {
12747ec681f3Smrg      *point = list_first_entry(&timeline->free_points,
12757ec681f3Smrg                                struct tu_timeline_point, link);
12767ec681f3Smrg      list_del(&(*point)->link);
12777ec681f3Smrg   }
12787ec681f3Smrg
12797ec681f3Smrg   (*point)->value = value;
12807ec681f3Smrg   list_addtail(&(*point)->link, &timeline->points);
12817ec681f3Smrg
12827ec681f3Smrg   return VK_SUCCESS;
12837ec681f3Smrg}
12847ec681f3Smrg
12857ec681f3Smrgstatic VkResult
12867ec681f3Smrgtu_queue_submit_timeline_locked(struct tu_queue *queue,
12877ec681f3Smrg                                struct tu_queue_submit *submit)
12887ec681f3Smrg{
12897ec681f3Smrg   VkResult result;
12907ec681f3Smrg   uint32_t timeline_idx =
12917ec681f3Smrg         submit->nr_out_syncobjs - submit->signal_timeline_count;
12927ec681f3Smrg
12937ec681f3Smrg   for (uint32_t i = 0; i < submit->signal_timeline_count; i++) {
12947ec681f3Smrg      struct tu_timeline *timeline = &submit->signal_timelines[i]->timeline;
12957ec681f3Smrg      uint64_t signal_value = submit->signal_timeline_values[i];
12967ec681f3Smrg      struct tu_timeline_point *point;
12977ec681f3Smrg
12987ec681f3Smrg      result = tu_timeline_add_point_locked(queue->device, timeline,
12997ec681f3Smrg            signal_value, &point);
13007ec681f3Smrg      if (result != VK_SUCCESS)
13017ec681f3Smrg         return result;
13027ec681f3Smrg
13037ec681f3Smrg      submit->out_syncobjs[timeline_idx + i] =
13047ec681f3Smrg         (struct drm_msm_gem_submit_syncobj) {
13057ec681f3Smrg            .handle = point->syncobj,
13067ec681f3Smrg            .flags = 0,
13077ec681f3Smrg         };
13087ec681f3Smrg   }
13097ec681f3Smrg
13107ec681f3Smrg   return tu_queue_submit_locked(queue, submit);
13117ec681f3Smrg}
13127ec681f3Smrg
13137ec681f3Smrgstatic VkResult
13147ec681f3Smrgtu_queue_submit_deferred_locked(struct tu_queue *queue, uint32_t *advance)
13157ec681f3Smrg{
13167ec681f3Smrg   VkResult result = VK_SUCCESS;
13177ec681f3Smrg
13187ec681f3Smrg   list_for_each_entry_safe(struct tu_queue_submit, submit,
13197ec681f3Smrg                            &queue->queued_submits, link) {
13207ec681f3Smrg      if (!tu_queue_submit_ready_locked(submit))
13217ec681f3Smrg         break;
13227ec681f3Smrg
13237ec681f3Smrg      (*advance)++;
13247ec681f3Smrg
13257ec681f3Smrg      result = tu_queue_submit_timeline_locked(queue, submit);
13267ec681f3Smrg
13277ec681f3Smrg      list_del(&submit->link);
13287ec681f3Smrg      tu_queue_submit_free(queue, submit);
13297ec681f3Smrg
13307ec681f3Smrg      if (result != VK_SUCCESS)
13317ec681f3Smrg         break;
13327ec681f3Smrg   }
13337ec681f3Smrg
13347ec681f3Smrg   return result;
13357ec681f3Smrg}
13367ec681f3Smrg
13377ec681f3SmrgVkResult
13387ec681f3Smrgtu_device_submit_deferred_locked(struct tu_device *dev)
13397ec681f3Smrg{
13407ec681f3Smrg    VkResult result = VK_SUCCESS;
13417ec681f3Smrg
13427ec681f3Smrg    uint32_t advance = 0;
13437ec681f3Smrg    do {
13447ec681f3Smrg       advance = 0;
13457ec681f3Smrg       for (uint32_t i = 0; i < dev->queue_count[0]; i++) {
13467ec681f3Smrg          /* Try again if there's signaled submission. */
13477ec681f3Smrg          result = tu_queue_submit_deferred_locked(&dev->queues[0][i],
13487ec681f3Smrg                &advance);
13497ec681f3Smrg          if (result != VK_SUCCESS)
13507ec681f3Smrg             return result;
13517ec681f3Smrg       }
13527ec681f3Smrg
13537ec681f3Smrg    } while(advance);
13547ec681f3Smrg
13557ec681f3Smrg    return result;
13567ec681f3Smrg}
13577ec681f3Smrg
13587ec681f3Smrgstatic inline void
13597ec681f3Smrgget_abs_timeout(struct drm_msm_timespec *tv, uint64_t ns)
13607ec681f3Smrg{
13617ec681f3Smrg   struct timespec t;
13627ec681f3Smrg   clock_gettime(CLOCK_MONOTONIC, &t);
13637ec681f3Smrg   tv->tv_sec = t.tv_sec + ns / 1000000000;
13647ec681f3Smrg   tv->tv_nsec = t.tv_nsec + ns % 1000000000;
13657ec681f3Smrg}
13667ec681f3Smrg
13677ec681f3SmrgVkResult
13687ec681f3Smrgtu_device_wait_u_trace(struct tu_device *dev, struct tu_u_trace_syncobj *syncobj)
13697ec681f3Smrg{
13707ec681f3Smrg   struct drm_msm_wait_fence req = {
13717ec681f3Smrg      .fence = syncobj->fence,
13727ec681f3Smrg      .queueid = syncobj->msm_queue_id,
13737ec681f3Smrg   };
13747ec681f3Smrg   int ret;
13757ec681f3Smrg
13767ec681f3Smrg   get_abs_timeout(&req.timeout, 1000000000);
13777ec681f3Smrg
13787ec681f3Smrg   ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req));
13797ec681f3Smrg   if (ret && (ret != -ETIMEDOUT)) {
13807ec681f3Smrg      fprintf(stderr, "wait-fence failed! %d (%s)", ret, strerror(errno));
13817ec681f3Smrg      return VK_TIMEOUT;
13827ec681f3Smrg   }
13837ec681f3Smrg
13847ec681f3Smrg   return VK_SUCCESS;
13857ec681f3Smrg}
13867ec681f3Smrg
13877ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
13887ec681f3Smrgtu_QueueSubmit(VkQueue _queue,
13897ec681f3Smrg               uint32_t submitCount,
13907ec681f3Smrg               const VkSubmitInfo *pSubmits,
13917ec681f3Smrg               VkFence _fence)
13927ec681f3Smrg{
13937ec681f3Smrg   TU_FROM_HANDLE(tu_queue, queue, _queue);
13947ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, fence, _fence);
13957ec681f3Smrg
13967ec681f3Smrg   for (uint32_t i = 0; i < submitCount; ++i) {
13977ec681f3Smrg      const VkSubmitInfo *submit = pSubmits + i;
13987ec681f3Smrg      const bool last_submit = (i == submitCount - 1);
13997ec681f3Smrg      uint32_t out_syncobjs_size = submit->signalSemaphoreCount;
14007ec681f3Smrg
14017ec681f3Smrg      const VkPerformanceQuerySubmitInfoKHR *perf_info =
14027ec681f3Smrg         vk_find_struct_const(pSubmits[i].pNext,
14037ec681f3Smrg                              PERFORMANCE_QUERY_SUBMIT_INFO_KHR);
14047ec681f3Smrg
14057ec681f3Smrg      if (last_submit && fence)
14067ec681f3Smrg         out_syncobjs_size += 1;
14077ec681f3Smrg
14087ec681f3Smrg      pthread_mutex_lock(&queue->device->submit_mutex);
14097ec681f3Smrg      struct tu_queue_submit *submit_req = NULL;
14107ec681f3Smrg
14117ec681f3Smrg      VkResult ret = tu_queue_submit_create_locked(queue, submit,
14127ec681f3Smrg            submit->waitSemaphoreCount, out_syncobjs_size,
14137ec681f3Smrg            last_submit, perf_info, &submit_req);
14147ec681f3Smrg
14157ec681f3Smrg      if (ret != VK_SUCCESS) {
14167ec681f3Smrg         pthread_mutex_unlock(&queue->device->submit_mutex);
14177ec681f3Smrg         return ret;
14187ec681f3Smrg      }
14197ec681f3Smrg
14207ec681f3Smrg      /* note: assuming there won't be any very large semaphore counts */
14217ec681f3Smrg      struct drm_msm_gem_submit_syncobj *in_syncobjs = submit_req->in_syncobjs;
14227ec681f3Smrg      struct drm_msm_gem_submit_syncobj *out_syncobjs = submit_req->out_syncobjs;
14237ec681f3Smrg      uint32_t nr_in_syncobjs = 0, nr_out_syncobjs = 0;
14247ec681f3Smrg
14257ec681f3Smrg      for (uint32_t i = 0; i < submit->waitSemaphoreCount; i++) {
14267ec681f3Smrg         TU_FROM_HANDLE(tu_syncobj, sem, submit->pWaitSemaphores[i]);
14277ec681f3Smrg         if (sem->type == TU_SEMAPHORE_TIMELINE)
14287ec681f3Smrg            continue;
14297ec681f3Smrg
14307ec681f3Smrg         in_syncobjs[nr_in_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
14317ec681f3Smrg            .handle = sem->binary.temporary ?: sem->binary.permanent,
14327ec681f3Smrg            .flags = MSM_SUBMIT_SYNCOBJ_RESET,
14337ec681f3Smrg         };
14347ec681f3Smrg      }
14357ec681f3Smrg
14367ec681f3Smrg      for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) {
14377ec681f3Smrg         TU_FROM_HANDLE(tu_syncobj, sem, submit->pSignalSemaphores[i]);
14387ec681f3Smrg
14397ec681f3Smrg         /* In case of timeline semaphores, we can defer the creation of syncobj
14407ec681f3Smrg          * and adding it at real submit time.
14417ec681f3Smrg          */
14427ec681f3Smrg         if (sem->type == TU_SEMAPHORE_TIMELINE)
14437ec681f3Smrg            continue;
14447ec681f3Smrg
14457ec681f3Smrg         out_syncobjs[nr_out_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
14467ec681f3Smrg            .handle = sem->binary.temporary ?: sem->binary.permanent,
14477ec681f3Smrg            .flags = 0,
14487ec681f3Smrg         };
14497ec681f3Smrg      }
14507ec681f3Smrg
14517ec681f3Smrg      if (last_submit && fence) {
14527ec681f3Smrg         out_syncobjs[nr_out_syncobjs++] = (struct drm_msm_gem_submit_syncobj) {
14537ec681f3Smrg            .handle = fence->binary.temporary ?: fence->binary.permanent,
14547ec681f3Smrg            .flags = 0,
14557ec681f3Smrg         };
14567ec681f3Smrg      }
14577ec681f3Smrg
14587ec681f3Smrg      /* Queue the current submit */
14597ec681f3Smrg      list_addtail(&submit_req->link, &queue->queued_submits);
14607ec681f3Smrg      ret = tu_device_submit_deferred_locked(queue->device);
14617ec681f3Smrg
14627ec681f3Smrg      pthread_mutex_unlock(&queue->device->submit_mutex);
14637ec681f3Smrg      if (ret != VK_SUCCESS)
14647ec681f3Smrg          return ret;
14657ec681f3Smrg   }
14667ec681f3Smrg
14677ec681f3Smrg   if (!submitCount && fence) {
14687ec681f3Smrg      /* signal fence imemediately since we don't have a submit to do it */
14697ec681f3Smrg      drmIoctl(queue->device->fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &(struct drm_syncobj_array) {
14707ec681f3Smrg         .handles = (uintptr_t) (uint32_t[]) { fence->binary.temporary ?: fence->binary.permanent },
14717ec681f3Smrg         .count_handles = 1,
14727ec681f3Smrg      });
14737ec681f3Smrg   }
14747ec681f3Smrg
14757ec681f3Smrg   return VK_SUCCESS;
14767ec681f3Smrg}
14777ec681f3Smrg
14787ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
14797ec681f3Smrgtu_CreateFence(VkDevice device,
14807ec681f3Smrg               const VkFenceCreateInfo *info,
14817ec681f3Smrg               const VkAllocationCallbacks *pAllocator,
14827ec681f3Smrg               VkFence *pFence)
14837ec681f3Smrg{
14847ec681f3Smrg   return sync_create(device, info->flags & VK_FENCE_CREATE_SIGNALED_BIT, true, true, 0,
14857ec681f3Smrg                      pAllocator, (void**) pFence);
14867ec681f3Smrg}
14877ec681f3Smrg
14887ec681f3SmrgVKAPI_ATTR void VKAPI_CALL
14897ec681f3Smrgtu_DestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator)
14907ec681f3Smrg{
14917ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, sync, fence);
14927ec681f3Smrg   sync_destroy(device, sync, pAllocator);
14937ec681f3Smrg}
14947ec681f3Smrg
14957ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
14967ec681f3Smrgtu_ImportFenceFdKHR(VkDevice device, const VkImportFenceFdInfoKHR *info)
14977ec681f3Smrg{
14987ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, sync, info->fence);
14997ec681f3Smrg   return sync_import(device, sync, info->flags & VK_FENCE_IMPORT_TEMPORARY_BIT,
15007ec681f3Smrg         info->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, info->fd);
15017ec681f3Smrg}
15027ec681f3Smrg
15037ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
15047ec681f3Smrgtu_GetFenceFdKHR(VkDevice device, const VkFenceGetFdInfoKHR *info, int *pFd)
15057ec681f3Smrg{
15067ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, sync, info->fence);
15077ec681f3Smrg   return sync_export(device, sync,
15087ec681f3Smrg         info->handleType == VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT, pFd);
15097ec681f3Smrg}
15107ec681f3Smrg
15117ec681f3Smrgstatic VkResult
15127ec681f3Smrgdrm_syncobj_wait(struct tu_device *device,
15137ec681f3Smrg                 const uint32_t *handles, uint32_t count_handles,
15147ec681f3Smrg                 int64_t timeout_nsec, bool wait_all)
15157ec681f3Smrg{
15167ec681f3Smrg   int ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_WAIT, &(struct drm_syncobj_wait) {
15177ec681f3Smrg      .handles = (uint64_t) (uintptr_t) handles,
15187ec681f3Smrg      .count_handles = count_handles,
15197ec681f3Smrg      .timeout_nsec = timeout_nsec,
15207ec681f3Smrg      .flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT |
15217ec681f3Smrg               COND(wait_all, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL)
15227ec681f3Smrg   });
15237ec681f3Smrg   if (ret) {
15247ec681f3Smrg      if (errno == ETIME)
15257ec681f3Smrg         return VK_TIMEOUT;
15267ec681f3Smrg
15277ec681f3Smrg      assert(0);
15287ec681f3Smrg      return VK_ERROR_DEVICE_LOST; /* TODO */
15297ec681f3Smrg   }
15307ec681f3Smrg   return VK_SUCCESS;
15317ec681f3Smrg}
15327ec681f3Smrg
15337ec681f3Smrgstatic uint64_t
15347ec681f3Smrggettime_ns(void)
15357ec681f3Smrg{
15367ec681f3Smrg   struct timespec current;
15377ec681f3Smrg   clock_gettime(CLOCK_MONOTONIC, &current);
15387ec681f3Smrg   return (uint64_t)current.tv_sec * 1000000000 + current.tv_nsec;
15397ec681f3Smrg}
15407ec681f3Smrg
15417ec681f3Smrg/* and the kernel converts it right back to relative timeout - very smart UAPI */
15427ec681f3Smrgstatic uint64_t
15437ec681f3Smrgabsolute_timeout(uint64_t timeout)
15447ec681f3Smrg{
15457ec681f3Smrg   if (timeout == 0)
15467ec681f3Smrg      return 0;
15477ec681f3Smrg   uint64_t current_time = gettime_ns();
15487ec681f3Smrg   uint64_t max_timeout = (uint64_t) INT64_MAX - current_time;
15497ec681f3Smrg
15507ec681f3Smrg   timeout = MIN2(max_timeout, timeout);
15517ec681f3Smrg
15527ec681f3Smrg   return (current_time + timeout);
15537ec681f3Smrg}
15547ec681f3Smrg
15557ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
15567ec681f3Smrgtu_WaitForFences(VkDevice _device,
15577ec681f3Smrg                 uint32_t fenceCount,
15587ec681f3Smrg                 const VkFence *pFences,
15597ec681f3Smrg                 VkBool32 waitAll,
15607ec681f3Smrg                 uint64_t timeout)
15617ec681f3Smrg{
15627ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
15637ec681f3Smrg
15647ec681f3Smrg   if (tu_device_is_lost(device))
15657ec681f3Smrg      return VK_ERROR_DEVICE_LOST;
15667ec681f3Smrg
15677ec681f3Smrg   uint32_t handles[fenceCount];
15687ec681f3Smrg   for (unsigned i = 0; i < fenceCount; ++i) {
15697ec681f3Smrg      TU_FROM_HANDLE(tu_syncobj, fence, pFences[i]);
15707ec681f3Smrg      handles[i] = fence->binary.temporary ?: fence->binary.permanent;
15717ec681f3Smrg   }
15727ec681f3Smrg
15737ec681f3Smrg   return drm_syncobj_wait(device, handles, fenceCount, absolute_timeout(timeout), waitAll);
15747ec681f3Smrg}
15757ec681f3Smrg
15767ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
15777ec681f3Smrgtu_ResetFences(VkDevice _device, uint32_t fenceCount, const VkFence *pFences)
15787ec681f3Smrg{
15797ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
15807ec681f3Smrg   int ret;
15817ec681f3Smrg
15827ec681f3Smrg   uint32_t handles[fenceCount];
15837ec681f3Smrg   for (unsigned i = 0; i < fenceCount; ++i) {
15847ec681f3Smrg      TU_FROM_HANDLE(tu_syncobj, fence, pFences[i]);
15857ec681f3Smrg      sync_set_temporary(device, fence, 0);
15867ec681f3Smrg      handles[i] = fence->binary.permanent;
15877ec681f3Smrg   }
15887ec681f3Smrg
15897ec681f3Smrg   ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_RESET, &(struct drm_syncobj_array) {
15907ec681f3Smrg      .handles = (uint64_t) (uintptr_t) handles,
15917ec681f3Smrg      .count_handles = fenceCount,
15927ec681f3Smrg   });
15937ec681f3Smrg   if (ret) {
15947ec681f3Smrg      tu_device_set_lost(device, "DRM_IOCTL_SYNCOBJ_RESET failure: %s",
15957ec681f3Smrg                         strerror(errno));
15967ec681f3Smrg   }
15977ec681f3Smrg
15987ec681f3Smrg   return VK_SUCCESS;
15997ec681f3Smrg}
16007ec681f3Smrg
16017ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
16027ec681f3Smrgtu_GetFenceStatus(VkDevice _device, VkFence _fence)
16037ec681f3Smrg{
16047ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
16057ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, fence, _fence);
16067ec681f3Smrg   VkResult result;
16077ec681f3Smrg
16087ec681f3Smrg   result = drm_syncobj_wait(device, (uint32_t[]){fence->binary.temporary ?: fence->binary.permanent}, 1, 0, false);
16097ec681f3Smrg   if (result == VK_TIMEOUT)
16107ec681f3Smrg      result = VK_NOT_READY;
16117ec681f3Smrg   return result;
16127ec681f3Smrg}
16137ec681f3Smrg
16147ec681f3Smrgint
16157ec681f3Smrgtu_signal_fences(struct tu_device *device, struct tu_syncobj *fence1, struct tu_syncobj *fence2)
16167ec681f3Smrg{
16177ec681f3Smrg   uint32_t handles[2], count = 0;
16187ec681f3Smrg   if (fence1)
16197ec681f3Smrg      handles[count++] = fence1->binary.temporary ?: fence1->binary.permanent;
16207ec681f3Smrg
16217ec681f3Smrg   if (fence2)
16227ec681f3Smrg      handles[count++] = fence2->binary.temporary ?: fence2->binary.permanent;
16237ec681f3Smrg
16247ec681f3Smrg   if (!count)
16257ec681f3Smrg      return 0;
16267ec681f3Smrg
16277ec681f3Smrg   return drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &(struct drm_syncobj_array) {
16287ec681f3Smrg      .handles = (uintptr_t) handles,
16297ec681f3Smrg      .count_handles = count
16307ec681f3Smrg   });
16317ec681f3Smrg}
16327ec681f3Smrg
16337ec681f3Smrgint
16347ec681f3Smrgtu_syncobj_to_fd(struct tu_device *device, struct tu_syncobj *sync)
16357ec681f3Smrg{
16367ec681f3Smrg   struct drm_syncobj_handle handle = { .handle = sync->binary.permanent };
16377ec681f3Smrg   int ret;
16387ec681f3Smrg
16397ec681f3Smrg   ret = drmIoctl(device->fd, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &handle);
16407ec681f3Smrg
16417ec681f3Smrg   return ret ? -1 : handle.fd;
16427ec681f3Smrg}
16437ec681f3Smrg
16447ec681f3Smrgstatic VkResult
16457ec681f3Smrgtu_timeline_gc_locked(struct tu_device *dev, struct tu_timeline *timeline)
16467ec681f3Smrg{
16477ec681f3Smrg   VkResult result = VK_SUCCESS;
16487ec681f3Smrg
16497ec681f3Smrg   /* Go through every point in the timeline and check if any signaled point */
16507ec681f3Smrg   list_for_each_entry_safe(struct tu_timeline_point, point,
16517ec681f3Smrg                            &timeline->points, link) {
16527ec681f3Smrg
16537ec681f3Smrg      /* If the value of the point is higher than highest_submitted,
16547ec681f3Smrg       * the point has not been submited yet.
16557ec681f3Smrg       */
16567ec681f3Smrg      if (point->wait_count || point->value > timeline->highest_submitted)
16577ec681f3Smrg         return VK_SUCCESS;
16587ec681f3Smrg
16597ec681f3Smrg      result = drm_syncobj_wait(dev, (uint32_t[]){point->syncobj}, 1, 0, true);
16607ec681f3Smrg
16617ec681f3Smrg      if (result == VK_TIMEOUT) {
16627ec681f3Smrg         /* This means the syncobj is still busy and it should wait
16637ec681f3Smrg          * with timeout specified by users via vkWaitSemaphores.
16647ec681f3Smrg          */
16657ec681f3Smrg         result = VK_SUCCESS;
16667ec681f3Smrg      } else {
16677ec681f3Smrg         timeline->highest_signaled =
16687ec681f3Smrg               MAX2(timeline->highest_signaled, point->value);
16697ec681f3Smrg         list_del(&point->link);
16707ec681f3Smrg         list_add(&point->link, &timeline->free_points);
16717ec681f3Smrg      }
16727ec681f3Smrg   }
16737ec681f3Smrg
16747ec681f3Smrg   return result;
16757ec681f3Smrg}
16767ec681f3Smrg
16777ec681f3Smrg
16787ec681f3Smrgstatic VkResult
16797ec681f3Smrgtu_timeline_wait_locked(struct tu_device *device,
16807ec681f3Smrg                        struct tu_timeline *timeline,
16817ec681f3Smrg                        uint64_t value,
16827ec681f3Smrg                        uint64_t abs_timeout)
16837ec681f3Smrg{
16847ec681f3Smrg   VkResult result;
16857ec681f3Smrg
16867ec681f3Smrg   while(timeline->highest_submitted < value) {
16877ec681f3Smrg      struct timespec abstime;
16887ec681f3Smrg      timespec_from_nsec(&abstime, abs_timeout);
16897ec681f3Smrg
16907ec681f3Smrg      pthread_cond_timedwait(&device->timeline_cond, &device->submit_mutex,
16917ec681f3Smrg            &abstime);
16927ec681f3Smrg
16937ec681f3Smrg      if (os_time_get_nano() >= abs_timeout &&
16947ec681f3Smrg            timeline->highest_submitted < value)
16957ec681f3Smrg         return VK_TIMEOUT;
16967ec681f3Smrg   }
16977ec681f3Smrg
16987ec681f3Smrg   /* Visit every point in the timeline and wait until
16997ec681f3Smrg    * the highest_signaled reaches the value.
17007ec681f3Smrg    */
17017ec681f3Smrg   while (1) {
17027ec681f3Smrg      result = tu_timeline_gc_locked(device, timeline);
17037ec681f3Smrg      if (result != VK_SUCCESS)
17047ec681f3Smrg         return result;
17057ec681f3Smrg
17067ec681f3Smrg      if (timeline->highest_signaled >= value)
17077ec681f3Smrg          return VK_SUCCESS;
17087ec681f3Smrg
17097ec681f3Smrg      struct tu_timeline_point *point =
17107ec681f3Smrg            list_first_entry(&timeline->points,
17117ec681f3Smrg                             struct tu_timeline_point, link);
17127ec681f3Smrg
17137ec681f3Smrg      point->wait_count++;
17147ec681f3Smrg      pthread_mutex_unlock(&device->submit_mutex);
17157ec681f3Smrg      result = drm_syncobj_wait(device, (uint32_t[]){point->syncobj}, 1,
17167ec681f3Smrg                                abs_timeout, true);
17177ec681f3Smrg
17187ec681f3Smrg      pthread_mutex_lock(&device->submit_mutex);
17197ec681f3Smrg      point->wait_count--;
17207ec681f3Smrg
17217ec681f3Smrg      if (result != VK_SUCCESS)
17227ec681f3Smrg         return result;
17237ec681f3Smrg   }
17247ec681f3Smrg
17257ec681f3Smrg   return result;
17267ec681f3Smrg}
17277ec681f3Smrg
17287ec681f3Smrgstatic VkResult
17297ec681f3Smrgtu_wait_timelines(struct tu_device *device,
17307ec681f3Smrg                  const VkSemaphoreWaitInfoKHR* pWaitInfo,
17317ec681f3Smrg                  uint64_t abs_timeout)
17327ec681f3Smrg{
17337ec681f3Smrg   if ((pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT_KHR) &&
17347ec681f3Smrg         pWaitInfo->semaphoreCount > 1) {
17357ec681f3Smrg      pthread_mutex_lock(&device->submit_mutex);
17367ec681f3Smrg
17377ec681f3Smrg      /* Visit every timline semaphore in the queue until timeout */
17387ec681f3Smrg      while (1) {
17397ec681f3Smrg         for(uint32_t i = 0; i < pWaitInfo->semaphoreCount; ++i) {
17407ec681f3Smrg            TU_FROM_HANDLE(tu_syncobj, semaphore, pWaitInfo->pSemaphores[i]);
17417ec681f3Smrg            VkResult result = tu_timeline_wait_locked(device,
17427ec681f3Smrg                  &semaphore->timeline, pWaitInfo->pValues[i], 0);
17437ec681f3Smrg
17447ec681f3Smrg            /* Returns result values including VK_SUCCESS except for VK_TIMEOUT */
17457ec681f3Smrg            if (result != VK_TIMEOUT) {
17467ec681f3Smrg               pthread_mutex_unlock(&device->submit_mutex);
17477ec681f3Smrg               return result;
17487ec681f3Smrg            }
17497ec681f3Smrg         }
17507ec681f3Smrg
17517ec681f3Smrg         if (os_time_get_nano() > abs_timeout) {
17527ec681f3Smrg            pthread_mutex_unlock(&device->submit_mutex);
17537ec681f3Smrg            return VK_TIMEOUT;
17547ec681f3Smrg         }
17557ec681f3Smrg      }
17567ec681f3Smrg   } else {
17577ec681f3Smrg      VkResult result = VK_SUCCESS;
17587ec681f3Smrg
17597ec681f3Smrg      pthread_mutex_lock(&device->submit_mutex);
17607ec681f3Smrg      for(uint32_t i = 0; i < pWaitInfo->semaphoreCount; ++i) {
17617ec681f3Smrg         TU_FROM_HANDLE(tu_syncobj, semaphore, pWaitInfo->pSemaphores[i]);
17627ec681f3Smrg         assert(semaphore->type == TU_SEMAPHORE_TIMELINE);
17637ec681f3Smrg
17647ec681f3Smrg         result = tu_timeline_wait_locked(device, &semaphore->timeline,
17657ec681f3Smrg               pWaitInfo->pValues[i], abs_timeout);
17667ec681f3Smrg         if (result != VK_SUCCESS)
17677ec681f3Smrg            break;
17687ec681f3Smrg      }
17697ec681f3Smrg      pthread_mutex_unlock(&device->submit_mutex);
17707ec681f3Smrg
17717ec681f3Smrg      return result;
17727ec681f3Smrg   }
17737ec681f3Smrg}
17747ec681f3Smrg
17757ec681f3Smrg
17767ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
17777ec681f3Smrgtu_GetSemaphoreCounterValue(VkDevice _device,
17787ec681f3Smrg                            VkSemaphore _semaphore,
17797ec681f3Smrg                            uint64_t* pValue)
17807ec681f3Smrg{
17817ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
17827ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, semaphore, _semaphore);
17837ec681f3Smrg
17847ec681f3Smrg   assert(semaphore->type == TU_SEMAPHORE_TIMELINE);
17857ec681f3Smrg
17867ec681f3Smrg   VkResult result;
17877ec681f3Smrg
17887ec681f3Smrg   pthread_mutex_lock(&device->submit_mutex);
17897ec681f3Smrg
17907ec681f3Smrg   result = tu_timeline_gc_locked(device, &semaphore->timeline);
17917ec681f3Smrg   *pValue = semaphore->timeline.highest_signaled;
17927ec681f3Smrg
17937ec681f3Smrg   pthread_mutex_unlock(&device->submit_mutex);
17947ec681f3Smrg
17957ec681f3Smrg   return result;
17967ec681f3Smrg}
17977ec681f3Smrg
17987ec681f3Smrg
17997ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
18007ec681f3Smrgtu_WaitSemaphores(VkDevice _device,
18017ec681f3Smrg                  const VkSemaphoreWaitInfoKHR* pWaitInfo,
18027ec681f3Smrg                  uint64_t timeout)
18037ec681f3Smrg{
18047ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
18057ec681f3Smrg
18067ec681f3Smrg   return tu_wait_timelines(device, pWaitInfo, absolute_timeout(timeout));
18077ec681f3Smrg}
18087ec681f3Smrg
18097ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
18107ec681f3Smrgtu_SignalSemaphore(VkDevice _device,
18117ec681f3Smrg                   const VkSemaphoreSignalInfoKHR* pSignalInfo)
18127ec681f3Smrg{
18137ec681f3Smrg   TU_FROM_HANDLE(tu_device, device, _device);
18147ec681f3Smrg   TU_FROM_HANDLE(tu_syncobj, semaphore, pSignalInfo->semaphore);
18157ec681f3Smrg   VkResult result;
18167ec681f3Smrg
18177ec681f3Smrg   assert(semaphore->type == TU_SEMAPHORE_TIMELINE);
18187ec681f3Smrg
18197ec681f3Smrg   pthread_mutex_lock(&device->submit_mutex);
18207ec681f3Smrg
18217ec681f3Smrg   result = tu_timeline_gc_locked(device, &semaphore->timeline);
18227ec681f3Smrg   if (result != VK_SUCCESS) {
18237ec681f3Smrg      pthread_mutex_unlock(&device->submit_mutex);
18247ec681f3Smrg      return result;
18257ec681f3Smrg   }
18267ec681f3Smrg
18277ec681f3Smrg   semaphore->timeline.highest_submitted = pSignalInfo->value;
18287ec681f3Smrg   semaphore->timeline.highest_signaled = pSignalInfo->value;
18297ec681f3Smrg
18307ec681f3Smrg   result = tu_device_submit_deferred_locked(device);
18317ec681f3Smrg
18327ec681f3Smrg   pthread_cond_broadcast(&device->timeline_cond);
18337ec681f3Smrg   pthread_mutex_unlock(&device->submit_mutex);
18347ec681f3Smrg
18357ec681f3Smrg   return result;
18367ec681f3Smrg}
18377ec681f3Smrg
18387ec681f3Smrg#ifdef ANDROID
18397ec681f3Smrg#include <libsync.h>
18407ec681f3Smrg
18417ec681f3SmrgVKAPI_ATTR VkResult VKAPI_CALL
18427ec681f3Smrgtu_QueueSignalReleaseImageANDROID(VkQueue _queue,
18437ec681f3Smrg                                  uint32_t waitSemaphoreCount,
18447ec681f3Smrg                                  const VkSemaphore *pWaitSemaphores,
18457ec681f3Smrg                                  VkImage image,
18467ec681f3Smrg                                  int *pNativeFenceFd)
18477ec681f3Smrg{
18487ec681f3Smrg   TU_FROM_HANDLE(tu_queue, queue, _queue);
18497ec681f3Smrg   VkResult result = VK_SUCCESS;
18507ec681f3Smrg
18517ec681f3Smrg   if (waitSemaphoreCount == 0) {
18527ec681f3Smrg      if (pNativeFenceFd)
18537ec681f3Smrg         *pNativeFenceFd = -1;
18547ec681f3Smrg      return VK_SUCCESS;
18557ec681f3Smrg   }
18567ec681f3Smrg
18577ec681f3Smrg   int fd = -1;
18587ec681f3Smrg
18597ec681f3Smrg   for (uint32_t i = 0; i < waitSemaphoreCount; ++i) {
18607ec681f3Smrg      int tmp_fd;
18617ec681f3Smrg      result = tu_GetSemaphoreFdKHR(
18627ec681f3Smrg         tu_device_to_handle(queue->device),
18637ec681f3Smrg         &(VkSemaphoreGetFdInfoKHR) {
18647ec681f3Smrg            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR,
18657ec681f3Smrg            .handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT,
18667ec681f3Smrg            .semaphore = pWaitSemaphores[i],
18677ec681f3Smrg         },
18687ec681f3Smrg         &tmp_fd);
18697ec681f3Smrg      if (result != VK_SUCCESS) {
18707ec681f3Smrg         if (fd >= 0)
18717ec681f3Smrg            close(fd);
18727ec681f3Smrg         return result;
18737ec681f3Smrg      }
18747ec681f3Smrg
18757ec681f3Smrg      if (fd < 0)
18767ec681f3Smrg         fd = tmp_fd;
18777ec681f3Smrg      else if (tmp_fd >= 0) {
18787ec681f3Smrg         sync_accumulate("tu", &fd, tmp_fd);
18797ec681f3Smrg         close(tmp_fd);
18807ec681f3Smrg      }
18817ec681f3Smrg   }
18827ec681f3Smrg
18837ec681f3Smrg   if (pNativeFenceFd) {
18847ec681f3Smrg      *pNativeFenceFd = fd;
18857ec681f3Smrg   } else if (fd >= 0) {
18867ec681f3Smrg      close(fd);
18877ec681f3Smrg      /* We still need to do the exports, to reset the semaphores, but
18887ec681f3Smrg       * otherwise we don't wait on them. */
18897ec681f3Smrg   }
18907ec681f3Smrg   return VK_SUCCESS;
1891361fc4cbSmaya}
18927ec681f3Smrg#endif
1893