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 #include "util/perf/cpu_trace.h"
28
29 #ifdef _WIN32
30 #include <windows.h>
31 #else
32 #include <unistd.h>
33 #endif
34
35 #include "vk_common_entrypoints.h"
36 #include "vk_device.h"
37 #include "vk_log.h"
38 #include "vk_physical_device.h"
39 #include "vk_util.h"
40
41 static VkExternalSemaphoreHandleTypeFlags
vk_sync_semaphore_import_types(const struct vk_sync_type * type,VkSemaphoreType semaphore_type)42 vk_sync_semaphore_import_types(const struct vk_sync_type *type,
43 VkSemaphoreType semaphore_type)
44 {
45 VkExternalSemaphoreHandleTypeFlags handle_types = 0;
46
47 if (type->import_opaque_fd)
48 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
49
50 if (type->export_sync_file && semaphore_type == VK_SEMAPHORE_TYPE_BINARY)
51 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
52
53 if (type->import_win32_handle) {
54 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT;
55 if (type->features & VK_SYNC_FEATURE_TIMELINE)
56 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT;
57 }
58
59 return handle_types;
60 }
61
62 static VkExternalSemaphoreHandleTypeFlags
vk_sync_semaphore_export_types(const struct vk_sync_type * type,VkSemaphoreType semaphore_type)63 vk_sync_semaphore_export_types(const struct vk_sync_type *type,
64 VkSemaphoreType semaphore_type)
65 {
66 VkExternalSemaphoreHandleTypeFlags handle_types = 0;
67
68 if (type->export_opaque_fd)
69 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
70
71 if (type->export_sync_file && semaphore_type == VK_SEMAPHORE_TYPE_BINARY)
72 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
73
74 if (type->export_win32_handle) {
75 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT;
76 if (type->features & VK_SYNC_FEATURE_TIMELINE)
77 handle_types |= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT;
78 }
79
80 return handle_types;
81 }
82
83 static VkExternalSemaphoreHandleTypeFlags
vk_sync_semaphore_handle_types(const struct vk_sync_type * type,VkSemaphoreType semaphore_type)84 vk_sync_semaphore_handle_types(const struct vk_sync_type *type,
85 VkSemaphoreType semaphore_type)
86 {
87 return vk_sync_semaphore_export_types(type, semaphore_type) &
88 vk_sync_semaphore_import_types(type, semaphore_type);
89 }
90
91 static const struct vk_sync_type *
get_semaphore_sync_type(struct vk_physical_device * pdevice,VkSemaphoreType semaphore_type,VkExternalSemaphoreHandleTypeFlags handle_types)92 get_semaphore_sync_type(struct vk_physical_device *pdevice,
93 VkSemaphoreType semaphore_type,
94 VkExternalSemaphoreHandleTypeFlags handle_types)
95 {
96 assert(semaphore_type == VK_SEMAPHORE_TYPE_BINARY ||
97 semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE);
98
99 enum vk_sync_features req_features = VK_SYNC_FEATURE_GPU_WAIT;
100 if (semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE) {
101 req_features |= VK_SYNC_FEATURE_TIMELINE |
102 VK_SYNC_FEATURE_CPU_WAIT;
103 } else {
104 req_features |= VK_SYNC_FEATURE_BINARY;
105 }
106
107 for (const struct vk_sync_type *const *t =
108 pdevice->supported_sync_types; *t; t++) {
109 if (req_features & ~(*t)->features)
110 continue;
111
112 if (handle_types & ~vk_sync_semaphore_handle_types(*t, semaphore_type))
113 continue;
114
115 return *t;
116 }
117
118 return NULL;
119 }
120
121 static VkSemaphoreType
get_semaphore_type(const void * pNext,uint64_t * initial_value)122 get_semaphore_type(const void *pNext, uint64_t *initial_value)
123 {
124 const VkSemaphoreTypeCreateInfo *type_info =
125 vk_find_struct_const(pNext, SEMAPHORE_TYPE_CREATE_INFO);
126
127 if (!type_info)
128 return VK_SEMAPHORE_TYPE_BINARY;
129
130 if (initial_value)
131 *initial_value = type_info->initialValue;
132 return type_info->semaphoreType;
133 }
134
135 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_CreateSemaphore(VkDevice _device,const VkSemaphoreCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkSemaphore * pSemaphore)136 vk_common_CreateSemaphore(VkDevice _device,
137 const VkSemaphoreCreateInfo *pCreateInfo,
138 const VkAllocationCallbacks *pAllocator,
139 VkSemaphore *pSemaphore)
140 {
141 VK_FROM_HANDLE(vk_device, device, _device);
142 struct vk_semaphore *semaphore;
143
144 assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO);
145
146 uint64_t initial_value = 0;
147 const VkSemaphoreType semaphore_type =
148 get_semaphore_type(pCreateInfo->pNext, &initial_value);
149
150 if (semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE)
151 assert(device->timeline_mode != VK_DEVICE_TIMELINE_MODE_NONE);
152
153 const VkExportSemaphoreCreateInfo *export =
154 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_CREATE_INFO);
155 VkExternalSemaphoreHandleTypeFlags handle_types =
156 export ? export->handleTypes : 0;
157
158 const struct vk_sync_type *sync_type =
159 get_semaphore_sync_type(device->physical, semaphore_type, handle_types);
160 if (sync_type == NULL) {
161 /* We should always be able to get a semaphore type for internal */
162 assert(get_semaphore_sync_type(device->physical, semaphore_type, 0) != NULL);
163 return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE,
164 "Combination of external handle types is unsupported "
165 "for VkSemaphore creation.");
166 }
167
168 /* If the timeline mode is ASSISTED, then any permanent binary semaphore
169 * types need to be able to support move. We don't require this for
170 * temporary unless that temporary is also used as a semaphore signal
171 * operation which is much trickier to assert early.
172 */
173 if (semaphore_type == VK_SEMAPHORE_TYPE_BINARY &&
174 vk_device_supports_threaded_submit(device))
175 assert(sync_type->move);
176
177 /* Allocate a vk_semaphore + vk_sync implementation. Because the permanent
178 * field of vk_semaphore is the base field of the vk_sync implementation,
179 * we can make the 2 structures overlap.
180 */
181 size_t size = offsetof(struct vk_semaphore, permanent) + sync_type->size;
182 semaphore = vk_object_zalloc(device, pAllocator, size,
183 VK_OBJECT_TYPE_SEMAPHORE);
184 if (semaphore == NULL)
185 return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
186
187 semaphore->type = semaphore_type;
188
189 enum vk_sync_flags sync_flags = 0;
190 if (semaphore_type == VK_SEMAPHORE_TYPE_TIMELINE)
191 sync_flags |= VK_SYNC_IS_TIMELINE;
192 if (handle_types)
193 sync_flags |= VK_SYNC_IS_SHAREABLE;
194
195 VkResult result = vk_sync_init(device, &semaphore->permanent,
196 sync_type, sync_flags, initial_value);
197 if (result != VK_SUCCESS) {
198 vk_object_free(device, pAllocator, semaphore);
199 return result;
200 }
201
202 #ifdef _WIN32
203 const VkExportSemaphoreWin32HandleInfoKHR *export_win32 =
204 vk_find_struct_const(pCreateInfo->pNext, EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR);
205 if (export_win32) {
206 result = vk_sync_set_win32_export_params(device, &semaphore->permanent, export_win32->pAttributes,
207 export_win32->dwAccess, export_win32->name);
208 if (result != VK_SUCCESS) {
209 vk_sync_finish(device, &semaphore->permanent);
210 vk_object_free(device, pAllocator, semaphore);
211 return result;
212 }
213 }
214 #endif
215
216 *pSemaphore = vk_semaphore_to_handle(semaphore);
217
218 return VK_SUCCESS;
219 }
220
221 void
vk_semaphore_reset_temporary(struct vk_device * device,struct vk_semaphore * semaphore)222 vk_semaphore_reset_temporary(struct vk_device *device,
223 struct vk_semaphore *semaphore)
224 {
225 if (semaphore->temporary == NULL)
226 return;
227
228 vk_sync_destroy(device, semaphore->temporary);
229 semaphore->temporary = NULL;
230 }
231
232 VKAPI_ATTR void VKAPI_CALL
vk_common_DestroySemaphore(VkDevice _device,VkSemaphore _semaphore,const VkAllocationCallbacks * pAllocator)233 vk_common_DestroySemaphore(VkDevice _device,
234 VkSemaphore _semaphore,
235 const VkAllocationCallbacks *pAllocator)
236 {
237 VK_FROM_HANDLE(vk_device, device, _device);
238 VK_FROM_HANDLE(vk_semaphore, semaphore, _semaphore);
239
240 if (semaphore == NULL)
241 return;
242
243 vk_semaphore_reset_temporary(device, semaphore);
244 vk_sync_finish(device, &semaphore->permanent);
245
246 vk_object_free(device, pAllocator, semaphore);
247 }
248
249 VKAPI_ATTR void VKAPI_CALL
vk_common_GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceExternalSemaphoreInfo * pExternalSemaphoreInfo,VkExternalSemaphoreProperties * pExternalSemaphoreProperties)250 vk_common_GetPhysicalDeviceExternalSemaphoreProperties(
251 VkPhysicalDevice physicalDevice,
252 const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo,
253 VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
254 {
255 VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice);
256
257 assert(pExternalSemaphoreInfo->sType ==
258 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO);
259 const VkExternalSemaphoreHandleTypeFlagBits handle_type =
260 pExternalSemaphoreInfo->handleType;
261
262 const VkSemaphoreType semaphore_type =
263 get_semaphore_type(pExternalSemaphoreInfo->pNext, NULL);
264
265 const struct vk_sync_type *sync_type =
266 get_semaphore_sync_type(pdevice, semaphore_type, handle_type);
267 if (sync_type == NULL) {
268 pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0;
269 pExternalSemaphoreProperties->compatibleHandleTypes = 0;
270 pExternalSemaphoreProperties->externalSemaphoreFeatures = 0;
271 return;
272 }
273
274 VkExternalSemaphoreHandleTypeFlagBits import =
275 vk_sync_semaphore_import_types(sync_type, semaphore_type);
276 VkExternalSemaphoreHandleTypeFlagBits export =
277 vk_sync_semaphore_export_types(sync_type, semaphore_type);
278
279 VkExternalSemaphoreHandleTypeFlagBits opaque_types[] = {
280 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT,
281 VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT,
282 };
283 for (uint32_t i = 0; i < ARRAY_SIZE(opaque_types); ++i) {
284 if (handle_type != opaque_types[i]) {
285 const struct vk_sync_type *opaque_sync_type =
286 get_semaphore_sync_type(pdevice, semaphore_type, opaque_types[i]);
287
288 /* If we're a different vk_sync_type than the one selected when only
289 * an opaque type is set, then we can't import/export that opaque type. Put
290 * differently, there can only be one OPAQUE_FD/WIN32_HANDLE sync type.
291 */
292 if (sync_type != opaque_sync_type) {
293 import &= ~opaque_types[i];
294 export &= ~opaque_types[i];
295 }
296 }
297 }
298
299 VkExternalSemaphoreHandleTypeFlags compatible = import & export;
300 VkExternalSemaphoreFeatureFlags features = 0;
301 if (handle_type & export)
302 features |= VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT;
303 if (handle_type & import)
304 features |= VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT;
305
306 pExternalSemaphoreProperties->exportFromImportedHandleTypes = export;
307 pExternalSemaphoreProperties->compatibleHandleTypes = compatible;
308 pExternalSemaphoreProperties->externalSemaphoreFeatures = features;
309 }
310
311 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_GetSemaphoreCounterValue(VkDevice _device,VkSemaphore _semaphore,uint64_t * pValue)312 vk_common_GetSemaphoreCounterValue(VkDevice _device,
313 VkSemaphore _semaphore,
314 uint64_t *pValue)
315 {
316 VK_FROM_HANDLE(vk_device, device, _device);
317 VK_FROM_HANDLE(vk_semaphore, semaphore, _semaphore);
318
319 if (vk_device_is_lost(device))
320 return VK_ERROR_DEVICE_LOST;
321
322 struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore);
323 return vk_sync_get_value(device, sync, pValue);
324 }
325
326 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_WaitSemaphores(VkDevice _device,const VkSemaphoreWaitInfo * pWaitInfo,uint64_t timeout)327 vk_common_WaitSemaphores(VkDevice _device,
328 const VkSemaphoreWaitInfo *pWaitInfo,
329 uint64_t timeout)
330 {
331 MESA_TRACE_FUNC();
332
333 VK_FROM_HANDLE(vk_device, device, _device);
334
335 if (vk_device_is_lost(device))
336 return VK_ERROR_DEVICE_LOST;
337
338 if (pWaitInfo->semaphoreCount == 0)
339 return VK_SUCCESS;
340
341 uint64_t abs_timeout_ns = os_time_get_absolute_timeout(timeout);
342
343 const uint32_t wait_count = pWaitInfo->semaphoreCount;
344 STACK_ARRAY(struct vk_sync_wait, waits, pWaitInfo->semaphoreCount);
345
346 for (uint32_t i = 0; i < wait_count; i++) {
347 VK_FROM_HANDLE(vk_semaphore, semaphore, pWaitInfo->pSemaphores[i]);
348 assert(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE);
349
350 waits[i] = (struct vk_sync_wait) {
351 .sync = vk_semaphore_get_active_sync(semaphore),
352 .stage_mask = ~(VkPipelineStageFlags2)0,
353 .wait_value = pWaitInfo->pValues[i],
354 };
355 }
356
357 enum vk_sync_wait_flags wait_flags = VK_SYNC_WAIT_COMPLETE;
358 if (pWaitInfo->flags & VK_SEMAPHORE_WAIT_ANY_BIT)
359 wait_flags |= VK_SYNC_WAIT_ANY;
360
361 VkResult result = vk_sync_wait_many(device, wait_count, waits,
362 wait_flags, abs_timeout_ns);
363
364 STACK_ARRAY_FINISH(waits);
365
366 VkResult device_status = vk_device_check_status(device);
367 if (device_status != VK_SUCCESS)
368 return device_status;
369
370 return result;
371 }
372
373 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_SignalSemaphore(VkDevice _device,const VkSemaphoreSignalInfo * pSignalInfo)374 vk_common_SignalSemaphore(VkDevice _device,
375 const VkSemaphoreSignalInfo *pSignalInfo)
376 {
377 VK_FROM_HANDLE(vk_device, device, _device);
378 VK_FROM_HANDLE(vk_semaphore, semaphore, pSignalInfo->semaphore);
379 struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore);
380 VkResult result;
381
382 /* From the Vulkan 1.2.194 spec:
383 *
384 * UID-VkSemaphoreSignalInfo-semaphore-03257
385 *
386 * "semaphore must have been created with a VkSemaphoreType of
387 * VK_SEMAPHORE_TYPE_TIMELINE."
388 */
389 assert(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE);
390
391 /* From the Vulkan 1.2.194 spec:
392 *
393 * VUID-VkSemaphoreSignalInfo-value-03258
394 *
395 * "value must have a value greater than the current value of the
396 * semaphore"
397 *
398 * Since 0 is the lowest possible semaphore timeline value, we can assert
399 * that a non-zero signal value is provided.
400 */
401 if (unlikely(pSignalInfo->value == 0)) {
402 return vk_device_set_lost(device,
403 "Tried to signal a timeline with value 0");
404 }
405
406 result = vk_sync_signal(device, sync, pSignalInfo->value);
407 if (unlikely(result != VK_SUCCESS))
408 return result;
409
410 if (device->submit_mode == VK_QUEUE_SUBMIT_MODE_DEFERRED) {
411 result = vk_device_flush(device);
412 if (unlikely(result != VK_SUCCESS))
413 return result;
414 }
415
416 return VK_SUCCESS;
417 }
418
419 #ifdef _WIN32
420
421 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_ImportSemaphoreWin32HandleKHR(VkDevice _device,const VkImportSemaphoreWin32HandleInfoKHR * pImportSemaphoreWin32HandleInfo)422 vk_common_ImportSemaphoreWin32HandleKHR(VkDevice _device,
423 const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo)
424 {
425 VK_FROM_HANDLE(vk_device, device, _device);
426 VK_FROM_HANDLE(vk_semaphore, semaphore, pImportSemaphoreWin32HandleInfo->semaphore);
427
428 assert(pImportSemaphoreWin32HandleInfo->sType ==
429 VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR);
430
431 const HANDLE handle = pImportSemaphoreWin32HandleInfo->handle;
432 const wchar_t *name = pImportSemaphoreWin32HandleInfo->name;
433 const VkExternalSemaphoreHandleTypeFlagBits handle_type =
434 pImportSemaphoreWin32HandleInfo->handleType;
435
436 struct vk_sync *temporary = NULL, *sync;
437 if (pImportSemaphoreWin32HandleInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
438 /* From the Vulkan 1.2.194 spec:
439 *
440 * VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-03322
441 *
442 * "If flags contains VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, the
443 * VkSemaphoreTypeCreateInfo::semaphoreType field of the semaphore
444 * from which handle or name was exported must not be
445 * VK_SEMAPHORE_TYPE_TIMELINE"
446 */
447 if (unlikely(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE)) {
448 return vk_errorf(device, VK_ERROR_UNKNOWN,
449 "Cannot temporarily import into a timeline "
450 "semaphore");
451 }
452
453 const struct vk_sync_type *sync_type =
454 get_semaphore_sync_type(device->physical, semaphore->type, handle_type);
455
456 VkResult result = vk_sync_create(device, sync_type, 0 /* flags */,
457 0 /* initial_value */, &temporary);
458 if (result != VK_SUCCESS)
459 return result;
460
461 sync = temporary;
462 } else {
463 sync = &semaphore->permanent;
464 }
465 assert(handle_type &
466 vk_sync_semaphore_handle_types(sync->type, semaphore->type));
467
468 VkResult result;
469 switch (pImportSemaphoreWin32HandleInfo->handleType) {
470 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
471 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT:
472 result = vk_sync_import_win32_handle(device, sync, handle, name);
473 break;
474
475 default:
476 result = vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE);
477 }
478
479 if (result != VK_SUCCESS) {
480 if (temporary != NULL)
481 vk_sync_destroy(device, temporary);
482 return result;
483 }
484
485 /* From a spec correctness point of view, we could probably replace the
486 * semaphore's temporary payload with the new vk_sync at the top. However,
487 * we choose to be nice to applications and only replace the semaphore if
488 * the import succeeded.
489 */
490 if (temporary) {
491 vk_semaphore_reset_temporary(device, semaphore);
492 semaphore->temporary = temporary;
493 }
494
495 return VK_SUCCESS;
496 }
497
498 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_GetSemaphoreWin32HandleKHR(VkDevice _device,const VkSemaphoreGetWin32HandleInfoKHR * pGetWin32HandleInfo,HANDLE * pHandle)499 vk_common_GetSemaphoreWin32HandleKHR(VkDevice _device,
500 const VkSemaphoreGetWin32HandleInfoKHR *pGetWin32HandleInfo,
501 HANDLE *pHandle)
502 {
503 VK_FROM_HANDLE(vk_device, device, _device);
504 VK_FROM_HANDLE(vk_semaphore, semaphore, pGetWin32HandleInfo->semaphore);
505
506 assert(pGetWin32HandleInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR);
507
508 struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore);
509
510 VkResult result;
511 switch (pGetWin32HandleInfo->handleType) {
512 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT:
513 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT:
514 result = vk_sync_export_win32_handle(device, sync, pHandle);
515 if (result != VK_SUCCESS)
516 return result;
517 break;
518
519 default:
520 unreachable("Invalid semaphore export handle type");
521 }
522
523 /* From the Vulkan 1.2.194 spec:
524 *
525 * "Export operations have the same transference as the specified
526 * handle type’s import operations. [...] If the semaphore was using
527 * a temporarily imported payload, the semaphore’s prior permanent
528 * payload will be restored."
529 */
530 vk_semaphore_reset_temporary(device, semaphore);
531
532 return VK_SUCCESS;
533 }
534
535 #else
536
537 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_ImportSemaphoreFdKHR(VkDevice _device,const VkImportSemaphoreFdInfoKHR * pImportSemaphoreFdInfo)538 vk_common_ImportSemaphoreFdKHR(VkDevice _device,
539 const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)
540 {
541 VK_FROM_HANDLE(vk_device, device, _device);
542 VK_FROM_HANDLE(vk_semaphore, semaphore, pImportSemaphoreFdInfo->semaphore);
543
544 assert(pImportSemaphoreFdInfo->sType ==
545 VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR);
546
547 const int fd = pImportSemaphoreFdInfo->fd;
548 const VkExternalSemaphoreHandleTypeFlagBits handle_type =
549 pImportSemaphoreFdInfo->handleType;
550
551 struct vk_sync *temporary = NULL, *sync;
552 if (pImportSemaphoreFdInfo->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT) {
553 /* From the Vulkan 1.2.194 spec:
554 *
555 * VUID-VkImportSemaphoreFdInfoKHR-flags-03323
556 *
557 * "If flags contains VK_SEMAPHORE_IMPORT_TEMPORARY_BIT, the
558 * VkSemaphoreTypeCreateInfo::semaphoreType field of the semaphore
559 * from which handle or name was exported must not be
560 * VK_SEMAPHORE_TYPE_TIMELINE"
561 */
562 if (unlikely(semaphore->type == VK_SEMAPHORE_TYPE_TIMELINE)) {
563 return vk_errorf(device, VK_ERROR_UNKNOWN,
564 "Cannot temporarily import into a timeline "
565 "semaphore");
566 }
567
568 const struct vk_sync_type *sync_type =
569 get_semaphore_sync_type(device->physical, semaphore->type, handle_type);
570
571 VkResult result = vk_sync_create(device, sync_type, 0 /* flags */,
572 0 /* initial_value */, &temporary);
573 if (result != VK_SUCCESS)
574 return result;
575
576 sync = temporary;
577 } else {
578 sync = &semaphore->permanent;
579 }
580 assert(handle_type &
581 vk_sync_semaphore_handle_types(sync->type, semaphore->type));
582
583 VkResult result;
584 switch (pImportSemaphoreFdInfo->handleType) {
585 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
586 result = vk_sync_import_opaque_fd(device, sync, fd);
587 break;
588
589 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
590 result = vk_sync_import_sync_file(device, sync, fd);
591 break;
592
593 default:
594 result = vk_error(semaphore, VK_ERROR_INVALID_EXTERNAL_HANDLE);
595 }
596
597 if (result != VK_SUCCESS) {
598 if (temporary != NULL)
599 vk_sync_destroy(device, temporary);
600 return result;
601 }
602
603 /* From the Vulkan 1.2.194 spec:
604 *
605 * "Importing a semaphore payload from a file descriptor transfers
606 * ownership of the file descriptor from the application to the Vulkan
607 * implementation. The application must not perform any operations on
608 * the file descriptor after a successful import."
609 *
610 * If the import fails, we leave the file descriptor open.
611 */
612 if (fd != -1)
613 close(fd);
614
615 /* From a spec correctness point of view, we could probably replace the
616 * semaphore's temporary payload with the new vk_sync at the top. However,
617 * we choose to be nice to applications and only replace the semaphore if
618 * the import succeeded.
619 */
620 if (temporary) {
621 vk_semaphore_reset_temporary(device, semaphore);
622 semaphore->temporary = temporary;
623 }
624
625 return VK_SUCCESS;
626 }
627
628 VKAPI_ATTR VkResult VKAPI_CALL
vk_common_GetSemaphoreFdKHR(VkDevice _device,const VkSemaphoreGetFdInfoKHR * pGetFdInfo,int * pFd)629 vk_common_GetSemaphoreFdKHR(VkDevice _device,
630 const VkSemaphoreGetFdInfoKHR *pGetFdInfo,
631 int *pFd)
632 {
633 VK_FROM_HANDLE(vk_device, device, _device);
634 VK_FROM_HANDLE(vk_semaphore, semaphore, pGetFdInfo->semaphore);
635
636 assert(pGetFdInfo->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR);
637
638 struct vk_sync *sync = vk_semaphore_get_active_sync(semaphore);
639
640 VkResult result;
641 switch (pGetFdInfo->handleType) {
642 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT:
643 result = vk_sync_export_opaque_fd(device, sync, pFd);
644 if (result != VK_SUCCESS)
645 return result;
646 break;
647
648 case VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT:
649 /* From the Vulkan 1.2.194 spec:
650 *
651 * VUID-VkSemaphoreGetFdInfoKHR-handleType-03253
652 *
653 * "If handleType refers to a handle type with copy payload
654 * transference semantics, semaphore must have been created with a
655 * VkSemaphoreType of VK_SEMAPHORE_TYPE_BINARY."
656 */
657 if (unlikely(semaphore->type != VK_SEMAPHORE_TYPE_BINARY)) {
658 return vk_errorf(device, VK_ERROR_INVALID_EXTERNAL_HANDLE,
659 "Cannot export a timeline semaphore as SYNC_FD");
660 }
661
662 /* From the Vulkan 1.2.194 spec:
663 * VUID-VkSemaphoreGetFdInfoKHR-handleType-03254
664 *
665 * "If handleType refers to a handle type with copy payload
666 * transference semantics, semaphore must have an associated
667 * semaphore signal operation that has been submitted for execution
668 * and any semaphore signal operations on which it depends (if any)
669 * must have also been submitted for execution."
670 *
671 * If we have real timelines, it's possible that the time point doesn't
672 * exist yet and is waiting for one of our submit threads to trigger.
673 * However, thanks to the above bit of spec text, that wait should never
674 * block for long.
675 */
676 if (vk_device_supports_threaded_submit(device)) {
677 result = vk_sync_wait(device, sync, 0,
678 VK_SYNC_WAIT_PENDING,
679 UINT64_MAX);
680 if (unlikely(result != VK_SUCCESS))
681 return result;
682 }
683
684 result = vk_sync_export_sync_file(device, sync, pFd);
685 if (unlikely(result != VK_SUCCESS))
686 return result;
687
688 /* From the Vulkan 1.2.194 spec:
689 *
690 * "Export operations have the same transference as the specified
691 * handle type’s import operations. Additionally, exporting a
692 * semaphore payload to a handle with copy transference has the same
693 * side effects on the source semaphore’s payload as executing a
694 * semaphore wait operation."
695 *
696 * In other words, exporting a sync file also resets the semaphore. We
697 * only care about this for the permanent payload because the temporary
698 * payload will be destroyed below.
699 */
700 if (sync == &semaphore->permanent) {
701 result = vk_sync_reset(device, sync);
702 if (unlikely(result != VK_SUCCESS))
703 return result;
704 }
705 break;
706
707 default:
708 unreachable("Invalid semaphore export handle type");
709 }
710
711 /* From the Vulkan 1.2.194 spec:
712 *
713 * "Export operations have the same transference as the specified
714 * handle type’s import operations. [...] If the semaphore was using
715 * a temporarily imported payload, the semaphore’s prior permanent
716 * payload will be restored."
717 */
718 vk_semaphore_reset_temporary(device, semaphore);
719
720 return VK_SUCCESS;
721 }
722
723 #endif /* !defined(_WIN32) */
724