Skip to content

Commit 829b30d

Browse files
authored
[SYCL][Bindless][UR] Add support for timeline semaphores (#17395)
Add support for timeline semaphores on linux and windows for CUDA backend and preliminary support in L0 backend. Update vulkan_interop/sampled_images.cpp to remove redundant wait when using semaphores.
1 parent e932cf9 commit 829b30d

File tree

15 files changed

+656
-51
lines changed

15 files changed

+656
-51
lines changed

sycl/doc/extensions/experimental/sycl_ext_oneapi_bindless_images.asciidoc

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,8 @@ enum class external_semaphore_handle_type {
20832083
opaque_fd = 0,
20842084
win32_nt_handle = 1,
20852085
win32_nt_dx12_fence = 2,
2086+
timeline_fd = 3,
2087+
timeline_win32_nt_handle = 4,
20862088
};
20872089

20882090
// Descriptor templated on specific resource type
@@ -2134,8 +2136,9 @@ The resulting `external_semaphore` can then be used in a SYCL command
21342136
group, to either wait until the semaphore signalled, or signal the semaphore.
21352137

21362138
If the type of semaphore imported supports setting the state of discrete
2137-
semaphore value (the semaphore type is `win32_nt_dx12_fence`), then the user
2138-
can specify which value the semaphore operation should wait on, or signal.
2139+
semaphore value (the semaphore type is `win32_nt_dx12_fence`, `timeline_fd` or
2140+
`timeline_win32_nt_handle`), then the user can specify which value the semaphore
2141+
operation should wait on, or signal.
21392142

21402143
We propose to extend the SYCL queue and handler classes with semaphore waiting
21412144
and signalling operations.
@@ -2226,17 +2229,19 @@ public:
22262229
The behaviour of waiting on a semaphore will depend on the type of the
22272230
semaphore which was imported.
22282231

2229-
If the semaphore does not support setting of a discrete state value (the
2230-
semaphore type is not `win32_nt_dx12_fence`), then any operations submitted to
2231-
the queue after a `ext_oneapi_wait_external_semaphore` call will not begin
2232-
until the imported semaphore is in a signalled state. After this, the semaphore
2233-
will be reset to a non-signalled state.
2234-
2235-
If the semaphore does support setting of a discrete state value (the semaphore
2236-
type is `win32_nt_dx12_fence`), then any operations submitted to the queue
2237-
after a `ext_oneapi_wait_external_semaphore` call will not begin until the
2238-
imported semaphore is in a state greater than or equal to the `wait_value`. The
2239-
state of this type of semaphore will not be altered by the call to
2232+
If the semaphore does not support setting of a discrete state value (the
2233+
semaphore type is not `win32_nt_dx12_fence`, `timeline_fd` or
2234+
`timeline_win32_nt_handle`), then any operations submitted to the queue after a
2235+
`ext_oneapi_wait_external_semaphore` call will not begin until the imported
2236+
semaphore is in a signalled state. After this, the semaphore will be reset to a
2237+
non-signalled state.
2238+
2239+
If the semaphore does support setting of a discrete state value (the semaphore
2240+
type is `win32_nt_dx12_fence`, `timeline_fd` or `timeline_win32_nt_handle`),
2241+
then any operations submitted to the queue after a
2242+
`ext_oneapi_wait_external_semaphore` call will not begin until the imported
2243+
semaphore is in a state greater than or equal to the `wait_value`. The state of
2244+
this type of semaphore will not be altered by the call to
22402245
`ext_oneapi_wait_external_semaphore`.
22412246

22422247
When `ext_oneapi_signal_external_semaphore` is called, the external semaphore
@@ -2570,4 +2575,5 @@ These features still need to be handled:
25702575
sub-copies.
25712576
- Add support for USM to USM copies and sub-copies.
25722577
- Add support for host to host copies and sub-copies.
2578+
|6.8|2025-03-13| - Add support for importing timeline semaphores.
25732579
|======================

sycl/include/sycl/ext/oneapi/bindless_images_interop.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ enum class external_semaphore_handle_type {
2828
opaque_fd = 0,
2929
win32_nt_handle = 1,
3030
win32_nt_dx12_fence = 2,
31+
timeline_fd = 3,
32+
timeline_win32_nt_handle = 4,
3133
};
3234

3335
/// Opaque external memory handle type

sycl/source/detail/bindless_images.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -639,16 +639,31 @@ __SYCL_EXPORT external_semaphore import_external_semaphore(
639639
urExternalSemDesc.stype = UR_STRUCTURE_TYPE_EXP_EXTERNAL_SEMAPHORE_DESC;
640640
urExternalSemDesc.pNext = &urFileDescriptor;
641641

642-
// For this specialization of `import_external_semaphore` the handleType is
643-
// always `OPAQUE_FD`.
642+
// This specialization handles timeline and binary semaphores which both
643+
// have the same underlying external semaphore handle type of opaque file
644+
// descriptor.
645+
646+
// Select appropriate semaphore handle type.
647+
ur_exp_external_semaphore_type_t urHandleType;
648+
switch (externalSemaphoreDesc.handle_type) {
649+
case external_semaphore_handle_type::opaque_fd:
650+
urHandleType = UR_EXP_EXTERNAL_SEMAPHORE_TYPE_OPAQUE_FD;
651+
break;
652+
case external_semaphore_handle_type::timeline_fd:
653+
urHandleType = UR_EXP_EXTERNAL_SEMAPHORE_TYPE_TIMELINE_FD;
654+
break;
655+
default:
656+
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
657+
"Invalid semaphore handle type");
658+
}
659+
644660
Adapter->call<
645661
sycl::errc::invalid,
646662
sycl::detail::UrApiKind::urBindlessImagesImportExternalSemaphoreExp>(
647-
C, Device, UR_EXP_EXTERNAL_SEMAPHORE_TYPE_OPAQUE_FD, &urExternalSemDesc,
648-
&urExternalSemaphore);
663+
C, Device, urHandleType, &urExternalSemDesc, &urExternalSemaphore);
649664

