DPC++ Runtime
Runtime libraries for oneAPI DPC++
backend.hpp
Go to the documentation of this file.
1 //==---------------- backend.hpp - SYCL UR backends ------------------------==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #pragma once
10 
11 #include <sycl/access/access.hpp> // for mode, placeholder
12 #include <sycl/accessor.hpp> // for accessor
13 #include <sycl/async_handler.hpp> // for async_handler
14 #include <sycl/backend_types.hpp> // for backend
15 #include <sycl/buffer.hpp> // for buffer_allocator
16 #include <sycl/context.hpp> // for context, get_na...
17 #include <sycl/detail/backend_traits.hpp> // for InteropFeatureS...
18 #include <sycl/detail/cl.h> // for _cl_event
19 #include <sycl/detail/defines_elementary.hpp> // for __SYCL_DEPRECATED
20 #include <sycl/detail/export.hpp> // for __SYCL_EXPORT
21 #include <sycl/detail/impl_utils.hpp> // for createSyclObjFr...
22 #include <sycl/device.hpp> // for device, get_native
23 #include <sycl/event.hpp> // for event, get_native
24 #include <sycl/exception.hpp> // for make_error_code
25 #include <sycl/feature_test.hpp> // for SYCL_BACKEND_OP...
26 #include <sycl/handler.hpp> // for buffer
27 #include <sycl/image.hpp> // for image, image_al...
28 #include <sycl/kernel.hpp> // for kernel, get_native
29 #include <sycl/kernel_bundle.hpp> // for kernel_bundle
30 #include <sycl/kernel_bundle_enums.hpp> // for bundle_state
31 #include <sycl/platform.hpp> // for platform, get_n...
32 #include <sycl/property_list.hpp> // for property_list
33 #include <sycl/queue.hpp> // for queue, get_native
34 #include <ur_api.h> // for ur_native_handle_t
35 
36 #if SYCL_BACKEND_OPENCL
37 #include <sycl/detail/backend_traits_opencl.hpp> // for interop
38 #endif
39 #if SYCL_EXT_ONEAPI_BACKEND_CUDA
40 #ifdef SYCL_EXT_ONEAPI_BACKEND_CUDA_EXPERIMENTAL
42 #else
44 #endif
45 #endif
46 #if SYCL_EXT_ONEAPI_BACKEND_HIP
48 #endif
49 #if SYCL_EXT_ONEAPI_BACKEND_LEVEL_ZERO
50 #include <sycl/detail/backend_traits_level_zero.hpp> // for _ze_command_lis...
51 #endif
52 
53 #include <sycl/detail/ur.hpp>
54 
55 #include <memory> // for shared_ptr
56 #include <stdint.h> // for int32_t
57 #include <type_traits> // for enable_if_t
58 #include <vector> // for vector
59 
60 namespace sycl {
61 inline namespace _V1 {
62 
63 namespace detail {
64 // TODO each backend can have its own custom errc enumeration
65 // but the details for this are not fully specified yet
66 enum class backend_errc : unsigned int {};
67 
68 // Convert from UR backend to SYCL backend enum
69 backend convertUrBackend(ur_platform_backend_t UrBackend);
70 } // namespace detail
71 
72 template <backend Backend> class backend_traits {
73 public:
74  template <class T>
76 
77  template <class T>
79 };
80 
81 template <backend Backend, typename SyclType>
83  typename backend_traits<Backend>::template input_type<SyclType>;
84 
85 template <backend Backend, typename SyclType>
87  typename backend_traits<Backend>::template return_type<SyclType>;
88 
89 namespace detail {
90 template <backend Backend, typename DataT, int Dimensions, typename AllocatorT>
91 struct BufferInterop {
92  using ReturnType =
94 
95  static ReturnType
96  GetNativeObjs(const std::vector<ur_native_handle_t> &Handle) {
97  ReturnType ReturnValue = 0;
98  if (Handle.size()) {
99  ReturnValue = detail::ur::cast<ReturnType>(Handle[0]);
100  }
101  return ReturnValue;
102  }
103 };
104 
105 template <typename DataT, int Dimensions, typename AllocatorT>
106 struct BufferInterop<backend::opencl, DataT, Dimensions, AllocatorT> {
107  using ReturnType =
109 
110  static ReturnType
111  GetNativeObjs(const std::vector<ur_native_handle_t> &Handle) {
112  ReturnType ReturnValue{};
113  for (auto &Obj : Handle) {
114  ReturnValue.push_back(
115  detail::ur::cast<typename decltype(ReturnValue)::value_type>(Obj));
116  }
117  return ReturnValue;
118  }
119 };
120 
121 #if SYCL_EXT_ONEAPI_BACKEND_LEVEL_ZERO
122 template <backend BackendName, typename DataT, int Dimensions,
123  typename AllocatorT>
125  -> backend_return_t<BackendName,
127  // No check for backend mismatch because buffer can be allocated on different
128  // backends
129  if (BackendName == backend::ext_oneapi_level_zero)
131  "Buffer interop is not supported by level zero yet");
132  return Obj.template getNative<BackendName>();
133 }
134 #endif
135 } // namespace detail
136 
137 template <backend BackendName, class SyclObjectT>
138 auto get_native(const SyclObjectT &Obj)
140  if (Obj.get_backend() != BackendName) {
142  "Backends mismatch");
143  }
144  return reinterpret_cast<backend_return_t<BackendName, SyclObjectT>>(
145  Obj.getNative());
146 }
147 
148 template <backend BackendName>
150  if (Obj.get_backend() != BackendName) {
152  "Backends mismatch");
153  }
154  int32_t IsImmCmdList;
155  ur_native_handle_t Handle = Obj.getNative(IsImmCmdList);
157  if constexpr (BackendName == backend::ext_oneapi_level_zero)
158  RetVal = IsImmCmdList
159  ? backend_return_t<BackendName, queue>{reinterpret_cast<
160  ze_command_list_handle_t>(Handle)}
162  reinterpret_cast<ze_command_queue_handle_t>(Handle)};
163  else
164  RetVal = reinterpret_cast<backend_return_t<BackendName, queue>>(Handle);
165 
166  return RetVal;
167 }
168 
169 template <backend BackendName, bundle_state State>
172  if (Obj.get_backend() != BackendName) {
174  "Backends mismatch");
175  }
176  return Obj.template getNative<BackendName>();
177 }
178 
179 template <backend BackendName, typename DataT, int Dimensions,
180  typename AllocatorT>
183  return detail::get_native_buffer<BackendName>(Obj);
184 }
185 
186 #if SYCL_BACKEND_OPENCL
187 template <>
188 inline backend_return_t<backend::opencl, event>
189 get_native<backend::opencl, event>(const event &Obj) {
190  if (Obj.get_backend() != backend::opencl) {
192  "Backends mismatch");
193  }
194  backend_return_t<backend::opencl, event> ReturnValue;
195  for (auto const &element : Obj.getNativeVector()) {
196  ReturnValue.push_back(
197  reinterpret_cast<
199  element));
200  }
201  return ReturnValue;
202 }
203 #endif
204 
205 #if SYCL_EXT_ONEAPI_BACKEND_CUDA
206 template <>
207 inline backend_return_t<backend::ext_oneapi_cuda, device>
208 get_native<backend::ext_oneapi_cuda, device>(const device &Obj) {
209  if (Obj.get_backend() != backend::ext_oneapi_cuda) {
211  "Backends mismatch");
212  }
213  // CUDA uses a 32-bit int instead of an opaque pointer like other backends,
214  // so we need a specialization with static_cast instead of reinterpret_cast.
215  return static_cast<backend_return_t<backend::ext_oneapi_cuda, device>>(
216  Obj.getNative());
217 }
218 
219 #ifndef SYCL_EXT_ONEAPI_BACKEND_CUDA_EXPERIMENTAL
220 template <>
222  "Context interop is deprecated for CUDA. If a native context is required,"
223  " use cuDevicePrimaryCtxRetain with a native device")
224 inline backend_return_t<backend::ext_oneapi_cuda, context> get_native<
225  backend::ext_oneapi_cuda, context>(const context &Obj) {
226  if (Obj.get_backend() != backend::ext_oneapi_cuda) {
228  "Backends mismatch");
229  }
230  return reinterpret_cast<backend_return_t<backend::ext_oneapi_cuda, context>>(
231  Obj.getNative());
232 }
233 
234 #endif // SYCL_EXT_ONEAPI_BACKEND_CUDA_EXPERIMENTAL
235 #endif // SYCL_EXT_ONEAPI_BACKEND_CUDA
236 
237 #if SYCL_EXT_ONEAPI_BACKEND_HIP
238 
239 template <>
241  "Context interop is deprecated for HIP. If a native context is required,"
242  " use hipDevicePrimaryCtxRetain with a native device")
243 inline backend_return_t<backend::ext_oneapi_hip, context> get_native<
244  backend::ext_oneapi_hip, context>(const context &Obj) {
245  if (Obj.get_backend() != backend::ext_oneapi_hip) {
247  "Backends mismatch");
248  }
249  return reinterpret_cast<backend_return_t<backend::ext_oneapi_hip, context>>(
250  Obj.getNative());
251 }
252 
253 #endif // SYCL_EXT_ONEAPI_BACKEND_HIP
254 
255 template <backend BackendName, typename DataT, int Dimensions,
256  access::mode AccessMode, access::target AccessTarget,
258 auto get_native(const accessor<DataT, Dimensions, AccessMode, AccessTarget,
259  IsPlaceholder> &Obj) ->
260  typename detail::interop<
261  BackendName, accessor<DataT, Dimensions, AccessMode, AccessTarget,
262  IsPlaceholder>>::type = delete;
263 
264 namespace detail {
265 // Forward declaration
266 class kernel_bundle_impl;
267 
268 __SYCL_EXPORT platform make_platform(ur_native_handle_t NativeHandle,
269  backend Backend);
270 __SYCL_EXPORT device make_device(ur_native_handle_t NativeHandle,
271  backend Backend);
272 __SYCL_EXPORT context make_context(ur_native_handle_t NativeHandle,
273  const async_handler &Handler,
274  backend Backend, bool KeepOwnership,
275  const std::vector<device> &DeviceList = {});
276 __SYCL_EXPORT queue make_queue(ur_native_handle_t NativeHandle,
277  int32_t nativeHandleDesc,
278  const context &TargetContext,
279  const device *TargetDevice, bool KeepOwnership,
280  const property_list &PropList,
281  const async_handler &Handler, backend Backend);
282 __SYCL_EXPORT event make_event(ur_native_handle_t NativeHandle,
283  const context &TargetContext, backend Backend);
284 __SYCL_EXPORT event make_event(ur_native_handle_t NativeHandle,
285  const context &TargetContext, bool KeepOwnership,
286  backend Backend);
287 // TODO: Unused. Remove when allowed.
288 __SYCL_EXPORT kernel make_kernel(ur_native_handle_t NativeHandle,
289  const context &TargetContext, backend Backend);
290 __SYCL_EXPORT kernel make_kernel(
291  const context &TargetContext,
292  const kernel_bundle<bundle_state::executable> &KernelBundle,
293  ur_native_handle_t NativeKernelHandle, bool KeepOwnership, backend Backend);
294 // TODO: Unused. Remove when allowed.
295 __SYCL_EXPORT std::shared_ptr<detail::kernel_bundle_impl>
296 make_kernel_bundle(ur_native_handle_t NativeHandle,
297  const context &TargetContext, bundle_state State,
298  backend Backend);
299 __SYCL_EXPORT std::shared_ptr<detail::kernel_bundle_impl>
300 make_kernel_bundle(ur_native_handle_t NativeHandle,
301  const context &TargetContext, bool KeepOwnership,
302  bundle_state State, backend Backend);
303 } // namespace detail
304 
305 template <backend Backend>
306 std::enable_if_t<
309  const typename backend_traits<Backend>::template input_type<platform>
310  &BackendObject) {
311  return detail::make_platform(
312  detail::ur::cast<ur_native_handle_t>(BackendObject), Backend);
313 }
314 
315 template <backend Backend>
316 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeDevice == true,
317  device>
318 make_device(const typename backend_traits<Backend>::template input_type<device>
319  &BackendObject) {
320  for (auto p : platform::get_platforms()) {
321  if (p.get_backend() != Backend)
322  continue;
323 
324  for (auto d : p.get_devices()) {
325  if (get_native<Backend>(d) == BackendObject)
326  return d;
327  }
328  }
329 
330  return detail::make_device(
331  detail::ur::cast<ur_native_handle_t>(BackendObject), Backend);
332 }
333 
334 template <backend Backend>
335 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeContext == true,
336  context>
338  const typename backend_traits<Backend>::template input_type<context>
339  &BackendObject,
340  const async_handler &Handler = {}) {
341  return detail::make_context(
342  detail::ur::cast<ur_native_handle_t>(BackendObject), Handler, Backend,
343  false /* KeepOwnership */);
344 }
345 
346 template <backend Backend>
347 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeQueue == true,
348  queue>
349 make_queue(const typename backend_traits<Backend>::template input_type<queue>
350  &BackendObject,
351  const context &TargetContext, const async_handler Handler = {}) {
352  auto KeepOwnership =
353  Backend == backend::ext_oneapi_cuda || Backend == backend::ext_oneapi_hip;
354  return detail::make_queue(detail::ur::cast<ur_native_handle_t>(BackendObject),
355  false, TargetContext, nullptr, KeepOwnership, {},
356  Handler, Backend);
357 }
358 
359 template <backend Backend>
360 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeEvent == true,
361  event>
362 make_event(const typename backend_traits<Backend>::template input_type<event>
363  &BackendObject,
364  const context &TargetContext) {
365  return detail::make_event(detail::ur::cast<ur_native_handle_t>(BackendObject),
366  TargetContext, Backend);
367 }
368 
369 template <backend Backend>
370 __SYCL_DEPRECATED("Use SYCL 2020 sycl::make_event free function")
371 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeEvent == true,
372  event> make_event(const typename backend_traits<Backend>::
373  template input_type<event>
374  &BackendObject,
375  const context &TargetContext,
376  bool KeepOwnership) {
377  return detail::make_event(detail::ur::cast<ur_native_handle_t>(BackendObject),
378  TargetContext, KeepOwnership, Backend);
379 }
380 
381 template <backend Backend, typename T, int Dimensions = 1,
382  typename AllocatorT = buffer_allocator<std::remove_const_t<T>>>
383 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeBuffer ==
384  true &&
386  buffer<T, Dimensions, AllocatorT>>
388  buffer<T, Dimensions, AllocatorT>> &BackendObject,
389  const context &TargetContext, event AvailableEvent = {}) {
390  return detail::make_buffer_helper<T, Dimensions, AllocatorT>(
391  detail::ur::cast<ur_native_handle_t>(BackendObject), TargetContext,
392  AvailableEvent);
393 }
394 
395 template <backend Backend, int Dimensions = 1,
396  typename AllocatorT = image_allocator>
397 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeImage == true &&
399  image<Dimensions, AllocatorT>>
401  image<Dimensions, AllocatorT>> &BackendObject,
402  const context &TargetContext, event AvailableEvent = {}) {
403  return image<Dimensions, AllocatorT>(
404  detail::ur::cast<ur_native_handle_t>(BackendObject), TargetContext,
405  AvailableEvent);
406 }
407 
408 template <backend Backend>
409 kernel
410 make_kernel(const typename backend_traits<Backend>::template input_type<kernel>
411  &BackendObject,
412  const context &TargetContext) {
413  return detail::make_kernel(
414  detail::ur::cast<ur_native_handle_t>(BackendObject), TargetContext,
415  Backend);
416 }
417 
418 template <backend Backend, bundle_state State>
419 std::enable_if_t<detail::InteropFeatureSupportMap<Backend>::MakeKernelBundle ==
420  true,
421  kernel_bundle<State>>
423  kernel_bundle<State>> &BackendObject,
424  const context &TargetContext) {
425  std::shared_ptr<detail::kernel_bundle_impl> KBImpl =
427  detail::ur::cast<ur_native_handle_t>(BackendObject), TargetContext,
428  false, State, Backend);
429  return detail::createSyclObjFromImpl<kernel_bundle<State>>(KBImpl);
430 }
431 } // namespace _V1
432 } // namespace sycl
The file contains implementations of accessor class.
struct _ze_command_queue_handle_t * ze_command_queue_handle_t
struct _ze_command_list_handle_t * ze_command_list_handle_t
typename detail::BackendReturn< Backend, T >::type return_type
Definition: backend.hpp:78
typename detail::BackendInput< Backend, T >::type input_type
Definition: backend.hpp:75
Defines a shared array that can be used by kernels in queues.
Definition: buffer.hpp:173
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:50
The SYCL device class encapsulates a single SYCL device on which kernels may be executed.
Definition: device.hpp:64
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:44
Defines a shared image data.
Definition: image.hpp:449
The kernel_bundle class represents collection of device images in a particular state.
Provides an abstraction of a SYCL kernel.
Definition: kernel.hpp:71
Encapsulates a SYCL platform on which kernels may be executed.
Definition: platform.hpp:99
static std::vector< platform > get_platforms()
Returns all available SYCL platforms in the system.
Definition: platform.cpp:51
Objects of the property_list class are containers for the SYCL properties.
Encapsulates a single SYCL queue which schedules kernels on a SYCL device.
Definition: queue.hpp:110
#define __SYCL_DEPRECATED(message)
To cast(std::vector< cl_event > value)
queue make_queue(ur_native_handle_t NativeHandle, int32_t nativeHandleDesc, const context &TargetContext, const device *TargetDevice, bool KeepOwnership, const property_list &PropList, const async_handler &Handler, backend Backend)
Definition: backend.cpp:116
context make_context(ur_native_handle_t NativeHandle, const async_handler &Handler, backend Backend, bool KeepOwnership, const std::vector< device > &DeviceList={})
Definition: backend.cpp:94
auto get_native_buffer(const buffer< DataT, Dimensions, Allocator, void > &Obj) -> backend_return_t< BackendName, buffer< DataT, Dimensions, Allocator, void >>
std::shared_ptr< detail::kernel_bundle_impl > make_kernel_bundle(ur_native_handle_t NativeHandle, const context &TargetContext, bundle_state State, backend Backend)
Definition: backend.cpp:303
device make_device(ur_native_handle_t NativeHandle, backend Backend)
Definition: backend.cpp:82
backend convertUrBackend(ur_platform_backend_t UrBackend)
Definition: backend.cpp:50
event make_event(ur_native_handle_t NativeHandle, const context &TargetContext, backend Backend)
Definition: backend.cpp:161
kernel make_kernel(ur_native_handle_t NativeHandle, const context &TargetContext, backend Backend)
Definition: backend.cpp:354
platform make_platform(ur_native_handle_t NativeHandle, backend Backend)
Definition: backend.cpp:70
sycl::detail::kernel_bundle_impl kernel_bundle_impl
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakeQueue==true, queue > make_queue(const typename backend_traits< Backend >::template input_type< queue > &BackendObject, const context &TargetContext, const async_handler Handler={})
Definition: backend.hpp:349
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakeDevice==true, device > make_device(const typename backend_traits< Backend >::template input_type< device > &BackendObject)
Definition: backend.hpp:318
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakeKernelBundle==true, kernel_bundle< State > > make_kernel_bundle(const typename backend_traits< Backend >::template input_type< kernel_bundle< State >> &BackendObject, const context &TargetContext)
Definition: backend.hpp:422
class __SYCL_EBO __SYCL_SPECIAL_CLASS Dimensions
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakeEvent==true, event > make_event(const typename backend_traits< Backend >::template input_type< event > &BackendObject, const context &TargetContext)
Definition: backend.hpp:362
auto get_native(const SyclObjectT &Obj) -> backend_return_t< BackendName, SyclObjectT >
Definition: backend.hpp:138
typename backend_traits< Backend >::template return_type< SyclType > backend_return_t
Definition: backend.hpp:87
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakeImage==true &&Backend !=backend::ext_oneapi_level_zero, image< Dimensions, AllocatorT > > make_image(const typename backend_traits< Backend >::template input_type< image< Dimensions, AllocatorT >> &BackendObject, const context &TargetContext, event AvailableEvent={})
Definition: backend.hpp:400
class __SYCL_EBO __SYCL_SPECIAL_CLASS IsPlaceholder
kernel make_kernel(const typename backend_traits< Backend >::template input_type< kernel > &BackendObject, const context &TargetContext)
Definition: backend.hpp:410
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakePlatform==true, platform > make_platform(const typename backend_traits< Backend >::template input_type< platform > &BackendObject)
Definition: backend.hpp:308
std::function< void(sycl::exception_list)> async_handler
class __SYCL_EBO __SYCL_SPECIAL_CLASS AccessMode
detail::aligned_allocator< byte > image_allocator
Definition: image.hpp:109
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakeContext==true, context > make_context(const typename backend_traits< Backend >::template input_type< context > &BackendObject, const async_handler &Handler={})
Definition: backend.hpp:337
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:65
std::enable_if_t< detail::InteropFeatureSupportMap< Backend >::MakeBuffer==true &&Backend !=backend::ext_oneapi_level_zero, buffer< T, Dimensions, AllocatorT > > make_buffer(const typename backend_traits< Backend >::template input_type< buffer< T, Dimensions, AllocatorT >> &BackendObject, const context &TargetContext, event AvailableEvent={})
Definition: backend.hpp:387
typename backend_traits< Backend >::template input_type< SyclType > backend_input_t
Definition: backend.hpp:83
const void value_type
Definition: multi_ptr.hpp:457
Definition: access.hpp:18
static ReturnType GetNativeObjs(const std::vector< ur_native_handle_t > &Handle)
Definition: backend.hpp:111
backend_return_t< backend::opencl, buffer< DataT, Dimensions, AllocatorT > > ReturnType
Definition: backend.hpp:108
backend_return_t< Backend, buffer< DataT, Dimensions, AllocatorT > > ReturnType
Definition: backend.hpp:93
static ReturnType GetNativeObjs(const std::vector< ur_native_handle_t > &Handle)
Definition: backend.hpp:96
C++ utilities for Unified Runtime integration.