Merge branch 'master' into blender2.8
[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_half.h"
25 #include "util/util_texture.h"
26 #include "util/util_types.h"
27 #include "util/util_vector.h"
28
29 CCL_NAMESPACE_BEGIN
30
31 class Device;
32
33 enum MemoryType {
34         MEM_READ_ONLY,
35         MEM_READ_WRITE,
36         MEM_DEVICE_ONLY,
37         MEM_TEXTURE,
38         MEM_PIXELS
39 };
40
41 /* Supported Data Types */
42
43 enum DataType {
44         TYPE_UNKNOWN,
45         TYPE_UCHAR,
46         TYPE_UINT16,
47         TYPE_UINT,
48         TYPE_INT,
49         TYPE_FLOAT,
50         TYPE_HALF,
51         TYPE_UINT64,
52 };
53
54 static inline size_t datatype_size(DataType datatype)
55 {
56         switch(datatype) {
57                 case TYPE_UNKNOWN: return 1;
58                 case TYPE_UCHAR: return sizeof(uchar);
59                 case TYPE_FLOAT: return sizeof(float);
60                 case TYPE_UINT: return sizeof(uint);
61                 case TYPE_UINT16: return sizeof(uint16_t);
62                 case TYPE_INT: return sizeof(int);
63                 case TYPE_HALF: return sizeof(half);
64                 case TYPE_UINT64: return sizeof(uint64_t);
65                 default: return 0;
66         }
67 }
68
69 /* Traits for data types */
70
71 template<typename T> struct device_type_traits {
72         static const DataType data_type = TYPE_UNKNOWN;
73         static const int num_elements = sizeof(T);
74 };
75
76 template<> struct device_type_traits<uchar> {
77         static const DataType data_type = TYPE_UCHAR;
78         static const int num_elements = 1;
79 };
80
81 template<> struct device_type_traits<uchar2> {
82         static const DataType data_type = TYPE_UCHAR;
83         static const int num_elements = 2;
84 };
85
86 template<> struct device_type_traits<uchar3> {
87         static const DataType data_type = TYPE_UCHAR;
88         static const int num_elements = 3;
89 };
90
91 template<> struct device_type_traits<uchar4> {
92         static const DataType data_type = TYPE_UCHAR;
93         static const int num_elements = 4;
94 };
95
96 template<> struct device_type_traits<uint> {
97         static const DataType data_type = TYPE_UINT;
98         static const int num_elements = 1;
99 };
100
101 template<> struct device_type_traits<uint2> {
102         static const DataType data_type = TYPE_UINT;
103         static const int num_elements = 2;
104 };
105
106 template<> struct device_type_traits<uint3> {
107         static const DataType data_type = TYPE_UINT;
108         static const int num_elements = 3;
109 };
110
111 template<> struct device_type_traits<uint4> {
112         static const DataType data_type = TYPE_UINT;
113         static const int num_elements = 4;
114 };
115
116 template<> struct device_type_traits<int> {
117         static const DataType data_type = TYPE_INT;
118         static const int num_elements = 1;
119 };
120
121 template<> struct device_type_traits<int2> {
122         static const DataType data_type = TYPE_INT;
123         static const int num_elements = 2;
124 };
125
126 template<> struct device_type_traits<int3> {
127         static const DataType data_type = TYPE_INT;
128         static const int num_elements = 3;
129 };
130
131 template<> struct device_type_traits<int4> {
132         static const DataType data_type = TYPE_INT;
133         static const int num_elements = 4;
134 };
135
136 template<> struct device_type_traits<float> {
137         static const DataType data_type = TYPE_FLOAT;
138         static const int num_elements = 1;
139 };
140
141 template<> struct device_type_traits<float2> {
142         static const DataType data_type = TYPE_FLOAT;
143         static const int num_elements = 2;
144 };
145
146 template<> struct device_type_traits<float3> {
147         static const DataType data_type = TYPE_FLOAT;
148         static const int num_elements = 4;
149 };
150
151 template<> struct device_type_traits<float4> {
152         static const DataType data_type = TYPE_FLOAT;
153         static const int num_elements = 4;
154 };
155
156 template<> struct device_type_traits<half> {
157         static const DataType data_type = TYPE_HALF;
158         static const int num_elements = 1;
159 };
160
161 template<> struct device_type_traits<ushort4> {
162         static const DataType data_type = TYPE_UINT16;
163         static const int num_elements = 4;
164 };
165
166 template<> struct device_type_traits<uint16_t> {
167         static const DataType data_type = TYPE_UINT16;
168         static const int num_elements = 1;
169 };
170
171 template<> struct device_type_traits<half4> {
172         static const DataType data_type = TYPE_HALF;
173         static const int num_elements = 4;
174 };
175
176 template<> struct device_type_traits<uint64_t> {
177         static const DataType data_type = TYPE_UINT64;
178         static const int num_elements = 1;
179 };
180
181 /* Device Memory
182  *
183  * Base class for all device memory. This should not be allocated directly,
184  * instead the appropriate subclass can be used. */
185
186 class device_memory
187 {
188 public:
189         size_t memory_size() { return data_size*data_elements*datatype_size(data_type); }
190         size_t memory_elements_size(int elements) {
191                 return elements*data_elements*datatype_size(data_type);
192         }
193
194         /* Data information. */
195         DataType data_type;
196         int data_elements;
197         size_t data_size;
198         size_t device_size;
199         size_t data_width;
200         size_t data_height;
201         size_t data_depth;
202         MemoryType type;
203         const char *name;
204         InterpolationType interpolation;
205         ExtensionType extension;
206
207         /* Pointers. */
208         Device *device;
209         device_ptr device_pointer;
210         void *host_pointer;
211         void *shared_pointer;
212
213         virtual ~device_memory();
214
215         void swap_device(Device *new_device, size_t new_device_size, device_ptr new_device_ptr);
216         void restore_device();
217
218 protected:
219         friend class CUDADevice;
220
221         /* Only create through subclasses. */
222         device_memory(Device *device, const char *name, MemoryType type);
223
224         /* No copying allowed. */
225         device_memory(const device_memory&);
226         device_memory& operator = (const device_memory&);
227
228         /* Host allocation on the device. All host_pointer memory should be
229          * allocated with these functions, for devices that support using
230          * the same pointer for host and device. */
231         void *host_alloc(size_t size);
232         void host_free();
233
234         /* Device memory allocation and copying. */
235         void device_alloc();
236         void device_free();
237         void device_copy_to();
238         void device_copy_from(int y, int w, int h, int elem);
239         void device_zero();
240
241         device_ptr original_device_ptr;
242         size_t original_device_size;
243         Device *original_device;
244 };
245
246 /* Device Only Memory
247  *
248  * Working memory only needed by the device, with no corresponding allocation
249  * on the host. Only used internally in the device implementations. */
250
251 template<typename T>
252 class device_only_memory : public device_memory
253 {
254 public:
255         device_only_memory(Device *device, const char *name)
256         : device_memory(device, name, MEM_DEVICE_ONLY)
257         {
258                 data_type = device_type_traits<T>::data_type;
259                 data_elements = max(device_type_traits<T>::num_elements, 1);
260         }
261
262         virtual ~device_only_memory()
263         {
264                 free();
265         }
266
267         void alloc_to_device(size_t num, bool shrink_to_fit = true)
268         {
269                 size_t new_size = num;
270                 bool reallocate;
271
272                 if(shrink_to_fit) {
273                         reallocate = (data_size != new_size);
274                 }
275                 else {
276                         reallocate = (data_size < new_size);
277                 }
278
279                 if(reallocate) {
280                         device_free();
281                         data_size = new_size;
282                         device_alloc();
283                 }
284         }
285
286         void free()
287         {
288                 device_free();
289                 data_size = 0;
290         }
291
292         void zero_to_device()
293         {
294                 device_zero();
295         }
296 };
297
298 /* Device Vector
299  *
300  * Data vector to exchange data between host and device. Memory will be
301  * allocated on the host first with alloc() and resize, and then filled
302  * in and copied to the device with copy_to_device(). Or alternatively
303  * allocated and set to zero on the device with zero_to_device().
304  *
305  * When using memory type MEM_TEXTURE, a pointer to this memory will be
306  * automatically attached to kernel globals, using the provided name
307  * matching an entry in kernel_textures.h. */
308
309 template<typename T> class device_vector : public device_memory
310 {
311 public:
312         device_vector(Device *device, const char *name, MemoryType type)
313         : device_memory(device, name, type)
314         {
315                 data_type = device_type_traits<T>::data_type;
316                 data_elements = device_type_traits<T>::num_elements;
317
318                 assert(data_elements > 0);
319         }
320
321         virtual ~device_vector()
322         {
323                 free();
324         }
325
326         /* Host memory allocation. */
327         T *alloc(size_t width, size_t height = 0, size_t depth = 0)
328         {
329                 size_t new_size = size(width, height, depth);
330
331                 if(new_size != data_size) {
332                         device_free();
333                         host_free();
334                         host_pointer = host_alloc(sizeof(T)*new_size);
335                         assert(device_pointer == 0);
336                 }
337
338                 data_size = new_size;
339                 data_width = width;
340                 data_height = height;
341                 data_depth = depth;
342
343                 return data();
344         }
345
346         /* Host memory resize. Only use this if the original data needs to be
347          * preserved, it is faster to call alloc() if it can be discarded. */
348         T *resize(size_t width, size_t height = 0, size_t depth = 0)
349         {
350                 size_t new_size = size(width, height, depth);
351
352                 if(new_size != data_size) {
353                         void *new_ptr = host_alloc(sizeof(T)*new_size);
354
355                         if(new_size && data_size) {
356                                 size_t min_size = ((new_size < data_size)? new_size: data_size);
357                                 memcpy((T*)new_ptr, (T*)host_pointer, sizeof(T)*min_size);
358                         }
359
360                         device_free();
361                         host_free();
362                         host_pointer = new_ptr;
363                         assert(device_pointer == 0);
364                 }
365
366                 data_size = new_size;
367                 data_width = width;
368                 data_height = height;
369                 data_depth = depth;
370
371                 return data();
372         }
373
374         /* Take over data from an existing array. */
375         void steal_data(array<T>& from)
376         {
377                 device_free();
378                 host_free();
379
380                 data_size = from.size();
381                 data_width = 0;
382                 data_height = 0;
383                 data_depth = 0;
384                 host_pointer = from.steal_pointer();
385                 assert(device_pointer == 0);
386         }
387
388         /* Free device and host memory. */
389         void free()
390         {
391                 device_free();
392                 host_free();
393
394                 data_size = 0;
395                 data_width = 0;
396                 data_height = 0;
397                 data_depth = 0;
398                 host_pointer = 0;
399                 assert(device_pointer == 0);
400         }
401
402         size_t size()
403         {
404                 return data_size;
405         }
406
407         T* data()
408         {
409                 return (T*)host_pointer;
410         }
411
412         T& operator[](size_t i)
413         {
414                 assert(i < data_size);
415                 return data()[i];
416         }
417
418         void copy_to_device()
419         {
420                 device_copy_to();
421         }
422
423         void copy_from_device(int y, int w, int h)
424         {
425                 device_copy_from(y, w, h, sizeof(T));
426         }
427
428         void zero_to_device()
429         {
430                 device_zero();
431         }
432
433 protected:
434         size_t size(size_t width, size_t height, size_t depth)
435         {
436                 return width * ((height == 0)? 1: height) * ((depth == 0)? 1: depth);
437         }
438 };
439
440 /* Pixel Memory
441  *
442  * Device memory to efficiently draw as pixels to the screen in interactive
443  * rendering. Only copying pixels from the device is supported, not copying to. */
444
445 template<typename T> class device_pixels : public device_vector<T>
446 {
447 public:
448         device_pixels(Device *device, const char *name)
449         : device_vector<T>(device, name, MEM_PIXELS)
450         {
451         }
452
453         void alloc_to_device(size_t width, size_t height, size_t depth = 0)
454         {
455                 device_vector<T>::alloc(width, height, depth);
456
457                 if(!device_memory::device_pointer) {
458                         device_memory::device_alloc();
459                 }
460         }
461
462         T *copy_from_device(int y, int w, int h)
463         {
464                 device_memory::device_copy_from(y, w, h, sizeof(T));
465                 return device_vector<T>::data();
466         }
467 };
468
469 /* Device Sub Memory
470  *
471  * Pointer into existing memory. It is not allocated separately, but created
472  * from an already allocated base memory. It is freed automatically when it
473  * goes out of scope, which should happen before base memory is freed.
474  *
475  * Note: some devices require offset and size of the sub_ptr to be properly
476  * aligned to device->mem_address_alingment(). */
477
478 class device_sub_ptr
479 {
480 public:
481         device_sub_ptr(device_memory& mem, int offset, int size);
482         ~device_sub_ptr();
483
484         device_ptr operator*() const
485         {
486                 return ptr;
487         }
488
489 protected:
490         /* No copying. */
491         device_sub_ptr& operator = (const device_sub_ptr&);
492
493         Device *device;
494         device_ptr ptr;
495 };
496
497 CCL_NAMESPACE_END
498
499 #endif /* __DEVICE_MEMORY_H__ */