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, ¤t); 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