2011-04-27 11:58:34 +00:00
|
|
|
/*
|
|
|
|
* Copyright 2011, Blender Foundation.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sstream>
|
|
|
|
|
|
|
|
#include "device.h"
|
|
|
|
#include "device_intern.h"
|
|
|
|
#include "device_network.h"
|
|
|
|
|
|
|
|
#include "util_foreach.h"
|
|
|
|
#include "util_list.h"
|
|
|
|
#include "util_map.h"
|
|
|
|
#include "util_time.h"
|
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
|
|
|
class MultiDevice : public Device
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
struct SubDevice {
|
|
|
|
SubDevice(Device *device_)
|
|
|
|
: device(device_) {}
|
|
|
|
|
|
|
|
Device *device;
|
|
|
|
map<device_ptr, device_ptr> ptr_map;
|
|
|
|
};
|
|
|
|
|
|
|
|
list<SubDevice> devices;
|
|
|
|
device_ptr unique_ptr;
|
|
|
|
|
2012-01-04 18:06:32 +00:00
|
|
|
MultiDevice(DeviceInfo& info, bool background_)
|
2011-04-27 11:58:34 +00:00
|
|
|
: unique_ptr(1)
|
|
|
|
{
|
|
|
|
Device *device;
|
2012-01-04 18:06:32 +00:00
|
|
|
background = background_;
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2012-01-04 18:06:32 +00:00
|
|
|
foreach(DeviceInfo& subinfo, info.multi_devices) {
|
|
|
|
device = Device::create(subinfo, background);
|
2011-04-27 11:58:34 +00:00
|
|
|
devices.push_back(SubDevice(device));
|
|
|
|
}
|
|
|
|
|
2012-01-04 18:06:32 +00:00
|
|
|
#if 0 //def WITH_NETWORK
|
2011-04-27 11:58:34 +00:00
|
|
|
/* try to add network devices */
|
|
|
|
ServerDiscovery discovery(true);
|
|
|
|
time_sleep(1.0);
|
|
|
|
|
|
|
|
list<string> servers = discovery.get_server_list();
|
|
|
|
|
|
|
|
foreach(string& server, servers) {
|
2012-01-04 18:06:32 +00:00
|
|
|
device = device_network_create(info, server.c_str());
|
2011-04-27 11:58:34 +00:00
|
|
|
if(device)
|
|
|
|
devices.push_back(SubDevice(device));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
~MultiDevice()
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices)
|
|
|
|
delete sub.device;
|
|
|
|
}
|
|
|
|
|
2011-10-16 18:54:27 +00:00
|
|
|
bool support_full_kernel()
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
if(!sub.device->support_full_kernel())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-01-04 18:06:32 +00:00
|
|
|
const string& error_message()
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
if(sub.device->error_message() != "") {
|
|
|
|
if(error_msg == "")
|
|
|
|
error_msg = sub.device->error_message();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return error_msg;
|
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
string description()
|
|
|
|
{
|
|
|
|
/* create map to find duplicate descriptions */
|
|
|
|
map<string, int> dupli_map;
|
|
|
|
map<string, int>::iterator dt;
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
string key = sub.device->description();
|
|
|
|
|
|
|
|
if(dupli_map.find(key) == dupli_map.end())
|
|
|
|
dupli_map[key] = 1;
|
|
|
|
else
|
|
|
|
dupli_map[key]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* generate string */
|
|
|
|
stringstream desc;
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
|
|
|
|
if(!first) desc << ", ";
|
|
|
|
first = false;
|
|
|
|
|
|
|
|
if(dt->second > 1)
|
|
|
|
desc << dt->second << "x " << dt->first;
|
|
|
|
else
|
|
|
|
desc << dt->first;
|
|
|
|
}
|
|
|
|
|
|
|
|
return desc.str();
|
|
|
|
}
|
|
|
|
|
2011-12-12 22:51:35 +00:00
|
|
|
bool load_kernels(bool experimental)
|
2011-09-12 13:13:56 +00:00
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices)
|
2011-12-12 22:51:35 +00:00
|
|
|
if(!sub.device->load_kernels(experimental))
|
2011-09-12 13:13:56 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
void mem_alloc(device_memory& mem, MemoryType type)
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = 0;
|
|
|
|
sub.device->mem_alloc(mem, type);
|
|
|
|
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = unique_ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mem_copy_to(device_memory& mem)
|
|
|
|
{
|
|
|
|
device_ptr tmp = mem.device_pointer;
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = sub.ptr_map[tmp];
|
|
|
|
sub.device->mem_copy_to(mem);
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = tmp;
|
|
|
|
}
|
|
|
|
|
2012-01-09 16:58:01 +00:00
|
|
|
void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
device_ptr tmp = mem.device_pointer;
|
2012-01-09 16:58:01 +00:00
|
|
|
int i = 0, sub_h = h/devices.size();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
2012-01-09 16:58:01 +00:00
|
|
|
int sy = y + i*sub_h;
|
|
|
|
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
mem.device_pointer = sub.ptr_map[tmp];
|
2012-01-09 16:58:01 +00:00
|
|
|
sub.device->mem_copy_from(mem, sy, w, sh, elem);
|
|
|
|
i++;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mem_zero(device_memory& mem)
|
|
|
|
{
|
|
|
|
device_ptr tmp = mem.device_pointer;
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = sub.ptr_map[tmp];
|
|
|
|
sub.device->mem_zero(mem);
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mem_free(device_memory& mem)
|
|
|
|
{
|
|
|
|
device_ptr tmp = mem.device_pointer;
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = sub.ptr_map[tmp];
|
|
|
|
sub.device->mem_free(mem);
|
|
|
|
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void const_copy_to(const char *name, void *host, size_t size)
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices)
|
|
|
|
sub.device->const_copy_to(name, host, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
void tex_alloc(const char *name, device_memory& mem, bool interpolation, bool periodic)
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = 0;
|
|
|
|
sub.device->tex_alloc(name, mem, interpolation, periodic);
|
|
|
|
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = unique_ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void tex_free(device_memory& mem)
|
|
|
|
{
|
|
|
|
device_ptr tmp = mem.device_pointer;
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = sub.ptr_map[tmp];
|
|
|
|
sub.device->tex_free(mem);
|
|
|
|
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pixels_alloc(device_memory& mem)
|
|
|
|
{
|
2011-09-12 13:13:56 +00:00
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = 0;
|
|
|
|
sub.device->pixels_alloc(mem);
|
|
|
|
sub.ptr_map[unique_ptr] = mem.device_pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = unique_ptr++;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pixels_free(device_memory& mem)
|
|
|
|
{
|
2011-09-12 13:13:56 +00:00
|
|
|
device_ptr tmp = mem.device_pointer;
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
mem.device_pointer = sub.ptr_map[tmp];
|
|
|
|
sub.device->pixels_free(mem);
|
|
|
|
sub.ptr_map.erase(sub.ptr_map.find(tmp));
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = 0;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void pixels_copy_from(device_memory& mem, int y, int w, int h)
|
|
|
|
{
|
|
|
|
device_ptr tmp = mem.device_pointer;
|
|
|
|
int i = 0, sub_h = h/devices.size();
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
int sy = y + i*sub_h;
|
|
|
|
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
|
|
|
|
|
|
|
|
mem.device_pointer = sub.ptr_map[tmp];
|
|
|
|
sub.device->pixels_copy_from(mem, sy, w, sh);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem.device_pointer = tmp;
|
|
|
|
}
|
|
|
|
|
2012-01-04 18:06:32 +00:00
|
|
|
void draw_pixels(device_memory& rgba, int y, int w, int h, int dy, int width, int height, bool transparent)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
device_ptr tmp = rgba.device_pointer;
|
|
|
|
int i = 0, sub_h = h/devices.size();
|
2011-09-12 13:13:56 +00:00
|
|
|
int sub_height = height/devices.size();
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
int sy = y + i*sub_h;
|
|
|
|
int sh = (i == (int)devices.size() - 1)? h - sub_h*i: sub_h;
|
2011-09-12 13:13:56 +00:00
|
|
|
int sheight = (i == (int)devices.size() - 1)? height - sub_height*i: sub_height;
|
2012-01-04 18:06:32 +00:00
|
|
|
int sdy = dy + i*sub_height;
|
2011-04-27 11:58:34 +00:00
|
|
|
/* adjust math for w/width */
|
|
|
|
|
|
|
|
rgba.device_pointer = sub.ptr_map[tmp];
|
2012-01-04 18:06:32 +00:00
|
|
|
sub.device->draw_pixels(rgba, sy, w, sh, sdy, width, sheight, transparent);
|
2011-04-27 11:58:34 +00:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
rgba.device_pointer = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
void task_add(DeviceTask& task)
|
|
|
|
{
|
|
|
|
ThreadQueue<DeviceTask> tasks;
|
|
|
|
task.split(tasks, devices.size());
|
|
|
|
|
|
|
|
foreach(SubDevice& sub, devices) {
|
|
|
|
DeviceTask subtask;
|
|
|
|
|
|
|
|
if(tasks.worker_wait_pop(subtask)) {
|
|
|
|
if(task.buffer) subtask.buffer = sub.ptr_map[task.buffer];
|
|
|
|
if(task.rng_state) subtask.rng_state = sub.ptr_map[task.rng_state];
|
|
|
|
if(task.rgba) subtask.rgba = sub.ptr_map[task.rgba];
|
2011-12-31 15:18:13 +00:00
|
|
|
if(task.shader_input) subtask.shader_input = sub.ptr_map[task.shader_input];
|
|
|
|
if(task.shader_output) subtask.shader_output = sub.ptr_map[task.shader_output];
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
sub.device->task_add(subtask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void task_wait()
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices)
|
|
|
|
sub.device->task_wait();
|
|
|
|
}
|
|
|
|
|
|
|
|
void task_cancel()
|
|
|
|
{
|
|
|
|
foreach(SubDevice& sub, devices)
|
|
|
|
sub.device->task_cancel();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2012-01-04 18:06:32 +00:00
|
|
|
Device *device_multi_create(DeviceInfo& info, bool background)
|
|
|
|
{
|
|
|
|
return new MultiDevice(info, background);
|
|
|
|
}
|
|
|
|
|
2012-01-09 16:58:01 +00:00
|
|
|
static void device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool with_display, const char *id_fmt, int num)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
2012-01-04 18:06:32 +00:00
|
|
|
DeviceInfo info;
|
|
|
|
|
|
|
|
/* create map to find duplicate descriptions */
|
|
|
|
map<string, int> dupli_map;
|
|
|
|
map<string, int>::iterator dt;
|
2012-01-09 16:58:01 +00:00
|
|
|
int num_added = 0, num_display = 0;
|
2012-01-04 18:06:32 +00:00
|
|
|
|
|
|
|
foreach(DeviceInfo& subinfo, devices) {
|
|
|
|
if(subinfo.type == type) {
|
2012-01-09 16:58:01 +00:00
|
|
|
if(subinfo.display_device) {
|
|
|
|
if(with_display)
|
|
|
|
num_display++;
|
|
|
|
else
|
|
|
|
continue;
|
2012-01-04 18:06:32 +00:00
|
|
|
}
|
|
|
|
|
2012-01-09 16:58:01 +00:00
|
|
|
string key = subinfo.description;
|
2012-01-04 18:06:32 +00:00
|
|
|
|
2012-01-09 16:58:01 +00:00
|
|
|
if(dupli_map.find(key) == dupli_map.end())
|
|
|
|
dupli_map[key] = 1;
|
|
|
|
else
|
|
|
|
dupli_map[key]++;
|
|
|
|
|
|
|
|
info.multi_devices.push_back(subinfo);
|
|
|
|
if(subinfo.display_device)
|
|
|
|
info.display_device = true;
|
|
|
|
num_added++;
|
2012-01-04 18:06:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-09 16:58:01 +00:00
|
|
|
if(num_added <= 1 || (with_display && num_display == 0))
|
2012-01-04 18:06:32 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* generate string */
|
|
|
|
stringstream desc;
|
|
|
|
vector<string> last_tokens;
|
|
|
|
bool first = true;
|
|
|
|
|
|
|
|
for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) {
|
|
|
|
if(!first) desc << " + ";
|
|
|
|
first = false;
|
|
|
|
|
|
|
|
/* get name and count */
|
|
|
|
string name = dt->first;
|
|
|
|
int count = dt->second;
|
|
|
|
|
|
|
|
/* strip common prefixes */
|
|
|
|
vector<string> tokens;
|
|
|
|
string_split(tokens, dt->first);
|
|
|
|
|
|
|
|
if(tokens.size() > 1) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = 0; i < tokens.size() && i < last_tokens.size(); i++)
|
|
|
|
if(tokens[i] != last_tokens[i])
|
|
|
|
break;
|
|
|
|
|
|
|
|
name = "";
|
|
|
|
for(; i < tokens.size(); i++) {
|
|
|
|
name += tokens[i];
|
|
|
|
if(i != tokens.size() - 1)
|
|
|
|
name += " ";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
last_tokens = tokens;
|
|
|
|
|
|
|
|
/* add */
|
|
|
|
if(count > 1)
|
|
|
|
desc << name << " (" << count << "x)";
|
|
|
|
else
|
|
|
|
desc << name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add info */
|
|
|
|
info.type = DEVICE_MULTI;
|
|
|
|
info.description = desc.str();
|
|
|
|
info.id = string_printf(id_fmt, num);
|
2012-01-09 16:58:01 +00:00
|
|
|
info.display_device = with_display;
|
2012-01-04 18:06:32 +00:00
|
|
|
info.num = 0;
|
|
|
|
|
2012-01-09 16:58:01 +00:00
|
|
|
if(with_display)
|
|
|
|
devices.push_back(info);
|
|
|
|
else
|
|
|
|
devices.insert(devices.begin(), info);
|
2012-01-04 18:06:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void device_multi_info(vector<DeviceInfo>& devices)
|
|
|
|
{
|
|
|
|
int num = 0;
|
|
|
|
device_multi_add(devices, DEVICE_CUDA, false, "CUDA_MULTI_%d", num++);
|
2012-01-09 16:58:01 +00:00
|
|
|
device_multi_add(devices, DEVICE_CUDA, true, "CUDA_MULTI_%d", num++);
|
2012-01-04 18:06:32 +00:00
|
|
|
|
|
|
|
num = 0;
|
|
|
|
device_multi_add(devices, DEVICE_OPENCL, false, "OPENCL_MULTI_%d", num++);
|
2012-01-09 16:58:01 +00:00
|
|
|
device_multi_add(devices, DEVICE_OPENCL, true, "OPENCL_MULTI_%d", num++);
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CCL_NAMESPACE_END
|
|
|
|
|