650665
return external_semaphore{urExternalSemaphore,
651-
external_semaphore_handle_type::opaque_fd};
666+
externalSemaphoreDesc.handle_type};
652667
}
653668

654669
template <>
@@ -688,6 +703,9 @@ __SYCL_EXPORT external_semaphore import_external_semaphore(
688703
case external_semaphore_handle_type::win32_nt_dx12_fence:
689704
urHandleType = UR_EXP_EXTERNAL_SEMAPHORE_TYPE_WIN32_NT_DX12_FENCE;
690705
break;
706+
case external_semaphore_handle_type::timeline_win32_nt_handle:
707+
urHandleType = UR_EXP_EXTERNAL_SEMAPHORE_TYPE_TIMELINE_WIN32_NT;
708+
break;
691709
default:
692710
throw sycl::exception(sycl::make_error_code(sycl::errc::invalid),
693711
"Invalid semaphore handle type");

sycl/source/handler.cpp

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,17 +1555,21 @@ void handler::ext_oneapi_wait_external_semaphore(
15551555
throwIfGraphAssociated<
15561556
ext::oneapi::experimental::detail::UnsupportedGraphFeatures::
15571557
sycl_ext_oneapi_bindless_images>();
1558-
if (ExtSemaphore.handle_type !=
1559-
sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1560-
opaque_fd &&
1561-
ExtSemaphore.handle_type !=
1562-
sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1563-
win32_nt_handle) {
1558+
1559+
switch (ExtSemaphore.handle_type) {
1560+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1561+
opaque_fd:
1562+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1563+
win32_nt_handle:
1564+
break;
1565+
default:
15641566
throw sycl::exception(
15651567
make_error_code(errc::invalid),
15661568
"Invalid type of semaphore for this operation. The "
15671569
"type of semaphore used needs a user passed wait value.");
1570+
break;
15681571
}
1572+
15691573
impl->MExternalSemaphore =
15701574
(ur_exp_external_semaphore_handle_t)ExtSemaphore.raw_handle;
15711575
impl->MWaitValue = {};
@@ -1578,14 +1582,23 @@ void handler::ext_oneapi_wait_external_semaphore(
15781582
throwIfGraphAssociated<
15791583
ext::oneapi::experimental::detail::UnsupportedGraphFeatures::
15801584
sycl_ext_oneapi_bindless_images>();
1581-
if (ExtSemaphore.handle_type !=
1582-
sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1583-
win32_nt_dx12_fence) {
1585+
1586+
switch (ExtSemaphore.handle_type) {
1587+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1588+
win32_nt_dx12_fence:
1589+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1590+
timeline_fd:
1591+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1592+
timeline_win32_nt_handle:
1593+
break;
1594+
default:
15841595
throw sycl::exception(
15851596
make_error_code(errc::invalid),
15861597
"Invalid type of semaphore for this operation. The "
15871598
"type of semaphore does not support user passed wait values.");
1599+
break;
15881600
}
1601+
15891602
impl->MExternalSemaphore =
15901603
(ur_exp_external_semaphore_handle_t)ExtSemaphore.raw_handle;
15911604
impl->MWaitValue = WaitValue;
@@ -1597,17 +1610,21 @@ void handler::ext_oneapi_signal_external_semaphore(
15971610
throwIfGraphAssociated<
15981611
ext::oneapi::experimental::detail::UnsupportedGraphFeatures::
15991612
sycl_ext_oneapi_bindless_images>();
1600-
if (ExtSemaphore.handle_type !=
1601-
sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1602-
opaque_fd &&
1603-
ExtSemaphore.handle_type !=
1604-
sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1605-
win32_nt_handle) {
1613+
1614+
switch (ExtSemaphore.handle_type) {
1615+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1616+
opaque_fd:
1617+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1618+
win32_nt_handle:
1619+
break;
1620+
default:
16061621
throw sycl::exception(
16071622
make_error_code(errc::invalid),
16081623
"Invalid type of semaphore for this operation. The "
16091624
"type of semaphore used needs a user passed signal value.");
1625+
break;
16101626
}
1627+
16111628
impl->MExternalSemaphore =
16121629
(ur_exp_external_semaphore_handle_t)ExtSemaphore.raw_handle;
16131630
impl->MSignalValue = {};
@@ -1620,14 +1637,23 @@ void handler::ext_oneapi_signal_external_semaphore(
16201637
throwIfGraphAssociated<
16211638
ext::oneapi::experimental::detail::UnsupportedGraphFeatures::
16221639
sycl_ext_oneapi_bindless_images>();
1623-
if (ExtSemaphore.handle_type !=
1624-
sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1625-
win32_nt_dx12_fence) {
1640+
1641+
switch (ExtSemaphore.handle_type) {
1642+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1643+
win32_nt_dx12_fence:
1644+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1645+
timeline_fd:
1646+
case sycl::ext::oneapi::experimental::external_semaphore_handle_type::
1647+
timeline_win32_nt_handle:
1648+
break;
1649+
default:
16261650
throw sycl::exception(
16271651
make_error_code(errc::invalid),
16281652
"Invalid type of semaphore for this operation. The "
16291653
"type of semaphore does not support user passed signal values.");
1654+
break;
16301655
}
1656+
16311657
impl->MExternalSemaphore =
16321658
(ur_exp_external_semaphore_handle_t)ExtSemaphore.raw_handle;
16331659
impl->MSignalValue = SignalValue;

sycl/test-e2e/bindless_images/vulkan_interop/sampled_images.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,11 @@ bool run_test(sycl::range<NDims> dims, sycl::range<NDims> localSize,
413413

414414
VK_CHECK_CALL(vkQueueSubmit(vk_transfer_queue, 1 /*submitCount*/,
415415
&submission, VK_NULL_HANDLE /*fence*/));
416+
// Do not wait when using semaphores as they can handle the kernel execution
417+
// order.
418+
#ifndef TEST_SEMAPHORE_IMPORT
416419
VK_CHECK_CALL(vkQueueWaitIdle(vk_transfer_queue));
420+
#endif
417421
}
418422

419423
printString("Getting memory file descriptors\n");

0 commit comments

Comments
 (0)