2 * Copyright 2011, Blender Foundation.
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.
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.
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.
23 #include "device_intern.h"
24 #include "device_network.h"
28 #include "util_foreach.h"
29 #include "util_list.h"
31 #include "util_time.h"
35 class MultiDevice : public Device
39 SubDevice(Device *device_)
43 map<device_ptr, device_ptr> ptr_map;
46 list<SubDevice> devices;
47 device_ptr unique_ptr;
49 MultiDevice(DeviceInfo& info, Stats &stats, bool background_)
50 : Device(stats), unique_ptr(1)
53 background = background_;
55 foreach(DeviceInfo& subinfo, info.multi_devices) {
56 device = Device::create(subinfo, stats, background);
57 devices.push_back(SubDevice(device));
60 #if 0 //def WITH_NETWORK
61 /* try to add network devices */
62 ServerDiscovery discovery(true);
65 list<string> servers = discovery.get_server_list();
67 foreach(string& server, servers) {
68 device = device_network_create(info, server.c_str());
70 devices.push_back(SubDevice(device));
77 foreach(SubDevice& sub, devices)
81 const string& error_message()
83 foreach(SubDevice& sub, devices) {
84 if(sub.device->error_message() != "") {
86 error_msg = sub.device->error_message();
94 bool load_kernels(bool experimental)
96 foreach(SubDevice& sub, devices)
97 if(!sub.device->load_kernels(experimental))
103 void mem_alloc(device_memory& mem, MemoryType type)
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;
111 mem.device_pointer = unique_ptr++;
114 void mem_copy_to(device_memory& mem)
116 device_ptr tmp = mem.device_pointer;
118 foreach(SubDevice& sub, devices) {
119 mem.device_pointer = sub.ptr_map[tmp];
120 sub.device->mem_copy_to(mem);
123 mem.device_pointer = tmp;
126 void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
128 device_ptr tmp = mem.device_pointer;
129 int i = 0, sub_h = h/devices.size();
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;
135 mem.device_pointer = sub.ptr_map[tmp];
136 sub.device->mem_copy_from(mem, sy, w, sh, elem);
140 mem.device_pointer = tmp;
143 void mem_zero(device_memory& mem)
145 device_ptr tmp = mem.device_pointer;
147 foreach(SubDevice& sub, devices) {
148 mem.device_pointer = sub.ptr_map[tmp];
149 sub.device->mem_zero(mem);
152 mem.device_pointer = tmp;
155 void mem_free(device_memory& mem)
157 device_ptr tmp = mem.device_pointer;
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));
165 mem.device_pointer = 0;
168 void const_copy_to(const char *name, void *host, size_t size)
170 foreach(SubDevice& sub, devices)
171 sub.device->const_copy_to(name, host, size);
174 void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
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;
182 mem.device_pointer = unique_ptr++;
185 void tex_free(device_memory& mem)
187 device_ptr tmp = mem.device_pointer;
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));
195 mem.device_pointer = 0;
198 void pixels_alloc(device_memory& mem)
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;
206 mem.device_pointer = unique_ptr++;
209 void pixels_free(device_memory& mem)
211 device_ptr tmp = mem.device_pointer;
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));
219 mem.device_pointer = 0;
222 void pixels_copy_from(device_memory& mem, int y, int w, int h)
224 device_ptr tmp = mem.device_pointer;
225 int i = 0, sub_h = h/devices.size();
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;
231 mem.device_pointer = sub.ptr_map[tmp];
232 sub.device->pixels_copy_from(mem, sy, w, sh);
236 mem.device_pointer = tmp;
239 void draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int width, int height, bool transparent)
241 device_ptr tmp = rgba.device_pointer;
242 int i = 0, sub_h = h/devices.size();
243 int sub_height = height/devices.size();
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 */
252 rgba.device_pointer = sub.ptr_map[tmp];
253 sub.device->draw_pixels(rgba, sy, w, sh, sdy, width, sheight, transparent);
257 rgba.device_pointer = tmp;
260 void map_tile(Device *sub_device, RenderTile& tile)
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];
271 int device_number(Device *sub_device)
275 foreach(SubDevice& sub, devices) {
276 if(sub.device == sub_device)
284 void task_add(DeviceTask& task)
286 list<DeviceTask> tasks;
287 task.split(tasks, devices.size());
289 foreach(SubDevice& sub, devices) {
291 DeviceTask subtask = tasks.front();
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];
299 sub.device->task_add(subtask);
306 foreach(SubDevice& sub, devices)
307 sub.device->task_wait();
312 foreach(SubDevice& sub, devices)
313 sub.device->task_cancel();
317 Device *device_multi_create(DeviceInfo& info, Stats &stats, bool background)
319 return new MultiDevice(info, stats, background);
322 static bool device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool with_display, bool with_advanced_shading, const char *id_fmt, int num)
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;
331 info.advanced_shading = with_advanced_shading;
332 info.pack_images = false;
333 info.extended_images = true;
335 foreach(DeviceInfo& subinfo, devices) {
336 if(subinfo.type == type) {
337 if(subinfo.advanced_shading != info.advanced_shading)
339 if(subinfo.display_device) {
346 string key = subinfo.description;
348 if(dupli_map.find(key) == dupli_map.end())
353 info.multi_devices.push_back(subinfo);
354 if(subinfo.display_device)
355 info.display_device = true;
356 info.pack_images = info.pack_images || subinfo.pack_images;
357 info.extended_images = info.extended_images && subinfo.extended_images;
362 if(num_added <= 1 || (with_display && num_display == 0))
365 /* generate string */
367 vector<string> last_tokens;
370 for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
371 if(!first) desc << " + ";
374 /* get name and count */
375 string name = dt->first;
376 int count = dt->second;
378 /* strip common prefixes */
379 vector<string> tokens;
380 string_split(tokens, dt->first);
382 if(tokens.size() > 1) {
385 for(i = 0; i < tokens.size() && i < last_tokens.size(); i++)
386 if(tokens[i] != last_tokens[i])
390 for(; i < tokens.size(); i++) {
392 if(i != tokens.size() - 1)
397 last_tokens = tokens;
401 desc << name << " (" << count << "x)";
407 info.type = DEVICE_MULTI;
408 info.description = desc.str();
409 info.id = string_printf(id_fmt, num);
410 info.display_device = with_display;
414 devices.push_back(info);
416 devices.insert(devices.begin(), info);
421 void device_multi_info(vector<DeviceInfo>& devices)
425 if(!device_multi_add(devices, DEVICE_CUDA, false, true, "CUDA_MULTI_%d", num++))
426 device_multi_add(devices, DEVICE_CUDA, false, false, "CUDA_MULTI_%d", num++);
427 if(!device_multi_add(devices, DEVICE_CUDA, true, true, "CUDA_MULTI_%d", num++))
428 device_multi_add(devices, DEVICE_CUDA, true, false, "CUDA_MULTI_%d", num++);
431 if(!device_multi_add(devices, DEVICE_OPENCL, false, true, "OPENCL_MULTI_%d", num++))
432 device_multi_add(devices, DEVICE_OPENCL, false, false, "OPENCL_MULTI_%d", num++);
433 if(!device_multi_add(devices, DEVICE_OPENCL, true, true, "OPENCL_MULTI_%d", num++))
434 device_multi_add(devices, DEVICE_OPENCL, true, false, "OPENCL_MULTI_%d", num++);