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