1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2021 Intel Corporation 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21bf215546Sopenharmony_ci * IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "vk_drm_syncobj.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include <sched.h> 27bf215546Sopenharmony_ci#include <xf86drm.h> 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_ci#include "drm-uapi/drm.h" 30bf215546Sopenharmony_ci 31bf215546Sopenharmony_ci#include "util/os_time.h" 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include "vk_device.h" 34bf215546Sopenharmony_ci#include "vk_log.h" 35bf215546Sopenharmony_ci#include "vk_util.h" 36bf215546Sopenharmony_ci 37bf215546Sopenharmony_cistatic struct vk_drm_syncobj * 38bf215546Sopenharmony_cito_drm_syncobj(struct vk_sync *sync) 39bf215546Sopenharmony_ci{ 40bf215546Sopenharmony_ci assert(vk_sync_type_is_drm_syncobj(sync->type)); 41bf215546Sopenharmony_ci return container_of(sync, struct vk_drm_syncobj, base); 42bf215546Sopenharmony_ci} 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_cistatic VkResult 45bf215546Sopenharmony_civk_drm_syncobj_init(struct vk_device *device, 46bf215546Sopenharmony_ci struct vk_sync *sync, 47bf215546Sopenharmony_ci uint64_t initial_value) 48bf215546Sopenharmony_ci{ 49bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 50bf215546Sopenharmony_ci 51bf215546Sopenharmony_ci uint32_t flags = 0; 52bf215546Sopenharmony_ci if (!(sync->flags & VK_SYNC_IS_TIMELINE) && initial_value) 53bf215546Sopenharmony_ci flags |= DRM_SYNCOBJ_CREATE_SIGNALED; 54bf215546Sopenharmony_ci 55bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 56bf215546Sopenharmony_ci int err = drmSyncobjCreate(device->drm_fd, flags, &sobj->syncobj); 57bf215546Sopenharmony_ci if (err < 0) { 58bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_OUT_OF_HOST_MEMORY, 59bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_CREATE failed: %m"); 60bf215546Sopenharmony_ci } 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci if ((sync->flags & VK_SYNC_IS_TIMELINE) && initial_value) { 63bf215546Sopenharmony_ci err = drmSyncobjTimelineSignal(device->drm_fd, &sobj->syncobj, 64bf215546Sopenharmony_ci &initial_value, 1); 65bf215546Sopenharmony_ci if (err < 0) { 66bf215546Sopenharmony_ci vk_drm_syncobj_finish(device, sync); 67bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_OUT_OF_HOST_MEMORY, 68bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_CREATE failed: %m"); 69bf215546Sopenharmony_ci } 70bf215546Sopenharmony_ci } 71bf215546Sopenharmony_ci 72bf215546Sopenharmony_ci return VK_SUCCESS; 73bf215546Sopenharmony_ci} 74bf215546Sopenharmony_ci 75bf215546Sopenharmony_civoid 76bf215546Sopenharmony_civk_drm_syncobj_finish(struct vk_device *device, 77bf215546Sopenharmony_ci struct vk_sync *sync) 78bf215546Sopenharmony_ci{ 79bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 82bf215546Sopenharmony_ci ASSERTED int err = drmSyncobjDestroy(device->drm_fd, sobj->syncobj); 83bf215546Sopenharmony_ci assert(err == 0); 84bf215546Sopenharmony_ci} 85bf215546Sopenharmony_ci 86bf215546Sopenharmony_cistatic VkResult 87bf215546Sopenharmony_civk_drm_syncobj_signal(struct vk_device *device, 88bf215546Sopenharmony_ci struct vk_sync *sync, 89bf215546Sopenharmony_ci uint64_t value) 90bf215546Sopenharmony_ci{ 91bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 94bf215546Sopenharmony_ci int err; 95bf215546Sopenharmony_ci if (sync->flags & VK_SYNC_IS_TIMELINE) 96bf215546Sopenharmony_ci err = drmSyncobjTimelineSignal(device->drm_fd, &sobj->syncobj, &value, 1); 97bf215546Sopenharmony_ci else 98bf215546Sopenharmony_ci err = drmSyncobjSignal(device->drm_fd, &sobj->syncobj, 1); 99bf215546Sopenharmony_ci if (err) { 100bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 101bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_SIGNAL failed: %m"); 102bf215546Sopenharmony_ci } 103bf215546Sopenharmony_ci 104bf215546Sopenharmony_ci return VK_SUCCESS; 105bf215546Sopenharmony_ci} 106bf215546Sopenharmony_ci 107bf215546Sopenharmony_cistatic VkResult 108bf215546Sopenharmony_civk_drm_syncobj_get_value(struct vk_device *device, 109bf215546Sopenharmony_ci struct vk_sync *sync, 110bf215546Sopenharmony_ci uint64_t *value) 111bf215546Sopenharmony_ci{ 112bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 115bf215546Sopenharmony_ci int err = drmSyncobjQuery(device->drm_fd, &sobj->syncobj, value, 1); 116bf215546Sopenharmony_ci if (err) { 117bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 118bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_QUERY failed: %m"); 119bf215546Sopenharmony_ci } 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci return VK_SUCCESS; 122bf215546Sopenharmony_ci} 123bf215546Sopenharmony_ci 124bf215546Sopenharmony_cistatic VkResult 125bf215546Sopenharmony_civk_drm_syncobj_reset(struct vk_device *device, 126bf215546Sopenharmony_ci struct vk_sync *sync) 127bf215546Sopenharmony_ci{ 128bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 131bf215546Sopenharmony_ci int err = drmSyncobjReset(device->drm_fd, &sobj->syncobj, 1); 132bf215546Sopenharmony_ci if (err) { 133bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 134bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_RESET failed: %m"); 135bf215546Sopenharmony_ci } 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci return VK_SUCCESS; 138bf215546Sopenharmony_ci} 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_cistatic VkResult 141bf215546Sopenharmony_cisync_has_sync_file(struct vk_device *device, struct vk_sync *sync) 142bf215546Sopenharmony_ci{ 143bf215546Sopenharmony_ci uint32_t handle = to_drm_syncobj(sync)->syncobj; 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci int fd = -1; 146bf215546Sopenharmony_ci int err = drmSyncobjExportSyncFile(device->drm_fd, handle, &fd); 147bf215546Sopenharmony_ci if (!err) { 148bf215546Sopenharmony_ci close(fd); 149bf215546Sopenharmony_ci return VK_SUCCESS; 150bf215546Sopenharmony_ci } 151bf215546Sopenharmony_ci 152bf215546Sopenharmony_ci /* On the off chance the sync_file export repeatedly fails for some 153bf215546Sopenharmony_ci * unexpected reason, we want to ensure this function will return success 154bf215546Sopenharmony_ci * eventually. Do a zero-time syncobj wait if the export failed. 155bf215546Sopenharmony_ci */ 156bf215546Sopenharmony_ci err = drmSyncobjWait(device->drm_fd, &handle, 1, 0 /* timeout */, 157bf215546Sopenharmony_ci DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, 158bf215546Sopenharmony_ci NULL /* first_signaled */); 159bf215546Sopenharmony_ci if (!err) { 160bf215546Sopenharmony_ci return VK_SUCCESS; 161bf215546Sopenharmony_ci } else if (errno == ETIME) { 162bf215546Sopenharmony_ci return VK_TIMEOUT; 163bf215546Sopenharmony_ci } else { 164bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 165bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_WAIT failed: %m"); 166bf215546Sopenharmony_ci } 167bf215546Sopenharmony_ci} 168bf215546Sopenharmony_ci 169bf215546Sopenharmony_cistatic VkResult 170bf215546Sopenharmony_cispin_wait_for_sync_file(struct vk_device *device, 171bf215546Sopenharmony_ci uint32_t wait_count, 172bf215546Sopenharmony_ci const struct vk_sync_wait *waits, 173bf215546Sopenharmony_ci enum vk_sync_wait_flags wait_flags, 174bf215546Sopenharmony_ci uint64_t abs_timeout_ns) 175bf215546Sopenharmony_ci{ 176bf215546Sopenharmony_ci if (wait_flags & VK_SYNC_WAIT_ANY) { 177bf215546Sopenharmony_ci while (1) { 178bf215546Sopenharmony_ci for (uint32_t i = 0; i < wait_count; i++) { 179bf215546Sopenharmony_ci VkResult result = sync_has_sync_file(device, waits[i].sync); 180bf215546Sopenharmony_ci if (result != VK_TIMEOUT) 181bf215546Sopenharmony_ci return result; 182bf215546Sopenharmony_ci } 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci if (os_time_get_nano() >= abs_timeout_ns) 185bf215546Sopenharmony_ci return VK_TIMEOUT; 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci sched_yield(); 188bf215546Sopenharmony_ci } 189bf215546Sopenharmony_ci } else { 190bf215546Sopenharmony_ci for (uint32_t i = 0; i < wait_count; i++) { 191bf215546Sopenharmony_ci while (1) { 192bf215546Sopenharmony_ci VkResult result = sync_has_sync_file(device, waits[i].sync); 193bf215546Sopenharmony_ci if (result != VK_TIMEOUT) 194bf215546Sopenharmony_ci return result; 195bf215546Sopenharmony_ci 196bf215546Sopenharmony_ci if (os_time_get_nano() >= abs_timeout_ns) 197bf215546Sopenharmony_ci return VK_TIMEOUT; 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci sched_yield(); 200bf215546Sopenharmony_ci } 201bf215546Sopenharmony_ci } 202bf215546Sopenharmony_ci } 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_ci return VK_SUCCESS; 205bf215546Sopenharmony_ci} 206bf215546Sopenharmony_ci 207bf215546Sopenharmony_cistatic VkResult 208bf215546Sopenharmony_civk_drm_syncobj_wait_many(struct vk_device *device, 209bf215546Sopenharmony_ci uint32_t wait_count, 210bf215546Sopenharmony_ci const struct vk_sync_wait *waits, 211bf215546Sopenharmony_ci enum vk_sync_wait_flags wait_flags, 212bf215546Sopenharmony_ci uint64_t abs_timeout_ns) 213bf215546Sopenharmony_ci{ 214bf215546Sopenharmony_ci if ((wait_flags & VK_SYNC_WAIT_PENDING) && 215bf215546Sopenharmony_ci !(waits[0].sync->type->features & VK_SYNC_FEATURE_TIMELINE)) { 216bf215546Sopenharmony_ci /* Sadly, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE was never implemented 217bf215546Sopenharmony_ci * for drivers that don't support timelines. Instead, we have to spin 218bf215546Sopenharmony_ci * on DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE until it succeeds. 219bf215546Sopenharmony_ci */ 220bf215546Sopenharmony_ci return spin_wait_for_sync_file(device, wait_count, waits, 221bf215546Sopenharmony_ci wait_flags, abs_timeout_ns); 222bf215546Sopenharmony_ci } 223bf215546Sopenharmony_ci 224bf215546Sopenharmony_ci /* Syncobj timeouts are signed */ 225bf215546Sopenharmony_ci abs_timeout_ns = MIN2(abs_timeout_ns, (uint64_t)INT64_MAX); 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci STACK_ARRAY(uint32_t, handles, wait_count); 228bf215546Sopenharmony_ci STACK_ARRAY(uint64_t, wait_values, wait_count); 229bf215546Sopenharmony_ci 230bf215546Sopenharmony_ci uint32_t j = 0; 231bf215546Sopenharmony_ci bool has_timeline = false; 232bf215546Sopenharmony_ci for (uint32_t i = 0; i < wait_count; i++) { 233bf215546Sopenharmony_ci /* The syncobj API doesn't like wait values of 0 but it's safe to skip 234bf215546Sopenharmony_ci * them because a wait for 0 is a no-op. 235bf215546Sopenharmony_ci */ 236bf215546Sopenharmony_ci if (waits[i].sync->flags & VK_SYNC_IS_TIMELINE) { 237bf215546Sopenharmony_ci if (waits[i].wait_value == 0) 238bf215546Sopenharmony_ci continue; 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci has_timeline = true; 241bf215546Sopenharmony_ci } 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci handles[j] = to_drm_syncobj(waits[i].sync)->syncobj; 244bf215546Sopenharmony_ci wait_values[j] = waits[i].wait_value; 245bf215546Sopenharmony_ci j++; 246bf215546Sopenharmony_ci } 247bf215546Sopenharmony_ci assert(j <= wait_count); 248bf215546Sopenharmony_ci wait_count = j; 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci uint32_t syncobj_wait_flags = DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT; 251bf215546Sopenharmony_ci if (!(wait_flags & VK_SYNC_WAIT_ANY)) 252bf215546Sopenharmony_ci syncobj_wait_flags |= DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL; 253bf215546Sopenharmony_ci 254bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 255bf215546Sopenharmony_ci int err; 256bf215546Sopenharmony_ci if (wait_count == 0) { 257bf215546Sopenharmony_ci err = 0; 258bf215546Sopenharmony_ci } else if (wait_flags & VK_SYNC_WAIT_PENDING) { 259bf215546Sopenharmony_ci /* We always use a timeline wait for WAIT_PENDING, even for binary 260bf215546Sopenharmony_ci * syncobjs because the non-timeline wait doesn't support 261bf215546Sopenharmony_ci * DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE. 262bf215546Sopenharmony_ci */ 263bf215546Sopenharmony_ci err = drmSyncobjTimelineWait(device->drm_fd, handles, wait_values, 264bf215546Sopenharmony_ci wait_count, abs_timeout_ns, 265bf215546Sopenharmony_ci syncobj_wait_flags | 266bf215546Sopenharmony_ci DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE, 267bf215546Sopenharmony_ci NULL /* first_signaled */); 268bf215546Sopenharmony_ci } else if (has_timeline) { 269bf215546Sopenharmony_ci err = drmSyncobjTimelineWait(device->drm_fd, handles, wait_values, 270bf215546Sopenharmony_ci wait_count, abs_timeout_ns, 271bf215546Sopenharmony_ci syncobj_wait_flags, 272bf215546Sopenharmony_ci NULL /* first_signaled */); 273bf215546Sopenharmony_ci } else { 274bf215546Sopenharmony_ci err = drmSyncobjWait(device->drm_fd, handles, 275bf215546Sopenharmony_ci wait_count, abs_timeout_ns, 276bf215546Sopenharmony_ci syncobj_wait_flags, 277bf215546Sopenharmony_ci NULL /* first_signaled */); 278bf215546Sopenharmony_ci } 279bf215546Sopenharmony_ci 280bf215546Sopenharmony_ci STACK_ARRAY_FINISH(handles); 281bf215546Sopenharmony_ci STACK_ARRAY_FINISH(wait_values); 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci if (err && errno == ETIME) { 284bf215546Sopenharmony_ci return VK_TIMEOUT; 285bf215546Sopenharmony_ci } else if (err) { 286bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 287bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_WAIT failed: %m"); 288bf215546Sopenharmony_ci } 289bf215546Sopenharmony_ci 290bf215546Sopenharmony_ci return VK_SUCCESS; 291bf215546Sopenharmony_ci} 292bf215546Sopenharmony_ci 293bf215546Sopenharmony_cistatic VkResult 294bf215546Sopenharmony_civk_drm_syncobj_import_opaque_fd(struct vk_device *device, 295bf215546Sopenharmony_ci struct vk_sync *sync, 296bf215546Sopenharmony_ci int fd) 297bf215546Sopenharmony_ci{ 298bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 301bf215546Sopenharmony_ci uint32_t new_handle; 302bf215546Sopenharmony_ci int err = drmSyncobjFDToHandle(device->drm_fd, fd, &new_handle); 303bf215546Sopenharmony_ci if (err) { 304bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 305bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE failed: %m"); 306bf215546Sopenharmony_ci } 307bf215546Sopenharmony_ci 308bf215546Sopenharmony_ci err = drmSyncobjDestroy(device->drm_fd, sobj->syncobj); 309bf215546Sopenharmony_ci assert(!err); 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci sobj->syncobj = new_handle; 312bf215546Sopenharmony_ci 313bf215546Sopenharmony_ci return VK_SUCCESS; 314bf215546Sopenharmony_ci} 315bf215546Sopenharmony_ci 316bf215546Sopenharmony_cistatic VkResult 317bf215546Sopenharmony_civk_drm_syncobj_export_opaque_fd(struct vk_device *device, 318bf215546Sopenharmony_ci struct vk_sync *sync, 319bf215546Sopenharmony_ci int *fd) 320bf215546Sopenharmony_ci{ 321bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 324bf215546Sopenharmony_ci int err = drmSyncobjHandleToFD(device->drm_fd, sobj->syncobj, fd); 325bf215546Sopenharmony_ci if (err) { 326bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 327bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD failed: %m"); 328bf215546Sopenharmony_ci } 329bf215546Sopenharmony_ci 330bf215546Sopenharmony_ci return VK_SUCCESS; 331bf215546Sopenharmony_ci} 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_cistatic VkResult 334bf215546Sopenharmony_civk_drm_syncobj_import_sync_file(struct vk_device *device, 335bf215546Sopenharmony_ci struct vk_sync *sync, 336bf215546Sopenharmony_ci int sync_file) 337bf215546Sopenharmony_ci{ 338bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 341bf215546Sopenharmony_ci int err = drmSyncobjImportSyncFile(device->drm_fd, sobj->syncobj, sync_file); 342bf215546Sopenharmony_ci if (err) { 343bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 344bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE failed: %m"); 345bf215546Sopenharmony_ci } 346bf215546Sopenharmony_ci 347bf215546Sopenharmony_ci return VK_SUCCESS; 348bf215546Sopenharmony_ci} 349bf215546Sopenharmony_ci 350bf215546Sopenharmony_cistatic VkResult 351bf215546Sopenharmony_civk_drm_syncobj_export_sync_file(struct vk_device *device, 352bf215546Sopenharmony_ci struct vk_sync *sync, 353bf215546Sopenharmony_ci int *sync_file) 354bf215546Sopenharmony_ci{ 355bf215546Sopenharmony_ci struct vk_drm_syncobj *sobj = to_drm_syncobj(sync); 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_ci assert(device->drm_fd >= 0); 358bf215546Sopenharmony_ci int err = drmSyncobjExportSyncFile(device->drm_fd, sobj->syncobj, sync_file); 359bf215546Sopenharmony_ci if (err) { 360bf215546Sopenharmony_ci return vk_errorf(device, VK_ERROR_UNKNOWN, 361bf215546Sopenharmony_ci "DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD failed: %m"); 362bf215546Sopenharmony_ci } 363bf215546Sopenharmony_ci 364bf215546Sopenharmony_ci return VK_SUCCESS; 365bf215546Sopenharmony_ci} 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_cistatic VkResult 368bf215546Sopenharmony_civk_drm_syncobj_move(struct vk_device *device, 369bf215546Sopenharmony_ci struct vk_sync *dst, 370bf215546Sopenharmony_ci struct vk_sync *src) 371bf215546Sopenharmony_ci{ 372bf215546Sopenharmony_ci struct vk_drm_syncobj *dst_sobj = to_drm_syncobj(dst); 373bf215546Sopenharmony_ci struct vk_drm_syncobj *src_sobj = to_drm_syncobj(src); 374bf215546Sopenharmony_ci VkResult result; 375bf215546Sopenharmony_ci 376bf215546Sopenharmony_ci if (!(dst->flags & VK_SYNC_IS_SHARED) && 377bf215546Sopenharmony_ci !(src->flags & VK_SYNC_IS_SHARED)) { 378bf215546Sopenharmony_ci result = vk_drm_syncobj_reset(device, dst); 379bf215546Sopenharmony_ci if (unlikely(result != VK_SUCCESS)) 380bf215546Sopenharmony_ci return result; 381bf215546Sopenharmony_ci 382bf215546Sopenharmony_ci uint32_t tmp = dst_sobj->syncobj; 383bf215546Sopenharmony_ci dst_sobj->syncobj = src_sobj->syncobj; 384bf215546Sopenharmony_ci src_sobj->syncobj = tmp; 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_ci return VK_SUCCESS; 387bf215546Sopenharmony_ci } else { 388bf215546Sopenharmony_ci int fd; 389bf215546Sopenharmony_ci result = vk_drm_syncobj_export_sync_file(device, src, &fd); 390bf215546Sopenharmony_ci if (result != VK_SUCCESS) 391bf215546Sopenharmony_ci return result; 392bf215546Sopenharmony_ci 393bf215546Sopenharmony_ci result = vk_drm_syncobj_import_sync_file(device, dst, fd); 394bf215546Sopenharmony_ci if (fd >= 0) 395bf215546Sopenharmony_ci close(fd); 396bf215546Sopenharmony_ci if (result != VK_SUCCESS) 397bf215546Sopenharmony_ci return result; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci return vk_drm_syncobj_reset(device, src); 400bf215546Sopenharmony_ci } 401bf215546Sopenharmony_ci} 402bf215546Sopenharmony_ci 403bf215546Sopenharmony_cistruct vk_sync_type 404bf215546Sopenharmony_civk_drm_syncobj_get_type(int drm_fd) 405bf215546Sopenharmony_ci{ 406bf215546Sopenharmony_ci uint32_t syncobj = 0; 407bf215546Sopenharmony_ci int err = drmSyncobjCreate(drm_fd, DRM_SYNCOBJ_CREATE_SIGNALED, &syncobj); 408bf215546Sopenharmony_ci if (err < 0) 409bf215546Sopenharmony_ci return (struct vk_sync_type) { .features = 0 }; 410bf215546Sopenharmony_ci 411bf215546Sopenharmony_ci struct vk_sync_type type = { 412bf215546Sopenharmony_ci .size = sizeof(struct vk_drm_syncobj), 413bf215546Sopenharmony_ci .features = VK_SYNC_FEATURE_BINARY | 414bf215546Sopenharmony_ci VK_SYNC_FEATURE_GPU_WAIT | 415bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_RESET | 416bf215546Sopenharmony_ci VK_SYNC_FEATURE_CPU_SIGNAL | 417bf215546Sopenharmony_ci VK_SYNC_FEATURE_WAIT_PENDING, 418bf215546Sopenharmony_ci .init = vk_drm_syncobj_init, 419bf215546Sopenharmony_ci .finish = vk_drm_syncobj_finish, 420bf215546Sopenharmony_ci .signal = vk_drm_syncobj_signal, 421bf215546Sopenharmony_ci .reset = vk_drm_syncobj_reset, 422bf215546Sopenharmony_ci .move = vk_drm_syncobj_move, 423bf215546Sopenharmony_ci .import_opaque_fd = vk_drm_syncobj_import_opaque_fd, 424bf215546Sopenharmony_ci .export_opaque_fd = vk_drm_syncobj_export_opaque_fd, 425bf215546Sopenharmony_ci .import_sync_file = vk_drm_syncobj_import_sync_file, 426bf215546Sopenharmony_ci .export_sync_file = vk_drm_syncobj_export_sync_file, 427bf215546Sopenharmony_ci }; 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci err = drmSyncobjWait(drm_fd, &syncobj, 1, 0, 430bf215546Sopenharmony_ci DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL, 431bf215546Sopenharmony_ci NULL /* first_signaled */); 432bf215546Sopenharmony_ci if (err == 0) { 433bf215546Sopenharmony_ci type.wait_many = vk_drm_syncobj_wait_many; 434bf215546Sopenharmony_ci type.features |= VK_SYNC_FEATURE_CPU_WAIT | 435bf215546Sopenharmony_ci VK_SYNC_FEATURE_WAIT_ANY; 436bf215546Sopenharmony_ci } 437bf215546Sopenharmony_ci 438bf215546Sopenharmony_ci uint64_t cap; 439bf215546Sopenharmony_ci err = drmGetCap(drm_fd, DRM_CAP_SYNCOBJ_TIMELINE, &cap); 440bf215546Sopenharmony_ci if (err == 0 && cap != 0) { 441bf215546Sopenharmony_ci type.get_value = vk_drm_syncobj_get_value; 442bf215546Sopenharmony_ci type.features |= VK_SYNC_FEATURE_TIMELINE; 443bf215546Sopenharmony_ci } 444bf215546Sopenharmony_ci 445bf215546Sopenharmony_ci err = drmSyncobjDestroy(drm_fd, syncobj); 446bf215546Sopenharmony_ci assert(err == 0); 447bf215546Sopenharmony_ci 448bf215546Sopenharmony_ci return type; 449bf215546Sopenharmony_ci} 450