Geometry Nodes: new Material input node
[blender.git] / intern / cycles / device / device_memory.h
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __DEVICE_MEMORY_H__
18 #define __DEVICE_MEMORY_H__
19
20 /* Device Memory
21  *
22  * Data types for allocating, copying and freeing device memory. */
23
24 #include "util/util_array.h"
25 #include "util/util_half.h"
26 #include "util/util_string.h"
27 #include "util/util_texture.h"
28 #include "util/util_types.h"
29 #include "util/util_vector.h"
30
31 CCL_NAMESPACE_BEGIN
32
33 class Device;
34
35 enum MemoryType {
36   MEM_READ_ONLY,
37   MEM_READ_WRITE,
38   MEM_DEVICE_ONLY,
39   MEM_GLOBAL,
40   MEM_TEXTURE,
41   MEM_PIXELS
42 };
43
44 /* Supported Data Types */
45
46 enum DataType {
47   TYPE_UNKNOWN,
48   TYPE_UCHAR,
49   TYPE_UINT16,
50   TYPE_UINT,
51   TYPE_INT,
52   TYPE_FLOAT,
53   TYPE_HALF,
54   TYPE_UINT64,
55 };
56
57 static inline size_t datatype_size(DataType datatype)
58 {
59   switch (datatype) {
60     case TYPE_UNKNOWN:
61       return 1;
62     case TYPE_UCHAR:
63       return sizeof(uchar);
64     case TYPE_FLOAT:
65       return sizeof(float);
66     case TYPE_UINT:
67       return sizeof(uint);
68     case TYPE_UINT16:
69       return sizeof(uint16_t);
70     case TYPE_INT:
71       return sizeof(int);
72     case TYPE_HALF:
73       return sizeof(half);
74     case TYPE_UINT64:
75       return sizeof(uint64_t);
76     default:
77       return 0;
78   }
79 }
80
81 /* Traits for data types */
82
83 template<typename T> struct device_type_traits {
84   static const DataType data_type = TYPE_UNKNOWN;
85   static const int num_elements = sizeof(T);
86 };
87
88 template<> struct device_type_traits<uchar> {
89   static const DataType data_type = TYPE_UCHAR;
90   static const int num_elements = 1;
91 };
92
93 template<> struct device_type_traits<uchar2> {
94   static const DataType data_type = TYPE_UCHAR;
95   static const int num_elements = 2;
96 };
97
98 template<> struct device_type_traits<uchar3> {
99   static const DataType data_type = TYPE_UCHAR;
100   static const int num_elements = 3;
101 };
102
103 template<> struct device_type_traits<uchar4> {
104   static const DataType data_type = TYPE_UCHAR;
105   static const int num_elements = 4;
106 };
107
108 template<> struct device_type_traits<uint> {
109   static const DataType data_type = TYPE_UINT;
110   static const int num_elements = 1;
111 };
112
113 template<> struct device_type_traits<uint2> {
114   static const DataType data_type = TYPE_UINT;
115   static const int num_elements = 2;
116 };
117
118 template<> struct device_type_traits<uint3> {
119   static const DataType data_type = TYPE_UINT;
120   static const int num_elements = 3;
121 };
122
123 template<> struct device_type_traits<uint4> {
124   static const DataType data_type = TYPE_UINT;
125   static const int num_elements = 4;
126 };
127
128 template<> struct device_type_traits<int> {
129   static const DataType data_type = TYPE_INT;
130   static const int num_elements = 1;
131 };
132
133 template<> struct device_type_traits<int2> {
134   static const DataType data_type = TYPE_INT;
135   static const int num_elements = 2;
136 };
137
138 template<> struct device_type_traits<int3> {
139   static const DataType data_type = TYPE_INT;
140   static const int num_elements = 3;
141 };
142
143 template<> struct device_type_traits<int4> {
144   static const DataType data_type = TYPE_INT;
145   static const int num_elements = 4;
146 };
147
148 template<> struct device_type_traits<float> {
149   static const DataType data_type = TYPE_FLOAT;
150   static const int num_elements = 1;
151 };
152
153 template<> struct device_type_traits<float2> {
154   static const DataType data_type = TYPE_FLOAT;
155   static const int num_elements = 2;
156 };
157
158 template<> struct device_type_traits<float3> {
159   static const DataType data_type = TYPE_FLOAT;
160   static const int num_elements = 4;
161 };
162
163 template<> struct device_type_traits<float4> {
164   static const DataType data_type = TYPE_FLOAT;
165   static const int num_elements = 4;
166 };
167
168 template<> struct device_type_traits<half> {
169   static const DataType data_type = TYPE_HALF;
170   static const int num_elements = 1;
171 };
172
173 template<> struct device_type_traits<ushort4> {
174   static const DataType data_type = TYPE_UINT16;
175   static const int num_elements = 4;
176 };
177
178 template<> struct device_type_traits<uint16_t> {
179   static const DataType data_type = TYPE_UINT16;
180   static const int num_elements = 1;
181 };
182
183 template<> struct device_type_traits<half4> {
184   static const DataType data_type = TYPE_HALF;
185   static const int num_elements = 4;
186 };
187
188 template<> struct device_type_traits<uint64_t> {
189   static const DataType data_type = TYPE_UINT64;
190   static const int num_elements = 1;
191 };
192
193 /* Device Memory
194  *
195  * Base class for all device memory. This should not be allocated directly,
196  * instead the appropriate subclass can be used. */
197
198 class device_memory {
199  public:
200   size_t memory_size()
201   {
202     return data_size * data_elements * datatype_size(data_type);
203   }
204   size_t memory_elements_size(int elements)
205   {
206     return elements * data_elements * datatype_size(data_type);
207   }
208
209   /* Data information. */
210   DataType data_type;
211   int data_elements;
212   size_t data_size;
213   size_t device_size;
214   size_t data_width;
215   size_t data_height;
216   size_t data_depth;
217   MemoryType type;
218   const char *name;
219
220   /* Pointers. */
221   Device *device;
222   device_ptr device_pointer;
223   void *host_pointer;
224   void *shared_pointer;
225   /* reference counter for shared_pointer */
226   int shared_counter;
227
228   virtual ~device_memory();
229
230   void swap_device(Device *new_device, size_t new_device_size, device_ptr new_device_ptr);
231   void restore_device();
232
233   bool is_resident(Device *sub_device) const;
234
235  protected:
236   friend class CUDADevice;
237   friend class OptiXDevice;
238
239   /* Only create through subclasses. */
240   device_memory(Device *device, const char *name, MemoryType type);
241
242   /* No copying allowed. */
243   device_memory(const device_memory &) = delete;
244   device_memory &operator=(const device_memory &) = delete;
245
246   /* Host allocation on the device. All host_pointer memory should be
247    * allocated with these functions, for devices that support using
248    * the same pointer for host and device. */
249   void *host_alloc(size_t size);
250   void host_free();
251
252   /* Device memory allocation and copying. */
253   void device_alloc();
254   void device_free();
255   void device_copy_to();
256   void device_copy_from(int y, int w, int h, int elem);
257   void device_zero();
258
259   device_ptr original_device_ptr;
260   size_t original_device_size;
261   Device *original_device;
262   bool need_realloc_;
263   bool modified;
264 };
265
266 /* Device Only Memory
267  *
268  * Working memory only needed by the device, with no corresponding allocation
269  * on the host. Only used internally in the device implementations. */
270
271 template<typename T> class device_only_memory : public device_memory {
272  public:
273   device_only_memory(Device *device, const char *name, bool allow_host_memory_fallback = false)
274       : device_memory(device, name, allow_host_memory_fallback ? MEM_READ_WRITE : MEM_DEVICE_ONLY)
275   {
276     data_type = device_type_traits<T>::data_type;
277     data_elements = max(device_type_traits<T>::num_elements, 1);
278   }
279
280   virtual ~device_only_memory()
281   {
282     free();
283   }
284
285   void alloc_to_device(size_t num, bool shrink_to_fit = true)
286   {
287     size_t new_size = num;
288     bool reallocate;
289
290     if (shrink_to_fit) {
291       reallocate = (data_size != new_size);
292     }
293     else {
294       reallocate = (data_size < new_size);
295     }
296
297     if (reallocate) {
298       device_free();
299       data_size = new_size;
300       device_alloc();
301     }
302   }
303
304   void free()
305   {
306     device_free();
307     data_size = 0;
308   }
309
310   void zero_to_device()
311   {
312     device_zero();
313   }
314 };
315
316 /* Device Vector
317  *
318  * Data vector to exchange data between host and device. Memory will be
319  * allocated on the host first with alloc() and resize, and then filled
320  * in and copied to the device with copy_to_device(). Or alternatively
321  * allocated and set to zero on the device with zero_to_device().
322  *
323  * When using memory type MEM_GLOBAL, a pointer to this memory will be
324  * automatically attached to kernel globals, using the provided name
325  * matching an entry in kernel_textures.h. */
326
327 template<typename T> class device_vector : public device_memory {
328  public:
329   device_vector(Device *device, const char *name, MemoryType type)
330       : device_memory(device, name, type)
331   {
332     data_type = device_type_traits<T>::data_type;
333     data_elements = device_type_traits<T>::num_elements;
334     modified = true;
335     need_realloc_ = true;
336
337     assert(data_elements > 0);
338   }
339
340   virtual ~device_vector()
341   {
342     free();
343   }
344
345   /* Host memory allocation. */
346   T *alloc(size_t width, size_t height = 0, size_t depth = 0)
347   {
348     size_t new_size = size(width, height, depth);
349
350     if (new_size != data_size) {
351       device_free();
352       host_free();
353       host_pointer = host_alloc(sizeof(T) * new_size);
354       modified = true;
355       assert(device_pointer == 0);
356     }
357
358     data_size = new_size;
359     data_width = width;
360     data_height = height;
361     data_depth = depth;
362
363     return data();
364   }
365
366   /* Host memory resize. Only use this if the original data needs to be
367    * preserved, it is faster to call alloc() if it can be discarded. */
368   T *resize(size_t width, size_t height = 0, size_t depth = 0)
369   {
370     size_t new_size = size(width, height, depth);
371
372     if (new_size != data_size) {
373       void *new_ptr = host_alloc(sizeof(T) * new_size);
374
375       if (new_size && data_size) {
376         size_t min_size = ((new_size < data_size) ? new_size : data_size);
377         memcpy((T *)new_ptr, (T *)host_pointer, sizeof(T) * min_size);
378       }
379
380       device_free();
381       host_free();
382       host_pointer = new_ptr;
383       assert(device_pointer == 0);
384     }
385
386     data_size = new_size;
387     data_width = width;
388     data_height = height;
389     data_depth = depth;
390
391     return data();
392   }
393
394   /* Take over data from an existing array. */
395   void steal_data(array<T> &from)
396   {
397     device_free();
398     host_free();
399
400     data_size = from.size();
401     data_width = 0;
402     data_height = 0;
403     data_depth = 0;
404     host_pointer = from.steal_pointer();
405     assert(device_pointer == 0);
406   }
407
408   void give_data(array<T> &to)
409   {
410     device_free();
411
412     to.set_data((T *)host_pointer, data_size);
413     data_size = 0;
414     data_width = 0;
415     data_height = 0;
416     data_depth = 0;
417     host_pointer = 0;
418     assert(device_pointer == 0);
419   }
420
421   /* Free device and host memory. */
422   void free()
423   {
424     device_free();
425     host_free();
426
427     data_size = 0;
428     data_width = 0;
429     data_height = 0;
430     data_depth = 0;
431     host_pointer = 0;
432     modified = true;
433     need_realloc_ = true;
434     assert(device_pointer == 0);
435   }
436
437   void free_if_need_realloc(bool force_free)
438   {
439     if (need_realloc_ || force_free) {
440       free();
441     }
442   }
443
444   bool is_modified() const
445   {
446     return modified;
447   }
448
449   bool need_realloc()
450   {
451     return need_realloc_;
452   }
453
454   void tag_modified()
455   {
456     modified = true;
457   }
458
459   void tag_realloc()
460   {
461     need_realloc_ = true;
462     tag_modified();
463   }
464
465   size_t size() const
466   {
467     return data_size;
468   }
469
470   T *data()
471   {
472     return (T *)host_pointer;
473   }
474
475   T &operator[](size_t i)
476   {
477     assert(i < data_size);
478     return data()[i];
479   }
480
481   void copy_to_device()
482   {
483     if (data_size != 0) {
484       device_copy_to();
485     }
486   }
487
488   void copy_to_device_if_modified()
489   {
490     if (!modified) {
491       return;
492     }
493
494     copy_to_device();
495   }
496
497   void clear_modified()
498   {
499     modified = false;
500     need_realloc_ = false;
501   }
502
503   void copy_from_device()
504   {
505     device_copy_from(0, data_width, data_height, sizeof(T));
506   }
507
508   void copy_from_device(int y, int w, int h)
509   {
510     device_copy_from(y, w, h, sizeof(T));
511   }
512
513   void zero_to_device()
514   {
515     device_zero();
516   }
517
518   void move_device(Device *new_device)
519   {
520     copy_from_device();
521     device_free();
522     device = new_device;
523     copy_to_device();
524   }
525
526  protected:
527   size_t size(size_t width, size_t height, size_t depth)
528   {
529     return width * ((height == 0) ? 1 : height) * ((depth == 0) ? 1 : depth);
530   }
531 };
532
533 /* Pixel Memory
534  *
535  * Device memory to efficiently draw as pixels to the screen in interactive
536  * rendering. Only copying pixels from the device is supported, not copying to. */
537
538 template<typename T> class device_pixels : public device_vector<T> {
539  public:
540   device_pixels(Device *device, const char *name) : device_vector<T>(device, name, MEM_PIXELS)
541   {
542   }
543
544   void alloc_to_device(size_t width, size_t height, size_t depth = 0)
545   {
546     device_vector<T>::alloc(width, height, depth);
547
548     if (!device_memory::device_pointer) {
549       device_memory::device_alloc();
550     }
551   }
552
553   T *copy_from_device(int y, int w, int h)
554   {
555     device_memory::device_copy_from(y, w, h, sizeof(T));
556     return device_vector<T>::data();
557   }
558 };
559
560 /* Device Sub Memory
561  *
562  * Pointer into existing memory. It is not allocated separately, but created
563  * from an already allocated base memory. It is freed automatically when it
564  * goes out of scope, which should happen before base memory is freed.
565  *
566  * Note: some devices require offset and size of the sub_ptr to be properly
567  * aligned to device->mem_address_alingment(). */
568
569 class device_sub_ptr {
570  public:
571   device_sub_ptr(device_memory &mem, int offset, int size);
572   ~device_sub_ptr();
573
574   device_ptr operator*() const
575   {
576     return ptr;
577   }
578
579  protected:
580   /* No copying. */
581   device_sub_ptr &operator=(const device_sub_ptr &);
582
583   Device *device;
584   device_ptr ptr;
585 };
586
587 /* Device Texture
588  *
589  * 2D or 3D image texture memory. */
590
591 class device_texture : public device_memory {
592  public:
593   device_texture(Device *device,
594                  const char *name,
595                  const uint slot,
596                  ImageDataType image_data_type,
597                  InterpolationType interpolation,
598                  ExtensionType extension);
599   ~device_texture();
600
601   void *alloc(const size_t width, const size_t height, const size_t depth = 0);
602   void copy_to_device();
603
604   uint slot;
605   TextureInfo info;
606
607  protected:
608   size_t size(const size_t width, const size_t height, const size_t depth)
609   {
610     return width * ((height == 0) ? 1 : height) * ((depth == 0) ? 1 : depth);
611   }
612 };
613
614 CCL_NAMESPACE_END
615
616 #endif /* __DEVICE_MEMORY_H__ */