Blender V2.61 - r43446
|
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