ClangFormat: apply to source, most of intern
[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/device.h"
21 #include "device/device_intern.h"
22 #include "device/device_network.h"
23
24 #include "render/buffers.h"
25
26 #include "util/util_foreach.h"
27 #include "util/util_list.h"
28 #include "util/util_logging.h"
29 #include "util/util_map.h"
30 #include "util/util_time.h"
31
32 CCL_NAMESPACE_BEGIN
33
34 class MultiDevice : public Device {
35  public:
36   struct SubDevice {
37     explicit SubDevice(Device *device_) : device(device_)
38     {
39     }
40
41     Device *device;
42     map<device_ptr, device_ptr> ptr_map;
43   };
44
45   list<SubDevice> devices;
46   device_ptr unique_key;
47
48   MultiDevice(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background_)
49       : Device(info, stats, profiler, background_), unique_key(1)
50   {
51     foreach (DeviceInfo &subinfo, info.multi_devices) {
52       Device *device = Device::create(subinfo, sub_stats_, profiler, background);
53
54       /* Always add CPU devices at the back since GPU devices can change
55        * host memory pointers, which CPU uses as device pointer. */
56       if (subinfo.type == DEVICE_CPU) {
57         devices.push_back(SubDevice(device));
58       }
59       else {
60         devices.push_front(SubDevice(device));
61       }
62     }
63
64 #ifdef WITH_NETWORK
65     /* try to add network devices */
66     ServerDiscovery discovery(true);
67     time_sleep(1.0);
68
69     vector<string> servers = discovery.get_server_list();
70
71     foreach (string &server, servers) {
72       Device *device = device_network_create(info, stats, profiler, server.c_str());
73       if (device)
74         devices.push_back(SubDevice(device));
75     }
76 #endif
77   }
78
79   ~MultiDevice()
80   {
81     foreach (SubDevice &sub, devices)
82       delete sub.device;
83   }
84
85   const string &error_message()
86   {
87     foreach (SubDevice &sub, devices) {
88       if (sub.device->error_message() != "") {
89         if (error_msg == "")
90           error_msg = sub.device->error_message();
91         break;
92       }
93     }
94
95     return error_msg;
96   }
97
98   virtual bool show_samples() const
99   {
100     if (devices.size() > 1) {
101       return false;
102     }
103     return devices.front().device->show_samples();
104   }
105
106   virtual BVHLayoutMask get_bvh_layout_mask() const
107   {
108     BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_ALL;
109     foreach (const SubDevice &sub_device, devices) {
110       bvh_layout_mask &= sub_device.device->get_bvh_layout_mask();
111     }
112     return bvh_layout_mask;
113   }
114
115   bool load_kernels(const DeviceRequestedFeatures &requested_features)
116   {
117     foreach (SubDevice &sub, devices)
118       if (!sub.device->load_kernels(requested_features))
119         return false;
120
121     return true;
122   }
123
124   bool wait_for_availability(const DeviceRequestedFeatures &requested_features)
125   {
126     foreach (SubDevice &sub, devices)
127       if (!sub.device->wait_for_availability(requested_features))
128         return false;
129
130     return true;
131   }
132
133   DeviceKernelStatus get_active_kernel_switch_state()
134   {
135     DeviceKernelStatus result = DEVICE_KERNEL_USING_FEATURE_KERNEL;
136
137     foreach (SubDevice &sub, devices) {
138       DeviceKernelStatus subresult = sub.device->get_active_kernel_switch_state();
139       switch (subresult) {
140         case DEVICE_KERNEL_WAITING_FOR_FEATURE_KERNEL:
141           result = subresult;
142           break;
143
144         case DEVICE_KERNEL_FEATURE_KERNEL_INVALID:
145         case DEVICE_KERNEL_FEATURE_KERNEL_AVAILABLE:
146           return subresult;
147
148         case DEVICE_KERNEL_USING_FEATURE_KERNEL:
149         case DEVICE_KERNEL_UNKNOWN:
150           break;
151       }
152     }
153     return result;
154   }
155
156   void mem_alloc(device_memory &mem)
157   {
158     device_ptr key = unique_key++;
159
160     foreach (SubDevice &sub, devices) {
161       mem.device = sub.device;
162       mem.device_pointer = 0;
163       mem.device_size = 0;
164
165       sub.device->mem_alloc(mem);
166       sub.ptr_map[key] = mem.device_pointer;
167     }
168
169     mem.device = this;
170     mem.device_pointer = key;
171     stats.mem_alloc(mem.device_size);
172   }
173
174   void mem_copy_to(device_memory &mem)
175   {
176     device_ptr existing_key = mem.device_pointer;
177     device_ptr key = (existing_key) ? existing_key : unique_key++;
178     size_t existing_size = mem.device_size;
179
180     foreach (SubDevice &sub, devices) {
181       mem.device = sub.device;
182       mem.device_pointer = (existing_key) ? sub.ptr_map[existing_key] : 0;
183       mem.device_size = existing_size;
184
185       sub.device->mem_copy_to(mem);
186       sub.ptr_map[key] = mem.device_pointer;
187     }
188
189     mem.device = this;
190     mem.device_pointer = key;
191     stats.mem_alloc(mem.device_size - existing_size);
192   }
193
194   void mem_copy_from(device_memory &mem, int y, int w, int h, int elem)
195   {
196     device_ptr key = mem.device_pointer;
197     int i = 0, sub_h = h / devices.size();
198
199     foreach (SubDevice &sub, devices) {
200       int sy = y + i * sub_h;
201       int sh = (i == (int)devices.size() - 1) ? h - sub_h * i : sub_h;
202
203       mem.device = sub.device;
204       mem.device_pointer = sub.ptr_map[key];
205
206       sub.device->mem_copy_from(mem, sy, w, sh, elem);
207       i++;
208     }
209
210     mem.device = this;
211     mem.device_pointer = key;
212   }
213
214   void mem_zero(device_memory &mem)
215   {
216     device_ptr existing_key = mem.device_pointer;
217     device_ptr key = (existing_key) ? existing_key : unique_key++;
218     size_t existing_size = mem.device_size;
219
220     foreach (SubDevice &sub, devices) {
221       mem.device = sub.device;
222       mem.device_pointer = (existing_key) ? sub.ptr_map[existing_key] : 0;
223       mem.device_size = existing_size;
224
225       sub.device->mem_zero(mem);
226       sub.ptr_map[key] = mem.device_pointer;
227     }
228
229     mem.device = this;
230     mem.device_pointer = key;
231     stats.mem_alloc(mem.device_size - existing_size);
232   }
233
234   void mem_free(device_memory &mem)
235   {
236     device_ptr key = mem.device_pointer;
237     size_t existing_size = mem.device_size;
238
239     foreach (SubDevice &sub, devices) {
240       mem.device = sub.device;
241       mem.device_pointer = sub.ptr_map[key];
242       mem.device_size = existing_size;
243
244       sub.device->mem_free(mem);
245       sub.ptr_map.erase(sub.ptr_map.find(key));
246     }
247
248     mem.device = this;
249     mem.device_pointer = 0;
250     mem.device_size = 0;
251     stats.mem_free(existing_size);
252   }
253
254   void const_copy_to(const char *name, void *host, size_t size)
255   {
256     foreach (SubDevice &sub, devices)
257       sub.device->const_copy_to(name, host, size);
258   }
259
260   void draw_pixels(device_memory &rgba,
261                    int y,
262                    int w,
263                    int h,
264                    int width,
265                    int height,
266                    int dx,
267                    int dy,
268                    int dw,
269                    int dh,
270                    bool transparent,
271                    const DeviceDrawParams &draw_params)
272   {
273     device_ptr key = rgba.device_pointer;
274     int i = 0, sub_h = h / devices.size();
275     int sub_height = height / devices.size();
276
277     foreach (SubDevice &sub, devices) {
278       int sy = y + i * sub_h;
279       int sh = (i == (int)devices.size() - 1) ? h - sub_h * i : sub_h;
280       int sheight = (i == (int)devices.size() - 1) ? height - sub_height * i : sub_height;
281       int sdy = dy + i * sub_height;
282       /* adjust math for w/width */
283
284       rgba.device_pointer = sub.ptr_map[key];
285       sub.device->draw_pixels(
286           rgba, sy, w, sh, width, sheight, dx, sdy, dw, dh, transparent, draw_params);
287       i++;
288     }
289
290     rgba.device_pointer = key;
291   }
292
293   void map_tile(Device *sub_device, RenderTile &tile)
294   {
295     foreach (SubDevice &sub, devices) {
296       if (sub.device == sub_device) {
297         if (tile.buffer)
298           tile.buffer = sub.ptr_map[tile.buffer];
299       }
300     }
301   }
302
303   int device_number(Device *sub_device)
304   {
305     int i = 0;
306
307     foreach (SubDevice &sub, devices) {
308       if (sub.device == sub_device)
309         return i;
310       i++;
311     }
312
313     return -1;
314   }
315
316   void map_neighbor_tiles(Device *sub_device, RenderTile *tiles)
317   {
318     for (int i = 0; i < 9; i++) {
319       if (!tiles[i].buffers) {
320         continue;
321       }
322
323       /* If the tile was rendered on another device, copy its memory to
324        * to the current device now, for the duration of the denoising task.
325        * Note that this temporarily modifies the RenderBuffers and calls
326        * the device, so this function is not thread safe. */
327       device_vector<float> &mem = tiles[i].buffers->buffer;
328       if (mem.device != sub_device) {
329         /* Only copy from device to host once. This is faster, but
330          * also required for the case where a CPU thread is denoising
331          * a tile rendered on the GPU. In that case we have to avoid
332          * overwriting the buffer being denoised by the CPU thread. */
333         if (!tiles[i].buffers->map_neighbor_copied) {
334           tiles[i].buffers->map_neighbor_copied = true;
335           mem.copy_from_device(0, mem.data_size, 1);
336         }
337
338         mem.swap_device(sub_device, 0, 0);
339
340         mem.copy_to_device();
341         tiles[i].buffer = mem.device_pointer;
342         tiles[i].device_size = mem.device_size;
343
344         mem.restore_device();
345       }
346     }
347   }
348
349   void unmap_neighbor_tiles(Device *sub_device, RenderTile *tiles)
350   {
351     /* Copy denoised result back to the host. */
352     device_vector<float> &mem = tiles[9].buffers->buffer;
353     mem.swap_device(sub_device, tiles[9].device_size, tiles[9].buffer);
354     mem.copy_from_device(0, mem.data_size, 1);
355     mem.restore_device();
356     /* Copy denoised result to the original device. */
357     mem.copy_to_device();
358
359     for (int i = 0; i < 9; i++) {
360       if (!tiles[i].buffers) {
361         continue;
362       }
363
364       device_vector<float> &mem = tiles[i].buffers->buffer;
365       if (mem.device != sub_device) {
366         mem.swap_device(sub_device, tiles[i].device_size, tiles[i].buffer);
367         sub_device->mem_free(mem);
368         mem.restore_device();
369       }
370     }
371   }
372
373   int get_split_task_count(DeviceTask &task)
374   {
375     int total_tasks = 0;
376     list<DeviceTask> tasks;
377     task.split(tasks, devices.size());
378     foreach (SubDevice &sub, devices) {
379       if (!tasks.empty()) {
380         DeviceTask subtask = tasks.front();
381         tasks.pop_front();
382
383         total_tasks += sub.device->get_split_task_count(subtask);
384       }
385     }
386     return total_tasks;
387   }
388
389   void task_add(DeviceTask &task)
390   {
391     list<DeviceTask> tasks;
392     task.split(tasks, devices.size());
393
394     foreach (SubDevice &sub, devices) {
395       if (!tasks.empty()) {
396         DeviceTask subtask = tasks.front();
397         tasks.pop_front();
398
399         if (task.buffer)
400           subtask.buffer = sub.ptr_map[task.buffer];
401         if (task.rgba_byte)
402           subtask.rgba_byte = sub.ptr_map[task.rgba_byte];
403         if (task.rgba_half)
404           subtask.rgba_half = sub.ptr_map[task.rgba_half];
405         if (task.shader_input)
406           subtask.shader_input = sub.ptr_map[task.shader_input];
407         if (task.shader_output)
408           subtask.shader_output = sub.ptr_map[task.shader_output];
409
410         sub.device->task_add(subtask);
411       }
412     }
413   }
414
415   void task_wait()
416   {
417     foreach (SubDevice &sub, devices)
418       sub.device->task_wait();
419   }
420
421   void task_cancel()
422   {
423     foreach (SubDevice &sub, devices)
424       sub.device->task_cancel();
425   }
426
427  protected:
428   Stats sub_stats_;
429 };
430
431 Device *device_multi_create(DeviceInfo &info, Stats &stats, Profiler &profiler, bool background)
432 {
433   return new MultiDevice(info, stats, profiler, background);
434 }
435
436 CCL_NAMESPACE_END