Merging r50192 through r50223 from trunk into soc-2011-tomato
[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 "buffers.h"
27
28 #include "util_foreach.h"
29 #include "util_list.h"
30 #include "util_map.h"
31 #include "util_time.h"
32
33 CCL_NAMESPACE_BEGIN
34
35 class MultiDevice : public Device
36 {
37 public:
38         struct SubDevice {
39                 SubDevice(Device *device_)
40                 : device(device_) {}
41
42                 Device *device;
43                 map<device_ptr, device_ptr> ptr_map;
44         };
45
46         list<SubDevice> devices;
47         device_ptr unique_ptr;
48
49         MultiDevice(DeviceInfo& info, bool background_)
50         : unique_ptr(1)
51         {
52                 Device *device;
53                 background = background_;
54
55                 foreach(DeviceInfo& subinfo, info.multi_devices) {
56                         device = Device::create(subinfo, background);
57                         devices.push_back(SubDevice(device));
58                 }
59
60 #if 0 //def WITH_NETWORK
61                 /* try to add network devices */
62                 ServerDiscovery discovery(true);
63                 time_sleep(1.0);
64
65                 list<string> servers = discovery.get_server_list();
66
67                 foreach(string& server, servers) {
68                         device = device_network_create(info, server.c_str());
69                         if(device)
70                                 devices.push_back(SubDevice(device));
71                 }
72 #endif
73         }
74
75         ~MultiDevice()
76         {
77                 foreach(SubDevice& sub, devices)
78                         delete sub.device;
79         }
80
81         const string& error_message()
82         {
83                 foreach(SubDevice& sub, devices) {
84                         if(sub.device->error_message() != "") {
85                                 if(error_msg == "")
86                                         error_msg = sub.device->error_message();
87                                 break;
88                         }
89                 }
90
91                 return error_msg;
92         }
93
94         bool load_kernels(bool experimental)
95         {
96                 foreach(SubDevice& sub, devices)
97                         if(!sub.device->load_kernels(experimental))
98                                 return false;
99
100                 return true;
101         }
102
103         void mem_alloc(device_memory& mem, MemoryType type)
104         {
105                 foreach(SubDevice& sub, devices) {
106                         mem.device_pointer = 0;
107                         sub.device->mem_alloc(mem, type);
108                         sub.ptr_map[unique_ptr] = mem.device_pointer;
109                 }
110
111                 mem.device_pointer = unique_ptr++;
112         }
113
114         void mem_copy_to(device_memory& mem)
115         {
116                 device_ptr tmp = mem.device_pointer;
117
118                 foreach(SubDevice& sub, devices) {
119                         mem.device_pointer = sub.ptr_map[tmp];
120                         sub.device->mem_copy_to(mem);
121                 }
122
123                 mem.device_pointer = tmp;
124         }
125
126         void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
127         {
128                 device_ptr tmp = mem.device_pointer;
129                 int i = 0, sub_h = h/devices.size();
130
131                 foreach(SubDevice& sub, devices) {
132                         int sy = y + i*sub_h;
133                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
134
135                         mem.device_pointer = sub.ptr_map[tmp];
136                         sub.device->mem_copy_from(mem, sy, w, sh, elem);
137                         i++;
138                 }
139
140                 mem.device_pointer = tmp;
141         }
142
143         void mem_zero(device_memory& mem)
144         {
145                 device_ptr tmp = mem.device_pointer;
146
147                 foreach(SubDevice& sub, devices) {
148                         mem.device_pointer = sub.ptr_map[tmp];
149                         sub.device->mem_zero(mem);
150                 }
151
152                 mem.device_pointer = tmp;
153         }
154
155         void mem_free(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_free(mem);
162                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
163                 }
164
165                 mem.device_pointer = 0;
166         }
167
168         void const_copy_to(const char *name, void *host, size_t size)
169         {
170                 foreach(SubDevice& sub, devices)
171                         sub.device->const_copy_to(name, host, size);
172         }
173
174         void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
175         {
176                 foreach(SubDevice& sub, devices) {
177                         mem.device_pointer = 0;
178                         sub.device->tex_alloc(name, mem, interpolation, periodic);
179                         sub.ptr_map[unique_ptr] = mem.device_pointer;
180                 }
181
182                 mem.device_pointer = unique_ptr++;
183         }
184
185         void tex_free(device_memory& mem)
186         {
187                 device_ptr tmp = mem.device_pointer;
188
189                 foreach(SubDevice& sub, devices) {
190                         mem.device_pointer = sub.ptr_map[tmp];
191                         sub.device->tex_free(mem);
192                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
193                 }
194
195                 mem.device_pointer = 0;
196         }
197
198         void pixels_alloc(device_memory& mem)
199         {
200                 foreach(SubDevice& sub, devices) {
201                         mem.device_pointer = 0;
202                         sub.device->pixels_alloc(mem);
203                         sub.ptr_map[unique_ptr] = mem.device_pointer;
204                 }
205
206                 mem.device_pointer = unique_ptr++;
207         }
208
209         void pixels_free(device_memory& mem)
210         {
211                 device_ptr tmp = mem.device_pointer;
212
213                 foreach(SubDevice& sub, devices) {
214                         mem.device_pointer = sub.ptr_map[tmp];
215                         sub.device->pixels_free(mem);
216                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
217                 }
218
219                 mem.device_pointer = 0;
220         }
221
222         void pixels_copy_from(device_memory& mem, int y, int w, int h)
223         {
224                 device_ptr tmp = mem.device_pointer;
225                 int i = 0, sub_h = h/devices.size();
226
227                 foreach(SubDevice& sub, devices) {
228                         int sy = y + i*sub_h;
229                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
230
231                         mem.device_pointer = sub.ptr_map[tmp];
232                         sub.device->pixels_copy_from(mem, sy, w, sh);
233                         i++;
234                 }
235
236                 mem.device_pointer = tmp;
237         }
238
239         void draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int width, int height, bool transparent)
240         {
241                 device_ptr tmp = rgba.device_pointer;
242                 int i = 0, sub_h = h/devices.size();
243                 int sub_height = height/devices.size();
244
245                 foreach(SubDevice& sub, devices) {
246                         int sy = y + i*sub_h;
247                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
248                         int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
249                         int sdy = dy + i*sub_height;
250                         /* adjust math for w/width */
251
252                         rgba.device_pointer = sub.ptr_map[tmp];
253                         sub.device->draw_pixels(rgba, sy, w, sh, sdy, width, sheight, transparent);
254                         i++;
255                 }
256
257                 rgba.device_pointer = tmp;
258         }
259
260         void map_tile(Device *sub_device, RenderTile& tile)
261         {
262                 foreach(SubDevice& sub, devices) {
263                         if(sub.device == sub_device) {
264                                 if(tile.buffer) tile.buffer = sub.ptr_map[tile.buffer];
265                                 if(tile.rng_state) tile.rng_state = sub.ptr_map[tile.rng_state];
266                                 if(tile.rgba) tile.rgba = sub.ptr_map[tile.rgba];
267                         }
268                 }
269         }
270
271         int device_number(Device *sub_device)
272         {
273                 int i = 0;
274
275                 foreach(SubDevice& sub, devices) {
276                         if(sub.device == sub_device)
277                                 return i;
278                         i++;
279                 }
280
281                 return -1;
282         }
283
284         void task_add(DeviceTask& task)
285         {
286                 list<DeviceTask> tasks;
287                 task.split(tasks, devices.size());
288
289                 foreach(SubDevice& sub, devices) {
290                         if(!tasks.empty()) {
291                                 DeviceTask subtask = tasks.front();
292                                 tasks.pop_front();
293
294                                 if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
295                                 if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
296                                 if(task.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
297                                 if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
298
299                                 sub.device->task_add(subtask);
300                         }
301                 }
302         }
303
304         void task_wait()
305         {
306                 foreach(SubDevice& sub, devices)
307                         sub.device->task_wait();
308         }
309
310         void task_cancel()
311         {
312                 foreach(SubDevice& sub, devices)
313                         sub.device->task_cancel();
314         }
315 };
316
317 Device *device_multi_create(DeviceInfo& info, bool background)
318 {
319         return new MultiDevice(info, background);
320 }
321
322 static bool device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool with_display, bool with_advanced_shading, const char *id_fmt, int num)
323 {
324         DeviceInfo info;
325
326         /* create map to find duplicate descriptions */
327         map<string, int> dupli_map;
328         map<string, int>::iterator dt;
329         int num_added = 0, num_display = 0;
330
331         info.advanced_shading = with_advanced_shading;
332         info.pack_images = false;
333
334         foreach(DeviceInfo& subinfo, devices) {
335                 if(subinfo.type == type) {
336                         if(subinfo.advanced_shading != info.advanced_shading)
337                                 continue;
338                         if(subinfo.display_device) {
339                                 if(with_display)
340                                         num_display++;
341                                 else
342                                         continue;
343                         }
344
345                         string key = subinfo.description;
346
347                         if(dupli_map.find(key) == dupli_map.end())
348                                 dupli_map[key] = 1;
349                         else
350                                 dupli_map[key]++;
351
352                         info.multi_devices.push_back(subinfo);
353                         if(subinfo.display_device)
354                                 info.display_device = true;
355                         info.pack_images = info.pack_images || subinfo.pack_images;
356                         num_added++;
357                 }
358         }
359
360         if(num_added <= 1 || (with_display && num_display == 0))
361                 return false;
362
363         /* generate string */
364         stringstream desc;
365         vector<string> last_tokens;
366         bool first = true;
367
368         for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
369                 if(!first) desc << " + ";
370                 first = false;
371
372                 /* get name and count */
373                 string name = dt->first;
374                 int count = dt->second;
375
376                 /* strip common prefixes */
377                 vector<string> tokens;
378                 string_split(tokens, dt->first);
379
380                 if(tokens.size() > 1) {
381                         int i;
382
383                         for(i = 0; i < tokens.size() && i < last_tokens.size(); i++)
384                                 if(tokens[i] != last_tokens[i])
385                                         break;
386
387                         name = "";
388                         for(; i < tokens.size(); i++) {
389                                 name += tokens[i];
390                                 if(i != tokens.size() - 1)
391                                         name += " ";
392                         }
393                 }
394
395                 last_tokens = tokens;
396
397                 /* add */
398                 if(count > 1)
399                         desc << name << " (" << count << "x)";
400                 else
401                         desc << name;
402         }
403
404         /* add info */
405         info.type = DEVICE_MULTI;
406         info.description = desc.str();
407         info.id = string_printf(id_fmt, num);
408         info.display_device = with_display;
409         info.num = 0;
410
411         if(with_display)
412                 devices.push_back(info);
413         else
414                 devices.insert(devices.begin(), info);
415         
416         return true;
417 }
418
419 void device_multi_info(vector<DeviceInfo>& devices)
420 {
421         int num = 0;
422
423         if(!device_multi_add(devices, DEVICE_CUDA, false, true, "CUDA_MULTI_%d", num++))
424                 device_multi_add(devices, DEVICE_CUDA, false, false, "CUDA_MULTI_%d", num++);
425         if(!device_multi_add(devices, DEVICE_CUDA, true, true, "CUDA_MULTI_%d", num++))
426                 device_multi_add(devices, DEVICE_CUDA, true, false, "CUDA_MULTI_%d", num++);
427
428         num = 0;
429         if(!device_multi_add(devices, DEVICE_OPENCL, false, true, "OPENCL_MULTI_%d", num++))
430                 device_multi_add(devices, DEVICE_OPENCL, false, false, "OPENCL_MULTI_%d", num++);
431         if(!device_multi_add(devices, DEVICE_OPENCL, true, true, "OPENCL_MULTI_%d", num++))
432                 device_multi_add(devices, DEVICE_OPENCL, true, false, "OPENCL_MULTI_%d", num++);
433 }
434
435 CCL_NAMESPACE_END
436