1/* 2 * Copyright © 2021 Intel Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "vk_semaphore.h" 25 26#include "util/os_time.h" 27 28#ifndef _WIN32 29#include <unistd.h> 30#endif 31 32#include "vk_common_entrypoints.h" 33#include "vk_device.h" 34#include "vk_log.h" 35#include "vk_physical_device.h" 36#include "vk_util.h" 37 38static VkExternalSemaphoreHandleTypeFlags 39vk_sync_semaphore_import_types(const struct vk_sync_type *type, 40 VkSemaphoreType semaphore_type) 41{ 42 VkExternalSemaphoreHandleTypeFlags handle_types = 0; 43 44 if (type->import_opaque_fd) 45 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 46 47 if (type->export_sync_file && semaphore_type == VK_SEMAPHORE_TYPE_BINARY) 48 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; 49 50 return handle_types; 51} 52 53static VkExternalSemaphoreHandleTypeFlags 54vk_sync_semaphore_export_types(const struct vk_sync_type *type, 55 VkSemaphoreType semaphore_type) 56{ 57 VkExternalSemaphoreHandleTypeFlags handle_types = 0; 58 59 if (type->export_opaque_fd) 60 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 61 62 if (type->export_sync_file && semaphore_type == VK_SEMAPHORE_TYPE_BINARY) 63 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT; 64 65 return handle_types; 66} 67 68static VkExternalSemaphoreHandleTypeFlags 69vk_sync_semaphore_handle_types(const struct vk_sync_type *type, 70 VkSemaphoreType semaphore_type) 71{ 72 return vk_sync_semaphore_export_types(type, semaphore_type) & 73 vk_sync_semaphore_import_types(type, semaphore_type); 74} 75 76static const struct vk_sync_type * 77get_semaphore_sync_type(struct vk_physical_device *pdevice, 78 VkSemaphoreType semaphore_type, 79 VkExternalSemaphoreHandleTypeFlags handle_types) 80{ 81 assert(semaphore_type == VK_SEMAPHORE_TYPE_BINARY || 82 semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE); 83 84 enum vk_sync_features req_features = VK_SYNC_FEATURE_GPU_WAIT; 85 if (semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE) { 86 req_features |= VK_SYNC_FEATURE_TIMELINE | 87 VK_SYNC_FEATURE_CPU_WAIT; 88 } else { 89 req_features |= VK_SYNC_FEATURE_BINARY; 90 } 91 92 for (const struct vk_sync_type *const *t = 93 pdevice->supported_sync_types; *t; t++) { 94 if (req_features & ~(*t)->features) 95 continue; 96 97 if (handle_types & ~vk_sync_semaphore_handle_types(*t, semaphore_type)) 98 continue; 99 100 return *t; 101 } 102 103 return NULL; 104} 105 106static VkSemaphoreType 107get_semaphore_type(const void *pNext, uint64_t *initial_value) 108{ 109 const VkSemaphoreTypeCreateInfo *type_info = 110 vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO); 111 112 if (!type_info) 113 return VK_SEMAPHORE_TYPE_BINARY; 114 115 if (initial_value) 116 *initial_value = type_info->initialValue; 117 return type_info->semaphoreType; 118} 119 120VKAPI_ATTR VkResult VKAPI_CALL 121vk_common_CreateSemaphore(VkDevice _device, 122 const VkSemaphoreCreateInfo *pCreateInfo, 123 const VkAllocationCallbacks *pAllocator, 124 VkSemaphore *pSemaphore) 125{ 126 VK_FROM_HANDLE(vk_device, device, _device); 127 struct vk_semaphore *semaphore; 128 129 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO); 130 131 uint64_t initial_value = 0; 132 const VkSemaphoreType semaphore_type = 133 get_semaphore_type(pCreateInfo->pNext, &initial_value); 134 135 if (semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE) 136 assert(device->timeline_mode != VK_DEVICE_TIMELINE_MODE_NONE); 137 138 const VkExportSemaphoreCreateInfo *export = 139 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO); 140 VkExternalSemaphoreHandleTypeFlags handle_types = 141 export ? export->handleTypes : 0; 142 143 const struct vk_sync_type *sync_type = 144 get_semaphore_sync_type(device->physical, semaphore_type, handle_types); 145 if (sync_type == NULL) { 146 /* We should always be able to get a semaphore type for internal */ 147 assert(get_semaphore_sync_type(device->physical, semaphore_type, 0) != NULL); 148 return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE, 149 "Combination of external handle types is unsupported " 150 "for VkSemaphore creation."); 151 } 152 153 /* If the timeline mode is ASSISTED, then any permanent binary semaphore 154 * types need to be able to support move. We don't require this for 155 * temporary unless that temporary is also used as a semaphore signal 156 * operation which is much trickier to assert early. 157 */ 158 if (semaphore_type == VK_SEMAPHORE_TYPE_BINARY && 159 vk_device_supports_threaded_submit(device)) 160 assert(sync_type->move); 161 162 /* Allocate a vk_semaphore + vk_sync implementation. Because the permanent 163 * field of vk_semaphore is the base field of the vk_sync implementation, 164 * we can make the 2 structures overlap. 165 */ 166 size_t size = offsetof(struct vk_semaphore, permanent) + sync_type->size; 167 semaphore = vk_object_zalloc(device, pAllocator, size, 168 VK_OBJECT_TYPE_SEMAPHORE); 169 if (semaphore == NULL) 170 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY); 171 172 semaphore->type = semaphore_type; 173 174 enum vk_sync_flags sync_flags = 0; 175 if (semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE) 176 sync_flags |= VK_SYNC_IS_TIMELINE; 177 if (handle_types) 178 sync_flags |= VK_SYNC_IS_SHAREABLE; 179 180 VkResult result = vk_sync_init(device, &semaphore->permanent, 181 sync_type, sync_flags, initial_value); 182 if (result != VK_SUCCESS) { 183 vk_object_free(device, pAllocator, semaphore); 184 return result; 185 } 186 187 *pSemaphore = vk_semaphore_to_handle(semaphore); 188 189 return VK_SUCCESS; 190} 191 192void 193vk_semaphore_reset_temporary(struct vk_device *device, 194 struct vk_semaphore *semaphore) 195{ 196 if (semaphore->temporary == NULL) 197 return; 198 199 vk_sync_destroy(device, semaphore->temporary); 200 semaphore->temporary = NULL; 201} 202 203VKAPI_ATTR void VKAPI_CALL 204vk_common_DestroySemaphore(VkDevice _device, 205 VkSemaphore _semaphore, 206 const VkAllocationCallbacks *pAllocator) 207{ 208 VK_FROM_HANDLE(vk_device, device, _device); 209 VK_FROM_HANDLE(vk_semaphore, semaphore, _semaphore); 210 211 if (semaphore == NULL) 212 return; 213 214 vk_semaphore_reset_temporary(device, semaphore); 215 vk_sync_finish(device, &semaphore->permanent); 216 217 vk_object_free(device, pAllocator, semaphore); 218} 219 220VKAPI_ATTR void VKAPI_CALL 221vk_common_GetPhysicalDeviceExternalSemaphoreProperties( 222 VkPhysicalDevice physicalDevice, 223 const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, 224 VkExternalSemaphoreProperties *pExternalSemaphoreProperties) 225{ 226 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); 227 228 assert(pExternalSemaphoreInfo->sType == 229 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO); 230 const VkExternalSemaphoreHandleTypeFlagBits handle_type = 231 pExternalSemaphoreInfo->handleType; 232 233 const VkSemaphoreType semaphore_type = 234 get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL); 235 236 const struct vk_sync_type *sync_type = 237 get_semaphore_sync_type(pdevice, semaphore_type, handle_type); 238 if (sync_type == NULL) { 239 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0; 240 pExternalSemaphoreProperties->compatibleHandleTypes = 0; 241 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0; 242 return; 243 } 244 245 VkExternalSemaphoreHandleTypeFlagBits import = 246 vk_sync_semaphore_import_types(sync_type, semaphore_type); 247 VkExternalSemaphoreHandleTypeFlagBits export = 248 vk_sync_semaphore_export_types(sync_type, semaphore_type); 249 250 if (handle_type != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) { 251 const struct vk_sync_type *opaque_sync_type = 252 get_semaphore_sync_type(pdevice, semaphore_type, 253 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT); 254 255 /* If we're a different vk_sync_type than the one selected when only 256 * OPAQUE_FD is set, then we can't import/export OPAQUE_FD. Put 257 * differently, there can only be one OPAQUE_FD sync type. 258 */ 259 if (sync_type != opaque_sync_type) { 260 import &= ~VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 261 export &= ~VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; 262 } 263 } 264 265 VkExternalSemaphoreHandleTypeFlags compatible = import & export; 266 VkExternalSemaphoreFeatureFlags features = 0; 267 if (handle_type & export) 268 features |= VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT; 269 if (handle_type & import) 270 features |= VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT; 271 272 pExternalSemaphoreProperties->exportFromImportedHandleTypes = export; 273 pExternalSemaphoreProperties->compatibleHandleTypes = compatible; 274 pExternalSemaphoreProperties->externalSemaphoreFeatures = features; 275} 276 277VKAPI_ATTR VkResult VKAPI_CALL 278vk_common_GetSemaphoreCounterValue(VkDevice _device, 279 VkSemaphore _semaphore, 280 uint64_t *pValue) 281{ 282 VK_FROM_HANDLE(vk_device, device, _device); 283 VK_FROM_HANDLE(vk_semaphore, semaphore, _semaphore); 284 285 if (vk_device_is_lost(device)) 286 return VK_ERROR_DEVICE_LOST; 287 288 struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore); 289 return vk_sync_get_value(device, sync, pValue); 290} 291 292VKAPI_ATTR VkResult VKAPI_CALL 293vk_common_WaitSemaphores(VkDevice _device, 294 const VkSemaphoreWaitInfo *pWaitInfo, 295 uint64_t timeout) 296{ 297 VK_FROM_HANDLE(vk_device, device, _device); 298 299 if (vk_device_is_lost(device)) 300 return VK_ERROR_DEVICE_LOST; 301 302 if (pWaitInfo->semaphoreCount == 0) 303 return VK_SUCCESS; 304 305 uint64_t abs_timeout_ns = os_time_get_absolute_timeout(timeout); 306 307 const uint32_t wait_count = pWaitInfo->semaphoreCount; 308 STACK_ARRAY(struct vk_sync_wait, waits, pWaitInfo->semaphoreCount); 309 310 for (uint32_t i = 0; i < wait_count; i++) { 311 VK_FROM_HANDLE(vk_semaphore, semaphore, pWaitInfo->pSemaphores[i]); 312 assert(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE); 313 314 waits[i] = (struct vk_sync_wait) { 315 .sync = vk_semaphore_get_active_sync(semaphore), 316 .stage_mask = ~(VkPipelineStageFlags2)0, 317 .wait_value = pWaitInfo->pValues[i], 318 }; 319 } 320 321 enum vk_sync_wait_flags wait_flags = VK_SYNC_WAIT_COMPLETE; 322 if (pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT) 323 wait_flags |= VK_SYNC_WAIT_ANY; 324 325 VkResult result = vk_sync_wait_many(device, wait_count, waits, 326 wait_flags, abs_timeout_ns); 327 328 STACK_ARRAY_FINISH(waits); 329 330 VkResult device_status = vk_device_check_status(device); 331 if (device_status != VK_SUCCESS) 332 return device_status; 333 334 return result; 335} 336 337VKAPI_ATTR VkResult VKAPI_CALL 338vk_common_SignalSemaphore(VkDevice _device, 339 const VkSemaphoreSignalInfo *pSignalInfo) 340{ 341 VK_FROM_HANDLE(vk_device, device, _device); 342 VK_FROM_HANDLE(vk_semaphore, semaphore, pSignalInfo->semaphore); 343 struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore); 344 VkResult result; 345 346 /* From the Vulkan 1.2.194 spec: 347 * 348 * UID-VkSemaphoreSignalInfo-semaphore-03257 349 * 350 * "semaphore must have been created with a VkSemaphoreType of 351 * VK_SEMAPHORE_TYPE_TIMELINE." 352 */ 353 assert(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE); 354 355 /* From the Vulkan 1.2.194 spec: 356 * 357 * VUID-VkSemaphoreSignalInfo-value-03258 358 * 359 * "value must have a value greater than the current value of the 360 * semaphore" 361 * 362 * Since 0 is the lowest possible semaphore timeline value, we can assert 363 * that a non-zero signal value is provided. 364 */ 365 if (unlikely(pSignalInfo->value == 0)) { 366 return vk_device_set_lost(device, 367 "Tried to signal a timeline with value 0"); 368 } 369 370 result = vk_sync_signal(device, sync, pSignalInfo->value); 371 if (unlikely(result != VK_SUCCESS)) 372 return result; 373 374 if (device->submit_mode == VK_QUEUE_SUBMIT_MODE_DEFERRED) { 375 result = vk_device_flush(device); 376 if (unlikely(result != VK_SUCCESS)) 377 return result; 378 } 379 380 return VK_SUCCESS; 381} 382 383#ifndef _WIN32 384 385VKAPI_ATTR VkResult VKAPI_CALL 386vk_common_ImportSemaphoreFdKHR(VkDevice _device, 387 const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo) 388{ 389 VK_FROM_HANDLE(vk_device, device, _device); 390 VK_FROM_HANDLE(vk_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore); 391 392 assert(pImportSemaphoreFdInfo->sType == 393 VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR); 394 395 const int fd = pImportSemaphoreFdInfo->fd; 396 const VkExternalSemaphoreHandleTypeFlagBits handle_type = 397 pImportSemaphoreFdInfo->handleType; 398 399 struct vk_sync *temporary = NULL, *sync; 400 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) { 401 /* From the Vulkan 1.2.194 spec: 402 * 403 * VUID-VkImportSemaphoreFdInfoKHR-flags-03323 404 * 405 * "If flags contains VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, the 406 * VkSemaphoreTypeCreateInfo::semaphoreType field of the semaphore 407 * from which handle or name was exported must not be 408 * VK_SEMAPHORE_TYPE_TIMELINE" 409 */ 410 if (unlikely(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE)) { 411 return vk_errorf(device, VK_ERROR_UNKNOWN, 412 "Cannot temporarily import into a timeline " 413 "semaphore"); 414 } 415 416 const struct vk_sync_type *sync_type = 417 get_semaphore_sync_type(device->physical, semaphore->type, handle_type); 418 419 VkResult result = vk_sync_create(device, sync_type, 0 /* flags */, 420 0 /* initial_value */, &temporary); 421 if (result != VK_SUCCESS) 422 return result; 423 424 sync = temporary; 425 } else { 426 sync = &semaphore->permanent; 427 } 428 assert(handle_type & 429 vk_sync_semaphore_handle_types(sync->type, semaphore->type)); 430 431 VkResult result; 432 switch (pImportSemaphoreFdInfo->handleType) { 433 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: 434 result = vk_sync_import_opaque_fd(device, sync, fd); 435 break; 436 437 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: 438 result = vk_sync_import_sync_file(device, sync, fd); 439 break; 440 441 default: 442 result = vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE); 443 } 444 445 if (result != VK_SUCCESS) { 446 if (temporary != NULL) 447 vk_sync_destroy(device, temporary); 448 return result; 449 } 450 451 /* From the Vulkan 1.2.194 spec: 452 * 453 * "Importing a semaphore payload from a file descriptor transfers 454 * ownership of the file descriptor from the application to the Vulkan 455 * implementation. The application must not perform any operations on 456 * the file descriptor after a successful import." 457 * 458 * If the import fails, we leave the file descriptor open. 459 */ 460 if (fd != -1) 461 close(fd); 462 463 /* From a spec correctness point of view, we could probably replace the 464 * semaphore's temporary payload with the new vk_sync at the top. However, 465 * we choose to be nice to applications and only replace the semaphore if 466 * the import succeeded. 467 */ 468 if (temporary) { 469 vk_semaphore_reset_temporary(device, semaphore); 470 semaphore->temporary = temporary; 471 } 472 473 return VK_SUCCESS; 474} 475 476VKAPI_ATTR VkResult VKAPI_CALL 477vk_common_GetSemaphoreFdKHR(VkDevice _device, 478 const VkSemaphoreGetFdInfoKHR *pGetFdInfo, 479 int *pFd) 480{ 481 VK_FROM_HANDLE(vk_device, device, _device); 482 VK_FROM_HANDLE(vk_semaphore, semaphore, pGetFdInfo->semaphore); 483 484 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR); 485 486 struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore); 487 488 VkResult result; 489 switch (pGetFdInfo->handleType) { 490 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT: 491 result = vk_sync_export_opaque_fd(device, sync, pFd); 492 if (result != VK_SUCCESS) 493 return result; 494 break; 495 496 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT: 497 /* From the Vulkan 1.2.194 spec: 498 * 499 * VUID-VkSemaphoreGetFdInfoKHR-handleType-03253 500 * 501 * "If handleType refers to a handle type with copy payload 502 * transference semantics, semaphore must have been created with a 503 * VkSemaphoreType of VK_SEMAPHORE_TYPE_BINARY." 504 */ 505 if (unlikely(semaphore->type != VK_SEMAPHORE_TYPE_BINARY)) { 506 return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE, 507 "Cannot export a timeline semaphore as SYNC_FD"); 508 } 509 510 /* From the Vulkan 1.2.194 spec: 511 * VUID-VkSemaphoreGetFdInfoKHR-handleType-03254 512 * 513 * "If handleType refers to a handle type with copy payload 514 * transference semantics, semaphore must have an associated 515 * semaphore signal operation that has been submitted for execution 516 * and any semaphore signal operations on which it depends (if any) 517 * must have also been submitted for execution." 518 * 519 * If we have real timelines, it's possible that the time point doesn't 520 * exist yet and is waiting for one of our submit threads to trigger. 521 * However, thanks to the above bit of spec text, that wait should never 522 * block for long. 523 */ 524 if (vk_device_supports_threaded_submit(device)) { 525 result = vk_sync_wait(device, sync, 0, 526 VK_SYNC_WAIT_PENDING, 527 UINT64_MAX); 528 if (unlikely(result != VK_SUCCESS)) 529 return result; 530 } 531 532 result = vk_sync_export_sync_file(device, sync, pFd); 533 if (unlikely(result != VK_SUCCESS)) 534 return result; 535 536 /* From the Vulkan 1.2.194 spec: 537 * 538 * "Export operations have the same transference as the specified 539 * handle type’s import operations. Additionally, exporting a 540 * semaphore payload to a handle with copy transference has the same 541 * side effects on the source semaphore’s payload as executing a 542 * semaphore wait operation." 543 * 544 * In other words, exporting a sync file also resets the semaphore. We 545 * only care about this for the permanent payload because the temporary 546 * payload will be destroyed below. 547 */ 548 if (sync == &semaphore->permanent) { 549 result = vk_sync_reset(device, sync); 550 if (unlikely(result != VK_SUCCESS)) 551 return result; 552 } 553 break; 554 555 default: 556 unreachable("Invalid semaphore export handle type"); 557 } 558 559 /* From the Vulkan 1.2.194 spec: 560 * 561 * "Export operations have the same transference as the specified 562 * handle type’s import operations. [...] If the semaphore was using 563 * a temporarily imported payload, the semaphore’s prior permanent 564 * payload will be restored." 565 */ 566 vk_semaphore_reset_temporary(device, semaphore); 567 568 return VK_SUCCESS; 569} 570 571#endif /* !defined(_WIN32) */ 572