@@ -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,17 @@ 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
+ if constexpr (!is_jit_v<Storage_>) {
214
216
if (value.size () != m_size)
215
217
jit_raise (" Texture::set_value(): unexpected array size!" );
216
- m_value.array () = value;
218
+ m_value.array () = std::forward<StorageT>( value) ;
217
219
} else /* JIT variant */ {
218
220
Storage padded_value;
219
221
220
222
if (m_channels_storage != m_channels) {
221
- using Mask = mask_t <_Storage >;
223
+ using Mask = mask_t <Storage_ >;
222
224
UInt32 idx = arange<UInt32 >(m_size);
223
225
UInt32 pixels_idx = idx / m_channels_storage;
224
226
UInt32 channel_idx = idx % m_channels_storage;
@@ -230,7 +232,9 @@ template <typename _Storage, size_t Dimension> class Texture {
230
232
}
231
233
232
234
if (padded_value.size () != m_size)
233
- jit_raise (" Texture::set_value(): unexpected array size!" );
235
+ jit_raise (
236
+ " Texture::set_value(): unexpected array size (%zu vs %zu)!" ,
237
+ padded_value.size (), m_size);
234
238
235
239
// We can always re-compute the unpadded values from the padded
236
240
// ones. However, if we systematically do that, users will not be
@@ -242,9 +246,11 @@ template <typename _Storage, size_t Dimension> class Texture {
242
246
// the correct gradient value.
243
247
// To solve this issue, we store the AD index now, and re-attach
244
248
// 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);
249
+ if constexpr (IsDiff) {
250
+ if (grad_enabled (value))
251
+ m_unpadded_value.array () =
252
+ replace_grad (m_unpadded_value.array (), value);
253
+ }
248
254
249
255
if constexpr (HasCudaTexture) {
250
256
if (m_use_accel) {
@@ -286,12 +292,13 @@ template <typename _Storage, size_t Dimension> class Texture {
286
292
* When \c migrate is set to \c true on CUDA mode, the texture information
287
293
* is *fully* migrated to GPU texture memory to avoid redundant storage.
288
294
*/
289
- void set_tensor (const TensorXf &tensor, bool migrate=false ) {
295
+ template <typename TensorT>
296
+ void set_tensor (TensorT &&tensor, bool migrate = false ) {
290
297
if (tensor.ndim () != Dimension + 1 )
291
298
jit_raise (" Texture::set_tensor(): tensor dimension must equal "
292
- " texture dimension plus one (channels)." );
299
+ " texture dimension plus one (channels)." );
293
300
294
- if (&tensor == &m_unpadded_value) {
301
+ if (( void *) &tensor == ( void *) &m_unpadded_value) {
295
302
jit_log (::LogLevel::Warn,
296
303
" Texture::set_tensor(): the `tensor` argument is a "
297
304
" reference to this texture's own tensor representation "
@@ -311,9 +318,12 @@ template <typename _Storage, size_t Dimension> class Texture {
311
318
312
319
// Only update tensors & CUDA texture if shape changed
313
320
init (tensor.shape ().data (), tensor.shape (Dimension),
314
- m_use_accel, m_filter_mode, m_wrap_mode, shape_changed);
321
+ m_use_accel, m_filter_mode, m_wrap_mode, shape_changed);
315
322
316
- set_value (tensor.array (), migrate);
323
+ if constexpr (std::is_lvalue_reference_v<TensorT>)
324
+ set_value (tensor.array (), migrate);
325
+ else
326
+ set_value (std::move (tensor.array ()), migrate);
317
327
}
318
328
319
329
/* *
@@ -342,7 +352,7 @@ template <typename _Storage, size_t Dimension> class Texture {
342
352
}
343
353
}
344
354
345
- if constexpr (!is_jit_v<_Storage >) {
355
+ if constexpr (!is_jit_v<Storage_ >) {
346
356
if (shape_changed)
347
357
init (m_unpadded_value.shape ().data (),
348
358
m_unpadded_value.shape (Dimension), m_use_accel, m_filter_mode,
@@ -371,7 +381,7 @@ template <typename _Storage, size_t Dimension> class Texture {
371
381
* \brief Return the texture data as a tensor object
372
382
*/
373
383
const TensorXf &tensor () const {
374
- if constexpr (!is_jit_v<_Storage >) {
384
+ if constexpr (!is_jit_v<Storage_ >) {
375
385
return m_value;
376
386
} else {
377
387
sync_device_data ();
@@ -412,7 +422,7 @@ template <typename _Storage, size_t Dimension> class Texture {
412
422
*/
413
423
TensorXf &tensor () {
414
424
return const_cast <TensorXf &>(
415
- const_cast <const Texture<_Storage , Dimension> *>(this )->tensor ());
425
+ const_cast <const Texture<Storage_ , Dimension> *>(this )->tensor ());
416
426
}
417
427
418
428
/* *
@@ -1386,7 +1396,7 @@ template <typename _Storage, size_t Dimension> class Texture {
1386
1396
m_channels = channels;
1387
1397
1388
1398
// Determine padding used for channels depending on backend
1389
- if constexpr (is_jit_v<_Storage >) {
1399
+ if constexpr (is_jit_v<Storage_ >) {
1390
1400
m_channels_storage = 1 ;
1391
1401
while (m_channels_storage < m_channels)
1392
1402
m_channels_storage <<= 1 ;
@@ -1413,10 +1423,18 @@ template <typename _Storage, size_t Dimension> class Texture {
1413
1423
m_wrap_mode = wrap_mode;
1414
1424
1415
1425
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);
1426
+ if constexpr (is_jit_v<Storage_>) {
1427
+ m_value =
1428
+ TensorXf (empty<Storage>(m_size), Dimension + 1 , tensor_shape);
1429
+ m_unpadded_value =
1430
+ TensorXf (empty<Storage>(unpadded_size), Dimension + 1 , m_shape);
1431
+ } else {
1432
+ // Don't allocate memory in scalar modes
1433
+ m_value =
1434
+ TensorXf (Storage::map_ (nullptr , m_size), Dimension + 1 , tensor_shape);
1435
+ m_unpadded_value =
1436
+ TensorXf (Storage::map_ (nullptr , unpadded_size), Dimension + 1 , m_shape);
1437
+ }
1420
1438
}
1421
1439
1422
1440
if constexpr (HasCudaTexture) {
0 commit comments