OpenVDB 13.1.0
Loading...
Searching...
No Matches
Buffer.h
Go to the documentation of this file.
1// Copyright Contributors to the OpenVDB Project
2// SPDX-License-Identifier: Apache-2.0
3//
4/// @file nanovdb/cuda/Buffer.h
5///
6/// @brief Typed containers for CUDA memory: the owning, resource-aware,
7/// stream-ordered cuda::Buffer and the non-owning cuda::BufferView.
8
9#ifndef NANOVDB_CUDA_BUFFER_H_HAS_BEEN_INCLUDED
10#define NANOVDB_CUDA_BUFFER_H_HAS_BEEN_INCLUDED
11
12#include <cuda_runtime_api.h>
15
16#include <cstddef>
17#include <limits>
18#include <stdexcept>
19#include <type_traits>
20#include <utility>
21
22namespace nanovdb {
23
24namespace cuda {
25
26/// @brief Tag type selecting the Buffer constructors that skip element
27/// initialization, leaving the contents indeterminate.
28struct NoInit {};
29inline constexpr NoInit noInit{};
30
31namespace detail {
32
33/// @brief Conditional stream storage for Buffer. The async specialization
34/// retains the stream of the most recent allocation; the synchronous
35/// specialization is an empty base, so a Buffer over a synchronous
36/// resource carries no stream state and exposes no stream API.
37template<bool IsAsync>
38struct StreamHolder {};
39
40template<>
41struct StreamHolder<true> { cudaStream_t mStream = 0; };
42
43} // namespace detail
44
45/// @brief Owning, typed container of @c T elements allocated from a memory
46/// resource @c R held by value.
47/// @tparam T element type; sizes are expressed in elements, not bytes
48/// @tparam R memory resource, either stream-ordered (AsyncResource concept,
49/// see is_async_resource) or synchronous (Resource concept, see
50/// is_resource). When @c R provides both interfaces the stream-ordered
51/// one is used.
52/// @details With a stream-ordered resource the Buffer retains the stream of
53/// the most recent allocation (or the one supplied via set_stream)
54/// and orders its deallocation on that stream. Buffer is move-only.
55/// @note Cross-stream ordering is the caller's, expressed with ordinary CUDA
56/// events -- the buffer deliberately tracks nothing. To hand a buffer's
57/// contents to work on another stream (a consumer library, a wrapped
58/// tensor), record after the last write and make the consumer wait:
59/// @code
60/// cudaEvent_t ready;
61/// cudaEventCreateWithFlags(&ready, cudaEventDisableTiming);
62/// cudaEventRecord(ready, producerStream); // after the last write
63/// cudaStreamWaitEvent(consumerStream, ready); // before the first read
64/// @endcode
65/// and order the buffer's destruction (which frees on its retained
66/// stream) after all consumers the same way, or synchronize.
67template<typename T, typename R = DeviceResource>
68class Buffer : private detail::StreamHolder<is_async_resource<R>::value>
69{
71 "Buffer requires R to model the AsyncResource or the Resource concept");
72 static_assert(std::is_trivially_copyable<T>::value,
73 "Buffer requires a trivially copyable T: elements are copied bytewise and never constructed or destroyed");
74
75 static constexpr bool IsAsync = is_async_resource<R>::value;
76
77public:
78 /// @brief Element and resource types, for generic code that rebinds one
79 /// or constructs sibling buffers over the same resource.
80 using ElementType = T;
81 using ResourceType = R;
82
83 /// @brief Alias for a sibling buffer over the same resource with a
84 /// different element type.
85 template<typename U>
87
88private:
89 R mResource;
90 T* mData = nullptr;
91 size_t mSize = 0; // element count
92
93public:
94 /// @brief Default c-tor of an empty buffer; performs no allocation.
95 Buffer() = default;
96
97 /// @brief C-tor allocating @c count uninitialized elements, stream-ordered
98 /// on @c stream. Parameter order follows cuda::buffer:
99 /// (stream, resource, count, no_init).
100 /// @param stream cuda stream the allocation is ordered on
101 /// @param resource resource instance the buffer takes ownership of
102 /// @param count number of elements
103 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
104 explicit Buffer(cudaStream_t stream, R resource, size_t count, NoInit)
105 : detail::StreamHolder<true>{stream}
106 , mResource(std::move(resource))
107 {
108 this->allocate(count, stream);
109 }
110
111 /// @brief Convenience c-tor using a default-constructed resource.
112 /// @param stream cuda stream the allocation is ordered on
113 /// @param count number of elements
114 /// @note There is deliberately no count c-tor without NoInit: implicit
115 /// initialization of freshly allocated memory costs a hidden fill
116 /// pass that the dominant allocate-then-overwrite pattern wastes,
117 /// so initialization is always explicit (matching cuda::buffer,
118 /// whose count c-tor likewise requires cuda::no_init).
119 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
120 Buffer(cudaStream_t stream, size_t count, NoInit) : Buffer(stream, R(), count, noInit) {}
121
122 /// @brief C-tor allocating @c count uninitialized elements from a
123 /// synchronous resource: the stream-less analog of
124 /// (stream, resource, count, no_init).
125 /// @param resource resource instance the buffer takes ownership of
126 /// @param count number of elements
127 template<typename S = R, std::enable_if_t<!is_async_resource<S>::value && is_resource<S>::value, int> = 0>
128 explicit Buffer(R resource, size_t count, NoInit)
129 : mResource(std::move(resource))
130 {
131 this->allocate(count, cudaStream_t{0});
132 }
133
134 /// @brief Convenience c-tor using a default-constructed resource.
135 /// @param count number of elements
136 template<typename S = R, std::enable_if_t<!is_async_resource<S>::value && is_resource<S>::value, int> = 0>
137 Buffer(size_t count, NoInit) : Buffer(R(), count, noInit) {}
138
139 /// @brief Explicitly disallow copy construction and assignment operation
140 Buffer(const Buffer&) = delete;
141 Buffer& operator=(const Buffer&) = delete;
142
143 /// @brief Move c-tor; steals the allocation (and retained stream, if any)
144 /// and leaves @c other empty.
145 Buffer(Buffer&& other) noexcept
147 , mResource(std::move(other.mResource))
148 , mData(other.mData)
149 , mSize(other.mSize)
150 {
151 other.mData = nullptr;
152 other.mSize = 0;
153 }
154
155 /// @brief Move assignment; frees the current allocation first, then steals
156 /// from @c other and leaves it empty. Self-move is a no-op.
157 Buffer& operator=(Buffer&& other) noexcept
158 {
159 if (this != &other) {
160 this->destroy();
161 static_cast<detail::StreamHolder<IsAsync>&>(*this) = other;
162 mResource = std::move(other.mResource);
163 mData = other.mData;
164 mSize = other.mSize;
165 other.mData = nullptr;
166 other.mSize = 0;
167 }
168 return *this;
169 }
170
171 /// @brief Returns a deep copy of this buffer, allocated from a copy of the
172 /// resource; the allocation and element copy are ordered on @c stream,
173 /// which becomes the copy's retained stream.
174 /// @param stream cuda stream the allocation and element copy are ordered on
175 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
176 Buffer copy(cudaStream_t stream) const
177 {
178 Buffer out(stream, mResource, mSize, noInit);
179 if (mData) cudaCheck(cudaMemcpyAsync(out.mData, mData, this->size_bytes(), cudaMemcpyDefault, stream));
180 return out;
181 }
182
183 /// @brief Returns a deep copy of this buffer ordered on the retained
184 /// stream, i.e. copy(this->stream()).
185 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
186 Buffer copy() const { return this->copy(this->stream()); }
187
188 /// @brief Returns a deep copy of this buffer, allocated from a copy of the
189 /// synchronous resource.
190 template<typename S = R, std::enable_if_t<!is_async_resource<S>::value && is_resource<S>::value, int> = 0>
191 Buffer copy() const
192 {
193 Buffer out(mResource, mSize, noInit);
194 if (mData) cudaCheck(cudaMemcpy(out.mData, mData, this->size_bytes(), cudaMemcpyDefault));
195 return out;
196 }
197
198 /// @brief D-tor. A stream-ordered resource frees on the retained stream;
199 /// a synchronous resource frees immediately.
200 ~Buffer() { this->destroy(); }
201
202 /// @brief Returns the retained stream, i.e. the stream the buffer's memory
203 /// will be freed on.
204 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
205 cudaStream_t stream() const { return this->mStream; }
206
207 /// @brief Replaces the retained stream without synchronizing; subsequent
208 /// deallocation (and destruction) is ordered on @c stream instead.
209 /// @param stream cuda stream subsequent deallocation is ordered on
210 /// @warning The caller is responsible for ordering @c stream after any
211 /// in-flight work that uses the buffer's memory. This deliberately
212 /// does not synchronize, matching cuda::buffer's set_stream, which
213 /// avoids implicit synchronization in fundamental primitives.
214 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
215 void set_stream(cudaStream_t stream) { this->mStream = stream; }
216
217 /// @brief Resizes the buffer to @c count elements, preserving the leading
218 /// min(old, new) elements. Every operation — the new allocation, the
219 /// prefix copy, and the free of the old block — is ordered on
220 /// @c stream, which becomes the retained stream: the prefix copy is
221 /// the old block's last use, so that is the stream its free must be
222 /// ordered on.
223 /// @param count number of elements
224 /// @param stream cuda stream the reallocation is ordered on
225 /// @warning The caller is responsible for ordering @c stream after any
226 /// in-flight work on the previously retained stream that uses the
227 /// buffer's memory.
228 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
229 void resize(size_t count, cudaStream_t stream)
230 {
231 if (count != mSize) {
232 // No member is mutated until every throwing operation has
233 // succeeded, so a failed resize leaves the buffer untouched --
234 // including its retained stream.
235 T* newData = count ? static_cast<T*>(mResource.allocate_async(checkedBytes(count), R::DEFAULT_ALIGNMENT, stream))
236 : nullptr;
237 if (newData && mData) {
238 const size_t prefix = count < mSize ? count : mSize;
239 try {
240 cudaCheck(cudaMemcpyAsync(newData, mData, prefix * sizeof(T), cudaMemcpyDefault, stream));
241 }
242 catch (...) {
243 mResource.deallocate_async(newData, checkedBytes(count), R::DEFAULT_ALIGNMENT, stream);
244 throw;
245 }
246 }
247 this->mStream = stream;
248 this->deallocate(mData, mSize); // ordered on stream: after the prefix copy
249 mData = newData;
250 mSize = count;
251 }
252 else {
253 this->mStream = stream; // no reallocation: set_stream semantics
254 }
255 }
256
257 /// @brief Resizes the buffer to @c count elements through the synchronous
258 /// resource, preserving the leading min(old, new) elements.
259 /// @param count number of elements
260 template<typename S = R, std::enable_if_t<!is_async_resource<S>::value && is_resource<S>::value, int> = 0>
261 void resize(size_t count)
262 {
263 if (count == mSize) return;
264 // No member is mutated until every throwing operation has succeeded,
265 // so a failed resize leaves the buffer untouched.
266 T* newData = count ? static_cast<T*>(mResource.allocate(checkedBytes(count), R::DEFAULT_ALIGNMENT))
267 : nullptr;
268 if (newData && mData) {
269 const size_t prefix = count < mSize ? count : mSize;
270 try {
271 cudaCheck(cudaMemcpy(newData, mData, prefix * sizeof(T), cudaMemcpyDefault));
272 }
273 catch (...) {
274 mResource.deallocate(newData, checkedBytes(count), R::DEFAULT_ALIGNMENT);
275 throw;
276 }
277 }
278 this->deallocate(mData, mSize);
279 mData = newData;
280 mSize = count;
281 }
282
283 /// @brief Returns a pointer to the elements, or nullptr if empty.
284 T* data() { return mData; }
285 const T* data() const { return mData; }
286
287 /// @brief Returns a copy of the resource; for a ResourceRef this refers
288 /// to the same underlying instance.
289 /// @note Requires R to be copy-constructible (the cuda::mr convention:
290 /// resources are cheap handles). A resource that owns its pool by
291 /// value hands the caller an independent copy of that pool.
292 R resource() const { return mResource; }
293
294 /// @brief Returns the number of elements.
295 size_t size() const { return mSize; }
296
297 /// @brief Returns the size of the buffer's allocation in bytes.
298 size_t size_bytes() const { return mSize * sizeof(T); }
299
300 /// @brief Returns true if this buffer manages no memory.
301 bool empty() const { return mSize == 0; }
302
303 /// @brief Frees the buffer memory (if any) and resets to the empty state.
304 /// A stream-ordered resource frees on the retained stream.
305 /// @note Spelled destroy to match cuda::buffer. This is the name to use.
306 void destroy()
307 {
308 this->deallocate(mData, mSize);
309 mData = nullptr;
310 mSize = 0;
311 }
312
313 /// @brief Frees the buffer memory (if any) and resets to the empty state.
314 /// @deprecated Use destroy(): the handles now dispatch to it directly.
315 [[deprecated("Use cuda::Buffer::destroy instead")]]
316 void clear() { this->destroy(); }
317
318 /// @brief Frees the buffer memory (if any) on @c stream and resets to the
319 /// empty state. @c stream becomes the retained stream.
320 /// @param stream cuda stream the deallocation is ordered on
321 /// @warning The caller is responsible for ordering @c stream after any
322 /// in-flight work that uses the buffer's memory.
323 template<typename S = R, std::enable_if_t<is_async_resource<S>::value, int> = 0>
324 void destroy(cudaStream_t stream)
325 {
326 this->mStream = stream;
327 this->destroy();
328 }
329
330 /// @brief Exchanges the contents of this buffer with @c other. Neither
331 /// buffer allocates, frees, or copies element data.
332 /// @param other buffer to exchange contents with
333 void swap(Buffer& other) noexcept
334 {
335 auto& lhs = static_cast<detail::StreamHolder<IsAsync>&>(*this);
336 auto& rhs = static_cast<detail::StreamHolder<IsAsync>&>(other);
337 std::swap(lhs, rhs);
338 std::swap(mResource, other.mResource);
339 std::swap(mData, other.mData);
340 std::swap(mSize, other.mSize);
341 }
342
343private:
344 /// @brief Returns @c count * sizeof(T), throwing std::runtime_error if the
345 /// byte size would overflow size_t instead of silently wrapping into
346 /// a tiny allocation.
347 /// @param count number of elements
348 static size_t checkedBytes(size_t count)
349 {
350 if (count > std::numeric_limits<size_t>::max() / sizeof(T))
351 throw std::runtime_error("nanovdb::cuda::Buffer: element count overflows the byte size");
352 return count * sizeof(T);
353 }
354
355 /// @brief Allocates @c count elements through the resource and records the
356 /// new extent. A zero count allocates nothing.
357 /// @param count number of elements
358 /// @param stream cuda stream the allocation is ordered on; used by the
359 /// stream-ordered form and ignored by the synchronous one
360 void allocate(size_t count, cudaStream_t stream)
361 {
362 if (count) {
363 if constexpr (IsAsync)
364 mData = static_cast<T*>(mResource.allocate_async(checkedBytes(count), R::DEFAULT_ALIGNMENT, stream));
365 else
366 mData = static_cast<T*>(mResource.allocate(checkedBytes(count), R::DEFAULT_ALIGNMENT));
367 }
368 mSize = count;
369 }
370
371 /// @brief Frees @c count elements at @c p through the resource; the
372 /// stream-ordered form frees on the retained stream. Null is a no-op.
373 /// @param p pointer to the elements to free
374 /// @param count number of elements
375 void deallocate(T* p, size_t count)
376 {
377 if (!p) return;
378 if constexpr (IsAsync)
379 mResource.deallocate_async(p, count * sizeof(T), R::DEFAULT_ALIGNMENT, this->mStream);
380 else
381 mResource.deallocate(p, count * sizeof(T), R::DEFAULT_ALIGNMENT);
382 }
383}; // Buffer<T, R> class
384
385/// @brief Non-owning, trivially copyable view of a contiguous range of @c T
386/// elements, with span semantics.
387/// @tparam T element type; spell constness in the element type
388/// (e.g. BufferView<const std::byte> is the read-only form), since
389/// const on the view itself is shallow.
390template<typename T>
392{
393 T* mData = nullptr;
394 size_t mSize = 0; // element count
395
396public:
397 /// @brief Default c-tor of an empty view.
398 BufferView() = default;
399
400 /// @brief C-tor viewing a contiguous range; the caller guarantees the
401 /// underlying storage outlives every use of the view.
402 /// @param data pointer to the first element
403 /// @param count number of elements
404 /// @throw std::runtime_error if @c data is null while @c count is non-zero.
405 BufferView(T* data, size_t count) : mData(data), mSize(count)
406 {
407 if (data == nullptr && count != 0)
408 throw std::runtime_error("BufferView: null data with a non-zero element count");
409 }
410
411 /// @brief Returns a pointer to the viewed elements, or nullptr if empty.
412 T* data() const { return mData; }
413
414 /// @brief Returns the number of viewed elements.
415 size_t size() const { return mSize; }
416
417 /// @brief Returns the size of the viewed range in bytes.
418 size_t size_bytes() const { return mSize * sizeof(T); }
419
420 /// @brief Returns true if this view references no elements.
421 bool empty() const { return mSize == 0; }
422
423 /// @brief Detaches the view (nulls the pointer and zeroes the size)
424 /// without touching the underlying storage -- the view is
425 /// non-owning, so "destroying" it releases nothing. This is the
426 /// one deliberate deviation from std::span, required by the buffer
427 /// static interface the handles consume through reset().
428 void destroy()
429 {
430 mData = nullptr;
431 mSize = 0;
432 }
433
434 /// @brief Detaches the view.
435 /// @deprecated Use destroy(): the handles now dispatch to it directly.
436 [[deprecated("Use cuda::BufferView::destroy instead")]]
437 void clear() { this->destroy(); }
438}; // BufferView<T> class
439
440} // namespace cuda
441
442// Primary template defined in HostBuffer.h; declared here so this header
443// stays self-contained without pulling in the host-buffer machinery.
444template<typename BufferT>
445struct BufferTraits;
446
447/// @brief GridHandle support for the single-space cuda::Buffer: the buffer
448/// owns exactly one allocation, resident on the device, so the handle
449/// parses metadata through a device read and exposes only the device
450/// accessors. Requires byte-addressed storage.
451/// @note This trait doubles as the definition of the single-space
452/// device-buffer concept: a buffer whose BufferTraits specialization
453/// sets hasDeviceSingle guarantees ElementType and ResourceType
454/// typedefs, data(), size() and size_bytes() (byte-addressed elements,
455/// enforced by the consumer), resource(), copy(), destroy(), and stream()
456/// when the resource is stream-ordered. Any consumer of hasDeviceSingle
457/// may rely on exactly this interface and nothing more; in particular,
458/// scratch allocates through resource() as a cuda::Buffer, so a
459/// conforming buffer never needs to be constructible by a consumer.
460template<typename T, typename R>
461struct BufferTraits<cuda::Buffer<T, R>>
462{
463 static constexpr bool hasDeviceDual = false;
464 // Device-resident storage; the byte-addressed requirement is enforced by
465 // the single-space GridHandle constructor, so trait queries stay
466 // answerable for any element type.
469 // A buffer over a host-accessible resource (e.g. PinnedResource) is
470 // host-readable single-space storage: GridHandle parses its metadata on
471 // the host, exposes the host accessors, and allocates reads and copies
472 // through the buffer's resource. A resource that is host- AND
473 // device-accessible (ManagedResource) sets both members: the handle
474 // parses metadata through the device (a host parse could race producer
475 // kernels) and exposes both accessor families.
477};
478
479} // namespace nanovdb
480
481#endif // end of NANOVDB_CUDA_BUFFER_H_HAS_BEEN_INCLUDED
BufferView()=default
Default c-tor of an empty view.
size_t size() const
Returns the number of viewed elements.
Definition Buffer.h:415
T * data() const
Returns a pointer to the viewed elements, or nullptr if empty.
Definition Buffer.h:412
BufferView(T *data, size_t count)
C-tor viewing a contiguous range; the caller guarantees the underlying storage outlives every use of ...
Definition Buffer.h:405
void destroy()
Detaches the view (nulls the pointer and zeroes the size) without touching the underlying storage – t...
Definition Buffer.h:428
bool empty() const
Returns true if this view references no elements.
Definition Buffer.h:421
void clear()
Detaches the view.
Definition Buffer.h:437
size_t size_bytes() const
Returns the size of the viewed range in bytes.
Definition Buffer.h:418
Buffer(cudaStream_t stream, size_t count, NoInit)
Convenience c-tor using a default-constructed resource.
Definition Buffer.h:120
T ElementType
Element and resource types, for generic code that rebinds one or constructs sibling buffers over the ...
Definition Buffer.h:80
R ResourceType
Definition Buffer.h:81
Buffer(const Buffer &)=delete
Explicitly disallow copy construction and assignment operation.
size_t size() const
Returns the number of elements.
Definition Buffer.h:295
Buffer()=default
Default c-tor of an empty buffer; performs no allocation.
void swap(Buffer &other) noexcept
Exchanges the contents of this buffer with other. Neither buffer allocates, frees,...
Definition Buffer.h:333
void destroy()
Frees the buffer memory (if any) and resets to the empty state. A stream-ordered resource frees on th...
Definition Buffer.h:306
cudaStream_t stream() const
Definition Buffer.h:205
Buffer< U, R > rebind
Alias for a sibling buffer over the same resource with a different element type.
Definition Buffer.h:86
const T * data() const
Definition Buffer.h:285
bool empty() const
Returns true if this buffer manages no memory.
Definition Buffer.h:301
Buffer(cudaStream_t stream, R resource, size_t count, NoInit)
C-tor allocating count uninitialized elements, stream-ordered on stream. Parameter order follows cuda...
Definition Buffer.h:104
Buffer copy(cudaStream_t stream) const
Returns a deep copy of this buffer, allocated from a copy of the resource; the allocation and element...
Definition Buffer.h:176
void destroy(cudaStream_t stream)
Frees the buffer memory (if any) on stream and resets to the empty state. stream becomes the retained...
Definition Buffer.h:324
R resource() const
Definition Buffer.h:292
Buffer(R resource, size_t count, NoInit)
C-tor allocating count uninitialized elements from a synchronous resource: the stream-less analog of ...
Definition Buffer.h:128
Buffer copy() const
Returns a deep copy of this buffer ordered on the retained stream, i.e. copy(this->stream()).
Definition Buffer.h:186
void resize(size_t count)
Resizes the buffer to count elements through the synchronous resource, preserving the leading min(old...
Definition Buffer.h:261
Buffer(size_t count, NoInit)
Convenience c-tor using a default-constructed resource.
Definition Buffer.h:137
void resize(size_t count, cudaStream_t stream)
Resizes the buffer to count elements, preserving the leading min(old, new) elements....
Definition Buffer.h:229
~Buffer()
D-tor. A stream-ordered resource frees on the retained stream; a synchronous resource frees immediate...
Definition Buffer.h:200
void clear()
Frees the buffer memory (if any) and resets to the empty state.
Definition Buffer.h:316
T * data()
Returns a pointer to the elements, or nullptr if empty.
Definition Buffer.h:284
void set_stream(cudaStream_t stream)
Replaces the retained stream without synchronizing; subsequent deallocation (and destruction) is orde...
Definition Buffer.h:215
Buffer(Buffer &&other) noexcept
Move c-tor; steals the allocation (and retained stream, if any) and leaves other empty.
Definition Buffer.h:145
Buffer & operator=(Buffer &&other) noexcept
Move assignment; frees the current allocation first, then steals from other and leaves it empty....
Definition Buffer.h:157
size_t size_bytes() const
Returns the size of the buffer's allocation in bytes.
Definition Buffer.h:298
Buffer & operator=(const Buffer &)=delete
Definition VoxToNanoVDB.h:15
Definition GridHandle.h:37
constexpr NoInit noInit
Definition Buffer.h:29
Defines a simple memory pool used to call cub functions that use dynamic temporary storage.
Definition GridHandle.h:31
Definition Coord.h:590
Cuda specific utility functions.
#define cudaCheck(ans)
Definition Util.h:49
static constexpr bool hasHostSingle
Definition Buffer.h:476
static constexpr bool hasDeviceSingle
Definition Buffer.h:467
static constexpr bool hasDeviceDual
Definition Buffer.h:463
Definition HostBuffer.h:101
Tag type selecting the Buffer constructors that skip element initialization, leaving the contents ind...
Definition Buffer.h:28
cudaStream_t mStream
Definition Buffer.h:41
Conditional stream storage for Buffer. The async specialization retains the stream of the most recent...
Definition Buffer.h:38
Detection trait: is_async_resource<R>::value is true iff R models the stream-ordered AsyncResource co...
Definition DeviceResource.h:118
Companion detection: is_device_accessible_resource<R>::value is true iff R declares static constexpr ...
Definition DeviceResource.h:147
Detection trait: is_host_accessible_resource<R>::value is true iff R declares static constexpr bool H...
Definition DeviceResource.h:135
Detection trait: is_resource<R>::value is true iff R models the synchronous Resource concept,...
Definition DeviceResource.h:165