Merge branch 'blender2.7'

This commit is contained in:
Brecht Van Lommel
2019-01-30 18:36:54 +01:00
6 changed files with 182 additions and 118 deletions

View File

@@ -363,13 +363,8 @@ static void options_parse(int argc, const char **argv)
string devicename = "CPU"; string devicename = "CPU";
bool list = false; bool list = false;
vector<DeviceType>& types = Device::available_types(); /* List devices for which support is compiled in. */
vector<DeviceType> types = Device::available_types();
/* TODO(sergey): Here's a feedback loop happens: on the one hand we want
* the device list to be printed in help message, on the other hand logging
* is not initialized yet so we wouldn't have debug log happening in the
* device initialization.
*/
foreach(DeviceType type, types) { foreach(DeviceType type, types) {
if(device_names != "") if(device_names != "")
device_names += ", "; device_names += ", ";
@@ -421,7 +416,7 @@ static void options_parse(int argc, const char **argv)
} }
if(list) { if(list) {
vector<DeviceInfo>& devices = Device::available_devices(); vector<DeviceInfo> devices = Device::available_devices();
printf("Devices:\n"); printf("Devices:\n");
foreach(DeviceInfo& info, devices) { foreach(DeviceInfo& info, devices) {
@@ -456,15 +451,12 @@ static void options_parse(int argc, const char **argv)
/* find matching device */ /* find matching device */
DeviceType device_type = Device::type_from_string(devicename.c_str()); DeviceType device_type = Device::type_from_string(devicename.c_str());
vector<DeviceInfo>& devices = Device::available_devices(); vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK(device_type));
bool device_available = false;
foreach(DeviceInfo& device, devices) { bool device_available = false;
if(device_type == device.type) { if (!devices.empty()) {
options.session_params.device = device; options.session_params.device = devices.front();
device_available = true; device_available = true;
break;
}
} }
/* handle invalid configurations */ /* handle invalid configurations */

View File

@@ -1453,7 +1453,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_devices(self): def get_devices(self):
import _cycles import _cycles
# Layout of the device tuples: (Name, Type, Persistent ID) # Layout of the device tuples: (Name, Type, Persistent ID)
device_list = _cycles.available_devices() device_list = _cycles.available_devices(self.compute_device_type)
# Make sure device entries are up to date and not referenced before # Make sure device entries are up to date and not referenced before
# we know we don't add new devices. This way we guarantee to not # we know we don't add new devices. This way we guarantee to not
# hold pointers to a resized array. # hold pointers to a resized array.
@@ -1477,7 +1477,7 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def get_num_gpu_devices(self): def get_num_gpu_devices(self):
import _cycles import _cycles
device_list = _cycles.available_devices() device_list = _cycles.available_devices(self.compute_device_type)
num = 0 num = 0
for device in device_list: for device in device_list:
if device[1] != self.compute_device_type: if device[1] != self.compute_device_type:
@@ -1490,25 +1490,32 @@ class CyclesPreferences(bpy.types.AddonPreferences):
def has_active_device(self): def has_active_device(self):
return self.get_num_gpu_devices() > 0 return self.get_num_gpu_devices() > 0
def draw_impl(self, layout, context): def _draw_devices(self, layout, device_type, devices):
available_device_types = self.get_device_types(context) box = layout.box()
if len(available_device_types) == 1:
layout.label(text="No compatible GPUs found", icon='INFO') found_device = False
for device in devices:
if device.type == device_type:
found_device = True
break
if not found_device:
box.label(text="No compatible GPUs found", icon='INFO')
return return
layout.row().prop(self, "compute_device_type", expand=True)
for device in devices:
box.prop(device, "use", text=device.name)
def draw_impl(self, layout, context):
row = layout.row()
row.prop(self, "compute_device_type", expand=True)
cuda_devices, opencl_devices = self.get_devices() cuda_devices, opencl_devices = self.get_devices()
row = layout.row() row = layout.row()
if self.compute_device_type == 'CUDA':
if self.compute_device_type == 'CUDA' and cuda_devices: self._draw_devices(row, 'CUDA', cuda_devices)
box = row.box() elif self.compute_device_type == 'OPENCL':
for device in cuda_devices: self._draw_devices(row, 'OPENCL', opencl_devices)
box.prop(device, "use", text=device.name)
if self.compute_device_type == 'OPENCL' and opencl_devices:
box = row.box()
for device in opencl_devices:
box.prop(device, "use", text=device.name)
def draw(self, context): def draw(self, context):
self.draw_impl(self.layout, context) self.draw_impl(self.layout, context)

View File

@@ -388,9 +388,18 @@ static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject *available_devices_func(PyObject * /*self*/, PyObject * /*args*/) static PyObject *available_devices_func(PyObject * /*self*/, PyObject * args)
{ {
vector<DeviceInfo>& devices = Device::available_devices(); const char *type_name;
if(!PyArg_ParseTuple(args, "s", &type_name)) {
return NULL;
}
DeviceType type = Device::type_from_string(type_name);
uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type);
mask |= DEVICE_MASK_CPU;
vector<DeviceInfo> devices = Device::available_devices(mask);
PyObject *ret = PyTuple_New(devices.size()); PyObject *ret = PyTuple_New(devices.size());
for(size_t i = 0; i < devices.size(); i++) { for(size_t i = 0; i < devices.size(); i++) {
@@ -746,11 +755,11 @@ static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*
static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/) static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
{ {
vector<DeviceInfo>& devices = Device::available_devices(); vector<DeviceType> device_types = Device::available_types();
bool has_cuda = false, has_opencl = false; bool has_cuda = false, has_opencl = false;
for(int i = 0; i < devices.size(); i++) { foreach(DeviceType device_type, device_types) {
has_cuda |= (devices[i].type == DEVICE_CUDA); has_cuda |= (device_type == DEVICE_CUDA);
has_opencl |= (devices[i].type == DEVICE_OPENCL); has_opencl |= (device_type == DEVICE_OPENCL);
} }
PyObject *list = PyTuple_New(2); PyObject *list = PyTuple_New(2);
PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda)); PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
@@ -772,7 +781,7 @@ static PyMethodDef methods[] = {
{"osl_update_node", osl_update_node_func, METH_VARARGS, ""}, {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
{"osl_compile", osl_compile_func, METH_VARARGS, ""}, {"osl_compile", osl_compile_func, METH_VARARGS, ""},
#endif #endif
{"available_devices", available_devices_func, METH_NOARGS, ""}, {"available_devices", available_devices_func, METH_VARARGS, ""},
{"system_info", system_info_func, METH_NOARGS, ""}, {"system_info", system_info_func, METH_NOARGS, ""},
#ifdef WITH_OPENCL #ifdef WITH_OPENCL
{"opencl_disable", opencl_disable_func, METH_NOARGS, ""}, {"opencl_disable", opencl_disable_func, METH_NOARGS, ""},

View File

@@ -741,24 +741,18 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
/* Background */ /* Background */
params.background = background; params.background = background;
/* device type */ /* Default to CPU device. */
vector<DeviceInfo>& devices = Device::available_devices(); params.device = Device::available_devices(DEVICE_MASK_CPU).front();
/* device default CPU */
foreach(DeviceInfo& device, devices) {
if(device.type == DEVICE_CPU) {
params.device = device;
break;
}
}
if(get_enum(cscene, "device") == 2) { if(get_enum(cscene, "device") == 2) {
/* find network device */ /* Find network device. */
foreach(DeviceInfo& info, devices) vector<DeviceInfo> devices = Device::available_devices(DEVICE_MASK_NETWORK);
if(info.type == DEVICE_NETWORK) if(!devices.empty()) {
params.device = info; params.device = devices.front();
}
} }
else if(get_enum(cscene, "device") == 1) { else if(get_enum(cscene, "device") == 1) {
/* Find cycles preferences. */
PointerRNA b_preferences; PointerRNA b_preferences;
BL::Preferences::addons_iterator b_addon_iter; BL::Preferences::addons_iterator b_addon_iter;
@@ -769,6 +763,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
} }
} }
/* Test if we are using GPU devices. */
enum ComputeDevice { enum ComputeDevice {
COMPUTE_DEVICE_CPU = 0, COMPUTE_DEVICE_CPU = 0,
COMPUTE_DEVICE_CUDA = 1, COMPUTE_DEVICE_CUDA = 1,
@@ -782,15 +777,20 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
COMPUTE_DEVICE_CPU); COMPUTE_DEVICE_CPU);
if(compute_device != COMPUTE_DEVICE_CPU) { if(compute_device != COMPUTE_DEVICE_CPU) {
/* Query GPU devices with matching types. */
uint mask = DEVICE_MASK_CPU;
if(compute_device == COMPUTE_DEVICE_CUDA) {
mask |= DEVICE_MASK_CUDA;
}
else if(compute_device == COMPUTE_DEVICE_OPENCL) {
mask |= DEVICE_MASK_OPENCL;
}
vector<DeviceInfo> devices = Device::available_devices(mask);
/* Match device preferences and available devices. */
vector<DeviceInfo> used_devices; vector<DeviceInfo> used_devices;
RNA_BEGIN(&b_preferences, device, "devices") { RNA_BEGIN(&b_preferences, device, "devices") {
ComputeDevice device_type = (ComputeDevice)get_enum(device, if(get_boolean(device, "use")) {
"type",
COMPUTE_DEVICE_NUM,
COMPUTE_DEVICE_CPU);
if(get_boolean(device, "use") &&
(device_type == compute_device || device_type == COMPUTE_DEVICE_CPU)) {
string id = get_string(device, "id"); string id = get_string(device, "id");
foreach(DeviceInfo& info, devices) { foreach(DeviceInfo& info, devices) {
if(info.id == id) { if(info.id == id) {
@@ -801,10 +801,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine,
} }
} RNA_END; } RNA_END;
if(used_devices.size() == 1) { if(!used_devices.empty()) {
params.device = used_devices[0];
}
else if(used_devices.size() > 1) {
params.device = Device::get_multi_device(used_devices, params.device = Device::get_multi_device(used_devices,
params.threads, params.threads,
params.background); params.background);

View File

@@ -36,8 +36,11 @@ CCL_NAMESPACE_BEGIN
bool Device::need_types_update = true; bool Device::need_types_update = true;
bool Device::need_devices_update = true; bool Device::need_devices_update = true;
thread_mutex Device::device_mutex; thread_mutex Device::device_mutex;
vector<DeviceType> Device::types; vector<DeviceInfo> Device::opencl_devices;
vector<DeviceInfo> Device::devices; vector<DeviceInfo> Device::cuda_devices;
vector<DeviceInfo> Device::cpu_devices;
vector<DeviceInfo> Device::network_devices;
uint Device::devices_initialized_mask = 0;
/* Device Requested Features */ /* Device Requested Features */
@@ -423,70 +426,108 @@ string Device::string_from_type(DeviceType type)
return ""; return "";
} }
vector<DeviceType>& Device::available_types() vector<DeviceType> Device::available_types()
{ {
thread_scoped_lock lock(device_mutex); vector<DeviceType> types;
if(need_types_update) { types.push_back(DEVICE_CPU);
types.clear();
types.push_back(DEVICE_CPU);
#ifdef WITH_CUDA #ifdef WITH_CUDA
if(device_cuda_init()) { types.push_back(DEVICE_CUDA);
types.push_back(DEVICE_CUDA);
}
#endif #endif
#ifdef WITH_OPENCL #ifdef WITH_OPENCL
if(device_opencl_init()) { types.push_back(DEVICE_OPENCL);
types.push_back(DEVICE_OPENCL);
}
#endif #endif
#ifdef WITH_NETWORK #ifdef WITH_NETWORK
types.push_back(DEVICE_NETWORK); types.push_back(DEVICE_NETWORK);
#endif #endif
need_types_update = false;
}
return types; return types;
} }
vector<DeviceInfo>& Device::available_devices() vector<DeviceInfo> Device::available_devices(uint mask)
{ {
/* Lazy initialize devices. On some platforms OpenCL or CUDA drivers can
* be broken and cause crashes when only trying to get device info, so
* we don't want to do any initialization until the user chooses to. */
thread_scoped_lock lock(device_mutex); thread_scoped_lock lock(device_mutex);
if(need_devices_update) { vector<DeviceInfo> devices;
devices.clear();
#ifdef WITH_OPENCL #ifdef WITH_OPENCL
if(device_opencl_init()) { if(mask & DEVICE_MASK_OPENCL) {
device_opencl_info(devices); if(!(devices_initialized_mask & DEVICE_MASK_OPENCL)) {
if(device_opencl_init()) {
device_opencl_info(opencl_devices);
}
devices_initialized_mask |= DEVICE_MASK_OPENCL;
} }
#endif foreach(DeviceInfo& info, opencl_devices) {
#ifdef WITH_CUDA devices.push_back(info);
if(device_cuda_init()) {
device_cuda_info(devices);
} }
#endif
device_cpu_info(devices);
#ifdef WITH_NETWORK
device_network_info(devices);
#endif
need_devices_update = false;
} }
#endif
#ifdef WITH_CUDA
if(mask & DEVICE_MASK_CUDA) {
if(!(devices_initialized_mask & DEVICE_MASK_CUDA)) {
if(device_cuda_init()) {
device_cuda_info(cuda_devices);
}
devices_initialized_mask |= DEVICE_MASK_CUDA;
}
foreach(DeviceInfo& info, cuda_devices) {
devices.push_back(info);
}
}
#endif
if(mask & DEVICE_MASK_CPU) {
if(!(devices_initialized_mask & DEVICE_MASK_CPU)) {
device_cpu_info(cpu_devices);
devices_initialized_mask |= DEVICE_MASK_CPU;
}
foreach(DeviceInfo& info, cpu_devices) {
devices.push_back(info);
}
}
#ifdef WITH_NETWORK
if(mask & DEVICE_MASK_NETWORK) {
if(!(devices_initialized_mask & DEVICE_MASK_NETWORK)) {
device_network_info(network_devices);
devices_initialized_mask |= DEVICE_MASK_NETWORK;
}
foreach(DeviceInfo& info, network_devices) {
devices.push_back(info);
}
}
#endif
return devices; return devices;
} }
string Device::device_capabilities() string Device::device_capabilities(uint mask)
{ {
string capabilities = "CPU device capabilities: "; thread_scoped_lock lock(device_mutex);
capabilities += device_cpu_capabilities() + "\n"; string capabilities = "";
if(mask & DEVICE_MASK_CPU) {
capabilities += "\nCPU device capabilities: ";
capabilities += device_cpu_capabilities() + "\n";
}
#ifdef WITH_OPENCL #ifdef WITH_OPENCL
if(device_opencl_init()) { if(mask & DEVICE_MASK_OPENCL) {
capabilities += "\nOpenCL device capabilities:\n"; if(device_opencl_init()) {
capabilities += device_opencl_capabilities(); capabilities += "\nOpenCL device capabilities:\n";
capabilities += device_opencl_capabilities();
}
} }
#endif #endif
#ifdef WITH_CUDA #ifdef WITH_CUDA
if(device_cuda_init()) { if(mask & DEVICE_MASK_CUDA) {
capabilities += "\nCUDA device capabilities:\n"; if(device_cuda_init()) {
capabilities += device_cuda_capabilities(); capabilities += "\nCUDA device capabilities:\n";
capabilities += device_cuda_capabilities();
}
} }
#endif #endif
@@ -495,7 +536,12 @@ string Device::device_capabilities()
DeviceInfo Device::get_multi_device(const vector<DeviceInfo>& subdevices, int threads, bool background) DeviceInfo Device::get_multi_device(const vector<DeviceInfo>& subdevices, int threads, bool background)
{ {
assert(subdevices.size() > 1); assert(subdevices.size() > 0);
if(subdevices.size() == 1) {
/* No multi device needed. */
return subdevices.front();
}
DeviceInfo info; DeviceInfo info;
info.type = DEVICE_MULTI; info.type = DEVICE_MULTI;
@@ -549,16 +595,16 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo>& subdevices, int th
void Device::tag_update() void Device::tag_update()
{ {
need_types_update = true; free_memory();
need_devices_update = true;
} }
void Device::free_memory() void Device::free_memory()
{ {
need_types_update = true; devices_initialized_mask = 0;
need_devices_update = true; cuda_devices.clear();
types.free_memory(); opencl_devices.clear();
devices.free_memory(); cpu_devices.clear();
network_devices.clear();
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

View File

@@ -40,7 +40,7 @@ class RenderTile;
/* Device Types */ /* Device Types */
enum DeviceType { enum DeviceType {
DEVICE_NONE, DEVICE_NONE = 0,
DEVICE_CPU, DEVICE_CPU,
DEVICE_OPENCL, DEVICE_OPENCL,
DEVICE_CUDA, DEVICE_CUDA,
@@ -48,6 +48,16 @@ enum DeviceType {
DEVICE_MULTI DEVICE_MULTI
}; };
enum DeviceTypeMask {
DEVICE_MASK_CPU = (1 << DEVICE_CPU),
DEVICE_MASK_OPENCL = (1 << DEVICE_OPENCL),
DEVICE_MASK_CUDA = (1 << DEVICE_CUDA),
DEVICE_MASK_NETWORK = (1 << DEVICE_NETWORK),
DEVICE_MASK_ALL = ~0
};
#define DEVICE_MASK(type) (DeviceTypeMask)(1 << type)
class DeviceInfo { class DeviceInfo {
public: public:
DeviceType type; DeviceType type;
@@ -342,9 +352,9 @@ public:
static DeviceType type_from_string(const char *name); static DeviceType type_from_string(const char *name);
static string string_from_type(DeviceType type); static string string_from_type(DeviceType type);
static vector<DeviceType>& available_types(); static vector<DeviceType> available_types();
static vector<DeviceInfo>& available_devices(); static vector<DeviceInfo> available_devices(uint device_type_mask = DEVICE_MASK_ALL);
static string device_capabilities(); static string device_capabilities(uint device_type_mask = DEVICE_MASK_ALL);
static DeviceInfo get_multi_device(const vector<DeviceInfo>& subdevices, static DeviceInfo get_multi_device(const vector<DeviceInfo>& subdevices,
int threads, int threads,
bool background); bool background);
@@ -371,8 +381,11 @@ private:
/* Indicted whether device types and devices lists were initialized. */ /* Indicted whether device types and devices lists were initialized. */
static bool need_types_update, need_devices_update; static bool need_types_update, need_devices_update;
static thread_mutex device_mutex; static thread_mutex device_mutex;
static vector<DeviceType> types; static vector<DeviceInfo> cuda_devices;
static vector<DeviceInfo> devices; static vector<DeviceInfo> opencl_devices;
static vector<DeviceInfo> cpu_devices;
static vector<DeviceInfo> network_devices;
static uint devices_initialized_mask;
}; };
CCL_NAMESPACE_END CCL_NAMESPACE_END