Skip to content

Commit bd97f28

Browse files
[Bindless][Exp] Windows & DX12 interop. Semaphore ops can take values. (#13860)
The following PI functions have been added to support importing various external handle types for both memory and semaphores: - `piextImportExternalMemory` - `piextImportExternalSemaphore` The following PI functions and their corresponding `pi2ur` functions are now deprecated: - `piextImportExternalSemaphoreOpaqueFD` - `piextMemImportOpaqueFD` All Vulkan tests have been updated to work on both Windows and Linux. Comments have been added to the Vulkan test files to make it easier to read and understand the code. Support has been added for interoperability of certain DirectX 12 resources, namely dedicated memory resources and fences. A test has been added that uses both functionalities. Support has been added for semaphore operations to take values passed by the user. The semaphore will either signal a given value, or wait for a value of the user's choice. --------- Co-authored-by: chedy.najjar <[email protected]>
1 parent 6385079 commit bd97f28

36 files changed

+2228
-313
lines changed

sycl/doc/extensions/experimental/sycl_ext_oneapi_bindless_images.asciidoc

Lines changed: 124 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,10 +1594,18 @@ struct.
15941594
```cpp
15951595
namespace sycl::ext::oneapi::experimental {
15961596

1597+
// Types of external memory handles
1598+
enum class external_mem_handle_type {
1599+
opaque_fd = 0,
1600+
win32_nt_handle = 1,
1601+
win32_nt_dx12_resource = 2,
1602+
};
1603+
15971604
// Descriptor templated on specific resource type
15981605
template <typename ResourceType>
15991606
struct external_mem_descriptor {
16001607
ResourceType external_resource;
1608+
external_mem_handle_type handle_type;
16011609
size_t size_in_bytes;
16021610
};
16031611

@@ -1609,9 +1617,13 @@ handle type, `ResourceType`, for their purposes, e.g. `resource_fd` to describe
16091617
a POSIX file descriptor resource on Linux systems, or a `resource_win32_handle`
16101618
for Windows NT resource handles.
16111619

1612-
Once the user populates the `external_mem_descriptor` with the appropriate
1613-
`ResourceType` values, and the size of the external memory in bytes,
1614-
they can then import that memory into SYCL through `import_external_memory`.
1620+
The user must populate the `external_mem_descriptor` with the appropriate
1621+
`ResourceType` values, a `handle_type`, and the size of the external memory in
1622+
bytes, before they can then import that memory into SYCL through
1623+
`import_external_memory`. Note that some handle types can only be used in
1624+
combination with certain resource types, for example the `opaque_fd` handle type
1625+
is only used on Linux systems and is only compatible with the `resource_fd`
1626+
resource type.
16151627

16161628
```cpp
16171629
namespace sycl::ext::oneapi::experimental {
@@ -1690,16 +1702,32 @@ memory resources handles can take different forms of structure and type
16901702
depending on the API and operating system, so do external semaphore resource
16911703
handles.
16921704

1705+
It is important to note, that the use of imported external semaphore objects
1706+
within SYCL has the restriction in that imported external semaphores can only
1707+
be used in conjuction with SYCL queues that have been constructed with the
1708+
`property::queue::in_order` property. The semaphore synchronization mechanism
1709+
is not supported for the default SYCL out-of-order queues. Use of the semaphore
1710+
synchronization mechanism with SYCL queues which were not constructed with the
1711+
`queue::in_order` property will result in undefined behaviour.
1712+
16931713
External semaphore import is facilitated through the following proposed
16941714
descriptor struct.
16951715

16961716
```cpp
16971717
namespace sycl::ext::oneapi::experimental {
16981718

1719+
// Types of external semaphore handles
1720+
enum class external_semaphore_handle_type {
1721+
opaque_fd = 0,
1722+
win32_nt_handle = 1,
1723+
win32_nt_dx12_fence = 2,
1724+
};
1725+
16991726
// Descriptor templated on specific resource type
17001727
template <typename ResourceType>
17011728
struct external_semaphore_descriptor {
17021729
ResourceType external_resource;
1730+
external_semaphore_handle_type handle_type;
17031731
};
17041732

17051733
}
@@ -1710,9 +1738,12 @@ appropriate handle type, `ResourceType`, for their purposes, e.g. `resource_fd`
17101738
to describe a POSIX file descriptor resource on Linux systems, or a
17111739
`resource_win32_handle` for Windows NT resource handles.
17121740

1713-
Once the user populates the `external_semaphore_descriptor` with the appropriate
1714-
`ResourceType` values, they can then import that semaphore into SYCL through
1715-
`import_external_semaphore`.
1741+
The user must populate the `external_semaphore_descriptor` with the appropriate
1742+
`ResourceType` values, and `handle_type`, before they can then import that
1743+
semaphore into SYCL through `import_external_semaphore`. Note that some handle
1744+
types can only be used in combination with certain resource types, for example
1745+
the `opaque_fd` handle type is only used on Linux systems and is only
1746+
compatible with the `resource_fd` resource type.
17161747

17171748
```cpp
17181749
namespace sycl::ext::oneapi::experimental {
@@ -1728,7 +1759,6 @@ interop_semaphore_handle import_external_semaphore(
17281759
externalSemaphoreDescriptor,
17291760
const sycl::device &syclDevice,
17301761
const sycl::context &syclContext);
1731-
}
17321762

17331763
template <typename ResourceType>
17341764
interop_semaphore_handle import_external_semaphore(
@@ -1739,8 +1769,11 @@ interop_semaphore_handle import_external_semaphore(
17391769
```
17401770

17411771
The resulting `interop_semaphore_handle` can then be used in a SYCL command
1742-
group, to either wait until the semaphore is in the signaled state, or set the
1743-
semaphore to a signaled state.
1772+
group, to either wait until the semaphore signalled, or signal the semaphore.
1773+
1774+
If the type of semaphore imported supports setting the state of discrete
1775+
semaphore value (the semaphore type is `win32_nt_dx12_fence`), then the user
1776+
can specify which value the semaphore operation should wait on, or signal.
17441777

17451778
We propose to extend the SYCL queue and handler classes with semaphore waiting
17461779
and signalling operations.
@@ -1754,9 +1787,19 @@ public:
17541787
ext::oneapi::experimental::interop_semaphore_handle
17551788
interop_semaphore_handle);
17561789

1790+
void ext_oneapi_wait_external_semaphore(
1791+
ext::oneapi::experimental::interop_semaphore_handle
1792+
interop_semaphore_handle,
1793+
uint64_t wait_value);
1794+
17571795
void ext_oneapi_signal_external_semaphore(
17581796
ext::oneapi::experimental::interop_semaphore_handle
17591797
interop_semaphore_handle);
1798+
1799+
void ext_oneapi_signal_external_semaphore(
1800+
ext::oneapi::experimental::interop_semaphore_handle
1801+
interop_semaphore_handle,
1802+
uint64_t signal_value);
17601803
};
17611804

17621805
class queue {
@@ -1773,6 +1816,21 @@ public:
17731816
interop_semaphore_handle,
17741817
const std::vector<event> &DepEvents);
17751818

1819+
event ext_oneapi_wait_external_semaphore(
1820+
ext::oneapi::experimental::interop_semaphore_handle
1821+
interop_semaphore_handle,
1822+
uint64_t wait_value);
1823+
event ext_oneapi_wait_external_semaphore(
1824+
ext::oneapi::experimental::interop_semaphore_handle
1825+
interop_semaphore_handle,
1826+
uint64_t wait_value,
1827+
event DepEvent);
1828+
event ext_oneapi_wait_external_semaphore(
1829+
ext::oneapi::experimental::interop_semaphore_handle
1830+
interop_semaphore_handle,
1831+
uint64_t wait_value,
1832+
const std::vector<event> &DepEvents);
1833+
17761834
event ext_oneapi_signal_external_semaphore(
17771835
ext::oneapi::experimental::interop_semaphore_handle
17781836
interop_semaphore_handle);
@@ -1784,17 +1842,46 @@ public:
17841842
ext::oneapi::experimental::interop_semaphore_handle
17851843
interop_semaphore_handle,
17861844
const std::vector<event> &DepEvents);
1845+
1846+
event ext_oneapi_signal_external_semaphore(
1847+
ext::oneapi::experimental::interop_semaphore_handle
1848+
interop_semaphore_handle,
1849+
uint64_t signal_value);
1850+
event ext_oneapi_signal_external_semaphore(
1851+
ext::oneapi::experimental::interop_semaphore_handle
1852+
interop_semaphore_handle,
1853+
uint64_t signal_value,
1854+
event DepEvent);
1855+
event ext_oneapi_signal_external_semaphore(
1856+
ext::oneapi::experimental::interop_semaphore_handle
1857+
interop_semaphore_handle,
1858+
uint64_t signal_value,
1859+
const std::vector<event> &DepEvents);
17871860
};
17881861
}
17891862
```
17901863

1791-
Any operations submitted to the queue after a
1792-
`ext_oneapi_wait_external_semaphore` call will not begin until the imported
1793-
semaphore is in a signaled state.
1864+
The behaviour of waiting on a semaphore will depend on the type of the
1865+
semaphore which was imported.
1866+
1867+
If the semaphore does not support setting of a discrete state value (the
1868+
semaphore type is not `win32_nt_dx12_fence`), then any operations submitted to
1869+
the queue after a `ext_oneapi_wait_external_semaphore` call will not begin
1870+
until the imported semaphore is in a signalled state. After this, the semaphore
1871+
will be reset to a non-signalled state.
1872+
1873+
If the semaphore does support setting of a discrete state value (the semaphore
1874+
type is `win32_nt_dx12_fence`), then any operations submitted to the queue
1875+
after a `ext_oneapi_wait_external_semaphore` call will not begin until the
1876+
imported semaphore is in a state greater than or equal to the `wait_value`. The
1877+
state of this type of semaphore will not be altered by the call to
1878+
`ext_oneapi_wait_external_semaphore`.
17941879

17951880
When `ext_oneapi_signal_external_semaphore` is called, the external semaphore
1796-
will be set to the signaled state after all commands submitted to the queue
1797-
prior to the `ext_oneapi_signal_external_semaphore` call complete.
1881+
will either be set to a signalled state, or the state of the semaphore will be
1882+
set to `signal_value`, depending on the type of semaphore which was imported.
1883+
This singalling will be done after all commands submitted to the queue prior to
1884+
the `ext_oneapi_signal_external_semaphore` call complete.
17981885

17991886
`ext_oneapi_wait_external_semaphore` and `ext_oneapi_signal_external_semaphore`
18001887
are non-blocking, asynchronous operations.
@@ -2366,13 +2453,17 @@ int external_output_image_file_descriptor = /* passed from external API */
23662453
// Extension: populate external memory descriptors
23672454
sycl::ext::oneapi::experimental::external_mem_descriptor<
23682455
sycl::ext::oneapi::experimental::resource_fd>
2369-
input_ext_mem_desc{external_input_image_file_descriptor,
2370-
img_size_in_bytes};
2456+
input_ext_mem_desc{
2457+
external_input_image_file_descriptor,
2458+
sycl::ext::oneapi::experimental::external_mem_handle_type::opaque_fd,
2459+
img_size_in_bytes};
23712460

23722461
sycl::ext::oneapi::experimental::external_mem_descriptor<
23732462
sycl::ext::oneapi::experimental::resource_fd>
2374-
output_ext_mem_desc{external_output_image_file_descriptor,
2375-
img_size_in_bytes};
2463+
output_ext_mem_desc{
2464+
external_output_image_file_descriptor,
2465+
sycl::ext::oneapi::experimental::external_mem_handle_type::opaque_fd,
2466+
img_size_in_bytes};
23762467

23772468
// An external API semaphore will signal this semaphore before our SYCL commands
23782469
// can begin execution
@@ -2386,11 +2477,13 @@ int done_semaphore_file_descriptor = /* passed from external API */;
23862477
// We assume POSIX file descriptor resource types
23872478
sycl::ext::oneapi::experimental::external_semaphore_descriptor<
23882479
sycl::ext::oneapi::experimental::resource_fd>
2389-
wait_external_semaphore_desc{wait_semaphore_file_descriptor};
2480+
wait_external_semaphore_desc{wait_semaphore_file_descriptor,
2481+
sycl::ext::oneapi::experimental::external_semaphore_handle_type::opaque_fd};
23902482

23912483
sycl::ext::oneapi::experimental::external_semaphore_descriptor<
23922484
sycl::ext::oneapi::experimental::resource_fd>
2393-
done_external_semaphore_desc{done_semaphore_file_descriptor};
2485+
done_external_semaphore_desc{done_semaphore_file_descriptor,
2486+
sycl::ext::oneapi::experimental::external_semaphore_handle_type::opaque_fd};
23942487

23952488
try {
23962489
// Extension: import external semaphores
@@ -2682,4 +2775,15 @@ These features still need to be handled:
26822775
This function is redundant since images don't have a notion
26832776
of channel order, only the channel size. Use
26842777
`get_num_channels()` instead.
2778+
|5.11|2024-05-27| - Added `external_mem_handle_type` and
2779+
`external_semaphore_handle_type` enums. These will allow
2780+
multiple handle types to be consumed by the same interop API.
2781+
- Added `handle_type` field to the `external_mem_descriptor`
2782+
and `external_semaphore_descriptor` structs. This allows
2783+
multiple handle types to be consumed by the API, such as
2784+
file descriptors, Windows NT handles, and other handles in
2785+
the future.
2786+
- Added semaphore operations which can accept values. These
2787+
are only supported for certain semaphore types
2788+
(e.g. `win32_nt_dx12_fence`).
26852789
|======================

sycl/include/sycl/detail/cg.hpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -534,33 +534,41 @@ class CGCopyImage : public CG {
534534
/// "Semaphore Wait" command group class.
535535
class CGSemaphoreWait : public CG {
536536
sycl::detail::pi::PiInteropSemaphoreHandle MInteropSemaphoreHandle;
537+
std::optional<uint64_t> MWaitValue;
537538

538539
public:
539540
CGSemaphoreWait(
540541
sycl::detail::pi::PiInteropSemaphoreHandle InteropSemaphoreHandle,
541-
CG::StorageInitHelper CGData, detail::code_location loc = {})
542+
std::optional<uint64_t> WaitValue, CG::StorageInitHelper CGData,
543+
detail::code_location loc = {})
542544
: CG(SemaphoreWait, std::move(CGData), std::move(loc)),
543-
MInteropSemaphoreHandle(InteropSemaphoreHandle) {}
545+
MInteropSemaphoreHandle(InteropSemaphoreHandle), MWaitValue(WaitValue) {
546+
}
544547

545548
sycl::detail::pi::PiInteropSemaphoreHandle getInteropSemaphoreHandle() const {
546549
return MInteropSemaphoreHandle;
547550
}
551+
std::optional<uint64_t> getWaitValue() const { return MWaitValue; }
548552
};
549553

550554
/// "Semaphore Signal" command group class.
551555
class CGSemaphoreSignal : public CG {
552556
sycl::detail::pi::PiInteropSemaphoreHandle MInteropSemaphoreHandle;
557+
std::optional<uint64_t> MSignalValue;
553558

554559
public:
555560
CGSemaphoreSignal(
556561
sycl::detail::pi::PiInteropSemaphoreHandle InteropSemaphoreHandle,
557-
CG::StorageInitHelper CGData, detail::code_location loc = {})
562+
std::optional<uint64_t> SignalValue, CG::StorageInitHelper CGData,
563+
detail::code_location loc = {})
558564
: CG(SemaphoreSignal, std::move(CGData), std::move(loc)),
559-
MInteropSemaphoreHandle(InteropSemaphoreHandle) {}
565+
MInteropSemaphoreHandle(InteropSemaphoreHandle),
566+
MSignalValue(SignalValue) {}
560567

561568
sycl::detail::pi::PiInteropSemaphoreHandle getInteropSemaphoreHandle() const {
562569
return MInteropSemaphoreHandle;
563570
}
571+
std::optional<uint64_t> getSignalValue() const { return MSignalValue; }
564572
};
565573

566574
/// "Execute command-buffer" command group class.

sycl/include/sycl/detail/pi.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,11 @@ _PI_API(piextMemMipmapFree)
206206

207207
// Interop
208208
_PI_API(piextMemImportOpaqueFD)
209+
_PI_API(piextImportExternalMemory)
209210
_PI_API(piextMemReleaseInterop)
210211
_PI_API(piextMemMapExternalArray)
211212
_PI_API(piextImportExternalSemaphoreOpaqueFD)
213+
_PI_API(piextImportExternalSemaphore)
212214
_PI_API(piextDestroyExternalSemaphore)
213215
_PI_API(piextWaitExternalSemaphore)
214216
_PI_API(piextSignalExternalSemaphore)

0 commit comments

Comments
 (0)