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