Skip to content

[Bindless][Exp] Windows & DX12 interop. Semaphore ops can take values. #13860

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 37 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9edef1e
[Bindless][Exp] Windows & DX12 interop. Semaphores can take values.
przemektmalon Nov 10, 2023
07bb904
Fix formatting
przemektmalon May 21, 2024
124824a
Format comment
przemektmalon May 21, 2024
386fb53
Use std::optional for semaphore values. Update test include file
przemektmalon May 22, 2024
9e2b777
Merge branch 'sycl' into przemek/windows-interop
przemektmalon May 22, 2024
6c59222
Fixes, formatting, and cleanup
przemektmalon May 22, 2024
4785052
Fix order of includes
przemektmalon May 22, 2024
06fbf3b
Revert PI to not take std optional
przemektmalon May 27, 2024
fb6d3a6
Merge branch 'sycl' into przemek/windows-interop
przemektmalon May 27, 2024
388c26d
Clarify spec on handle type compatibility
przemektmalon May 27, 2024
210e074
Fix PiMockPlugin
przemektmalon May 27, 2024
5f814d2
Merge branch 'sycl' into przemek/windows-interop
przemektmalon May 27, 2024
58ec8ec
Generate linux symbols dump
przemektmalon May 29, 2024
4d7e38d
Merge branch 'sycl' into przemek/windows-interop
przemektmalon May 29, 2024
0d3306e
Merge branch 'sycl' into przemek/windows-interop
przemektmalon May 30, 2024
1be7d64
Merge branch 'sycl' into przemek/windows-interop
przemektmalon May 31, 2024
65b4eaa
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 3, 2024
b4ba7c1
Re-generate linux symbols
przemektmalon Jun 3, 2024
ec7e4fe
Fix linux symbols
przemektmalon Jun 3, 2024
731d483
Fix linux symbols
przemektmalon Jun 3, 2024
97cb1a0
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 4, 2024
362c53d
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 4, 2024
0a20152
Update UR tag
przemektmalon Jun 4, 2024
c2d3bb9
Clarify that semaphores only work with in-order queues
przemektmalon Jun 6, 2024
6723298
Update UR TAG
przemektmalon Jun 6, 2024
33c275b
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 6, 2024
0aea35e
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 6, 2024
f9798a3
Update UR TAG
przemektmalon Jun 6, 2024
de9166a
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 6, 2024
284e65b
Update UR TAG
przemektmalon Jun 7, 2024
442b693
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 7, 2024
5edacec
Fix UR TAG typo
przemektmalon Jun 7, 2024
6fc952c
Remove unnecessary whitespace
przemektmalon Jun 7, 2024
bed1342
Update UR TAG
przemektmalon Jun 7, 2024
ece7eda
Merge branch 'sycl' into przemek/windows-interop
przemektmalon Jun 12, 2024
9946fd4
Merge branch 'sycl' into przemek/windows-interop
cppchedy Jun 18, 2024
8f8ad69
update UR tag
cppchedy Jun 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1594,10 +1594,18 @@ struct.
```cpp
namespace sycl::ext::oneapi::experimental {

// Types of external memory handles
enum class external_mem_handle_type {
opaque_fd = 0,
win32_nt_handle = 1,
win32_nt_dx12_resource = 2,
};

// Descriptor templated on specific resource type
template <typename ResourceType>
struct external_mem_descriptor {
ResourceType external_resource;
external_mem_handle_type handle_type;
size_t size_in_bytes;
};

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

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

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

It is important to note, that the use of imported external semaphore objects
within SYCL has the restriction in that imported external semaphores can only
be used in conjuction with SYCL queues that have been constructed with the
`property::queue::in_order` property. The semaphore synchronization mechanism
is not supported for the default SYCL out-of-order queues. Use of the semaphore
synchronization mechanism with SYCL queues which were not constructed with the
`queue::in_order` property will result in undefined behaviour.

External semaphore import is facilitated through the following proposed
descriptor struct.

```cpp
namespace sycl::ext::oneapi::experimental {

// Types of external semaphore handles
enum class external_semaphore_handle_type {
opaque_fd = 0,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not: You could maybe write that opaque_fd isn't supported on windows.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some minor notes to clarify that opaque_fd is only supported on linux based systems. I think going more into depth about which handle types are supported by which operating systems is beyond the scope of this document, and advanced users who want to use the interop APIs will have to know this already when exporting handles from third-party APIs before they even reach SYCL.

win32_nt_handle = 1,
win32_nt_dx12_fence = 2,
};

// Descriptor templated on specific resource type
template <typename ResourceType>
struct external_semaphore_descriptor {
ResourceType external_resource;
external_semaphore_handle_type handle_type;
};

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

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

```cpp
namespace sycl::ext::oneapi::experimental {
Expand All @@ -1728,7 +1759,6 @@ interop_semaphore_handle import_external_semaphore(
externalSemaphoreDescriptor,
const sycl::device &syclDevice,
const sycl::context &syclContext);
}

template <typename ResourceType>
interop_semaphore_handle import_external_semaphore(
Expand All @@ -1739,8 +1769,11 @@ interop_semaphore_handle import_external_semaphore(
```

The resulting `interop_semaphore_handle` can then be used in a SYCL command
group, to either wait until the semaphore is in the signaled state, or set the
semaphore to a signaled state.
group, to either wait until the semaphore signalled, or signal the semaphore.

If the type of semaphore imported supports setting the state of discrete
semaphore value (the semaphore type is `win32_nt_dx12_fence`), then the user
can specify which value the semaphore operation should wait on, or signal.

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

void ext_oneapi_wait_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t wait_value);

