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