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