Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / intern / cycles / device / device_multi.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include <stdlib.h>
20 #include <sstream>
21
22 #include "device.h"
23 #include "device_intern.h"
24 #include "device_network.h"
25
26 #include "util_foreach.h"
27 #include "util_list.h"
28 #include "util_map.h"
29 #include "util_time.h"
30
31 CCL_NAMESPACE_BEGIN
32
33 class MultiDevice : public Device
34 {
35 public:
36         struct SubDevice {
37                 SubDevice(Device *device_)
38                 : device(device_) {}
39
40                 Device *device;
41                 map<device_ptr, device_ptr> ptr_map;
42         };
43
44         list<SubDevice> devices;
45         device_ptr unique_ptr;
46
47         MultiDevice(bool background_)
48         : unique_ptr(1)
49         {
50                 Device *device;
51
52                 /* add CPU device */
53                 device = Device::create(DEVICE_CPU, background);
54                 devices.push_back(SubDevice(device));
55
56 #ifdef WITH_CUDA
57                 /* try to add GPU device */
58                 device = Device::create(DEVICE_CUDA, background);
59                 if(device) {
60                         devices.push_back(SubDevice(device));
61                 }
62                 else
63 #endif
64                 {
65 #ifdef WITH_OPENCL
66                         device = Device::create(DEVICE_OPENCL, background);
67                         if(device)
68                                 devices.push_back(SubDevice(device));
69 #endif
70                 }
71
72 #ifdef WITH_NETWORK
73                 /* try to add network devices */
74                 ServerDiscovery discovery(true);
75                 time_sleep(1.0);
76
77                 list<string> servers = discovery.get_server_list();
78
79                 foreach(string& server, servers) {
80                         device = device_network_create(server.c_str());
81                         if(device)
82                                 devices.push_back(SubDevice(device));
83                 }
84 #endif
85         }
86
87         ~MultiDevice()
88         {
89                 foreach(SubDevice& sub, devices)
90                         delete sub.device;
91         }
92
93         bool support_full_kernel()
94         {
95                 foreach(SubDevice& sub, devices) {
96                         if(!sub.device->support_full_kernel())
97                                 return false;
98                 }
99
100                 return true;
101         }
102
103         string description()
104         {
105                 /* create map to find duplicate descriptions */
106                 map<string, int> dupli_map;
107                 map<string, int>::iterator dt;
108
109                 foreach(SubDevice& sub, devices) {
110                         string key = sub.device->description();
111
112                         if(dupli_map.find(key) == dupli_map.end())
113                                 dupli_map[key] = 1;
114                         else
115                                 dupli_map[key]++;
116                 }
117
118                 /* generate string */
119                 stringstream desc;
120                 bool first = true;
121
122                 for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
123                         if(!first) desc << ", ";
124                         first = false;
125
126                         if(dt->second > 1)
127                                 desc << dt->second << "x " << dt->first;
128                         else
129                                 desc << dt->first;
130                 }
131
132                 return desc.str();
133         }
134
135         bool load_kernels()
136         {
137                 foreach(SubDevice& sub, devices)
138                         if(!sub.device->load_kernels())
139                                 return false;
140
141                 return true;
142         }
143
144         void mem_alloc(device_memory& mem, MemoryType type)
145         {
146                 foreach(SubDevice& sub, devices) {
147                         mem.device_pointer = 0;
148                         sub.device->mem_alloc(mem, type);
149                         sub.ptr_map[unique_ptr] = mem.device_pointer;
150                 }
151
152                 mem.device_pointer = unique_ptr++;
153         }
154
155         void mem_copy_to(device_memory& mem)
156         {
157                 device_ptr tmp = mem.device_pointer;
158
159                 foreach(SubDevice& sub, devices) {
160                         mem.device_pointer = sub.ptr_map[tmp];
161                         sub.device->mem_copy_to(mem);
162                 }
163
164                 mem.device_pointer = tmp;
165         }
166
167         void mem_copy_from(device_memory& mem, size_t offset, size_t size)
168         {
169                 device_ptr tmp = mem.device_pointer;
170
171                 /* todo: how does this work? */
172                 foreach(SubDevice& sub, devices) {
173                         mem.device_pointer = sub.ptr_map[tmp];
174                         sub.device->mem_copy_from(mem, offset, size);
175                         break;
176                 }
177
178                 mem.device_pointer = tmp;
179         }
180
181         void mem_zero(device_memory& mem)
182         {
183                 device_ptr tmp = mem.device_pointer;
184
185                 foreach(SubDevice& sub, devices) {
186                         mem.device_pointer = sub.ptr_map[tmp];
187                         sub.device->mem_zero(mem);
188                 }
189
190                 mem.device_pointer = tmp;
191         }
192
193         void mem_free(device_memory& mem)
194         {
195                 device_ptr tmp = mem.device_pointer;
196
197                 foreach(SubDevice& sub, devices) {
198                         mem.device_pointer = sub.ptr_map[tmp];
199                         sub.device->mem_free(mem);
200                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
201                 }
202
203                 mem.device_pointer = 0;
204         }
205
206         void const_copy_to(const char *name, void *host, size_t size)
207         {
208                 foreach(SubDevice& sub, devices)
209                         sub.device->const_copy_to(name, host, size);
210         }
211
212         void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
213         {
214                 foreach(SubDevice& sub, devices) {
215                         mem.device_pointer = 0;
216                         sub.device->tex_alloc(name, mem, interpolation, periodic);
217                         sub.ptr_map[unique_ptr] = mem.device_pointer;
218                 }
219
220                 mem.device_pointer = unique_ptr++;
221         }
222
223         void tex_free(device_memory& mem)
224         {
225                 device_ptr tmp = mem.device_pointer;
226
227                 foreach(SubDevice& sub, devices) {
228                         mem.device_pointer = sub.ptr_map[tmp];
229                         sub.device->tex_free(mem);
230                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
231                 }
232
233                 mem.device_pointer = 0;
234         }
235
236         void pixels_alloc(device_memory& mem)
237         {
238                 foreach(SubDevice& sub, devices) {
239                         mem.device_pointer = 0;
240                         sub.device->pixels_alloc(mem);
241                         sub.ptr_map[unique_ptr] = mem.device_pointer;
242                 }
243
244                 mem.device_pointer = unique_ptr++;
245         }
246
247         void pixels_free(device_memory& mem)
248         {
249                 device_ptr tmp = mem.device_pointer;
250
251                 foreach(SubDevice& sub, devices) {
252                         mem.device_pointer = sub.ptr_map[tmp];
253                         sub.device->pixels_free(mem);
254                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
255                 }
256
257                 mem.device_pointer = 0;
258         }
259
260         void pixels_copy_from(device_memory& mem, int y, int w, int h)
261         {
262                 device_ptr tmp = mem.device_pointer;
263                 int i = 0, sub_h = h/devices.size();
264
265                 foreach(SubDevice& sub, devices) {
266                         int sy = y + i*sub_h;
267                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
268
269                         mem.device_pointer = sub.ptr_map[tmp];
270                         sub.device->pixels_copy_from(mem, sy, w, sh);
271                         i++;
272                 }
273
274                 mem.device_pointer = tmp;
275         }
276
277         void draw_pixels(device_memory& rgba, int y, int w, int h, int width, int height, bool transparent)
278         {
279                 device_ptr tmp = rgba.device_pointer;
280                 int i = 0, sub_h = h/devices.size();
281                 int sub_height = height/devices.size();
282
283                 foreach(SubDevice& sub, devices) {
284                         int sy = y + i*sub_h;
285                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
286                         int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
287                         /* adjust math for w/width */
288
289                         rgba.device_pointer = sub.ptr_map[tmp];
290                         sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, transparent);
291                         i++;
292                 }
293
294                 rgba.device_pointer = tmp;
295         }
296
297         void task_add(DeviceTask& task)
298         {
299                 ThreadQueue<DeviceTask> tasks;
300                 task.split(tasks, devices.size());
301
302                 foreach(SubDevice& sub, devices) {
303                         DeviceTask subtask;
304
305                         if(tasks.worker_wait_pop(subtask)) {
306                                 if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
307                                 if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
308                                 if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
309                                 if(task.displace_input) subtask.displace_input = sub.ptr_map[task.displace_input];
310                                 if(task.displace_offset) subtask.displace_offset = sub.ptr_map[task.displace_offset];
311
312                                 sub.device->task_add(subtask);
313                         }
314                 }
315         }
316
317         void task_wait()
318         {
319                 foreach(SubDevice& sub, devices)
320                         sub.device->task_wait();
321         }
322
323         void task_cancel()
324         {
325                 foreach(SubDevice& sub, devices)
326                         sub.device->task_cancel();
327         }
328 };
329
330 Device *device_multi_create(bool background)
331 {
332         return new MultiDevice(background);
333 }
334
335 CCL_NAMESPACE_END
336