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