DPC++ Runtime
Runtime libraries for oneAPI DPC++
buffer.hpp
Go to the documentation of this file.
1 //==----------- buffer.hpp --- SYCL buffer ---------------------------------==//
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 placeholder
12 #include <sycl/backend_types.hpp> // for backend, backe...
13 #include <sycl/context.hpp> // for context
14 #include <sycl/detail/array.hpp> // for array
15 #include <sycl/detail/common.hpp> // for code_location
16 #include <sycl/detail/defines_elementary.hpp> // for __SYCL2020_DEP...
17 #include <sycl/detail/export.hpp> // for __SYCL_EXPORT
18 #include <sycl/detail/helpers.hpp> // for buffer_impl
19 #include <sycl/detail/owner_less_base.hpp> // for OwnerLessBase
20 #include <sycl/detail/pi.h> // for pi_native_handle and PI_ERROR_INVAL
21 #include <sycl/detail/property_helper.hpp> // for PropWithDataKind
22 #include <sycl/detail/stl_type_traits.hpp> // for iterator_value...
23 #include <sycl/detail/stl_type_traits.hpp> // for iterator_to_const_type_t
24 #include <sycl/detail/sycl_mem_obj_allocator.hpp> // for SYCLMemObjAllo...
25 #include <sycl/detail/type_traits.hpp> // for remove_pointer_t
26 #include <sycl/event.hpp> // for event
27 #include <sycl/exception.hpp> // for invalid_object...
28 #include <sycl/ext/oneapi/accessor_property_list.hpp> // for accessor_prope...
29 #include <sycl/id.hpp> // for id
30 #include <sycl/property_list.hpp> // for property_list
31 #include <sycl/range.hpp> // for range, rangeTo...
32 #include <sycl/stl.hpp> // for make_unique_ptr
33 #include <sycl/types.hpp> // for is_device_copyable
34 
35 #include <cstddef> // for size_t, nullptr_t
36 #include <functional> // for function
37 #include <iterator> // for iterator_traits
38 #include <memory> // for shared_ptr
39 #include <stdint.h> // for uint32_t
40 #include <string> // for string
41 #include <type_traits> // for enable_if_t
42 #include <typeinfo> // for type_info
43 #include <utility> // for declval, move
44 #include <variant> // for hash
45 #include <vector> // for vector
46 
47 namespace sycl {
48 inline namespace _V1 {
49 
50 class handler;
51 class queue;
52 template <int dimensions> class range;
53 
54 template <typename DataT>
55 using buffer_allocator = detail::sycl_memory_object_allocator<DataT>;
56 
57 template <typename DataT, int Dimensions, access::mode AccessMode>
58 class host_accessor;
59 
60 template <typename T, int Dimensions, typename AllocatorT, typename Enable>
61 class buffer;
62 
63 namespace ext::oneapi {
64 template <typename SYCLObjT> class weak_object;
65 } // namespace ext::oneapi
66 
67 namespace detail {
68 
69 class buffer_impl;
70 
71 template <typename T, int Dimensions, typename AllocatorT>
73 make_buffer_helper(pi_native_handle Handle, const context &Ctx, event Evt = {},
74  bool OwnNativeHandle = true) {
75  return buffer<T, Dimensions, AllocatorT, void>(Handle, Ctx, OwnNativeHandle,
76  Evt);
77 }
78 
79 template <backend BackendName, typename DataT, int Dimensions,
80  typename Allocator>
82  -> backend_return_t<BackendName,
84 
85 template <backend Backend, typename DataT, int Dimensions,
86  typename AllocatorT = buffer_allocator<std::remove_const_t<DataT>>>
87 struct BufferInterop;
88 
89 // The non-template base for the sycl::buffer class
90 class __SYCL_EXPORT buffer_plain {
91 protected:
92  buffer_plain(size_t SizeInBytes, size_t, const property_list &Props,
93  std::unique_ptr<detail::SYCLMemObjAllocator> Allocator);
94 
95  buffer_plain(void *HostData, size_t SizeInBytes, size_t RequiredAlign,
96  const property_list &Props,
97  std::unique_ptr<detail::SYCLMemObjAllocator> Allocator);
98 
99  buffer_plain(const void *HostData, size_t SizeInBytes, size_t RequiredAlign,
100  const property_list &Props,
101  std::unique_ptr<detail::SYCLMemObjAllocator> Allocator);
102 
103  buffer_plain(const std::shared_ptr<const void> &HostData,
104  const size_t SizeInBytes, size_t RequiredAlign,
105  const property_list &Props,
106  std::unique_ptr<detail::SYCLMemObjAllocator> Allocator,
107  bool IsConstPtr);
108 
109  buffer_plain(const std::function<void(void *)>
110  &CopyFromInput, // EnableIfNotConstIterator<InputIterator>
111  // First, InputIterator Last,
112  const size_t SizeInBytes, size_t RequiredAlign,
113  const property_list &Props,
114  std::unique_ptr<detail::SYCLMemObjAllocator> Allocator,
115  bool IsConstPtr);
116 
117  buffer_plain(pi_native_handle MemObject, context SyclContext,
118  std::unique_ptr<detail::SYCLMemObjAllocator> Allocator,
119  bool OwnNativeHandle, event AvailableEvent);
120 
121  buffer_plain(const std::shared_ptr<detail::buffer_impl> &impl) : impl(impl) {}
122 
123  void set_final_data_internal();
124 
125  void set_final_data_internal(
126  const std::function<void(const std::function<void(void *const Ptr)> &)>
127  &FinalDataFunc);
128 
129  void set_write_back(bool NeedWriteBack);
130 
132  void *UserObj, const void *HostObj,
133  const void *Type, uint32_t Dim,
134  uint32_t ElemType, size_t Range[3]);
135 
136  template <typename propertyT> bool has_property() const noexcept;
137 
138  template <typename propertyT> propertyT get_property() const;
139 
140  std::vector<pi_native_handle> getNativeVector(backend BackendName) const;
141 
142  const std::unique_ptr<SYCLMemObjAllocator> &get_allocator_internal() const;
143 
144  void deleteAccProps(const sycl::detail::PropWithDataKind &Kind);
145 
146  void addOrReplaceAccessorProperties(const property_list &PropertyList);
147 
148  size_t getSize() const;
149 
150  void handleRelease() const;
151 
152  std::shared_ptr<detail::buffer_impl> impl;
153 };
154 
155 } // namespace detail
156 
165 template <typename T, int dimensions = 1,
166  typename AllocatorT = buffer_allocator<std::remove_const_t<T>>,
167  typename __Enabled =
168  typename std::enable_if_t<(dimensions > 0) && (dimensions <= 3)>>
169 class buffer : public detail::buffer_plain,
170  public detail::OwnerLessBase<buffer<T, dimensions, AllocatorT>> {
171 #ifdef __INTEL_PREVIEW_BREAKING_CHANGES
172  static_assert(is_device_copyable_v<T>,
173  "Underlying type of a buffer must be device copyable!");
174 #else
175  static_assert(!std::is_same_v<T, std::string>,
176  "'std::string' is not a device copyable type");
177 #endif
178 
179 public:
180  using value_type = T;
182  using const_reference = const value_type &;
183  using allocator_type = AllocatorT;
184  template <int dims>
185  using EnableIfOneDimension = typename std::enable_if_t<1 == dims>;
186  // using same requirement for contiguous container as std::span
187  template <class Container>
189  std::void_t<std::enable_if_t<std::is_convertible_v<
191  decltype(std::declval<Container>().data())> (*)[],
192  const T (*)[]>>,
193  decltype(std::declval<Container>().size())>;
194  template <class It>
195  using EnableIfItInputIterator = std::enable_if_t<std::is_convertible_v<
196  typename std::iterator_traits<It>::iterator_category,
197  std::input_iterator_tag>>;
198  template <typename ItA, typename ItB>
199  using EnableIfSameNonConstIterators = typename std::enable_if_t<
200  std::is_same_v<ItA, ItB> && !std::is_const_v<ItA>, ItA>;
201 
202  buffer(const range<dimensions> &bufferRange,
203  const property_list &propList = {},
205  : buffer_plain(bufferRange.size() * sizeof(T), alignof(T), propList,
208  Range(bufferRange) {
210  CodeLoc, (void *)impl.get(), nullptr, (const void *)typeid(T).name(),
211  dimensions, sizeof(T), detail::rangeToArray(Range).data());
212  }
213 
214  buffer(const range<dimensions> &bufferRange, AllocatorT allocator,
215  const property_list &propList = {},
217  : buffer_plain(
218  bufferRange.size() * sizeof(T), alignof(T), propList,
219  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
220  allocator)),
221  Range(bufferRange) {
223  CodeLoc, (void *)impl.get(), nullptr, (const void *)typeid(T).name(),
224  dimensions, sizeof(T), detail::rangeToArray(Range).data());
225  }
226 
227  buffer(T *hostData, const range<dimensions> &bufferRange,
228  const property_list &propList = {},
230  : buffer_plain(hostData, bufferRange.size() * sizeof(T), alignof(T),
231  propList,
234  Range(bufferRange) {
236  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
237  dimensions, sizeof(T), detail::rangeToArray(Range).data());
238  }
239 
240  buffer(T *hostData, const range<dimensions> &bufferRange,
241  AllocatorT allocator, const property_list &propList = {},
243  : buffer_plain(
244  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
245  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
246  allocator)),
247  Range(bufferRange) {
249  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
250  dimensions, sizeof(T), detail::rangeToArray(Range).data());
251  }
252 
253  template <typename _T = T>
255  const range<dimensions> &bufferRange,
256  const property_list &propList = {},
258  : buffer_plain(hostData, bufferRange.size() * sizeof(T), alignof(T),
259  propList,
262  Range(bufferRange) {
264  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
265  dimensions, sizeof(T), detail::rangeToArray(Range).data());
266  }
267 
268  template <typename _T = T>
270  const range<dimensions> &bufferRange, AllocatorT allocator,
271  const property_list &propList = {},
273  : buffer_plain(
274  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
275  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
276  allocator)),
277  Range(bufferRange) {
279  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
280  dimensions, sizeof(T), detail::rangeToArray(Range).data());
281  }
282 
283  buffer(const std::shared_ptr<T> &hostData,
284  const range<dimensions> &bufferRange, AllocatorT allocator,
285  const property_list &propList = {},
287  : buffer_plain(
288  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
289  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
290  allocator),
291  std::is_const<T>::value),
292  Range(bufferRange) {
294  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
295  (const void *)typeid(T).name(), dimensions, sizeof(T),
296  detail::rangeToArray(Range).data());
297  }
298 
299  buffer(const std::shared_ptr<T[]> &hostData,
300  const range<dimensions> &bufferRange, AllocatorT allocator,
301  const property_list &propList = {},
303  : buffer_plain(
304  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
305  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
306  allocator),
307  std::is_const<T>::value),
308  Range(bufferRange) {
310  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
311  (const void *)typeid(T).name(), dimensions, sizeof(T),
312  detail::rangeToArray(Range).data());
313  }
314 
315  buffer(const std::shared_ptr<T> &hostData,
316  const range<dimensions> &bufferRange,
317  const property_list &propList = {},
319  : buffer_plain(
320  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
321  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(),
322  std::is_const<T>::value),
323  Range(bufferRange) {
325  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
326  (const void *)typeid(T).name(), dimensions, sizeof(T),
327  detail::rangeToArray(Range).data());
328  }
329 
330  buffer(const std::shared_ptr<T[]> &hostData,
331  const range<dimensions> &bufferRange,
332  const property_list &propList = {},
334  : buffer_plain(
335  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
336  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(),
337  std::is_const<T>::value),
338  Range(bufferRange) {
340  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
341  (const void *)typeid(T).name(), dimensions, sizeof(T),
342  detail::rangeToArray(Range).data());
343  }
344 
345  template <class InputIterator, int N = dimensions,
346  typename = EnableIfOneDimension<N>,
347  typename = EnableIfItInputIterator<InputIterator>>
348  buffer(InputIterator first, InputIterator last, AllocatorT allocator,
349  const property_list &propList = {},
351  : buffer_plain(
352  // The functor which will be used to initialize the data
353  [first, last](void *ToPtr) {
354  // We need to cast MUserPtr to pointer to the iteration type to
355  // get correct offset in std::copy when it will increment
356  // destination pointer.
357  using IteratorValueType =
359  using IteratorNonConstValueType =
360  std::remove_const_t<IteratorValueType>;
361  using IteratorPointerToNonConstValueType =
362  std::add_pointer_t<IteratorNonConstValueType>;
363  std::copy(first, last,
364  static_cast<IteratorPointerToNonConstValueType>(ToPtr));
365  },
366  std::distance(first, last) * sizeof(T), alignof(T), propList,
367  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
368  allocator),
369  detail::iterator_to_const_type_t<InputIterator>::value),
370  Range(range<1>(std::distance(first, last))) {
371  size_t r[3] = {Range[0], 0, 0};
372  buffer_plain::constructorNotification(CodeLoc, (void *)impl.get(), &first,
373  (const void *)typeid(T).name(),
374  dimensions, sizeof(T), r);
375  }
376 
377  template <class InputIterator, int N = dimensions,
378  typename = EnableIfOneDimension<N>,
379  typename = EnableIfItInputIterator<InputIterator>>
380  buffer(InputIterator first, InputIterator last,
381  const property_list &propList = {},
383  : buffer_plain(
384  // The functor which will be used to initialize the data
385  [first, last](void *ToPtr) {
386  // We need to cast MUserPtr to pointer to the iteration type to
387  // get correct offset in std::copy when it will increment
388  // destination pointer.
389  using IteratorValueType =
391  using IteratorNonConstValueType =
392  std::remove_const_t<IteratorValueType>;
393  using IteratorPointerToNonConstValueType =
394  std::add_pointer_t<IteratorNonConstValueType>;
395  std::copy(first, last,
396  static_cast<IteratorPointerToNonConstValueType>(ToPtr));
397  },
398  std::distance(first, last) * sizeof(T), alignof(T), propList,
399  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(),
400  detail::iterator_to_const_type_t<InputIterator>::value),
401  Range(range<1>(std::distance(first, last))) {
402  size_t r[3] = {Range[0], 0, 0};
403  buffer_plain::constructorNotification(CodeLoc, (void *)impl.get(), &first,
404  (const void *)typeid(T).name(),
405  dimensions, sizeof(T), r);
406  }
407 
408  // This constructor is a prototype for a future SYCL specification
409  template <class Container, int N = dimensions,
410  typename = EnableIfOneDimension<N>,
411  typename = EnableIfContiguous<Container>>
412  buffer(Container &container, AllocatorT allocator,
413  const property_list &propList = {},
415  : buffer_plain(
416  container.data(), container.size() * sizeof(T), alignof(T),
417  propList,
418  make_unique_ptr<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
419  allocator)),
420  Range(range<1>(container.size())) {
421  size_t r[3] = {Range[0], 0, 0};
423  CodeLoc, (void *)impl.get(), container.data(),
424  (const void *)typeid(T).name(), dimensions, sizeof(T), r);
425  }
426 
427  // This constructor is a prototype for a future SYCL specification
428  template <class Container, int N = dimensions,
429  typename = EnableIfOneDimension<N>,
430  typename = EnableIfContiguous<Container>>
431  buffer(Container &container, const property_list &propList = {},
433  : buffer(container, {}, propList, CodeLoc) {}
434 
436  const range<dimensions> &subRange,
438  : buffer_plain(b.impl), Range(subRange),
439  OffsetInBytes(getOffsetInBytes<T>(baseIndex, b.Range)),
440  IsSubBuffer(true) {
442  CodeLoc, (void *)impl.get(), impl.get(), (const void *)typeid(T).name(),
443  dimensions, sizeof(T), detail::rangeToArray(Range).data());
444 
445  if (b.is_sub_buffer())
446  throw sycl::invalid_object_error(
447  "Cannot create sub buffer from sub buffer.", PI_ERROR_INVALID_VALUE);
448  if (isOutOfBounds(baseIndex, subRange, b.Range))
449  throw sycl::invalid_object_error(
450  "Requested sub-buffer size exceeds the size of the parent buffer",
451  PI_ERROR_INVALID_VALUE);
452  if (!isContiguousRegion(baseIndex, subRange, b.Range))
453  throw sycl::invalid_object_error(
454  "Requested sub-buffer region is not contiguous",
455  PI_ERROR_INVALID_VALUE);
456  }
457 
458  buffer(const buffer &rhs,
460  : buffer_plain(rhs.impl), Range(rhs.Range),
461  OffsetInBytes(rhs.OffsetInBytes), IsSubBuffer(rhs.IsSubBuffer) {
463  CodeLoc, (void *)impl.get(), impl.get(), (const void *)typeid(T).name(),
464  dimensions, sizeof(T), detail::rangeToArray(Range).data());
465  }
466 
467  buffer(buffer &&rhs,
469  : buffer_plain(std::move(rhs.impl)), Range(rhs.Range),
470  OffsetInBytes(rhs.OffsetInBytes), IsSubBuffer(rhs.IsSubBuffer) {
472  CodeLoc, (void *)impl.get(), impl.get(), (const void *)typeid(T).name(),
473  dimensions, sizeof(T), detail::rangeToArray(Range).data());
474  }
475 
476  buffer &operator=(const buffer &rhs) = default;
477 
478  buffer &operator=(buffer &&rhs) = default;
479 
481 
482  bool operator==(const buffer &rhs) const { return impl == rhs.impl; }
483 
484  bool operator!=(const buffer &rhs) const { return !(*this == rhs); }
485 
486  /* -- common interface members -- */
487 
488  /* -- property interface members -- */
489 
490  range<dimensions> get_range() const { return Range; }
491 
492  __SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead")
493  size_t get_count() const { return size(); }
494  size_t size() const noexcept { return Range.size(); }
495 
497  "get_size() is deprecated, please use byte_size() instead")
498  size_t get_size() const { return byte_size(); }
499  size_t byte_size() const noexcept { return size() * sizeof(T); }
500 
501  AllocatorT get_allocator() const {
503  ->template getAllocator<AllocatorT>();
504  }
505 
506  template <access::mode Mode, access::target Target = access::target::device>
507  accessor<T, dimensions, Mode, Target, access::placeholder::false_t,
510  handler &CommandGroupHandler,
512  return accessor<T, dimensions, Mode, Target, access::placeholder::false_t,
514  *this, CommandGroupHandler, {}, CodeLoc);
515  }
516 
517  template <access::mode mode>
518  __SYCL2020_DEPRECATED("get_access for host_accessor is deprecated, please "
519  "use get_host_access instead")
520  accessor<
521  T, dimensions, mode, access::target::host_buffer,
522  access::placeholder::false_t,
523  ext::oneapi::
524  accessor_property_list<>> get_access(const detail::code_location
525  CodeLoc =
526  detail::code_location::
527  current()) {
528  return accessor<T, dimensions, mode, access::target::host_buffer,
530  ext::oneapi::accessor_property_list<>>(*this, {}, CodeLoc);
531  }
532 
533  template <access::mode mode, access::target target = access::target::device>
536  get_access(
537  handler &commandGroupHandler, range<dimensions> accessRange,
538  id<dimensions> accessOffset = {},
540  if (isOutOfBounds(accessOffset, accessRange, this->Range))
541  throw sycl::invalid_object_error(
542  "Requested accessor would exceed the bounds of the buffer",
543  PI_ERROR_INVALID_VALUE);
544 
545  return accessor<T, dimensions, mode, target, access::placeholder::false_t,
547  *this, commandGroupHandler, accessRange, accessOffset, {}, CodeLoc);
548  }
549 
550  template <access::mode mode>
551  __SYCL2020_DEPRECATED("get_access for host_accessor is deprecated, please "
552  "use get_host_access instead")
553  accessor<
554  T, dimensions, mode, access::target::host_buffer,
555  access::placeholder::false_t,
556  ext::oneapi::
557  accessor_property_list<>> get_access(range<dimensions> accessRange,
558  id<dimensions> accessOffset = {},
560  CodeLoc =
562  current()) {
563  if (isOutOfBounds(accessOffset, accessRange, this->Range))
564  throw sycl::invalid_object_error(
565  "Requested accessor would exceed the bounds of the buffer",
566  PI_ERROR_INVALID_VALUE);
567 
568  return accessor<T, dimensions, mode, access::target::host_buffer,
571  *this, accessRange, accessOffset, {}, CodeLoc);
572  }
573 
574  template <typename... Ts> auto get_access(Ts... args) {
575  return accessor{*this, args...};
576  }
577 
578  template <typename... Ts>
579  auto get_access(handler &commandGroupHandler, Ts... args) {
580  return accessor{*this, commandGroupHandler, args...};
581  }
582 
583  template <typename... Ts> auto get_host_access(Ts... args) {
584  return host_accessor{*this, args...};
585  }
586 
587  template <typename... Ts>
588  auto get_host_access(handler &commandGroupHandler, Ts... args) {
589  return host_accessor{*this, commandGroupHandler, args...};
590  }
591 
592  template <typename Destination = std::nullptr_t>
593  void set_final_data(Destination finalData = nullptr) {
594  this->set_final_data_internal(finalData);
595  }
596 
597  void set_final_data_internal(std::nullptr_t) {
599  }
600 
601  template <template <typename WeakT> class WeakPtrT, typename WeakT>
602  std::enable_if_t<std::is_convertible_v<WeakPtrT<WeakT>, std::weak_ptr<WeakT>>>
603  set_final_data_internal(WeakPtrT<WeakT> FinalData) {
604  std::weak_ptr<WeakT> TempFinalData(FinalData);
605  this->set_final_data_internal(TempFinalData);
606  }
607 
608  template <typename WeakT>
609  void set_final_data_internal(std::weak_ptr<WeakT> FinalData) {
611  [FinalData](const std::function<void(void *const Ptr)> &F) {
612  if (std::shared_ptr<WeakT> LockedFinalData = FinalData.lock())
613  F(LockedFinalData.get());
614  });
615  }
616 
617  template <typename Destination>
619  set_final_data_internal(Destination FinalData) {
620  if (!FinalData)
622  else
624  [FinalData](const std::function<void(void *const Ptr)> &F) {
625  F(FinalData);
626  });
627  }
628 
629  template <typename Destination>
631  set_final_data_internal(Destination FinalData) {
632  const size_t Size = size();
634  [FinalData, Size](const std::function<void(void *const Ptr)> &F) {
635  using DestinationValueT = detail::iterator_value_type_t<Destination>;
636  // TODO if Destination is ContiguousIterator then don't create
637  // ContiguousStorage. updateHostMemory works only with pointer to
638  // continuous data.
639  std::unique_ptr<DestinationValueT[]> ContiguousStorage(
640  new DestinationValueT[Size]);
641  F(ContiguousStorage.get());
642  std::copy(ContiguousStorage.get(), ContiguousStorage.get() + Size,
643  FinalData);
644  });
645  }
646 
647  void set_final_data(std::nullptr_t) {
649  }
650 
651  void set_write_back(bool flag = true) { buffer_plain::set_write_back(flag); }
652 
653  bool is_sub_buffer() const { return IsSubBuffer; }
654 
655  template <typename ReinterpretT, int ReinterpretDim>
656  buffer<ReinterpretT, ReinterpretDim,
657  typename std::allocator_traits<AllocatorT>::template rebind_alloc<
658  std::remove_const_t<ReinterpretT>>>
659  reinterpret(range<ReinterpretDim> reinterpretRange) const {
660  if (sizeof(ReinterpretT) * reinterpretRange.size() != byte_size())
661  throw sycl::invalid_object_error(
662  "Total size in bytes represented by the type and range of the "
663  "reinterpreted SYCL buffer does not equal the total size in bytes "
664  "represented by the type and range of this SYCL buffer",
665  PI_ERROR_INVALID_VALUE);
666 
667  return buffer<ReinterpretT, ReinterpretDim,
668  typename std::allocator_traits<AllocatorT>::
669  template rebind_alloc<std::remove_const_t<ReinterpretT>>>(
670  impl, reinterpretRange, OffsetInBytes, IsSubBuffer);
671  }
672 
673  template <typename ReinterpretT, int ReinterpretDim = dimensions>
674  std::enable_if_t<
675  (sizeof(ReinterpretT) == sizeof(T)) && (dimensions == ReinterpretDim),
676  buffer<ReinterpretT, ReinterpretDim,
677  typename std::allocator_traits<AllocatorT>::template rebind_alloc<
678  std::remove_const_t<ReinterpretT>>>>
679  reinterpret() const {
680  return buffer<ReinterpretT, ReinterpretDim,
681  typename std::allocator_traits<AllocatorT>::
682  template rebind_alloc<std::remove_const_t<ReinterpretT>>>(
683  impl, get_range(), OffsetInBytes, IsSubBuffer);
684  }
685 
686  template <typename ReinterpretT, int ReinterpretDim = dimensions>
687  std::enable_if_t<(ReinterpretDim == 1) &&
688  ((dimensions != ReinterpretDim) ||
689  (sizeof(ReinterpretT) != sizeof(T))),
691  reinterpret() const {
692  long sz = byte_size();
693  if (sz % sizeof(ReinterpretT) != 0)
694  throw sycl::invalid_object_error(
695  "Total byte size of buffer is not evenly divisible by the size of "
696  "the reinterpreted type",
697  PI_ERROR_INVALID_VALUE);
698 
700  impl, range<1>{sz / sizeof(ReinterpretT)}, OffsetInBytes, IsSubBuffer);
701  }
702 
703  template <typename propertyT> bool has_property() const noexcept {
704  return buffer_plain::template has_property<propertyT>();
705  }
706 
707  template <typename propertyT> propertyT get_property() const {
708  return buffer_plain::template get_property<propertyT>();
709  }
710 
711 protected:
712  bool isOutOfBounds(const id<dimensions> &offset,
713  const range<dimensions> &newRange,
714  const range<dimensions> &parentRange) {
715  bool outOfBounds = false;
716  for (int i = 0; i < dimensions; ++i)
717  outOfBounds |= newRange[i] + offset[i] > parentRange[i];
718 
719  return outOfBounds;
720  }
721 
722 private:
723  template <class Obj>
724  friend decltype(Obj::impl) detail::getSyclObjImpl(const Obj &SyclObject);
725  template <typename A, int dims, typename C, typename Enable>
726  friend class buffer;
727  template <typename DataT, int dims, access::mode mode, access::target target,
728  access::placeholder isPlaceholder, typename PropertyListT>
729  friend class accessor;
730  template <typename HT, int HDims, typename HAllocT>
733  template <typename SYCLObjT> friend class ext::oneapi::weak_object;
734 
735  // NOTE: These members are required for reconstructing the buffer, but are not
736  // part of the implementation class. If more members are added, they should
737  // also be added to the weak_object specialization for buffers.
738  range<dimensions> Range;
739  // Offset field specifies the origin of the sub buffer inside the parent
740  // buffer
741  size_t OffsetInBytes = 0;
742  bool IsSubBuffer = false;
743 
744  // Interop constructor
745  template <int N = dimensions, typename = EnableIfOneDimension<N>>
746  buffer(pi_native_handle MemObject, const context &SyclContext,
747  bool OwnNativeHandle, event AvailableEvent = {},
749  : buffer_plain(
750  MemObject, SyclContext,
752  OwnNativeHandle, std::move(AvailableEvent)),
753  Range{0} {
754 
755  Range[0] = buffer_plain::getSize() / sizeof(T);
757  CodeLoc, (void *)impl.get(), &MemObject, (const void *)typeid(T).name(),
758  dimensions, sizeof(T), detail::rangeToArray(Range).data());
759  }
760 
761  void addOrReplaceAccessorProperties(const property_list &PropertyList) {
763  }
764 
765  void deleteAccProps(const sycl::detail::PropWithDataKind &Kind) {
767  }
768 
769  // Reinterpret contructor
770  buffer(const std::shared_ptr<detail::buffer_impl> &Impl,
771  range<dimensions> reinterpretRange, size_t reinterpretOffset,
772  bool isSubBuffer,
773  const detail::code_location CodeLoc = detail::code_location::current())
774  : buffer_plain(Impl), Range(reinterpretRange),
775  OffsetInBytes(reinterpretOffset), IsSubBuffer(isSubBuffer) {
777  CodeLoc, (void *)impl.get(), Impl.get(), (const void *)typeid(T).name(),
778  dimensions, sizeof(T), detail::rangeToArray(Range).data());
779  }
780 
781  template <typename Type, int N>
782  size_t getOffsetInBytes(const id<N> &offset, const range<N> &range) {
783  return detail::getLinearIndex(offset, range) * sizeof(Type);
784  }
785 
786  bool isContiguousRegion(const id<1> &, const range<1> &, const range<1> &) {
787  // 1D sub buffer always has contiguous region
788  return true;
789  }
790 
791  bool isContiguousRegion(const id<2> &offset, const range<2> &newRange,
792  const range<2> &parentRange) {
793  // For 2D sub buffer there are 2 cases:
794  // 1) Offset {Any, Any} | a piece of any line of a buffer
795  // Range {1, Any} |
796  // 2) Offset {Any, 0 } | any number of full lines
797  // Range {Any, Col} |
798  // where Col is a number of columns of original buffer
799  if (offset[1])
800  return newRange[0] == 1;
801  return newRange[1] == parentRange[1];
802  }
803 
804  bool isContiguousRegion(const id<3> &offset, const range<3> &newRange,
805  const range<3> &parentRange) {
806  // For 3D sub buffer there are 3 cases:
807  // 1) Offset {Any, Any, Any} | a piece of any line in any slice of a buffer
808  // Range {1, 1, Any} |
809  // 2) Offset {Any, Any, 0 } | any number of full lines in any slice
810  // Range {1, Any, Col} |
811  // 3) Offset {Any, 0, 0 } | any number of slices
812  // Range {Any, Row, Col} |
813  // where Row and Col are numbers of rows and columns of original buffer
814  if (offset[2])
815  return newRange[0] == 1 && newRange[1] == 1;
816  if (offset[1])
817  return newRange[0] == 1 && newRange[2] == parentRange[2];
818  return newRange[1] == parentRange[1] && newRange[2] == parentRange[2];
819  }
820 
821  template <backend BackendName, typename DataT, int Dimensions,
822  typename Allocator>
823  friend auto detail::get_native_buffer(
825  -> backend_return_t<BackendName,
827 
828  template <backend BackendName>
830  getNative() const {
831  auto NativeHandles = buffer_plain::getNativeVector(BackendName);
832  return detail::BufferInterop<BackendName, T, dimensions,
833  AllocatorT>::GetNativeObjs(NativeHandles);
834  }
835 };
836 
837 #ifdef __cpp_deduction_guides
838 template <class InputIterator, class AllocatorT>
839 buffer(InputIterator, InputIterator, AllocatorT, const property_list & = {})
840  -> buffer<typename std::iterator_traits<InputIterator>::value_type, 1,
841  AllocatorT>;
842 template <class InputIterator>
843 buffer(InputIterator, InputIterator, const property_list & = {})
844  -> buffer<typename std::iterator_traits<InputIterator>::value_type, 1>;
845 template <class Container, class AllocatorT>
846 buffer(Container &, AllocatorT, const property_list & = {})
847  -> buffer<typename Container::value_type, 1, AllocatorT>;
848 template <class Container>
849 buffer(Container &, const property_list & = {})
850  -> buffer<typename Container::value_type, 1>;
851 template <class T, int dimensions, class AllocatorT>
852 buffer(const T *, const range<dimensions> &, AllocatorT,
853  const property_list & = {}) -> buffer<T, dimensions, AllocatorT>;
854 template <class T, int dimensions>
855 buffer(const T *, const range<dimensions> &, const property_list & = {})
856  -> buffer<T, dimensions>;
857 #endif // __cpp_deduction_guides
858 
859 } // namespace _V1
860 } // namespace sycl
861 
862 namespace std {
863 template <typename T, int dimensions, typename AllocatorT>
864 struct hash<sycl::buffer<T, dimensions, AllocatorT>> {
866  return hash<std::shared_ptr<sycl::detail::buffer_impl>>()(
868  }
869 };
870 } // namespace std
Defines a shared array that can be used by kernels in queues.
Definition: buffer.hpp:170
buffer & operator=(const buffer &rhs)=default
AllocatorT get_allocator() const
Definition: buffer.hpp:501
__SYCL2020_DEPRECATED("get_size() is deprecated, please use byte_size() instead") size_t get_size() const
Definition: buffer.hpp:496
buffer(buffer &&rhs, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:467
buffer(InputIterator first, InputIterator last, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:380
__SYCL2020_DEPRECATED("get_access for host_accessor is deprecated, please " "use get_host_access instead") accessor< T
buffer(const buffer &rhs, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:458
buffer(InputIterator first, InputIterator last, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:348
buffer(EnableIfSameNonConstIterators< T, _T > const *hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:269
buffer(T *hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:227
buffer(const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:202
size_t byte_size() const noexcept
Definition: buffer.hpp:499
buffer(Container &container, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:431
buffer(const std::shared_ptr< T[]> &hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:330
bool operator!=(const buffer &rhs) const
Definition: buffer.hpp:484
buffer(buffer< T, dimensions, AllocatorT > &b, const id< dimensions > &baseIndex, const range< dimensions > &subRange, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:435
size_t size() const noexcept
Definition: buffer.hpp:494
std::enable_if_t< std::is_convertible_v< typename std::iterator_traits< It >::iterator_category, std::input_iterator_tag > > EnableIfItInputIterator
Definition: buffer.hpp:197
buffer(const std::shared_ptr< T > &hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:315
std::void_t< std::enable_if_t< std::is_convertible_v< detail::remove_pointer_t< decltype(std::declval< Container >().data())>(*)[], const T(*)[]> >, decltype(std::declval< Container >().size())> EnableIfContiguous
Definition: buffer.hpp:193
buffer(const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:214
bool operator==(const buffer &rhs) const
Definition: buffer.hpp:482
const value_type & const_reference
Definition: buffer.hpp:182
range< dimensions > get_range() const
Definition: buffer.hpp:490
buffer(T *hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:240
buffer & operator=(buffer &&rhs)=default
buffer(Container &container, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:412
buffer(EnableIfSameNonConstIterators< T, _T > const *hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:254
buffer(const std::shared_ptr< T[]> &hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:299
__SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead") size_t get_count() const
Definition: buffer.hpp:492
typename std::enable_if_t< std::is_same_v< ItA, ItB > &&!std::is_const_v< ItA >, ItA > EnableIfSameNonConstIterators
Definition: buffer.hpp:200
buffer(const std::shared_ptr< T > &hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:283
accessor< T, dimensions, Mode, Target, access::placeholder::false_t, ext::oneapi::accessor_property_list<> > get_access(handler &CommandGroupHandler, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:509
value_type & reference
Definition: buffer.hpp:181
typename std::enable_if_t< 1==dims > EnableIfOneDimension
Definition: buffer.hpp:185
AllocatorT allocator_type
Definition: buffer.hpp:183
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:51
void deleteAccProps(const sycl::detail::PropWithDataKind &Kind)
Definition: buffer.cpp:113
std::vector< pi_native_handle > getNativeVector(backend BackendName) const
Definition: buffer.cpp:104
bool has_property() const noexcept
std::shared_ptr< detail::buffer_impl > impl
Definition: buffer.hpp:152
buffer_plain(const std::shared_ptr< detail::buffer_impl > &impl)
Definition: buffer.hpp:121
buffer_plain(void *HostData, size_t SizeInBytes, size_t RequiredAlign, const property_list &Props, std::unique_ptr< detail::SYCLMemObjAllocator > Allocator)
void constructorNotification(const detail::code_location &CodeLoc, void *UserObj, const void *HostObj, const void *Type, uint32_t Dim, uint32_t ElemType, size_t Range[3])
Definition: buffer.cpp:73
const std::unique_ptr< SYCLMemObjAllocator > & get_allocator_internal() const
Definition: buffer.cpp:109
void set_write_back(bool NeedWriteBack)
Definition: buffer.cpp:81
void addOrReplaceAccessorProperties(const property_list &PropertyList)
Definition: buffer.cpp:117
An event object can be used to synchronize memory transfers, enqueues of kernels and signaling barrie...
Definition: event.hpp:44
Command group handler class.
Definition: handler.hpp:454
A unique identifier of an item in an index space.
Definition: id.hpp:36
Objects of the property_list class are containers for the SYCL properties.
Defines the iteration domain of either a single work-group in a parallel dispatch,...
Definition: range.hpp:26
size_t size() const
Definition: range.hpp:56
std::enable_if_t< std::is_pointer_v< DataT > > EnableIfOutputPointerT
Definition: common.hpp:34
size_t getLinearIndex(const T< Dims > &Index, const U< Dims > &Range)
Definition: common.hpp:367
typename std::iterator_traits< T >::value_type iterator_value_type_t
typename remove_pointer< T >::type remove_pointer_t
std::array< size_t, 3 > rangeToArray(const range< 3 > &r)
Definition: range.hpp:234
auto get_native_buffer(const buffer< DataT, Dimensions, Allocator, void > &Obj) -> backend_return_t< BackendName, buffer< DataT, Dimensions, Allocator, void >>
decltype(Obj::impl) getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:30
void constructorNotification(void *BufferObj, void *AccessorObj, access::target Target, access::mode Mode, const code_location &CodeLoc)
std::enable_if_t< !std::is_pointer_v< DataT > > EnableIfOutputIteratorT
Definition: common.hpp:38
struct __SYCL2020_DEPRECATED("This type isn't device copyable in SYCL 2020") IsDeprecatedDeviceCopyable< T
buffer< T, Dimensions, AllocatorT, void > make_buffer_helper(pi_native_handle Handle, const context &Ctx, event Evt={}, bool OwnNativeHandle=true)
Definition: buffer.hpp:73
static constexpr bool has_property()
static constexpr auto get_property()
float distance(T p0, T p1)
std::unique_ptr< T > make_unique_ptr(ArgsT &&...Args)
Definition: stl.hpp:43
class __SYCL_EBO __SYCL_SPECIAL_CLASS __SYCL_TYPE(local_accessor) local_accessor class __SYCL_EBO __SYCL_SPECIAL_CLASS Dimensions
Definition: accessor.hpp:3233
y y maxval[j] maxval b
detail::sycl_memory_object_allocator< DataT > buffer_allocator
Definition: buffer.hpp:55
typename backend_traits< Backend >::template return_type< SyclType > backend_return_t
Definition: backend.hpp:87
Definition: access.hpp:18
uintptr_t pi_native_handle
Definition: pi.h:206
_Abi const simd< _Tp, _Abi > & noexcept
Definition: simd.hpp:1324
size_t operator()(const sycl::buffer< T, dimensions, AllocatorT > &b) const
Definition: buffer.hpp:865
static constexpr code_location current(const char *fileName=__CODELOC_FILE_NAME, const char *funcName=__CODELOC_FUNCTION, unsigned long lineNo=__CODELOC_LINE, unsigned long columnNo=__CODELOC_COLUMN) noexcept
Definition: common.hpp:68