void ext_oneapi_signal_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle);

void ext_oneapi_signal_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t signal_value);
};

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

event ext_oneapi_wait_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t wait_value);
event ext_oneapi_wait_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t wait_value,
event DepEvent);
event ext_oneapi_wait_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t wait_value,
const std::vector<event> &DepEvents);

event ext_oneapi_signal_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle);
Expand All @@ -1784,17 +1842,46 @@ public:
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
const std::vector<event> &DepEvents);

event ext_oneapi_signal_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t signal_value);
event ext_oneapi_signal_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t signal_value,
event DepEvent);
event ext_oneapi_signal_external_semaphore(
ext::oneapi::experimental::interop_semaphore_handle
interop_semaphore_handle,
uint64_t signal_value,
const std::vector<event> &DepEvents);
};
}
```

Any operations submitted to the queue after a
`ext_oneapi_wait_external_semaphore` call will not begin until the imported
semaphore is in a signaled state.
The behaviour of waiting on a semaphore will depend on the type of the
semaphore which was imported.

If the semaphore does not support setting of a discrete state value (the
semaphore type is not `win32_nt_dx12_fence`), then any operations submitted to
the queue after a `ext_oneapi_wait_external_semaphore` call will not begin
until the imported semaphore is in a signalled state. After this, the semaphore
will be reset to a non-signalled state.

If the semaphore does support setting of a discrete state value (the semaphore
type is `win32_nt_dx12_fence`), then any operations submitted to the queue
after a `ext_oneapi_wait_external_semaphore` call will not begin until the
imported semaphore is in a state greater than or equal to the `wait_value`. The
state of this type of semaphore will not be altered by the call to
`ext_oneapi_wait_external_semaphore`.

When `ext_oneapi_signal_external_semaphore` is called, the external semaphore
will be set to the signaled state after all commands submitted to the queue
prior to the `ext_oneapi_signal_external_semaphore` call complete.
will either be set to a signalled state, or the state of the semaphore will be
set to `signal_value`, depending on the type of semaphore which was imported.
This singalling will be done after all commands submitted to the queue prior to
the `ext_oneapi_signal_external_semaphore` call complete.

`ext_oneapi_wait_external_semaphore` and `ext_oneapi_signal_external_semaphore`
are non-blocking, asynchronous operations.
Expand Down Expand Up @@ -2366,13 +2453,17 @@ int external_output_image_file_descriptor = /* passed from external API */
// Extension: populate external memory descriptors
sycl::ext::oneapi::experimental::external_mem_descriptor<
sycl::ext::oneapi::experimental::resource_fd>
input_ext_mem_desc{external_input_image_file_descriptor,
img_size_in_bytes};
input_ext_mem_desc{
external_input_image_file_descriptor,
sycl::ext::oneapi::experimental::external_mem_handle_type::opaque_fd,
img_size_in_bytes};

sycl::ext::oneapi::experimental::external_mem_descriptor<
sycl::ext::oneapi::experimental::resource_fd>
output_ext_mem_desc{external_output_image_file_descriptor,
img_size_in_bytes};
output_ext_mem_desc{
external_output_image_file_descriptor,
sycl::ext::oneapi::experimental::external_mem_handle_type::opaque_fd,
img_size_in_bytes};

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

sycl::ext::oneapi::experimental::external_semaphore_descriptor<
sycl::ext::oneapi::experimental::resource_fd>
done_external_semaphore_desc{done_semaphore_file_descriptor};
done_external_semaphore_desc{done_semaphore_file_descriptor,
sycl::ext::oneapi::experimental::external_semaphore_handle_type::opaque_fd};

try {
// Extension: import external semaphores
Expand Down Expand Up @@ -2682,4 +2775,15 @@ These features still need to be handled:
This function is redundant since images don't have a notion
of channel order, only the channel size. Use
`get_num_channels()` instead.
|5.11|2024-05-27| - Added `external_mem_handle_type` and
`external_semaphore_handle_type` enums. These will allow
multiple handle types to be consumed by the same interop API.
- Added `handle_type` field to the `external_mem_descriptor`
and `external_semaphore_descriptor` structs. This allows
multiple handle types to be consumed by the API, such as
file descriptors, Windows NT handles, and other handles in
the future.
- Added semaphore operations which can accept values. These
are only supported for certain semaphore types
(e.g. `win32_nt_dx12_fence`).
|======================
16 changes: 12 additions & 4 deletions sycl/include/sycl/detail/cg.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,33 +534,41 @@ class CGCopyImage : public CG {
/// "Semaphore Wait" command group class.
class CGSemaphoreWait : public CG {
sycl::detail::pi::PiInteropSemaphoreHandle MInteropSemaphoreHandle;
std::optional<uint64_t> MWaitValue;

public:
CGSemaphoreWait(
sycl::detail::pi::PiInteropSemaphoreHandle InteropSemaphoreHandle,
CG::StorageInitHelper CGData, detail::code_location loc = {})
std::optional<uint64_t> WaitValue, CG::StorageInitHelper CGData,
detail::code_location loc = {})
: CG(SemaphoreWait, std::move(CGData), std::move(loc)),
MInteropSemaphoreHandle(InteropSemaphoreHandle) {}
MInteropSemaphoreHandle(InteropSemaphoreHandle), MWaitValue(WaitValue) {
}

sycl::detail::pi::PiInteropSemaphoreHandle getInteropSemaphoreHandle() const {
return MInteropSemaphoreHandle;
}
std::optional<uint64_t> getWaitValue() const { return MWaitValue; }
};

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

public:
CGSemaphoreSignal(
sycl::detail::pi::PiInteropSemaphoreHandle InteropSemaphoreHandle,
CG::StorageInitHelper CGData, detail::code_location loc = {})
std::optional<uint64_t> SignalValue, CG::StorageInitHelper CGData,
detail::code_location loc = {})
: CG(SemaphoreSignal, std::move(CGData), std::move(loc)),
MInteropSemaphoreHandle(InteropSemaphoreHandle) {}
MInteropSemaphoreHandle(InteropSemaphoreHandle),
MSignalValue(SignalValue) {}

sycl::detail::pi::PiInteropSemaphoreHandle getInteropSemaphoreHandle() const {
return MInteropSemaphoreHandle;
}
std::optional<uint64_t> getSignalValue() const { return MSignalValue; }
};

/// "Execute command-buffer" command group class.
Expand Down
2 changes: 2 additions & 0 deletions sycl/include/sycl/detail/pi.def
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,11 @@ _PI_API(piextMemMipmapFree)

// Interop
_PI_API(piextMemImportOpaqueFD)
_PI_API(piextImportExternalMemory)
_PI_API(piextMemReleaseInterop)
_PI_API(piextMemMapExternalArray)
_PI_API(piextImportExternalSemaphoreOpaqueFD)
_PI_API(piextImportExternalSemaphore)
_PI_API(piextDestroyExternalSemaphore)
_PI_API(piextWaitExternalSemaphore)
_PI_API(piextSignalExternalSemaphore)
Expand Down
Loading