• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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