Code refactor: add WorkTile struct for passing work to kernel.
[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  * This file defines data types that can be used in device memory arrays, and
23  * a device_vector<T> type to store such arrays.
24  *
25  * device_vector<T> contains an STL vector, metadata about the data type,
26  * dimensions, elements, and a device pointer. For the CPU device this is just
27  * a pointer to the STL vector data, as no copying needs to take place. For
28  * other devices this is a pointer to device memory, where we will copy memory
29  * to and from. */
30
31 #include "util/util_debug.h"
32 #include "util/util_half.h"
33 #include "util/util_types.h"
34 #include "util/util_vector.h"
35
36 CCL_NAMESPACE_BEGIN
37
38 class Device;
39
40 enum MemoryType {
41         MEM_READ_ONLY,
42         MEM_WRITE_ONLY,
43         MEM_READ_WRITE
44 };
45
46 /* Supported Data Types */
47
48 enum DataType {
49         TYPE_UNKNOWN,
50         TYPE_UCHAR,
51         TYPE_UINT,
52         TYPE_INT,
53         TYPE_FLOAT,
54         TYPE_HALF,
55         TYPE_UINT64,
56 };
57
58 static inline size_t datatype_size(DataType datatype) 
59 {
60         switch(datatype) {
61                 case TYPE_UNKNOWN: return 1;
62                 case TYPE_UCHAR: return sizeof(uchar);
63                 case TYPE_FLOAT: return sizeof(float);
64                 case TYPE_UINT: return sizeof(uint);
65                 case TYPE_INT: return sizeof(int);
66                 case TYPE_HALF: return sizeof(half);
67                 case TYPE_UINT64: return sizeof(uint64_t);
68                 default: return 0;
69         }
70 }
71
72 /* Traits for data types */
73
74 template<typename T> struct device_type_traits {
75         static const DataType data_type = TYPE_UNKNOWN;
76         static const int num_elements = sizeof(T);
77 };
78
79 template<> struct device_type_traits<uchar> {
80         static const DataType data_type = TYPE_UCHAR;
81         static const int num_elements = 1;
82 };
83
84 template<> struct device_type_traits<uchar2> {
85         static const DataType data_type = TYPE_UCHAR;
86         static const int num_elements = 2;
87 };
88
89 template<> struct device_type_traits<uchar3> {
90         static const DataType data_type = TYPE_UCHAR;
91         static const int num_elements = 3;
92 };
93
94 template<> struct device_type_traits<uchar4> {
95         static const DataType data_type = TYPE_UCHAR;
96         static const int num_elements = 4;
97 };
98
99 template<> struct device_type_traits<uint> {
100         static const DataType data_type = TYPE_UINT;
101         static const int num_elements = 1;
102 };
103
104 template<> struct device_type_traits<uint2> {
105         static const DataType data_type = TYPE_UINT;
106         static const int num_elements = 2;
107 };
108
109 template<> struct device_type_traits<uint3> {
110         static const DataType data_type = TYPE_UINT;
111         static const int num_elements = 3;
112 };
113
114 template<> struct device_type_traits<uint4> {
115         static const DataType data_type = TYPE_UINT;
116         static const int num_elements = 4;
117 };
118
119 template<> struct device_type_traits<int> {
120         static const DataType data_type = TYPE_INT;
121         static const int num_elements = 1;
122 };
123
124 template<> struct device_type_traits<int2> {
125         static const DataType data_type = TYPE_INT;
126         static const int num_elements = 2;
127 };
128
129 template<> struct device_type_traits<int3> {
130         static const DataType data_type = TYPE_INT;
131         static const int num_elements = 3;
132 };
133
134 template<> struct device_type_traits<int4> {
135         static const DataType data_type = TYPE_INT;
136         static const int num_elements = 4;
137 };
138
139 template<> struct device_type_traits<float> {
140         static const DataType data_type = TYPE_FLOAT;
141         static const int num_elements = 1;
142 };
143
144 template<> struct device_type_traits<float2> {
145         static const DataType data_type = TYPE_FLOAT;
146         static const int num_elements = 2;
147 };
148
149 template<> struct device_type_traits<float3> {
150         static const DataType data_type = TYPE_FLOAT;
151         static const int num_elements = 4;
152 };
153
154 template<> struct device_type_traits<float4> {
155         static const DataType data_type = TYPE_FLOAT;
156         static const int num_elements = 4;
157 };
158
159 template<> struct device_type_traits<half> {
160         static const DataType data_type = TYPE_HALF;
161         static const int num_elements = 1;
162 };
163
164 template<> struct device_type_traits<half4> {
165         static const DataType data_type = TYPE_HALF;
166         static const int num_elements = 4;
167 };
168
169 template<> struct device_type_traits<uint64_t> {
170         static const DataType data_type = TYPE_UINT64;
171         static const int num_elements = 1;
172 };
173
174 /* Device Memory */
175
176 class device_memory
177 {
178 public:
179         size_t memory_size() { return data_size*data_elements*datatype_size(data_type); }
180         size_t memory_elements_size(int elements) {
181                 return elements*data_elements*datatype_size(data_type);
182         }
183
184         /* data information */
185         DataType data_type;
186         int data_elements;
187         device_ptr data_pointer;
188         size_t data_size;
189         size_t device_size;
190         size_t data_width;
191         size_t data_height;
192         size_t data_depth;
193
194         /* device pointer */
195         device_ptr device_pointer;
196
197         device_memory()
198         {
199                 data_type = device_type_traits<uchar>::data_type;
200                 data_elements = device_type_traits<uchar>::num_elements;
201                 data_pointer = 0;
202                 data_size = 0;
203                 device_size = 0;
204                 data_width = 0;
205                 data_height = 0;
206                 data_depth = 0;
207                 device_pointer = 0;
208         }
209         virtual ~device_memory() { assert(!device_pointer); }
210
211         void resize(size_t size)
212         {
213                 data_size = size;
214                 data_width = size;
215         }
216
217 protected:
218         /* no copying */
219         device_memory(const device_memory&);
220         device_memory& operator = (const device_memory&);
221 };
222
223 template<typename T>
224 class device_only_memory : public device_memory
225 {
226 public:
227         device_only_memory()
228         {
229                 data_type = device_type_traits<T>::data_type;
230                 data_elements = max(device_type_traits<T>::num_elements, 1);
231         }
232
233         void resize(size_t num)
234         {
235                 device_memory::resize(num*sizeof(T));
236         }
237 };
238
239 /* Device Vector */
240
241 template<typename T> class device_vector : public device_memory
242 {
243 public:
244         device_vector()
245         {
246                 data_type = device_type_traits<T>::data_type;
247                 data_elements = device_type_traits<T>::num_elements;
248
249                 assert(data_elements > 0);
250         }
251
252         virtual ~device_vector() {}
253
254         /* vector functions */
255         T *resize(size_t width, size_t height = 0, size_t depth = 0)
256         {
257                 data_size = width * ((height == 0)? 1: height) * ((depth == 0)? 1: depth);
258                 if(data.resize(data_size) == NULL) {
259                         clear();
260                         return NULL;
261                 }
262                 data_width = width;
263                 data_height = height;
264                 data_depth = depth;
265                 if(data_size == 0) {
266                         data_pointer = 0;
267                         return NULL;
268                 }
269                 data_pointer = (device_ptr)&data[0];
270                 return &data[0];
271         }
272
273         T *copy(T *ptr, size_t width, size_t height = 0, size_t depth = 0)
274         {
275                 T *mem = resize(width, height, depth);
276                 if(mem != NULL) {
277                         memcpy(mem, ptr, memory_size());
278                 }
279                 return mem;
280         }
281
282         void copy_at(T *ptr, size_t offset, size_t size)
283         {
284                 if(size > 0) {
285                         size_t mem_size = size*data_elements*datatype_size(data_type);
286                         memcpy(&data[0] + offset, ptr, mem_size);
287                 }
288         }
289
290         void reference(T *ptr, size_t width, size_t height = 0, size_t depth = 0)
291         {
292                 data.clear();
293                 data_size = width * ((height == 0)? 1: height) * ((depth == 0)? 1: depth);
294                 data_pointer = (device_ptr)ptr;
295                 data_width = width;
296                 data_height = height;
297                 data_depth = depth;
298         }
299
300         void clear()
301         {
302                 data.clear();
303                 data_pointer = 0;
304                 data_width = 0;
305                 data_height = 0;
306                 data_depth = 0;
307                 data_size = 0;
308                 device_pointer = 0;
309         }
310
311         size_t size()
312         {
313                 return data.size();
314         }
315
316         T* get_data()
317         {
318                 return &data[0];
319         }
320
321 private:
322         array<T> data;
323 };
324
325 /* A device_sub_ptr is a pointer into another existing memory.
326  * Therefore, it is not allocated separately, but just created from the already allocated base memory.
327  * It is freed automatically when it goes out of scope, which should happen before the base memory is freed.
328  * Note that some devices require the offset and size of the sub_ptr to be properly aligned. */
329 class device_sub_ptr
330 {
331 public:
332         device_sub_ptr(Device *device, device_memory& mem, int offset, int size, MemoryType type);
333         ~device_sub_ptr();
334         /* No copying. */
335         device_sub_ptr& operator = (const device_sub_ptr&);
336
337         device_ptr operator*() const
338         {
339                 return ptr;
340         }
341 protected:
342         Device *device;
343         device_ptr ptr;
344 };
345
346 CCL_NAMESPACE_END
347
348 #endif /* __DEVICE_MEMORY_H__ */
349