Skip to content

Commit 8b3c8c4

Browse files
authored
[SYCL] Add support for get_native for buffer and fix backend_return_t (#5881)
1 parent cc3930b commit 8b3c8c4

File tree

10 files changed

+190
-22
lines changed

10 files changed

+190
-22
lines changed

sycl/doc/PreprocessorMacros.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ This file describes macros that have effect on SYCL compiler and run-time.
6161
will change the behavior of `sycl::get_native()` function and using types for
6262
next structs: `interop<backend::opencl, event>`, `BackendInput<backend::opencl, event>`,
6363
`BackendReturn<backend::opencl, event>` to be in line with the spec.
64+
2) According to spec, `backend_return_t` for opencl buffer
65+
should be `std::vector<cl_mem>` instead of `cl_mem`. Defining this macro
66+
will change the behavior of `interop_handle::get_native_mem()` and `sycl::get_native()` functions
67+
and using type for `BackendReturn<backend::opencl, buffer>` to be in line with the spec.
6468

6569
## Version macros
6670

sycl/include/CL/sycl/backend.hpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,54 @@ template <backend Backend, typename SyclType>
6464
using backend_return_t =
6565
typename backend_traits<Backend>::template return_type<SyclType>;
6666

67+
namespace detail {
68+
template <backend Backend, typename DataT, int Dimensions, typename AllocatorT>
69+
struct BufferInterop {
70+
using ReturnType =
71+
backend_return_t<Backend, buffer<DataT, Dimensions, AllocatorT>>;
72+
73+
static ReturnType GetNativeObjs(const std::vector<pi_native_handle> &Handle) {
74+
ReturnType ReturnValue = 0;
75+
if (Handle.size()) {
76+
ReturnValue = detail::pi::cast<ReturnType>(Handle[0]);
77+
}
78+
return ReturnValue;
79+
}
80+
};
81+
82+
#ifdef SYCL2020_CONFORMANT_APIS
83+
template <typename DataT, int Dimensions, typename AllocatorT>
84+
struct BufferInterop<backend::opencl, DataT, Dimensions, AllocatorT> {
85+
using ReturnType =
86+
backend_return_t<backend::opencl, buffer<DataT, Dimensions, AllocatorT>>;
87+
88+
static ReturnType GetNativeObjs(const std::vector<pi_native_handle> &Handle) {
89+
ReturnType ReturnValue{};
90+
for (auto &Obj : Handle) {
91+
ReturnValue.push_back(
92+
detail::pi::cast<typename decltype(ReturnValue)::value_type>(Obj));
93+
}
94+
return ReturnValue;
95+
}
96+
};
97+
#endif
98+
99+
template <backend BackendName, typename DataT, int Dimensions,
100+
typename AllocatorT>
101+
auto get_native_buffer(const buffer<DataT, Dimensions, AllocatorT, void> &Obj)
102+
-> backend_return_t<BackendName,
103+
buffer<DataT, Dimensions, AllocatorT, void>> {
104+
// No check for backend mismatch because buffer can be allocated on different
105+
// backends
106+
if (BackendName == backend::ext_oneapi_level_zero)
107+
throw sycl::runtime_error(
108+
errc::feature_not_supported,
109+
"Buffer interop is not supported by level zero yet",
110+
PI_INVALID_OPERATION);
111+
return Obj.template getNative<BackendName>();
112+
}
113+
} // namespace detail
114+
67115
template <backend BackendName, class SyclObjectT>
68116
auto get_native(const SyclObjectT &Obj)
69117
-> backend_return_t<BackendName, SyclObjectT> {
@@ -75,6 +123,28 @@ auto get_native(const SyclObjectT &Obj)
75123
return Obj.template get_native<BackendName>();
76124
}
77125

126+
template <backend BackendName, typename DataT, int Dimensions,
127+
typename AllocatorT,
128+
std::enable_if_t<BackendName == backend::opencl> * = nullptr>
129+
#ifndef SYCL2020_CONFORMANT_APIS
130+
__SYCL_DEPRECATED(
131+
"get_native<backend::opencl, buffer>, which return type "
132+
"cl_mem is deprecated. According to SYCL 2020 spec, please define "
133+
"SYCL2020_CONFORMANT_APIS and use vector<cl_mem> instead.")
134+
#endif
135+
auto get_native(const buffer<DataT, Dimensions, AllocatorT> &Obj)
136+
-> backend_return_t<BackendName, buffer<DataT, Dimensions, AllocatorT>> {
137+
return detail::get_native_buffer<BackendName>(Obj);
138+
}
139+
140+
template <backend BackendName, typename DataT, int Dimensions,
141+
typename AllocatorT,
142+
std::enable_if_t<BackendName != backend::opencl> * = nullptr>
143+
auto get_native(const buffer<DataT, Dimensions, AllocatorT> &Obj)
144+
-> backend_return_t<BackendName, buffer<DataT, Dimensions, AllocatorT>> {
145+
return detail::get_native_buffer<BackendName>(Obj);
146+
}
147+
78148
// define SYCL2020_CONFORMANT_APIS to correspond SYCL 2020 spec and return
79149
// vector<cl_event> from get_native instead of just cl_event
80150
#ifdef SYCL2020_CONFORMANT_APIS

