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/detail/array.hpp>
14 #include <sycl/detail/common.hpp>
16 #include <sycl/detail/export.hpp>
17 #include <sycl/detail/helpers.hpp>
25 #include <sycl/id.hpp>
26 #include <sycl/property_list.hpp>
27 #include <sycl/range.hpp>
28 #include <ur_api.h> // for ur_native_handle_t
29 
30 #include <cstddef> // for size_t, nullptr_t
31 #include <functional> // for function
32 #include <iterator> // for iterator_traits
33 #include <memory> // for shared_ptr
34 #include <stdint.h> // for uint32_t
35 #include <string> // for string
36 #include <type_traits> // for enable_if_t
37 #include <typeinfo> // for type_info
38 #include <utility> // for declval, move
39 #include <variant> // for hash
40 #include <vector> // for vector
41 
42 namespace sycl {
43 inline namespace _V1 {
44 
45 class handler;
46 class queue;
47 class context;
48 class event;
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(ur_native_handle_t Handle, const context &Ctx,
71  const event &Evt, 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(ur_native_handle_t MemObject, const context &SyclContext,
115  std::unique_ptr<detail::SYCLMemObjAllocator> Allocator,
116  bool OwnNativeHandle, const 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  return getPropList().template has_property<propertyT>();
135  }
136 
137  template <typename propertyT> propertyT get_property() const {
138  return getPropList().template get_property<propertyT>();
139  }
140 
141  std::vector<ur_native_handle_t> getNativeVector(backend BackendName) const;
142 
143  const std::unique_ptr<SYCLMemObjAllocator> &get_allocator_internal() const;
144 
145  void deleteAccProps(const sycl::detail::PropWithDataKind &Kind);
146 
147  void addOrReplaceAccessorProperties(const property_list &PropertyList);
148 
149  size_t getSize() const;
150 
151  void handleRelease() const;
152 
153  std::shared_ptr<detail::buffer_impl> impl;
154 
155  const property_list &getPropList() const;
156 };
157 
158 } // namespace detail
159 
168 template <typename T, int dimensions = 1,
169  typename AllocatorT = buffer_allocator<std::remove_const_t<T>>,
170  typename __Enabled =
171  typename std::enable_if_t<(dimensions > 0) && (dimensions <= 3)>>
173  public detail::OwnerLessBase<buffer<T, dimensions, AllocatorT>> {
174  static_assert(is_device_copyable_v<T>,
175  "Underlying type of a buffer must be device copyable!");
176 
177 public:
178  using value_type = T;
180  using const_reference = const value_type &;
181  using allocator_type = AllocatorT;
182  template <int dims>
183  using EnableIfOneDimension = typename std::enable_if_t<1 == dims>;
184  // using same requirement for contiguous container as std::span
185  template <class Container>
187  std::void_t<std::enable_if_t<std::is_convertible_v<
189  decltype(std::declval<Container>().data())> (*)[],
190  const T (*)[]>>,
191  decltype(std::declval<Container>().size())>;
192  template <class It>
193  using EnableIfItInputIterator = std::enable_if_t<std::is_convertible_v<
194  typename std::iterator_traits<It>::iterator_category,
195  std::input_iterator_tag>>;
196  template <typename ItA, typename ItB>
197  using EnableIfSameNonConstIterators = typename std::enable_if_t<
198  std::is_same_v<ItA, ItB> && !std::is_const_v<ItA>, ItA>;
199 
200  buffer(const range<dimensions> &bufferRange,
201  const property_list &propList = {},
203  : buffer_plain(bufferRange.size() * sizeof(T), alignof(T), propList,
204  std::make_unique<
206  Range(bufferRange) {
208  CodeLoc, (void *)impl.get(), nullptr, (const void *)typeid(T).name(),
209  dimensions, sizeof(T), detail::rangeToArray(Range).data());
210  }
211 
212  buffer(const range<dimensions> &bufferRange, AllocatorT allocator,
213  const property_list &propList = {},
215  : buffer_plain(
216  bufferRange.size() * sizeof(T), alignof(T), propList,
217  std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
218  allocator)),
219  Range(bufferRange) {
221  CodeLoc, (void *)impl.get(), nullptr, (const void *)typeid(T).name(),
222  dimensions, sizeof(T), detail::rangeToArray(Range).data());
223  }
224 
225  buffer(T *hostData, const range<dimensions> &bufferRange,
226  const property_list &propList = {},
228  : buffer_plain(hostData, bufferRange.size() * sizeof(T), alignof(T),
229  propList,
230  std::make_unique<
232  Range(bufferRange) {
234  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
235  dimensions, sizeof(T), detail::rangeToArray(Range).data());
236  }
237 
238  buffer(T *hostData, const range<dimensions> &bufferRange,
239  AllocatorT allocator, const property_list &propList = {},
241  : buffer_plain(
242  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
243  std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
244  allocator)),
245  Range(bufferRange) {
247  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
248  dimensions, sizeof(T), detail::rangeToArray(Range).data());
249  }
250 
251  template <typename _T = T>
253  const range<dimensions> &bufferRange,
254  const property_list &propList = {},
256  : buffer_plain(hostData, bufferRange.size() * sizeof(T), alignof(T),
257  propList,
258  std::make_unique<
260  Range(bufferRange) {
262  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
263  dimensions, sizeof(T), detail::rangeToArray(Range).data());
264  }
265 
266  template <typename _T = T>
268  const range<dimensions> &bufferRange, AllocatorT allocator,
269  const property_list &propList = {},
271  : buffer_plain(
272  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
273  std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
274  allocator)),
275  Range(bufferRange) {
277  CodeLoc, (void *)impl.get(), hostData, (const void *)typeid(T).name(),
278  dimensions, sizeof(T), detail::rangeToArray(Range).data());
279  }
280 
281  buffer(const std::shared_ptr<T> &hostData,
282  const range<dimensions> &bufferRange, AllocatorT allocator,
283  const property_list &propList = {},
285  : buffer_plain(
286  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
287  std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
288  allocator),
289  std::is_const<T>::value),
290  Range(bufferRange) {
292  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
293  (const void *)typeid(T).name(), dimensions, sizeof(T),
294  detail::rangeToArray(Range).data());
295  }
296 
297  buffer(const std::shared_ptr<T[]> &hostData,
298  const range<dimensions> &bufferRange, AllocatorT allocator,
299  const property_list &propList = {},
301  : buffer_plain(
302  hostData, bufferRange.size() * sizeof(T), alignof(T), propList,
303  std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
304  allocator),
305  std::is_const<T>::value),
306  Range(bufferRange) {
308  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
309  (const void *)typeid(T).name(), dimensions, sizeof(T),
310  detail::rangeToArray(Range).data());
311  }
312 
313  buffer(const std::shared_ptr<T> &hostData,
314  const range<dimensions> &bufferRange,
315  const property_list &propList = {},
317  : buffer_plain(hostData, bufferRange.size() * sizeof(T), alignof(T),
318  propList,
319  std::make_unique<
321  std::is_const<T>::value),
322  Range(bufferRange) {
324  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
325  (const void *)typeid(T).name(), dimensions, sizeof(T),
326  detail::rangeToArray(Range).data());
327  }
328 
329  buffer(const std::shared_ptr<T[]> &hostData,
330  const range<dimensions> &bufferRange,
331  const property_list &propList = {},
333  : buffer_plain(hostData, bufferRange.size() * sizeof(T), alignof(T),
334  propList,
335  std::make_unique<
337  std::is_const<T>::value),
338  Range(bufferRange) {
340  CodeLoc, (void *)impl.get(), (void *)hostData.get(),
341  (const void *)typeid(T).name(), dimensions, sizeof(T),
342  detail::rangeToArray(Range).data());
343  }
344 
345  template <class InputIterator, int N = dimensions,
346  typename = EnableIfOneDimension<N>,
347  typename = EnableIfItInputIterator<InputIterator>>
348  buffer(InputIterator first, InputIterator last, AllocatorT allocator,
349  const property_list &propList = {},
351  : buffer_plain(
352  // The functor which will be used to initialize the data
353  [first, last](void *ToPtr) {
354  // We need to cast MUserPtr to pointer to the iteration type to
355  // get correct offset in std::copy when it will increment
356  // destination pointer.
357  using IteratorValueType =
359  using IteratorNonConstValueType =
360  std::remove_const_t<IteratorValueType>;
361  using IteratorPointerToNonConstValueType =
362  std::add_pointer_t<IteratorNonConstValueType>;
363  std::copy(first, last,
364  static_cast<IteratorPointerToNonConstValueType>(ToPtr));
365  },
366  std::distance(first, last) * sizeof(T), alignof(T), propList,
367  std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
368  allocator),
369  detail::iterator_to_const_type_t<InputIterator>::value),
370  Range(range<1>(std::distance(first, last))) {
371  size_t r[3] = {Range[0], 0, 0};
372  buffer_plain::constructorNotification(CodeLoc, (void *)impl.get(), &first,
373  (const void *)typeid(T).name(),
374  dimensions, sizeof(T), r);
375  }
376 
377  template <class InputIterator, int N = dimensions,
378  typename = EnableIfOneDimension<N>,
379  typename = EnableIfItInputIterator<InputIterator>>
380  buffer(InputIterator first, InputIterator last,
381  const property_list &propList = {},
383  : buffer_plain(
384  // The functor which will be used to initialize the data
385  [first, last](void *ToPtr) {
386  // We need to cast MUserPtr to pointer to the iteration type to
387  // get correct offset in std::copy when it will increment
388  // destination pointer.
389  using IteratorValueType =
391  using IteratorNonConstValueType =
392  std::remove_const_t<IteratorValueType>;
393  using IteratorPointerToNonConstValueType =
394  std::add_pointer_t<IteratorNonConstValueType>;
395  std::copy(first, last,
396  static_cast<IteratorPointerToNonConstValueType>(ToPtr));
397  },
398  std::distance(first, last) * sizeof(T), alignof(T), propList,
399  std::make_unique<
400  detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(),
401  detail::iterator_to_const_type_t<InputIterator>::value),
402  Range(range<1>(std::distance(first, last))) {
403  size_t r[3] = {Range[0], 0, 0};
404  buffer_plain::constructorNotification(CodeLoc, (void *)impl.get(), &first,
405  (const void *)typeid(T).name(),
406  dimensions, sizeof(T), r);
407  }
408 
409  // This constructor is a prototype for a future SYCL specification
410  template <class Container, int N = dimensions,
411  typename = EnableIfOneDimension<N>,
412  typename = EnableIfContiguous<Container>>
413  buffer(Container &container, AllocatorT allocator,
414  const property_list &propList = {},
416  : buffer_plain(
417  container.data(), container.size() * sizeof(T), alignof(T),
418  propList,
419  std::make_unique<detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(
420  allocator)),
421  Range(range<1>(container.size())) {
422  size_t r[3] = {Range[0], 0, 0};
424  CodeLoc, (void *)impl.get(), container.data(),
425  (const void *)typeid(T).name(), dimensions, sizeof(T), r);
426  }
427 
428  // This constructor is a prototype for a future SYCL specification
429  template <class Container, int N = dimensions,
430  typename = EnableIfOneDimension<N>,
431  typename = EnableIfContiguous<Container>>
432  buffer(Container &container, const property_list &propList = {},
434  : buffer(container, {}, propList, CodeLoc) {}
435 
437  const range<dimensions> &subRange,
439  : buffer_plain(b.impl), Range(subRange),
440  OffsetInBytes(getOffsetInBytes<T>(baseIndex, b.Range)),
441  IsSubBuffer(true) {
443  CodeLoc, (void *)impl.get(), impl.get(), (const void *)typeid(T).name(),
444  dimensions, sizeof(T), detail::rangeToArray(Range).data());
445 
446  if (b.is_sub_buffer())
448  "Cannot create sub buffer from sub buffer.");
449  if (isOutOfBounds(baseIndex, subRange, b.Range))
451  "Requested sub-buffer size exceeds the size of the parent buffer");
452  if (!isContiguousRegion(baseIndex, subRange, b.Range))
454  "Requested sub-buffer region is not contiguous");
455  }
456 
457  buffer(const buffer &rhs,
459  : buffer_plain(rhs.impl), Range(rhs.Range),
460  OffsetInBytes(rhs.OffsetInBytes), IsSubBuffer(rhs.IsSubBuffer) {
462  CodeLoc, (void *)impl.get(), impl.get(), (const void *)typeid(T).name(),
463  dimensions, sizeof(T), detail::rangeToArray(Range).data());
464  }
465 
466  buffer(buffer &&rhs,
468  : buffer_plain(std::move(rhs.impl)), Range(rhs.Range),
469  OffsetInBytes(rhs.OffsetInBytes), IsSubBuffer(rhs.IsSubBuffer) {
471  CodeLoc, (void *)impl.get(), impl.get(), (const void *)typeid(T).name(),
472  dimensions, sizeof(T), detail::rangeToArray(Range).data());
473  }
474 
475  buffer &operator=(const buffer &rhs) = default;
476 
477  buffer &operator=(buffer &&rhs) = default;
478 
480  try {
481  buffer_plain::handleRelease();
482  } catch (std::exception &e) {
483  __SYCL_REPORT_EXCEPTION_TO_STREAM("exception in ~buffer", e);
484  }
485  }
486 
487  bool operator==(const buffer &rhs) const { return impl == rhs.impl; }
488 
489  bool operator!=(const buffer &rhs) const { return !(*this == rhs); }
490 
491  /* -- common interface members -- */
492 
493  /* -- property interface members -- */
494 
495  range<dimensions> get_range() const { return Range; }
496 
497  __SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead")
498  size_t get_count() const { return size(); }
499  size_t size() const noexcept { return Range.size(); }
500 
502  "get_size() is deprecated, please use byte_size() instead")
503  size_t get_size() const { return byte_size(); }
504  size_t byte_size() const noexcept { return size() * sizeof(T); }
505 
506  AllocatorT get_allocator() const {
507  return buffer_plain::get_allocator_internal()
508  ->template getAllocator<AllocatorT>();
509  }
510 
511  template <access::mode Mode, access::target Target = access::target::device>
515  handler &CommandGroupHandler,
519  *this, CommandGroupHandler, {}, CodeLoc);
520  }
521 
522  template <access::mode mode>
523  __SYCL2020_DEPRECATED("get_access for host_accessor is deprecated, please "
524  "use get_host_access instead")
525  accessor<
526  T, dimensions, mode, access::target::host_buffer,
527  access::placeholder::false_t,
528  ext::oneapi::
529  accessor_property_list<>> get_access(const detail::code_location
530  CodeLoc =
531  detail::code_location::
532  current()) {
533  return accessor<T, dimensions, mode, access::target::host_buffer,
535  ext::oneapi::accessor_property_list<>>(*this, {}, CodeLoc);
536  }
537 
538  template <access::mode mode, access::target target = access::target::device>
541  get_access(
542  handler &commandGroupHandler, range<dimensions> accessRange,
543  id<dimensions> accessOffset = {},
545  if (isOutOfBounds(accessOffset, accessRange, this->Range))
547  "Requested accessor would exceed the bounds of the buffer");
548 
551  *this, commandGroupHandler, accessRange, accessOffset, {}, CodeLoc);
552  }
553 
554  template <access::mode mode>
555  __SYCL2020_DEPRECATED("get_access for host_accessor is deprecated, please "
556  "use get_host_access instead")
557  accessor<
558  T, dimensions, mode, access::target::host_buffer,
559  access::placeholder::false_t,
560  ext::oneapi::
561  accessor_property_list<>> get_access(range<dimensions> accessRange,
562  id<dimensions> accessOffset = {},
564  CodeLoc =
566  current()) {
567  if (isOutOfBounds(accessOffset, accessRange, this->Range))
569  "Requested accessor would exceed the bounds of the buffer");
570 
571  return accessor<T, dimensions, mode, access::target::host_buffer,
574  *this, accessRange, accessOffset, {}, CodeLoc);
575  }
576 
577  template <typename... Ts> auto get_access(Ts... args) {
578  return accessor{*this, args...};
579  }
580 
581  template <typename... Ts>
582  auto get_access(handler &commandGroupHandler, Ts... args) {
583  return accessor{*this, commandGroupHandler, args...};
584  }
585 
586  template <typename... Ts> auto get_host_access(Ts... args) {
587  return host_accessor{*this, args...};
588  }
589 
590  template <typename... Ts>
591  auto get_host_access(handler &commandGroupHandler, Ts... args) {
592  return host_accessor{*this, commandGroupHandler, args...};
593  }
594 
595  template <typename Destination = std::nullptr_t>
596  void set_final_data(Destination finalData = nullptr) {
597  this->set_final_data_internal(finalData);
598  }
599 
600  void set_final_data_internal(std::nullptr_t) {
601  buffer_plain::set_final_data_internal();
602  }
603 
604  template <template <typename WeakT> class WeakPtrT, typename WeakT>
605  std::enable_if_t<std::is_convertible_v<WeakPtrT<WeakT>, std::weak_ptr<WeakT>>>
606  set_final_data_internal(WeakPtrT<WeakT> FinalData) {
607  std::weak_ptr<WeakT> TempFinalData(FinalData);
608  this->set_final_data_internal(TempFinalData);
609  }
610 
611  template <typename WeakT>
612  void set_final_data_internal(std::weak_ptr<WeakT> FinalData) {
613  buffer_plain::set_final_data_internal(
614  [FinalData](const std::function<void(void *const Ptr)> &F) {
615  if (std::shared_ptr<WeakT> LockedFinalData = FinalData.lock())
616  F(LockedFinalData.get());
617  });
618  }
619 
620  template <typename Destination>
622  set_final_data_internal(Destination FinalData) {
623  if (!FinalData)
624  buffer_plain::set_final_data_internal();
625  else
626  buffer_plain::set_final_data_internal(
627  [FinalData](const std::function<void(void *const Ptr)> &F) {
628  F(FinalData);
629  });
630  }
631 
632  template <typename Destination>
634  set_final_data_internal(Destination FinalData) {
635  const size_t Size = size();
636  buffer_plain::set_final_data_internal(
637  [FinalData, Size](const std::function<void(void *const Ptr)> &F) {
638  using DestinationValueT = detail::iterator_value_type_t<Destination>;
639  // TODO if Destination is ContiguousIterator then don't create
640  // ContiguousStorage. updateHostMemory works only with pointer to
641  // continuous data.
642  std::unique_ptr<DestinationValueT[]> ContiguousStorage(
643  new DestinationValueT[Size]);
644  F(ContiguousStorage.get());
645  std::copy(ContiguousStorage.get(), ContiguousStorage.get() + Size,
646  FinalData);
647  });
648  }
649 
650  void set_final_data(std::nullptr_t) {
651  buffer_plain::set_final_data_internal();
652  }
653 
654  void set_write_back(bool flag = true) { buffer_plain::set_write_back(flag); }
655 
656  bool is_sub_buffer() const { return IsSubBuffer; }
657 
658  template <typename ReinterpretT, int ReinterpretDim>
659  buffer<ReinterpretT, ReinterpretDim,
660  typename std::allocator_traits<AllocatorT>::template rebind_alloc<
661  std::remove_const_t<ReinterpretT>>>
662  reinterpret(range<ReinterpretDim> reinterpretRange) const {
663  if (sizeof(ReinterpretT) * reinterpretRange.size() != byte_size())
664  throw sycl::exception(
666  "Total size in bytes represented by the type and range of the "
667  "reinterpreted SYCL buffer does not equal the total size in bytes "
668  "represented by the type and range of this SYCL buffer");
669 
670  return buffer<ReinterpretT, ReinterpretDim,
671  typename std::allocator_traits<AllocatorT>::
672  template rebind_alloc<std::remove_const_t<ReinterpretT>>>(
673  impl, reinterpretRange, OffsetInBytes, IsSubBuffer);
674  }
675 
676  template <typename ReinterpretT, int ReinterpretDim = dimensions>
677  std::enable_if_t<
678  (sizeof(ReinterpretT) == sizeof(T)) && (dimensions == ReinterpretDim),
679  buffer<ReinterpretT, ReinterpretDim,
680  typename std::allocator_traits<AllocatorT>::template rebind_alloc<
681  std::remove_const_t<ReinterpretT>>>>
682  reinterpret() const {
683  return buffer<ReinterpretT, ReinterpretDim,
684  typename std::allocator_traits<AllocatorT>::
685  template rebind_alloc<std::remove_const_t<ReinterpretT>>>(
686  impl, get_range(), OffsetInBytes, IsSubBuffer);
687  }
688 
689  template <typename ReinterpretT, int ReinterpretDim = dimensions>
690  std::enable_if_t<(ReinterpretDim == 1) &&
691  ((dimensions != ReinterpretDim) ||
692  (sizeof(ReinterpretT) != sizeof(T))),
694  reinterpret() const {
695  long sz = byte_size();
696  if (sz % sizeof(ReinterpretT) != 0)
698  "Total byte size of buffer is not evenly divisible "
699  "by the size of the reinterpreted type");
700 
702  impl, range<1>{sz / sizeof(ReinterpretT)}, OffsetInBytes, IsSubBuffer);
703  }
704 
705  template <typename propertyT> bool has_property() const noexcept {
706  return buffer_plain::template has_property<propertyT>();
707  }
708 
709  template <typename propertyT> propertyT get_property() const {
710  return buffer_plain::template get_property<propertyT>();
711  }
712 
713 protected:
714  bool isOutOfBounds(const id<dimensions> &offset,
715  const range<dimensions> &newRange,
716  const range<dimensions> &parentRange) {
717  bool outOfBounds = false;
718  for (int i = 0; i < dimensions; ++i)
719  outOfBounds |= newRange[i] + offset[i] > parentRange[i];
720 
721  return outOfBounds;
722  }
723 
724 private:
725  template <class Obj>
726  friend const decltype(Obj::impl) &
727  detail::getSyclObjImpl(const Obj &SyclObject);
728  template <typename A, int dims, typename C, typename Enable>
729  friend class buffer;
730  template <typename DataT, int dims, access::mode mode, access::target target,
731  access::placeholder isPlaceholder, typename PropertyListT>
732  friend class accessor;
733  template <typename HT, int HDims, typename HAllocT>
735  detail::make_buffer_helper(ur_native_handle_t, const context &, const event &,
736  bool);
737  template <typename SYCLObjT> friend class ext::oneapi::weak_object;
738 
739  // NOTE: These members are required for reconstructing the buffer, but are not
740  // part of the implementation class. If more members are added, they should
741  // also be added to the weak_object specialization for buffers.
742  range<dimensions> Range;
743  // Offset field specifies the origin of the sub buffer inside the parent
744  // buffer
745  size_t OffsetInBytes = 0;
746  bool IsSubBuffer = false;
747 
748  // Interop constructor
749  template <int N = dimensions, typename = EnableIfOneDimension<N>>
750  buffer(ur_native_handle_t MemObject, const context &SyclContext,
751  bool OwnNativeHandle, const event &AvailableEvent,
753  : buffer_plain(MemObject, SyclContext,
754  std::make_unique<
755  detail::SYCLMemObjAllocatorHolder<AllocatorT, T>>(),
756  OwnNativeHandle, AvailableEvent),
757  Range{0} {
758 
759  Range[0] = buffer_plain::getSize() / sizeof(T);
761  CodeLoc, (void *)impl.get(), &MemObject, (const void *)typeid(T).name(),
762  dimensions, sizeof(T), detail::rangeToArray(Range).data());
763  }
764 
765  void addOrReplaceAccessorProperties(const property_list &PropertyList) {
766  buffer_plain::addOrReplaceAccessorProperties(PropertyList);
767  }
768 
769  void deleteAccProps(const sycl::detail::PropWithDataKind &Kind) {
770  buffer_plain::deleteAccProps(Kind);
771  }
772 
773  // Reinterpret contructor
774  buffer(const std::shared_ptr<detail::buffer_impl> &Impl,
775  range<dimensions> reinterpretRange, size_t reinterpretOffset,
776  bool isSubBuffer,
777  const detail::code_location CodeLoc = detail::code_location::current())
778  : buffer_plain(Impl), Range(reinterpretRange),
779  OffsetInBytes(reinterpretOffset), IsSubBuffer(isSubBuffer) {
781  CodeLoc, (void *)impl.get(), Impl.get(), (const void *)typeid(T).name(),
782  dimensions, sizeof(T), detail::rangeToArray(Range).data());
783  }
784 
785  template <typename Type, int N>
786  size_t getOffsetInBytes(const id<N> &offset, const range<N> &range) {
787  return detail::getLinearIndex(offset, range) * sizeof(Type);
788  }
789 
790  bool isContiguousRegion(const id<1> &, const range<1> &, const range<1> &) {
791  // 1D sub buffer always has contiguous region
792  return true;
793  }
794 
795  bool isContiguousRegion(const id<2> &offset, const range<2> &newRange,
796  const range<2> &parentRange) {
797  // For 2D sub buffer there are 2 cases:
798  // 1) Offset {Any, Any} | a piece of any line of a buffer
799  // Range {1, Any} |
800  // 2) Offset {Any, 0 } | any number of full lines
801  // Range {Any, Col} |
802  // where Col is a number of columns of original buffer
803  if (offset[1])
804  return newRange[0] == 1;
805  return newRange[1] == parentRange[1];
806  }
807 
808  bool isContiguousRegion(const id<3> &offset, const range<3> &newRange,
809  const range<3> &parentRange) {
810  // For 3D sub buffer there are 3 cases:
811  // 1) Offset {Any, Any, Any} | a piece of any line in any slice of a buffer
812  // Range {1, 1, Any} |
813  // 2) Offset {Any, Any, 0 } | any number of full lines in any slice
814  // Range {1, Any, Col} |
815  // 3) Offset {Any, 0, 0 } | any number of slices
816  // Range {Any, Row, Col} |
817  // where Row and Col are numbers of rows and columns of original buffer
818  if (offset[2])
819  return newRange[0] == 1 && newRange[1] == 1;
820  if (offset[1])
821  return newRange[0] == 1 && newRange[2] == parentRange[2];
822  return newRange[1] == parentRange[1] && newRange[2] == parentRange[2];
823  }
824 
825  template <backend BackendName, typename DataT, int Dimensions,
826  typename Allocator>
827  friend auto detail::get_native_buffer(
829  -> backend_return_t<BackendName,
831 
832  template <backend BackendName>
834  getNative() const {
835  auto NativeHandles = buffer_plain::getNativeVector(BackendName);
836  return detail::BufferInterop<BackendName, T, dimensions,
837  AllocatorT>::GetNativeObjs(NativeHandles);
838  }
839 };
840 
841 #ifdef __cpp_deduction_guides
842 template <class InputIterator, class AllocatorT>
843 buffer(InputIterator, InputIterator, AllocatorT, const property_list & = {})
845  AllocatorT>;
846 template <class InputIterator>
847 buffer(InputIterator, InputIterator, const property_list & = {})
849 template <class Container, class AllocatorT>
850 buffer(Container &, AllocatorT, const property_list & = {})
851  -> buffer<typename Container::value_type, 1, AllocatorT>;
852 template <class Container>
853 buffer(Container &,
854  const property_list & = {}) -> buffer<typename Container::value_type, 1>;
855 template <class T, int dimensions, class AllocatorT>
856 buffer(const T *, const range<dimensions> &, AllocatorT,
857  const property_list & = {}) -> buffer<T, dimensions, AllocatorT>;
858 template <class T, int dimensions>
859 buffer(const T *, const range<dimensions> &,
860  const property_list & = {}) -> buffer<T, dimensions>;
861 #endif // __cpp_deduction_guides
862 
863 } // namespace _V1
864 } // namespace sycl
865 
866 namespace std {
867 template <typename T, int dimensions, typename AllocatorT>
868 struct hash<sycl::buffer<T, dimensions, AllocatorT>> {
870  return hash<std::shared_ptr<sycl::detail::buffer_impl>>()(
872  }
873 };
874 } // namespace std
Defines a shared array that can be used by kernels in queues.
Definition: buffer.hpp:173
bool has_property() const noexcept
Definition: buffer.hpp:703
buffer & operator=(const buffer &rhs)=default
AllocatorT get_allocator() const
Definition: buffer.hpp:506
__SYCL2020_DEPRECATED("get_size() is deprecated, please use byte_size() instead") size_t get_size() const
Definition: buffer.hpp:501
buffer(buffer &&rhs, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:466
buffer(InputIterator first, InputIterator last, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:380
__SYCL2020_DEPRECATED("get_access for host_accessor is deprecated, please " "use get_host_access instead") accessor< T
buffer(const buffer &rhs, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:457
buffer(InputIterator first, InputIterator last, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:348
buffer(EnableIfSameNonConstIterators< T, _T > const *hostData, const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:267
propertyT get_property() const
Definition: buffer.hpp:707
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:191
buffer(T *hostData, const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:225
buffer(const range< dimensions > &bufferRange, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:200
friend class buffer
Definition: buffer.hpp:727
size_t byte_size() const noexcept
Definition: buffer.hpp:504
buffer(Container &container, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:432
std::enable_if_t<(sizeof(ReinterpretT)==sizeof(T)) &&(dimensions==ReinterpretDim), buffer< ReinterpretT, ReinterpretDim, typename std::allocator_traits< AllocatorT >::template rebind_alloc< std::remove_const_t< ReinterpretT > > > > reinterpret() const
Definition: buffer.hpp:680
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:329
bool isOutOfBounds(const id< dimensions > &offset, const range< dimensions > &newRange, const range< dimensions > &parentRange)
Definition: buffer.hpp:712
bool operator!=(const buffer &rhs) const
Definition: buffer.hpp:489
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:436
size_t size() const noexcept
Definition: buffer.hpp:499
void set_final_data(Destination finalData=nullptr)
Definition: buffer.hpp:594
std::enable_if_t< std::is_convertible_v< typename std::iterator_traits< It >::iterator_category, std::input_iterator_tag > > EnableIfItInputIterator
Definition: buffer.hpp:195
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:313
buffer(const range< dimensions > &bufferRange, AllocatorT allocator, const property_list &propList={}, const detail::code_location CodeLoc=detail::code_location::current())
Definition: buffer.hpp:212
bool operator==(const buffer &rhs) const
Definition: buffer.hpp:487
bool is_sub_buffer() const
Definition: buffer.hpp:654
const value_type & const_reference
Definition: buffer.hpp:180
range< dimensions > get_range() const
Definition: buffer.hpp:495
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:238
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:413
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:252
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:297
auto get_host_access(Ts... args)
Definition: buffer.hpp:584
__SYCL2020_DEPRECATED("get_count() is deprecated, please use size() instead") size_t get_count() const
Definition: buffer.hpp:497
void set_write_back(bool flag=true)
Definition: buffer.hpp:652
typename std::enable_if_t< std::is_same_v< ItA, ItB > &&!std::is_const_v< ItA >, ItA > EnableIfSameNonConstIterators
Definition: buffer.hpp:198
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:281
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:514
value_type & reference
Definition: buffer.hpp:179
typename std::enable_if_t< 1==dims > EnableIfOneDimension
Definition: buffer.hpp:183
AllocatorT allocator_type
Definition: buffer.hpp:181
The context class represents a SYCL context on which kernel functions may be executed.
Definition: context.hpp:50
buffer_plain(size_t SizeInBytes, size_t, const property_list &Props, std::unique_ptr< detail::SYCLMemObjAllocator > Allocator)
Definition: buffer.cpp:14
bool has_property() const noexcept
Definition: buffer.hpp:133
std::shared_ptr< detail::buffer_impl > impl
Definition: buffer.hpp:153
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)
propertyT get_property() const
Definition: buffer.hpp:137
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:467
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
#define __SYCL_REPORT_EXCEPTION_TO_STREAM(str, e)
Definition: common.hpp:367
std::enable_if_t< std::is_pointer_v< DataT > > EnableIfOutputPointerT
Definition: common.hpp:34
decltype(Obj::impl) const & getSyclObjImpl(const Obj &SyclObject)
Definition: impl_utils.hpp:31
size_t getLinearIndex(const T< Dims > &Index, const U< Dims > &Range)
Definition: common.hpp:286
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 >>
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
buffer< T, Dimensions, AllocatorT, void > make_buffer_helper(ur_native_handle_t Handle, const context &Ctx, const event &Evt, bool OwnNativeHandle=true)
Definition: buffer.hpp:70
void copy(handler &CGH, const T *Src, T *Dest, size_t Count)
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
std::error_code make_error_code(sycl::errc E) noexcept
Constructs an error code using e and sycl_category()
Definition: exception.cpp:65
const void value_type
Definition: multi_ptr.hpp:457
Definition: access.hpp:18
_Abi const simd< _Tp, _Abi > & noexcept
Definition: simd.hpp:1324
size_t operator()(const sycl::buffer< T, dimensions, AllocatorT > &b) const
Definition: buffer.hpp:869
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