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