sycl/include/CL/sycl/buffer.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ make_buffer_helper(pi_native_handle Handle, const context &Ctx, event Evt = {},
3131
return buffer<T, Dimensions, AllocatorT, void>(Handle, Ctx, OwnNativeHandle,
3232
Evt);
3333
}
34+
35+
template <backend BackendName, typename DataT, int Dimensions,
36+
typename Allocator>
37+
auto get_native_buffer(const buffer<DataT, Dimensions, Allocator, void> &Obj)
38+
-> backend_return_t<BackendName,
39+
buffer<DataT, Dimensions, Allocator, void>>;
40+
41+
template <backend Backend, typename DataT, int Dimensions,
42+
typename AllocatorT = cl::sycl::buffer_allocator>
43+
struct BufferInterop;
3444
} // namespace detail
3545

3646
/// Defines a shared array that can be used by kernels in queues.
@@ -605,6 +615,21 @@ class buffer {
605615
return newRange[0] == 1 && newRange[2] == parentRange[2];
606616
return newRange[1] == parentRange[1] && newRange[2] == parentRange[2];
607617
}
618+
619+
template <backend BackendName, typename DataT, int Dimensions,
620+
typename Allocator>
621+
friend auto detail::get_native_buffer(
622+
const buffer<DataT, Dimensions, Allocator, void> &Obj)
623+
-> backend_return_t<BackendName,
624+
buffer<DataT, Dimensions, Allocator, void>>;
625+
626+
template <backend BackendName>
627+
backend_return_t<BackendName, buffer<T, dimensions, AllocatorT>>
628+
getNative() const {
629+
auto NativeHandles = impl->getNativeVector(BackendName);
630+
return detail::BufferInterop<BackendName, T, dimensions,
631+
AllocatorT>::GetNativeObjs(NativeHandles);
632+
}
608633
};
609634

610635
#ifdef __cpp_deduction_guides

sycl/include/CL/sycl/detail/backend_traits_opencl.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,17 @@ struct BackendInput<backend::opencl, buffer<DataT, Dimensions, AllocatorT>> {
8383
using type = cl_mem;
8484
};
8585

86+
#ifdef SYCL2020_CONFORMANT_APIS
87+
template <typename DataT, int Dimensions, typename AllocatorT>
88+
struct BackendReturn<backend::opencl, buffer<DataT, Dimensions, AllocatorT>> {
89+
using type = std::vector<cl_mem>;
90+
};
91+
#else
8692
template <typename DataT, int Dimensions, typename AllocatorT>
8793
struct BackendReturn<backend::opencl, buffer<DataT, Dimensions, AllocatorT>> {
8894
using type = cl_mem;
8995
};
96+
#endif
9097

9198
template <> struct BackendInput<backend::opencl, context> {
9299
using type = cl_context;

sycl/include/CL/sycl/detail/buffer_impl.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ class __SYCL_EXPORT buffer_impl final : public SYCLMemObjT {
189189
}
190190

191191
void resize(size_t size) { BaseT::MSizeInBytes = size; }
192+
193+
void addInteropObject(std::vector<pi_native_handle> &Handles) const;
194+
195+
std::vector<pi_native_handle> getNativeVector(backend BackendName) const;
192196
};
193197

194198
} // namespace detail

sycl/include/CL/sycl/interop_handle.hpp

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class interop_handle {
6767
#else
6868
(void)Acc;
6969
// we believe this won't be ever called on device side
70-
return 0;
70+
return backend_return_t<Backend, buffer<DataT, Dims>>{0};
7171
#endif
7272
}
7373

