Cycles: Refactor Progress system to provide better estimates
[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                 explicit 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, sub_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         virtual bool show_samples() const
93         {
94                 if(devices.size() > 1) {
95                         return false;
96                 }
97                 return devices.front().device->show_samples();
98         }
99
100         bool load_kernels(const DeviceRequestedFeatures& requested_features)
101         {
102                 foreach(SubDevice& sub, devices)
103                         if(!sub.device->load_kernels(requested_features))
104                                 return false;
105
106                 return true;
107         }
108
109         void mem_alloc(device_memory& mem, MemoryType type)
110         {
111                 foreach(SubDevice& sub, devices) {
112                         mem.device_pointer = 0;
113                         sub.device->mem_alloc(mem, type);
114                         sub.ptr_map[unique_ptr] = mem.device_pointer;
115                 }
116
117                 mem.device_pointer = unique_ptr++;
118                 stats.mem_alloc(mem.device_size);
119         }
120
121         void mem_copy_to(device_memory& mem)
122         {
123                 device_ptr tmp = mem.device_pointer;
124
125                 foreach(SubDevice& sub, devices) {
126                         mem.device_pointer = sub.ptr_map[tmp];
127                         sub.device->mem_copy_to(mem);
128                 }
129
130                 mem.device_pointer = tmp;
131         }
132
133         void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
134         {
135                 device_ptr tmp = mem.device_pointer;
136                 int i = 0, sub_h = h/devices.size();
137
138                 foreach(SubDevice& sub, devices) {
139                         int sy = y + i*sub_h;
140                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
141
142                         mem.device_pointer = sub.ptr_map[tmp];
143                         sub.device->mem_copy_from(mem, sy, w, sh, elem);
144                         i++;
145                 }
146
147                 mem.device_pointer = tmp;
148         }
149
150         void mem_zero(device_memory& mem)
151         {
152                 device_ptr tmp = mem.device_pointer;
153
154                 foreach(SubDevice& sub, devices) {
155                         mem.device_pointer = sub.ptr_map[tmp];
156                         sub.device->mem_zero(mem);
157                 }
158
159                 mem.device_pointer = tmp;
160         }
161
162         void mem_free(device_memory& mem)
163         {
164                 device_ptr tmp = mem.device_pointer;
165
166                 foreach(SubDevice& sub, devices) {
167                         mem.device_pointer = sub.ptr_map[tmp];
168                         sub.device->mem_free(mem);
169                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
170                 }
171
172                 mem.device_pointer = 0;
173                 stats.mem_free(mem.device_size);
174         }
175
176         void const_copy_to(const char *name, void *host, size_t size)
177         {
178                 foreach(SubDevice& sub, devices)
179                         sub.device->const_copy_to(name, host, size);
180         }
181
182         void tex_alloc(const char *name,
183                        device_memory& mem,
184                        InterpolationType
185                        interpolation,
186                        ExtensionType extension)
187         {
188                 VLOG(1) << "Texture allocate: " << name << ", "
189                         << string_human_readable_number(mem.memory_size()) << " bytes. ("
190                         << string_human_readable_size(mem.memory_size()) << ")";
191
192                 foreach(SubDevice& sub, devices) {
193                         mem.device_pointer = 0;
194                         sub.device->tex_alloc(name, mem, interpolation, extension);
195                         sub.ptr_map[unique_ptr] = mem.device_pointer;
196                 }
197
198                 mem.device_pointer = unique_ptr++;
199                 stats.mem_alloc(mem.device_size);
200         }
201
202         void tex_free(device_memory& mem)
203         {
204                 device_ptr tmp = mem.device_pointer;
205
206                 foreach(SubDevice& sub, devices) {
207                         mem.device_pointer = sub.ptr_map[tmp];
208                         sub.device->tex_free(mem);
209                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
210                 }
211
212                 mem.device_pointer = 0;
213                 stats.mem_free(mem.device_size);
214         }
215
216         void pixels_alloc(device_memory& mem)
217         {
218                 foreach(SubDevice& sub, devices) {
219                         mem.device_pointer = 0;
220                         sub.device->pixels_alloc(mem);
221                         sub.ptr_map[unique_ptr] = mem.device_pointer;
222                 }
223
224                 mem.device_pointer = unique_ptr++;
225         }
226
227         void pixels_free(device_memory& mem)
228         {
229                 device_ptr tmp = mem.device_pointer;
230
231                 foreach(SubDevice& sub, devices) {
232                         mem.device_pointer = sub.ptr_map[tmp];
233                         sub.device->pixels_free(mem);
234                         sub.ptr_map.erase(sub.ptr_map.find(tmp));
235                 }
236
237                 mem.device_pointer = 0;
238         }
239
240         void pixels_copy_from(device_memory& mem, int y, int w, int h)
241         {
242                 device_ptr tmp = mem.device_pointer;
243                 int i = 0, sub_h = h/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
249                         mem.device_pointer = sub.ptr_map[tmp];
250                         sub.device->pixels_copy_from(mem, sy, w, sh);
251                         i++;
252                 }
253
254                 mem.device_pointer = tmp;
255         }
256
257         void draw_pixels(device_memory& rgba, int y, int w, int h, int dx, int dy, int width, int height, bool transparent,
258                 const DeviceDrawParams &draw_params)
259         {
260                 device_ptr tmp = rgba.device_pointer;
261                 int i = 0, sub_h = h/devices.size();
262                 int sub_height = height/devices.size();
263
264                 foreach(SubDevice& sub, devices) {
265                         int sy = y + i*sub_h;
266                         int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
267                         int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
268                         int sdy = dy + i*sub_height;
269                         /* adjust math for w/width */
270
271                         rgba.device_pointer = sub.ptr_map[tmp];
272                         sub.device->draw_pixels(rgba, sy, w, sh, dx, sdy, width, sheight, transparent, draw_params);
273                         i++;
274                 }
275
276                 rgba.device_pointer = tmp;
277         }
278
279         void map_tile(Device *sub_device, RenderTile& tile)
280         {
281                 foreach(SubDevice& sub, devices) {
282                         if(sub.device == sub_device) {
283                                 if(tile.buffer) tile.buffer = sub.ptr_map[tile.buffer];
284                                 if(tile.rng_state) tile.rng_state = sub.ptr_map[tile.rng_state];
285                         }
286                 }
287         }
288
289         int device_number(Device *sub_device)
290         {
291                 int i = 0;
292
293                 foreach(SubDevice& sub, devices) {
294                         if(sub.device == sub_device)
295                                 return i;
296                         i++;
297                 }
298
299                 return -1;
300         }
301
302         int get_split_task_count(DeviceTask& task)
303         {
304                 int total_tasks = 0;
305                 list<DeviceTask> tasks;
306                 task.split(tasks, devices.size());
307                 foreach(SubDevice& sub, devices) {
308                         if(!tasks.empty()) {
309                                 DeviceTask subtask = tasks.front();
310                                 tasks.pop_front();
311
312                                 total_tasks += sub.device->get_split_task_count(subtask);
313                         }
314                 }
315                 return total_tasks;
316         }
317
318         void task_add(DeviceTask& task)
319         {
320                 list<DeviceTask> tasks;
321                 task.split(tasks, devices.size());
322
323                 foreach(SubDevice& sub, devices) {
324                         if(!tasks.empty()) {
325                                 DeviceTask subtask = tasks.front();
326                                 tasks.pop_front();
327
328                                 if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
329                                 if(task.rgba_byte) subtask.rgba_byte = sub.ptr_map[task.rgba_byte];
330                                 if(task.rgba_half) subtask.rgba_half = sub.ptr_map[task.rgba_half];
331                                 if(task.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
332                                 if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
333                                 if(task.shader_output_luma) subtask.shader_output_luma = sub.ptr_map[task.shader_output_luma];
334
335                                 sub.device->task_add(subtask);
336                         }
337                 }
338         }
339
340         void task_wait()
341         {
342                 foreach(SubDevice& sub, devices)
343                         sub.device->task_wait();
344         }
345
346         void task_cancel()
347         {
348                 foreach(SubDevice& sub, devices)
349                         sub.device->task_cancel();
350         }
351
352 protected:
353         Stats sub_stats_;
354 };
355
356 Device *device_multi_create(DeviceInfo& info, Stats &stats, bool background)
357 {
358         return new MultiDevice(info, stats, background);
359 }
360
361 CCL_NAMESPACE_END
362