@@ -42,34 +42,34 @@ enum class CudaTextureFormat : uint32_t {
42
42
Float16 = 1 , // / Half precision storage format
43
43
};
44
44
45
- template <typename _Storage , size_t Dimension> class Texture {
45
+ template <typename Storage_ , size_t Dimension> class Texture {
46
46
public:
47
- static constexpr bool IsCUDA = is_cuda_v<_Storage >;
48
- static constexpr bool IsDiff = is_diff_v<_Storage >;
49
- static constexpr bool IsDynamic = is_dynamic_v<_Storage >;
47
+ static constexpr bool IsCUDA = is_cuda_v<Storage_ >;
48
+ static constexpr bool IsDiff = is_diff_v<Storage_ >;
49
+ static constexpr bool IsDynamic = is_dynamic_v<Storage_ >;
50
50
// Only half/single-precision floating-point CUDA textures are supported
51
- static constexpr bool IsHalf = std::is_same_v<scalar_t <_Storage >, drjit::half>;
52
- static constexpr bool IsSingle = std::is_same_v<scalar_t <_Storage >, float >;
51
+ static constexpr bool IsHalf = std::is_same_v<scalar_t <Storage_ >, drjit::half>;
52
+ static constexpr bool IsSingle = std::is_same_v<scalar_t <Storage_ >, float >;
53
53
static constexpr bool HasCudaTexture = (IsHalf || IsSingle) && IsCUDA;
54
54
static constexpr int CudaFormat = HasCudaTexture ?
55
55
IsHalf ? (int )CudaTextureFormat::Float16 : (int )CudaTextureFormat::Float32 : -1 ;
56
56
57
- using Int32 = int32_array_t <_Storage >;
58
- using UInt32 = uint32_array_t <_Storage >;
59
- using Storage = std::conditional_t <IsDynamic, _Storage , DynamicArray<_Storage >>;
60
- using Packet = std::conditional_t <is_jit_v<_Storage >,
61
- DynamicArray<_Storage >, _Storage *>;
57
+ using Int32 = int32_array_t <Storage_ >;
58
+ using UInt32 = uint32_array_t <Storage_ >;
59
+ using Storage = std::conditional_t <IsDynamic, Storage_ , DynamicArray<Storage_ >>;
60
+ using Packet = std::conditional_t <is_jit_v<Storage_ >,
61
+ DynamicArray<Storage_ >, Storage_ *>;
62
62
using TensorXf = Tensor<Storage>;
63
63
64
64
#define DR_TEX_ALLOC_PACKET (name, size ) \
65
65
Packet _packet; \
66
- _Storage * name; \
66
+ Storage_ * name; \
67
67
\
68
68
if constexpr (is_jit_v<Value>) { \
69
69
_packet = empty<Packet>(m_channels_storage); \
70
70
name = _packet.data (); \
71
71
} else { \
72
- name = (_Storage *) alloca (sizeof (_Storage ) * size); \
72
+ name = (Storage_ *) alloca (sizeof (Storage_ ) * size); \
73
73
(void ) _packet; \
74
74
}
75
75
@@ -125,15 +125,16 @@ template <typename _Storage, size_t Dimension> class Texture {
125
125
* Both the \c filter_mode and \c wrap_mode have the same defaults and
126
126
* behaviors as for the previous constructor.
127
127
*/
128
- Texture (const TensorXf &tensor, bool use_accel = true , bool migrate = true ,
128
+ template <typename TensorT>
129
+ Texture (TensorT &&tensor, bool use_accel = true , bool migrate = true ,
129
130
FilterMode filter_mode = FilterMode::Linear,
130
131
WrapMode wrap_mode = WrapMode::Clamp) {
131
132
if (tensor.ndim () != Dimension + 1 )
132
133
jit_raise (" Texture::Texture(): tensor dimension must equal "
133
134
" texture dimension plus one." );
134
135
init (tensor.shape ().data (), tensor.shape (Dimension), use_accel,
135
136
filter_mode, wrap_mode);
136
- set_tensor (tensor, migrate);
137
+ set_tensor (std::forward<TensorT>( tensor) , migrate);
137
138
}
138
139
139
140
Texture (Texture &&other) noexcept {
@@ -209,16 +210,21 @@ template <typename _Storage, size_t Dimension> class Texture {
209
210
* When \c migrate is set to \c true on CUDA mode, the texture information
210
211
* is *fully* migrated to GPU texture memory to avoid redundant storage.
211
212
*/
212
- void set_value (const Storage &value, bool migrate=false ) {
213
- if constexpr (!is_jit_v<_Storage>) {
213
+ template <typename StorageT>
214
+ void set_value (StorageT &&value, bool migrate = false ) {
215
+ static_assert (
216
+ std::is_same_v<std::decay_t <StorageT>, Storage>,
217
+ " Texture::set_value(): argument has an unsupported type!" );
218
+
219
+ if constexpr (!is_jit_v<Storage_>) {
214
220
if (value.size () != m_size)
215
221
jit_raise (" Texture::set_value(): unexpected array size!" );
216
- m_value.array () = value;
222
+ m_value.array () = std::forward<StorageT>( value) ;
217
223
} else /* JIT variant */ {
218
224
Storage padded_value;
219
225
220
226
if (m_channels_storage != m_channels) {
221
- using Mask = mask_t <_Storage >;
227
+ using Mask = mask_t <Storage_ >;
222
228
UInt32 idx = arange<UInt32 >(m_size);
223
229
UInt32 pixels_idx = idx / m_channels_storage;
224
230
UInt32 channel_idx = idx % m_channels_storage;
@@ -230,7 +236,9 @@ template <typename _Storage, size_t Dimension> class Texture {
230
236
}
231
237
232
238
if (padded_value.size () != m_size)
233
- jit_raise (" Texture::set_value(): unexpected array size!" );
239
+ jit_raise (
240
+ " Texture::set_value(): unexpected array size (%zu vs %zu)!" ,
241
+ padded_value.size (), m_size);
234
242
235
243
// We can always re-compute the unpadded values from the padded
236
244
// ones. However, if we systematically do that, users will not be
@@ -242,9 +250,11 @@ template <typename _Storage, size_t Dimension> class Texture {
242
250
// the correct gradient value.
243
251
// To solve this issue, we store the AD index now, and re-attach
244
252
// it to the output of `tensor()` on every call.
245
- if constexpr (IsDiff)
246
- m_unpadded_value.array () =
247
- replace_grad (m_unpadded_value.array (), value);
253
+ if constexpr (IsDiff) {
254
+ if (grad_enabled (value))
255
+ m_unpadded_value.array () =
256
+ replace_grad (m_unpadded_value.array (), value);
257
+ }
248
258
249
259
if constexpr (HasCudaTexture) {
250
260
if (m_use_accel) {
@@ -286,12 +296,13 @@ template <typename _Storage, size_t Dimension> class Texture {
286
296
* When \c migrate is set to \c true on CUDA mode, the texture information
287
297
* is *fully* migrated to GPU texture memory to avoid redundant storage.
288
298
*/
289
- void set_tensor (const TensorXf &tensor, bool migrate=false ) {
299
+ template <typename TensorT>
300
+ void set_tensor (TensorT &&tensor, bool migrate = false ) {
290
301
if (tensor.ndim () != Dimension + 1 )
291
302
jit_raise (" Texture::set_tensor(): tensor dimension must equal "
292
- " texture dimension plus one (channels)." );
303
+ " texture dimension plus one (channels)." );
293
304
294
- if (&tensor == &m_unpadded_value) {
305
+ if (( void *) &tensor == ( void *) &m_unpadded_value) {
295
306
jit_log (::LogLevel::Warn,
296
307
" Texture::set_tensor(): the `tensor` argument is a "
297
308
" reference to this texture's own tensor representation "
@@ -311,9 +322,12 @@ template <typename _Storage, size_t Dimension> class Texture {
311
322
312
323
// Only update tensors & CUDA texture if shape changed
313
324
init (tensor.shape ().data (), tensor.shape (Dimension),
314
- m_use_accel, m_filter_mode, m_wrap_mode, shape_changed);
325
+ m_use_accel, m_filter_mode, m_wrap_mode, shape_changed);
315
326
316
- set_value (tensor.array (), migrate);
327
+ if constexpr (std::is_lvalue_reference_v<TensorT>)
328
+ set_value (tensor.array (), migrate);
329
+ else
330
+ set_value (std::move (tensor.array ()), migrate);
317
331
}
318
332
319
333
/* *
@@ -342,7 +356,7 @@ template <typename _Storage, size_t Dimension> class Texture {
342
356
}
343
357
}
344
358
345
- if constexpr (!is_jit_v<_Storage >) {
359
+ if constexpr (!is_jit_v<Storage_ >) {
346
360
if (shape_changed)
347
361
init (m_unpadded_value.shape ().data (),
348
362
m_unpadded_value.shape (Dimension), m_use_accel, m_filter_mode,
@@ -371,7 +385,7 @@ template <typename _Storage, size_t Dimension> class Texture {
371
385
* \brief Return the texture data as a tensor object
372
386
*/
373
387
const TensorXf &tensor () const {
374
- if constexpr (!is_jit_v<_Storage >) {
388
+ if constexpr (!is_jit_v<Storage_ >) {
375
389
return m_value;
376
390
} else {
377
391
sync_device_data ();
@@ -412,7 +426,7 @@ template <typename _Storage, size_t Dimension> class Texture {
412
426
*/
413
427
TensorXf &tensor () {
414
428
return const_cast <TensorXf &>(
415
- const_cast <const Texture<_Storage , Dimension> *>(this )->tensor ());
429
+ const_cast <const Texture<Storage_ , Dimension> *>(this )->tensor ());
416
430
}
417
431
418
432
/* *
@@ -1386,7 +1400,7 @@ template <typename _Storage, size_t Dimension> class Texture {
1386
1400
m_channels = channels;
1387
1401
1388
1402
// Determine padding used for channels depending on backend
1389
- if constexpr (is_jit_v<_Storage >) {
1403
+ if constexpr (is_jit_v<Storage_ >) {
1390
1404
m_channels_storage = 1 ;
1391
1405
while (m_channels_storage < m_channels)
1392
1406
m_channels_storage <<= 1 ;
@@ -1413,10 +1427,18 @@ template <typename _Storage, size_t Dimension> class Texture {
1413
1427
m_wrap_mode = wrap_mode;
1414
1428
1415
1429
if (init_tensor) {
1416
- m_value =
1417
- TensorXf (empty<Storage>(m_size), Dimension + 1 , tensor_shape);
1418
- m_unpadded_value =
1419
- TensorXf (empty<Storage>(unpadded_size), Dimension + 1 , m_shape);
1430
+ if constexpr (is_jit_v<Storage_>) {
1431
+ m_value =
1432
+ TensorXf (empty<Storage>(m_size), Dimension + 1 , tensor_shape);
1433
+ m_unpadded_value =
1434
+ TensorXf (empty<Storage>(unpadded_size), Dimension + 1 , m_shape);
1435
+ } else {
1436
+ // Don't allocate memory in scalar modes
1437
+ m_value =
1438
+ TensorXf (Storage::map_ (nullptr , m_size), Dimension + 1 , tensor_shape);
1439
+ m_unpadded_value =
1440
+ TensorXf (Storage::map_ (nullptr , unpadded_size), Dimension + 1 , m_shape);
1441
+ }
1420
1442
}
1421
1443
1422
1444
if constexpr (HasCudaTexture) {
0 commit comments