@@ -158,25 +158,9 @@ class interop_handle {
158158
template <backend Backend, typename DataT, int Dims>
159159
backend_return_t<Backend, buffer<DataT, Dims>>
160160
getMemImpl(detail::Requirement *Req) const {
161-
/*
162-
Do not update this cast: a C-style cast is required here.
163-
164-
This function tries to cast pi_native_handle to the native handle type.
165-
pi_native_handle is a typedef of uintptr_t. It is used to store opaque
166-
pointers, such as cl_device, and integer handles, such as CUdevice. To
167-
convert a uintptr_t to a pointer type, such as cl_device, reinterpret_cast
168-
must be used. However, reinterpret_cast cannot be used to convert
169-
uintptr_t to a different integer type, such as CUdevice. For this,
170-
static_cast must be used. This function must employ a cast that is capable
171-
of reinterpret_cast and static_cast depending on the arguments passed to
172-
it. A C-style cast will achieve this. The compiler will attempt to
173-
interpret it as a static_cast, and will fall back to reinterpret_cast
174-
where appropriate.
175-
176-
https://en.cppreference.com/w/cpp/language/reinterpret_cast
177-
https://en.cppreference.com/w/cpp/language/explicit_cast
178-
*/
179-
return (backend_return_t<Backend, buffer<DataT, Dims>>)(getNativeMem(Req));
161+
std::vector<pi_native_handle> NativeHandles{getNativeMem(Req)};
162+
return detail::BufferInterop<Backend, DataT, Dims>::GetNativeObjs(
163+
NativeHandles);
180164
}
181165

182166
__SYCL_EXPORT pi_native_handle getNativeMem(detail::Requirement *Req) const;

sycl/source/detail/buffer_impl.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,53 @@ void buffer_impl::constructorNotification(const detail::code_location &CodeLoc,
4848
void buffer_impl::destructorNotification(void *UserObj) {
4949
XPTIRegistry::bufferDestructorNotification(UserObj);
5050
}
51+
52+
void buffer_impl::addInteropObject(
53+
std::vector<pi_native_handle> &Handles) const {
54+
if (MOpenCLInterop) {
55+
if (std::find(Handles.begin(), Handles.end(),
56+
pi::cast<pi_native_handle>(MInteropMemObject)) ==
57+
Handles.end()) {
58+
const plugin &Plugin = getPlugin();
59+
Plugin.call<PiApiKind::piMemRetain>(
60+
pi::cast<RT::PiMem>(MInteropMemObject));
61+
Handles.push_back(pi::cast<pi_native_handle>(MInteropMemObject));
62+
}
63+
}
64+
}
65+
66+
std::vector<pi_native_handle>
67+
buffer_impl::getNativeVector(backend BackendName) const {
68+
std::vector<pi_native_handle> Handles{};
69+
if (!MRecord) {
70+
addInteropObject(Handles);
71+
return Handles;
72+
}
73+
74+
for (auto &Cmd : MRecord->MAllocaCommands) {
75+
RT::PiMem NativeMem = pi::cast<RT::PiMem>(Cmd->getMemAllocation());
76+
auto Ctx = Cmd->getWorkerContext();
77+
auto Platform = Ctx->getPlatformImpl();
78+
// If Host Shared Memory is not supported then there is alloca for host that
79+
// doesn't have platform
80+
if (!Platform)
81+
continue;
82+
auto Plugin = Platform->getPlugin();
83+
84+
if (Plugin.getBackend() != BackendName)
85+
continue;
86+
if (Plugin.getBackend() == backend::opencl) {
87+
Plugin.call<PiApiKind::piMemRetain>(NativeMem);
88+
}
89+
90+
pi_native_handle Handle;
91+
Plugin.call<PiApiKind::piextMemGetNativeHandle>(NativeMem, &Handle);
92+
Handles.push_back(Handle);
93+
}
94+
95+
addInteropObject(Handles);
96+
return Handles;
97+
}
5198
} // namespace detail
5299
} // namespace sycl
53100
} // __SYCL_INLINE_NAMESPACE(cl)

sycl/test/abi/sycl_symbols_linux.dump

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4156,6 +4156,8 @@ _ZNK2cl4sycl6detail10image_implILi3EE9get_countEv
41564156
_ZNK2cl4sycl6detail10image_implILi3EE9get_rangeEv
41574157
_ZNK2cl4sycl6detail11SYCLMemObjT9getPluginEv
41584158
_ZNK2cl4sycl6detail11SYCLMemObjT9isInteropEv
4159+
_ZNK2cl4sycl6detail11buffer_impl15getNativeVectorENS0_7backendE
4160+
_ZNK2cl4sycl6detail11buffer_impl16addInteropObjectERSt6vectorImSaImEE
41594161
_ZNK2cl4sycl6detail11stream_impl22get_max_statement_sizeEv
41604162
_ZNK2cl4sycl6detail11stream_impl8get_sizeEv
41614163
_ZNK2cl4sycl6detail12sampler_impl18get_filtering_modeEv

