Blender V2.61 - r43446

device_multi.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #include <stdlib.h>
00020 #include <sstream>
00021 
00022 #include "device.h"
00023 #include "device_intern.h"
00024 #include "device_network.h"
00025 
00026 #include "util_foreach.h"
00027 #include "util_list.h"
00028 #include "util_map.h"
00029 #include "util_time.h"
00030 
00031 CCL_NAMESPACE_BEGIN
00032 
00033 class MultiDevice : public Device
00034 {
00035 public:
00036     struct SubDevice {
00037         SubDevice(Device *device_)
00038         : device(device_) {}
00039 
00040         Device *device;
00041         map<device_ptr, device_ptr> ptr_map;
00042     };
00043 
00044     list<SubDevice> devices;
00045     device_ptr unique_ptr;
00046 
00047     MultiDevice(DeviceInfo& info, bool background_)
00048     : unique_ptr(1)
00049     {
00050         Device *device;
00051         background = background_;
00052 
00053         foreach(DeviceInfo& subinfo, info.multi_devices) {
00054             device = Device::create(subinfo, background);
00055             devices.push_back(SubDevice(device));
00056         }
00057 
00058 #if 0 //def WITH_NETWORK
00059         /* try to add network devices */
00060         ServerDiscovery discovery(true);
00061         time_sleep(1.0);
00062 
00063         list<string> servers = discovery.get_server_list();
00064 
00065         foreach(string& server, servers) {
00066             device = device_network_create(info, server.c_str());
00067             if(device)
00068                 devices.push_back(SubDevice(device));
00069         }
00070 #endif
00071     }
00072 
00073     ~MultiDevice()
00074     {
00075         foreach(SubDevice& sub, devices)
00076             delete sub.device;
00077     }
00078 
00079     bool support_full_kernel()
00080     {
00081         foreach(SubDevice& sub, devices) {
00082             if(!sub.device->support_full_kernel())
00083                 return false;
00084         }
00085 
00086         return true;
00087     }
00088 
00089     const string& error_message()
00090     {
00091         foreach(SubDevice& sub, devices) {
00092             if(sub.device->error_message() != "") {
00093                 if(error_msg == "")
00094                     error_msg = sub.device->error_message();
00095                 break;
00096             }
00097         }
00098 
00099         return error_msg;
00100     }
00101 
00102     string description()
00103     {
00104         /* create map to find duplicate descriptions */
00105         map<string, int> dupli_map;
00106         map<string, int>::iterator dt;
00107 
00108         foreach(SubDevice& sub, devices) {
00109             string key = sub.device->description();
00110 
00111             if(dupli_map.find(key) == dupli_map.end())
00112                 dupli_map[key] = 1;
00113             else
00114                 dupli_map[key]++;
00115         }
00116 
00117         /* generate string */
00118         stringstream desc;
00119         bool first = true;
00120 
00121         for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
00122             if(!first) desc << ", ";
00123             first = false;
00124 
00125             if(dt->second > 1)
00126                 desc << dt->second << "x " << dt->first;
00127             else
00128                 desc << dt->first;
00129         }
00130 
00131         return desc.str();
00132     }
00133 
00134     bool load_kernels(bool experimental)
00135     {
00136         foreach(SubDevice& sub, devices)
00137             if(!sub.device->load_kernels(experimental))
00138                 return false;
00139 
00140         return true;
00141     }
00142 
00143     void mem_alloc(device_memory& mem, MemoryType type)
00144     {
00145         foreach(SubDevice& sub, devices) {
00146             mem.device_pointer = 0;
00147             sub.device->mem_alloc(mem, type);
00148             sub.ptr_map[unique_ptr] = mem.device_pointer;
00149         }
00150 
00151         mem.device_pointer = unique_ptr++;
00152     }
00153 
00154     void mem_copy_to(device_memory& mem)
00155     {
00156         device_ptr tmp = mem.device_pointer;
00157 
00158         foreach(SubDevice& sub, devices) {
00159             mem.device_pointer = sub.ptr_map[tmp];
00160             sub.device->mem_copy_to(mem);
00161         }
00162 
00163         mem.device_pointer = tmp;
00164     }
00165 
00166     void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
00167     {
00168         device_ptr tmp = mem.device_pointer;
00169         int i = 0, sub_h = h/devices.size();
00170 
00171         foreach(SubDevice& sub, devices) {
00172             int sy = y + i*sub_h;
00173             int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
00174 
00175             mem.device_pointer = sub.ptr_map[tmp];
00176             sub.device->mem_copy_from(mem, sy, w, sh, elem);
00177             i++;
00178         }
00179 
00180         mem.device_pointer = tmp;
00181     }
00182 
00183     void mem_zero(device_memory& mem)
00184     {
00185         device_ptr tmp = mem.device_pointer;
00186 
00187         foreach(SubDevice& sub, devices) {
00188             mem.device_pointer = sub.ptr_map[tmp];
00189             sub.device->mem_zero(mem);
00190         }
00191 
00192         mem.device_pointer = tmp;
00193     }
00194 
00195     void mem_free(device_memory& mem)
00196     {
00197         device_ptr tmp = mem.device_pointer;
00198 
00199         foreach(SubDevice& sub, devices) {
00200             mem.device_pointer = sub.ptr_map[tmp];
00201             sub.device->mem_free(mem);
00202             sub.ptr_map.erase(sub.ptr_map.find(tmp));
00203         }
00204 
00205         mem.device_pointer = 0;
00206     }
00207 
00208     void const_copy_to(const char *name, void *host, size_t size)
00209     {
00210         foreach(SubDevice& sub, devices)
00211             sub.device->const_copy_to(name, host, size);
00212     }
00213 
00214     void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
00215     {
00216         foreach(SubDevice& sub, devices) {
00217             mem.device_pointer = 0;
00218             sub.device->tex_alloc(name, mem, interpolation, periodic);
00219             sub.ptr_map[unique_ptr] = mem.device_pointer;
00220         }
00221 
00222         mem.device_pointer = unique_ptr++;
00223     }
00224 
00225     void tex_free(device_memory& mem)
00226     {
00227         device_ptr tmp = mem.device_pointer;
00228 
00229         foreach(SubDevice& sub, devices) {
00230             mem.device_pointer = sub.ptr_map[tmp];
00231             sub.device->tex_free(mem);
00232             sub.ptr_map.erase(sub.ptr_map.find(tmp));
00233         }
00234 
00235         mem.device_pointer = 0;
00236     }
00237 
00238     void pixels_alloc(device_memory& mem)
00239     {
00240         foreach(SubDevice& sub, devices) {
00241             mem.device_pointer = 0;
00242             sub.device->pixels_alloc(mem);
00243             sub.ptr_map[unique_ptr] = mem.device_pointer;
00244         }
00245 
00246         mem.device_pointer = unique_ptr++;
00247     }
00248 
00249     void pixels_free(device_memory& mem)
00250     {
00251         device_ptr tmp = mem.device_pointer;
00252 
00253         foreach(SubDevice& sub, devices) {
00254             mem.device_pointer = sub.ptr_map[tmp];
00255             sub.device->pixels_free(mem);
00256             sub.ptr_map.erase(sub.ptr_map.find(tmp));
00257         }
00258 
00259         mem.device_pointer = 0;
00260     }
00261 
00262     void pixels_copy_from(device_memory& mem, int y, int w, int h)
00263     {
00264         device_ptr tmp = mem.device_pointer;
00265         int i = 0, sub_h = h/devices.size();
00266 
00267         foreach(SubDevice& sub, devices) {
00268             int sy = y + i*sub_h;
00269             int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
00270 
00271             mem.device_pointer = sub.ptr_map[tmp];
00272             sub.device->pixels_copy_from(mem, sy, w, sh);
00273             i++;
00274         }
00275 
00276         mem.device_pointer = tmp;
00277     }
00278 
00279     void draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int width, int height, bool transparent)
00280     {
00281         device_ptr tmp = rgba.device_pointer;
00282         int i = 0, sub_h = h/devices.size();
00283         int sub_height = height/devices.size();
00284 
00285         foreach(SubDevice& sub, devices) {
00286             int sy = y + i*sub_h;
00287             int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
00288             int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
00289             int sdy = dy + i*sub_height;
00290             /* adjust math for w/width */
00291 
00292             rgba.device_pointer = sub.ptr_map[tmp];
00293             sub.device->draw_pixels(rgba, sy, w, sh, sdy, width, sheight, transparent);
00294             i++;
00295         }
00296 
00297         rgba.device_pointer = tmp;
00298     }
00299 
00300     void task_add(DeviceTask& task)
00301     {
00302         ThreadQueue<DeviceTask> tasks;
00303         task.split(tasks, devices.size());
00304 
00305         foreach(SubDevice& sub, devices) {
00306             DeviceTask subtask;
00307 
00308             if(tasks.worker_wait_pop(subtask)) {
00309                 if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
00310                 if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
00311                 if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
00312                 if(task.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
00313                 if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
00314 
00315                 sub.device->task_add(subtask);
00316             }
00317         }
00318     }
00319 
00320     void task_wait()
00321     {
00322         foreach(SubDevice& sub, devices)
00323             sub.device->task_wait();
00324     }
00325 
00326     void task_cancel()
00327     {
00328         foreach(SubDevice& sub, devices)
00329             sub.device->task_cancel();
00330     }
00331 };
00332 
00333 Device *device_multi_create(DeviceInfo& info, bool background)
00334 {
00335     return new MultiDevice(info, background);
00336 }
00337 
00338 static void device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool with_display, const char *id_fmt, int num)
00339 {
00340     DeviceInfo info;
00341 
00342     /* create map to find duplicate descriptions */
00343     map<string, int> dupli_map;
00344     map<string, int>::iterator dt;
00345     int num_added = 0, num_display = 0;
00346 
00347     foreach(DeviceInfo& subinfo, devices) {
00348         if(subinfo.type == type) {
00349             if(subinfo.display_device) {
00350                 if(with_display)
00351                     num_display++;
00352                 else
00353                     continue;
00354             }
00355 
00356             string key = subinfo.description;
00357 
00358             if(dupli_map.find(key) == dupli_map.end())
00359                 dupli_map[key] = 1;
00360             else
00361                 dupli_map[key]++;
00362 
00363             info.multi_devices.push_back(subinfo);
00364             if(subinfo.display_device)
00365                 info.display_device = true;
00366             num_added++;
00367         }
00368     }
00369 
00370     if(num_added <= 1 || (with_display && num_display == 0))
00371         return;
00372 
00373     /* generate string */
00374     stringstream desc;
00375     vector<string> last_tokens;
00376     bool first = true;
00377 
00378     for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
00379         if(!first) desc << " + ";
00380         first = false;
00381 
00382         /* get name and count */
00383         string name = dt->first;
00384         int count = dt->second;
00385 
00386         /* strip common prefixes */
00387         vector<string> tokens;
00388         string_split(tokens, dt->first);
00389 
00390         if(tokens.size() > 1) {
00391             int i;
00392 
00393             for(i = 0; i < tokens.size() && i < last_tokens.size(); i++)
00394                 if(tokens[i] != last_tokens[i])
00395                     break;
00396 
00397             name = "";
00398             for(; i < tokens.size(); i++) {
00399                 name += tokens[i];
00400                 if(i != tokens.size() - 1)
00401                     name += " ";
00402             }
00403         }
00404 
00405         last_tokens = tokens;
00406 
00407         /* add */
00408         if(count > 1)
00409             desc << name << " (" << count << "x)";
00410         else
00411             desc << name;
00412     }
00413 
00414     /* add info */
00415     info.type = DEVICE_MULTI;
00416     info.description = desc.str();
00417     info.id = string_printf(id_fmt, num);
00418     info.display_device = with_display;
00419     info.num = 0;
00420 
00421     if(with_display)
00422         devices.push_back(info);
00423     else
00424         devices.insert(devices.begin(), info);
00425 }
00426 
00427 void device_multi_info(vector<DeviceInfo>& devices)
00428 {
00429     int num = 0;
00430     device_multi_add(devices, DEVICE_CUDA, false, "CUDA_MULTI_%d", num++);
00431     device_multi_add(devices, DEVICE_CUDA, true, "CUDA_MULTI_%d", num++);
00432 
00433     num = 0;
00434     device_multi_add(devices, DEVICE_OPENCL, false, "OPENCL_MULTI_%d", num++);
00435     device_multi_add(devices, DEVICE_OPENCL, true, "OPENCL_MULTI_%d", num++);
00436 }
00437 
00438 CCL_NAMESPACE_END
00439