f2f6251685e77e6b925666cac46bdfbf6659056c
[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         string description()
94         {
95                 /* create map to find duplicate descriptions */
96                 map<string, int> dupli_map;
97                 map<string, int>::iterator dt;
98
99                 foreach(SubDevice& sub, devices) {
100                         string key = sub.device->description();
101
102                         if(dupli_map.find(key) == dupli_map.end())
103                                 dupli_map[key] = 1;
104                         else
105                                 dupli_map[key]++;
106                 }
107
108                 /* generate string */
109                 stringstream desc;
110                 bool first = true;
111
112                 for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
113                         if(!first) desc << ", ";
114                         first = false;
115
116                         if(dt->second > 1)
117                                 desc << dt->second << "x " << dt->first;
118                         else
119                                 desc << dt->first;
120                 }
121
122                 return desc.str();
123         }
124
125         bool load_kernels()
126         {
127                 foreach(SubDevice& sub, devices)
128                         if(!sub.device->load_kernels())
129                                 return false;
130
131                 return true;
132         }
133
134         void mem_alloc(device_memory& mem, MemoryType type)
135         {
136                 foreach(SubDevice& sub, devices) {
137                         mem.device_pointer = 0;
138                         sub.device->mem_alloc(mem, type);
139                         sub.ptr_map[unique_ptr] = mem.device_pointer;
140                 }
141
142                 mem.device_pointer = unique_ptr++;
143         }
144
145         void mem_copy_to(device_memory& mem)
146         {
147                 device_ptr tmp = mem.device_pointer;
148
149                 foreach(SubDevice& sub, devices) {
150                         mem.device_pointer = sub.ptr_map[tmp];
151                         sub.device->mem_copy_to(mem);
152                 }
153
154                 mem.device_pointer = tmp;
155         }
156
157         void mem_copy_from(device_memory& mem, size_t offset, size_t size)
158         {
159                 device_ptr tmp = mem.device_pointer;
160
161                 /* todo: how does this work? */
162                 foreach(SubDevice& sub, devices) {
163                         mem.device_pointer = sub.ptr_map[tmp];
164                         sub.device->mem_copy_from(mem, offset, size);
165                         break;
166                 }
167
168                 mem.device_pointer = tmp;
169         }
170
171         void mem_zero(device_memory& mem)
172         {
173                 device_ptr tmp = mem.device_pointer;
174
175                 foreach(SubDevice& sub, devices) {
176                         mem.device_pointer = sub.ptr_map[tmp];
177                         sub.device->mem_zero(mem);
178                 }
179
180                 mem.device_pointer = tmp;
181         }
182
183         void mem_free(device_memory& mem)
184         {
185                 device_ptr tmp = mem.device_pointer;
186
187                 foreach(SubDevice& sub, devices) {
188                         mem.device_pointer = sub.ptr_map[tmp];
189                         sub.device->mem_free(mem);
190                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
191                 }
192
193                 mem.device_pointer = 0;
194         }
195
196         void const_copy_to(const char *name, void *host, size_t size)
197         {
198                 foreach(SubDevice& sub, devices)
199                         sub.device->const_copy_to(name, host, size);
200         }
201
202         void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
203         {
204                 foreach(SubDevice& sub, devices) {
205                         mem.device_pointer = 0;
206                         sub.device->tex_alloc(name, mem, interpolation, periodic);
207                         sub.ptr_map[unique_ptr] = mem.device_pointer;
208                 }
209
210                 mem.device_pointer = unique_ptr++;
211         }
212
213         void tex_free(device_memory& mem)
214         {
215                 device_ptr tmp = mem.device_pointer;
216
217                 foreach(SubDevice& sub, devices) {
218                         mem.device_pointer = sub.ptr_map[tmp];
219                         sub.device->tex_free(mem);
220                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
221                 }
222
223                 mem.device_pointer = 0;
224         }
225
226         void pixels_alloc(device_memory& mem)
227         {
228                 foreach(SubDevice& sub, devices) {
229                         mem.device_pointer = 0;
230                         sub.device->pixels_alloc(mem);
231                         sub.ptr_map[unique_ptr] = mem.device_pointer;
232                 }
233
234                 mem.device_pointer = unique_ptr++;
235         }
236
237         void pixels_free(device_memory& mem)
238         {
239                 device_ptr tmp = mem.device_pointer;
240
241                 foreach(SubDevice& sub, devices) {
242                         mem.device_pointer = sub.ptr_map[tmp];
243                         sub.device->pixels_free(mem);
244                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
245                 }
246
247                 mem.device_pointer = 0;
248         }
249
250         void pixels_copy_from(device_memory& mem, int y, int w, int h)
251         {
252                 device_ptr tmp = mem.device_pointer;
253                 int i = 0, sub_h = h/devices.size();
254
255                 foreach(SubDevice& sub, devices) {
256                         int sy = y + i*sub_h;
257                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
258
259                         mem.device_pointer = sub.ptr_map[tmp];
260                         sub.device->pixels_copy_from(mem, sy, w, sh);
261                         i++;
262                 }
263
264                 mem.device_pointer = tmp;
265         }
266
267         void draw_pixels(device_memory& rgba, int y, int w, int h, int width, int height, bool transparent)
268         {
269                 device_ptr tmp = rgba.device_pointer;
270                 int i = 0, sub_h = h/devices.size();
271                 int sub_height = height/devices.size();
272
273                 foreach(SubDevice& sub, devices) {
274                         int sy = y + i*sub_h;
275                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
276                         int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
277                         /* adjust math for w/width */
278
279                         rgba.device_pointer = sub.ptr_map[tmp];
280                         sub.device->draw_pixels(rgba, sy, w, sh, width, sheight, transparent);
281                         i++;
282                 }
283
284                 rgba.device_pointer = tmp;
285         }
286
287         void task_add(DeviceTask& task)
288         {
289                 ThreadQueue<DeviceTask> tasks;
290                 task.split(tasks, devices.size());
291
292                 foreach(SubDevice& sub, devices) {
293                         DeviceTask subtask;
294
295                         if(tasks.worker_wait_pop(subtask)) {
296                                 if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
297                                 if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
298                                 if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
299                                 if(task.displace_input) subtask.displace_input = sub.ptr_map[task.displace_input];
300                                 if(task.displace_offset) subtask.displace_offset = sub.ptr_map[task.displace_offset];
301
302                                 sub.device->task_add(subtask);
303                         }
304                 }
305         }
306
307         void task_wait()
308         {
309                 foreach(SubDevice& sub, devices)
310                         sub.device->task_wait();
311         }
312
313         void task_cancel()
314         {
315                 foreach(SubDevice& sub, devices)
316                         sub.device->task_cancel();
317         }
318 };
319
320 Device *device_multi_create(bool background)
321 {
322         return new MultiDevice(background);
323 }
324
325 CCL_NAMESPACE_END
326