sycl/test/abi/sycl_symbols_windows.dump

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1095,6 +1095,7 @@
10951095
?acospi@__host_std@cl@@YANN@Z
10961096
?add@device_global_map@detail@sycl@cl@@YAXPEBXPEBD@Z
10971097
?addHostAccessorAndWait@detail@sycl@cl@@YAXPEAVAccessorImplHost@123@@Z
1098+
?addInteropObject@buffer_impl@detail@sycl@cl@@QEBAXAEAV?$vector@_KV?$allocator@_K@std@@@std@@@Z
10981099
?addOrReplaceAccessorProperties@SYCLMemObjT@detail@sycl@cl@@QEAAXAEBVproperty_list@34@@Z
10991100
?addReduction@handler@sycl@cl@@AEAAXAEBV?$shared_ptr@$$CBX@std@@@Z
11001101
?addStream@handler@sycl@cl@@AEAAXAEBV?$shared_ptr@Vstream_impl@detail@sycl@cl@@@std@@@Z
@@ -2193,6 +2194,7 @@
21932194
?getNativeImpl@kernel@sycl@cl@@AEBA_KXZ
21942195
?getNativeMem@interop_handle@sycl@cl@@AEBA_KPEAVAccessorImplHost@detail@23@@Z
21952196
?getNativeQueue@interop_handle@sycl@cl@@AEBA_KXZ
2197+
?getNativeVector@buffer_impl@detail@sycl@cl@@QEBA?AV?$vector@_KV?$allocator@_K@std@@@std@@W4backend@34@@Z
21962198
?getNativeVector@event@sycl@cl@@AEBA?AV?$vector@_KV?$allocator@_K@std@@@std@@XZ
21972199
?getOSMemSize@OSUtil@detail@sycl@cl@@SA_KXZ
21982200
?getOSModuleHandle@OSUtil@detail@sycl@cl@@SA_JPEBX@Z

sycl/unittests/SYCL2020/GetNativeOpenCL.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include <helpers/CommonRedefinitions.hpp>
1717
#include <helpers/PiMock.hpp>
18+
#include <helpers/TestKernel.hpp>
1819

1920
#include <gtest/gtest.h>
2021

@@ -52,6 +53,17 @@ static pi_result redefinedEventRetain(pi_event c) {
5253
return PI_SUCCESS;
5354
}
5455

56+
static pi_result redefinedMemRetain(pi_mem c) {
57+
++TestCounter;
58+
return PI_SUCCESS;
59+
}
60+
61+
pi_result redefinedMemBufferCreate(pi_context, pi_mem_flags, size_t size,
62+
void *, pi_mem *,
63+
const pi_mem_properties *) {
64+
return PI_SUCCESS;
65+
}
66+
5567
pi_result redefinedEventGetInfo(pi_event event, pi_event_info param_name,
5668
size_t param_value_size, void *param_value,
5769
size_t *param_value_size_ret) {
@@ -93,6 +105,9 @@ TEST(GetNative, GetNativeHandle) {
93105
Mock.redefine<detail::PiApiKind::piDeviceRetain>(redefinedDeviceRetain);
94106
Mock.redefine<detail::PiApiKind::piProgramRetain>(redefinedProgramRetain);
95107
Mock.redefine<detail::PiApiKind::piEventRetain>(redefinedEventRetain);
108+
Mock.redefine<detail::PiApiKind::piMemRetain>(redefinedMemRetain);
109+
Mock.redefine<sycl::detail::PiApiKind::piMemBufferCreate>(
110+
redefinedMemBufferCreate);
96111
Mock.redefine<detail::PiApiKind::piextUSMEnqueueMemset>(
97112
redefinedUSMEnqueueMemset);
98113

@@ -108,14 +123,22 @@ TEST(GetNative, GetNativeHandle) {
108123
unsigned char *HostAlloc = (unsigned char *)malloc_host(1, Context);
109124
auto Event = Queue.memset(HostAlloc, 42, 1);
110125

126+
int Data[1] = {0};
127+
sycl::buffer<int, 1> Buffer(&Data[0], sycl::range<1>(1));
128+
Queue.submit([&](sycl::handler &cgh) {
129+
auto Acc = Buffer.get_access<sycl::access::mode::read_write>(cgh);
130+
cgh.single_task<TestKernel>([=]() { (void)Acc; });
131+
});
132+
111133
get_native<backend::opencl>(Context);
112134
get_native<backend::opencl>(Queue);
113135
get_native<backend::opencl>(Program);
114136
get_native<backend::opencl>(Device);
115137
get_native<backend::opencl>(Event);
138+
get_native<backend::opencl>(Buffer);
116139

117140
// Depending on global caches state, piDeviceRetain is called either once or
118-
// twice, so there'll be 5 or 6 calls.
119-
ASSERT_EQ(TestCounter, 5 + DeviceRetainCounter - 1)
141+
// twice, so there'll be 6 or 7 calls.
142+
ASSERT_EQ(TestCounter, 6 + DeviceRetainCounter - 1)
120143
<< "Not all the retain methods were called";
121144
}

0 commit comments

Comments
 (0)