Fix T52645, T52645: AMD OpenCL compiler crash with recent drivers.
[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_UCHAR,
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_UCHAR: return sizeof(uchar);
61                 case TYPE_FLOAT: return sizeof(float);
62                 case TYPE_UINT: return sizeof(uint);
63                 case TYPE_INT: return sizeof(int);
64                 case TYPE_HALF: return sizeof(half);
65                 case TYPE_UINT64: return sizeof(uint64_t);
66                 default: return 0;
67         }
68 }
69
70 /* Traits for data types */
71
72 template<typename T> struct device_type_traits {
73         static const DataType data_type = TYPE_UCHAR;
74         static const int num_elements = 0;
75 };
76
77 template<> struct device_type_traits<uchar> {
78         static const DataType data_type = TYPE_UCHAR;
79         static const int num_elements = 1;
80 };
81
82 template<> struct device_type_traits<uchar2> {
83         static const DataType data_type = TYPE_UCHAR;
84         static const int num_elements = 2;
85 };
86
87 template<> struct device_type_traits<uchar3> {
88         static const DataType data_type = TYPE_UCHAR;
89         static const int num_elements = 3;
90 };
91
92 template<> struct device_type_traits<uchar4> {
93         static const DataType data_type = TYPE_UCHAR;
94         static const int num_elements = 4;
95 };
96
97 template<> struct device_type_traits<uint> {
98         static const DataType data_type = TYPE_UINT;
99         static const int num_elements = 1;
100 };
101
102 template<> struct device_type_traits<uint2> {
103         static const DataType data_type = TYPE_UINT;
104         static const int num_elements = 2;
105 };
106
107 template<> struct device_type_traits<uint3> {
108         static const DataType data_type = TYPE_UINT;
109         static const int num_elements = 3;
110 };
111
112 template<> struct device_type_traits<uint4> {
113         static const DataType data_type = TYPE_UINT;
114         static const int num_elements = 4;
115 };
116
117 template<> struct device_type_traits<int> {
118         static const DataType data_type = TYPE_INT;
119         static const int num_elements = 1;
120 };
121
122 template<> struct device_type_traits<int2> {
123         static const DataType data_type = TYPE_INT;
124         static const int num_elements = 2;
125 };
126
127 template<> struct device_type_traits<int3> {
128         static const DataType data_type = TYPE_INT;
129         static const int num_elements = 3;
130 };
131
132 template<> struct device_type_traits<int4> {
133         static const DataType data_type = TYPE_INT;
134         static const int num_elements = 4;
135 };
136
137 template<> struct device_type_traits<float> {
138         static const DataType data_type = TYPE_FLOAT;
139         static const int num_elements = 1;
140 };
141
142 template<> struct device_type_traits<float2> {
143         static const DataType data_type = TYPE_FLOAT;
144         static const int num_elements = 2;
145 };
146
147 template<> struct device_type_traits<float3> {
148         static const DataType data_type = TYPE_FLOAT;
149         static const int num_elements = 4;
150 };
151
152 template<> struct device_type_traits<float4> {
153         static const DataType data_type = TYPE_FLOAT;
154         static const int num_elements = 4;
155 };
156
157 template<> struct device_type_traits<half> {
158         static const DataType data_type = TYPE_HALF;
159         static const int num_elements = 1;
160 };
161
162 template<> struct device_type_traits<half4> {
163         static const DataType data_type = TYPE_HALF;
164         static const int num_elements = 4;
165 };
166
167 template<> struct device_type_traits<uint64_t> {
168         static const DataType data_type = TYPE_UINT64;
169         static const int num_elements = 1;
170 };
171
172 /* Device Memory */
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         device_ptr data_pointer;
186         size_t data_size;
187         size_t device_size;
188         size_t data_width;
189         size_t data_height;
190         size_t data_depth;
191
192         /* device pointer */
193         device_ptr device_pointer;
194
195         device_memory()
196         {
197                 data_type = device_type_traits<uchar>::data_type;
198                 data_elements = device_type_traits<uchar>::num_elements;
199                 data_pointer = 0;
200                 data_size = 0;
201                 device_size = 0;
202                 data_width = 0;
203                 data_height = 0;
204                 data_depth = 0;
205                 device_pointer = 0;
206         }
207         virtual ~device_memory() { assert(!device_pointer); }
208
209         void resize(size_t size)
210         {
211                 data_size = size;
212                 data_width = size;
213         }
214
215 protected:
216         /* no copying */
217         device_memory(const device_memory&);
218         device_memory& operator = (const device_memory&);
219 };
220
221 template<typename T>
222 class device_only_memory : public device_memory
223 {
224 public:
225         device_only_memory()
226         {
227                 data_type = device_type_traits<T>::data_type;
228                 data_elements = max(device_type_traits<T>::num_elements, 1);
229         }
230
231         void resize(size_t num)
232         {
233                 device_memory::resize(num*sizeof(T));
234         }
235 };
236
237 /* Device Vector */
238
239 template<typename T> class device_vector : public device_memory
240 {
241 public:
242         device_vector()
243         {
244                 data_type = device_type_traits<T>::data_type;
245                 data_elements = device_type_traits<T>::num_elements;
246
247                 assert(data_elements > 0);
248         }
249
250         virtual ~device_vector() {}
251
252         /* vector functions */
253         T *resize(size_t width, size_t height = 0, size_t depth = 0)
254         {
255                 data_size = width * ((height == 0)? 1: height) * ((depth == 0)? 1: depth);
256                 if(data.resize(data_size) == NULL) {
257                         clear();
258                         return NULL;
259                 }
260                 data_width = width;
261                 data_height = height;
262                 data_depth = depth;
263                 if(data_size == 0) {
264                         data_pointer = 0;
265                         return NULL;
266                 }
267                 data_pointer = (device_ptr)&data[0];
268                 return &data[0];
269         }
270
271         T *copy(T *ptr, size_t width, size_t height = 0, size_t depth = 0)
272         {
273                 T *mem = resize(width, height, depth);
274                 if(mem != NULL) {
275                         memcpy(mem, ptr, memory_size());
276                 }
277                 return mem;
278         }
279
280         void copy_at(T *ptr, size_t offset, size_t size)
281         {
282                 if(size > 0) {
283                         size_t mem_size = size*data_elements*datatype_size(data_type);
284                         memcpy(&data[0] + offset, ptr, mem_size);
285                 }
286         }
287
288         void reference(T *ptr, size_t width, size_t height = 0, size_t depth = 0)
289         {
290                 data.clear();
291                 data_size = width * ((height == 0)? 1: height) * ((depth == 0)? 1: depth);
292                 data_pointer = (device_ptr)ptr;
293                 data_width = width;
294                 data_height = height;
295                 data_depth = depth;
296         }
297
298         void clear()
299         {
300                 data.clear();
301                 data_pointer = 0;
302                 data_width = 0;
303                 data_height = 0;
304                 data_depth = 0;
305                 data_size = 0;
306                 device_pointer = 0;
307         }
308
309         size_t size()
310         {
311                 return data.size();
312         }
313
314         T* get_data()
315         {
316                 return &data[0];
317         }
318
319 private:
320         array<T> data;
321 };
322
323 /* A device_sub_ptr is a pointer into another existing memory.
324  * Therefore, it is not allocated separately, but just created from the already allocated base memory.
325  * It is freed automatically when it goes out of scope, which should happen before the base memory is freed.
326  * Note that some devices require the offset and size of the sub_ptr to be properly aligned. */
327 class device_sub_ptr
328 {
329 public:
330         device_sub_ptr(Device *device, device_memory& mem, int offset, int size, MemoryType type);
331         ~device_sub_ptr();
332         /* No copying. */
333         device_sub_ptr& operator = (const device_sub_ptr&);
334
335         device_ptr operator*() const
336         {
337                 return ptr;
338         }
339 protected:
340         Device *device;
341         device_ptr ptr;
342 };
343
344 CCL_NAMESPACE_END
345
346 #endif /* __DEVICE_MEMORY_H__ */
347