Cycles: multi GPU rendering support.

The rendering device is now set in User Preferences > System, where you can
choose between OpenCL/CUDA and devices. Per scene you can then still choose
to use CPU or GPU rendering.

Load balancing still needs to be improved, now it just splits the entire
render in two, that will be done in a separate commit.
This commit is contained in:
Brecht Van Lommel 2012-01-09 16:58:01 +00:00
parent 47d9c6689b
commit d7932ceea8
30 changed files with 360 additions and 147 deletions

@ -0,0 +1,46 @@
/*
* 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.
*/
#ifndef CCL_API_H
#define CCL_API_H
#ifdef __cplusplus
extern "C" {
#endif
/* returns a list of devices for selection, array is name NULL pointer
* terminated and must not be freed */
typedef struct CCLDeviceInfo {
const char *identifier;
const char *name;
int value;
} CCLDeviceInfo;
CCLDeviceInfo *CCL_compute_device_list(int opencl);
/* create python module _cycles used by addon */
void *CCL_python_module_init(void);
#ifdef __cplusplus
}
#endif
#endif /* CCL_API_H */

@ -27,6 +27,7 @@ set(SRC
blender_shader.cpp blender_shader.cpp
blender_sync.cpp blender_sync.cpp
CCL_api.h
blender_sync.h blender_sync.h
blender_session.h blender_session.h
blender_util.h blender_util.h

@ -35,6 +35,7 @@ def create(engine, data, scene, region=0, v3d=0, rv3d=0):
import _cycles import _cycles
data = data.as_pointer() data = data.as_pointer()
userpref = bpy.context.user_preferences.as_pointer()
scene = scene.as_pointer() scene = scene.as_pointer()
if region: if region:
region = region.as_pointer() region = region.as_pointer()
@ -43,7 +44,7 @@ def create(engine, data, scene, region=0, v3d=0, rv3d=0):
if rv3d: if rv3d:
rv3d = rv3d.as_pointer() rv3d = rv3d.as_pointer()
engine.session = _cycles.create(engine.as_pointer(), data, scene, region, v3d, rv3d) engine.session = _cycles.create(engine.as_pointer(), userpref, data, scene, region, v3d, rv3d)
def free(engine): def free(engine):

@ -20,29 +20,9 @@
from . import engine from . import engine
def get_gpu_device():
available_devices = engine.available_devices()
cuda = 'cuda' in available_devices
opencl = 'opencl' in available_devices
if cuda and opencl:
gpu_string = "GPU"
elif cuda and not opencl:
gpu_string = "CUDA GPU"
else:
gpu_string = "OpenCL GPU"
return gpu_string
devices = ( devices = (
("CPU", "CPU", "Processor"), ("CPU", "CPU", "Use CPU for rendering"),
("GPU", get_gpu_device(), "Graphics card"), ("GPU", "GPU Compute", "Use GPU compute device for rendering, configured in user preferences"))
)
gpu_type = (
("CUDA", "CUDA", "NVidia only"),
("OPENCL", "OpenCL", ""),
)
feature_set = ( feature_set = (
("SUPPORTED", "Supported", "Only use finished and supported features"), ("SUPPORTED", "Supported", "Only use finished and supported features"),

@ -38,9 +38,6 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
cls.device = EnumProperty(name="Device", description="Device to use for rendering", cls.device = EnumProperty(name="Device", description="Device to use for rendering",
items=enums.devices, default="CPU") items=enums.devices, default="CPU")
cls.gpu_type = EnumProperty(name="GPU Type", description="Processing system to use on the GPU",
items=enums.gpu_type, default="CUDA")
cls.feature_set = EnumProperty(name="Feature Set", description="Feature set to use for rendering", cls.feature_set = EnumProperty(name="Feature Set", description="Feature set to use for rendering",
items=enums.feature_set, default="SUPPORTED") items=enums.feature_set, default="SUPPORTED")

@ -148,7 +148,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel):
sub.prop(cscene, "debug_bvh_type", text="") sub.prop(cscene, "debug_bvh_type", text="")
sub.prop(cscene, "debug_use_spatial_splits") sub.prop(cscene, "debug_use_spatial_splits")
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel): class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
bl_label = "Layers" bl_label = "Layers"
bl_options = {'DEFAULT_CLOSED'} bl_options = {'DEFAULT_CLOSED'}
@ -712,19 +711,12 @@ def draw_device(self, context):
cscene = scene.cycles cscene = scene.cycles
layout.prop(cscene, "feature_set") layout.prop(cscene, "feature_set")
experimental = cscene.feature_set == 'EXPERIMENTAL'
available_devices = engine.available_devices() device_type = context.user_preferences.system.compute_device_type
available_cuda = 'cuda' in available_devices if device_type == 'CUDA':
available_opencl = experimental and 'opencl' in available_devices layout.prop(cscene, "device")
elif device_type == 'OPENCL' and cscene.feature_set == 'EXPERIMENTAL':
if available_cuda or available_opencl:
layout.prop(cscene, "device") layout.prop(cscene, "device")
if cscene.device == 'GPU' and available_cuda and available_opencl:
layout.prop(cscene, "gpu_type")
if experimental and cscene.device == 'CPU' and engine.with_osl():
layout.prop(cscene, "shading_system")
def draw_pause(self, context): def draw_pause(self, context):
layout = self.layout layout = self.layout

@ -18,9 +18,12 @@
#include <Python.h> #include <Python.h>
#include "CCL_api.h"
#include "blender_sync.h" #include "blender_sync.h"
#include "blender_session.h" #include "blender_session.h"
#include "util_foreach.h"
#include "util_opengl.h" #include "util_opengl.h"
#include "util_path.h" #include "util_path.h"
@ -40,9 +43,9 @@ static PyObject *init_func(PyObject *self, PyObject *args)
static PyObject *create_func(PyObject *self, PyObject *args) static PyObject *create_func(PyObject *self, PyObject *args)
{ {
PyObject *pyengine, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d; PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
if(!PyArg_ParseTuple(args, "OOOOOO", &pyengine, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d)) if(!PyArg_ParseTuple(args, "OOOOOOO", &pyengine, &pyuserpref, &pydata, &pyscene, &pyregion, &pyv3d, &pyrv3d))
return NULL; return NULL;
/* RNA */ /* RNA */
@ -50,6 +53,10 @@ static PyObject *create_func(PyObject *self, PyObject *args)
RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr); RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
BL::RenderEngine engine(engineptr); BL::RenderEngine engine(engineptr);
PointerRNA userprefptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyuserpref), &userprefptr);
BL::UserPreferences userpref(userprefptr);
PointerRNA dataptr; PointerRNA dataptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr); RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr);
BL::BlendData data(dataptr); BL::BlendData data(dataptr);
@ -78,11 +85,11 @@ static PyObject *create_func(PyObject *self, PyObject *args)
int width = region.width(); int width = region.width();
int height = region.height(); int height = region.height();
session = new BlenderSession(engine, data, scene, v3d, rv3d, width, height); session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height);
} }
else { else {
/* offline session */ /* offline session */
session = new BlenderSession(engine, data, scene); session = new BlenderSession(engine, userpref, data, scene);
} }
return PyLong_FromVoidPtr(session); return PyLong_FromVoidPtr(session);
@ -137,13 +144,12 @@ static PyObject *sync_func(PyObject *self, PyObject *value)
static PyObject *available_devices_func(PyObject *self, PyObject *args) static PyObject *available_devices_func(PyObject *self, PyObject *args)
{ {
vector<DeviceType> types = Device::available_types(); vector<DeviceInfo>& devices = Device::available_devices();
PyObject *ret = PyTuple_New(devices.size());
PyObject *ret = PyTuple_New(types.size()); for(size_t i = 0; i < devices.size(); i++) {
DeviceInfo& device = devices[i];
for(size_t i = 0; i < types.size(); i++) { PyTuple_SET_ITEM(ret, i, PyUnicode_FromString(device.description.c_str()));
string name = Device::string_from_type(types[i]);
PyTuple_SET_ITEM(ret, i, PyUnicode_FromString(name.c_str()));
} }
return ret; return ret;
@ -169,11 +175,44 @@ static struct PyModuleDef module = {
NULL, NULL, NULL, NULL NULL, NULL, NULL, NULL
}; };
CCLDeviceInfo *compute_device_list(DeviceType type)
{
/* device list stored static */
static ccl::vector<CCLDeviceInfo> device_list;
static ccl::DeviceType device_type = DEVICE_NONE;
/* create device list if it's not already done */
if(type != device_type) {
ccl::vector<DeviceInfo>& devices = ccl::Device::available_devices();
device_type = type;
device_list.clear();
/* add devices */
int i = 0;
foreach(DeviceInfo& info, devices) {
if(info.type == type ||
(info.type == DEVICE_MULTI && info.multi_devices[0].type == type)) {
CCLDeviceInfo cinfo = {info.id.c_str(), info.description.c_str(), i++};
device_list.push_back(cinfo);
}
}
/* null terminate */
if(!device_list.empty()) {
CCLDeviceInfo cinfo = {NULL, NULL, 0};
device_list.push_back(cinfo);
}
}
return (device_list.empty())? NULL: &device_list[0];
}
CCL_NAMESPACE_END CCL_NAMESPACE_END
extern "C" PyObject *CYCLES_initPython(); void *CCL_python_module_init()
PyObject *CYCLES_initPython()
{ {
PyObject *mod= PyModule_Create(&ccl::module); PyObject *mod= PyModule_Create(&ccl::module);
@ -185,6 +224,12 @@ PyObject *CYCLES_initPython()
Py_INCREF(Py_False); Py_INCREF(Py_False);
#endif #endif
return mod; return (void*)mod;
}
CCLDeviceInfo *CCL_compute_device_list(int opencl)
{
ccl::DeviceType type = (opencl)? ccl::DEVICE_OPENCL: ccl::DEVICE_CUDA;
return ccl::compute_device_list(type);
} }

@ -39,8 +39,10 @@
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_) BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL), BL::BlendData b_data_, BL::Scene b_scene_)
: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL),
b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL) b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
{ {
/* offline render */ /* offline render */
@ -54,10 +56,11 @@ BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_
create_session(); create_session();
} }
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_, BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
BL::BlendData b_data_, BL::Scene b_scene_,
BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_) BL::SpaceView3D b_v3d_, BL::RegionView3D b_rv3d_, int width_, int height_)
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(b_v3d_), b_rv3d(b_rv3d_), : b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL) b_v3d(b_v3d_), b_rv3d(b_rv3d_), b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
{ {
/* 3d view render */ /* 3d view render */
width = width_; width = width_;
@ -77,7 +80,7 @@ BlenderSession::~BlenderSession()
void BlenderSession::create_session() void BlenderSession::create_session()
{ {
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
SessionParams session_params = BlenderSync::get_session_params(b_scene, background); SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
/* reset status/progress */ /* reset status/progress */
last_status= ""; last_status= "";
@ -184,7 +187,7 @@ void BlenderSession::synchronize()
{ {
/* on session/scene parameter changes, we recreate session entirely */ /* on session/scene parameter changes, we recreate session entirely */
SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background); SceneParams scene_params = BlenderSync::get_scene_params(b_scene, background);
SessionParams session_params = BlenderSync::get_session_params(b_scene, background); SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
if(session->params.modified(session_params) || if(session->params.modified(session_params) ||
scene->params.modified(scene_params)) { scene->params.modified(scene_params)) {
@ -258,7 +261,7 @@ bool BlenderSession::draw(int w, int h)
/* reset if requested */ /* reset if requested */
if(reset) { if(reset) {
SessionParams session_params = BlenderSync::get_session_params(b_scene, background); SessionParams session_params = BlenderSync::get_session_params(b_userpref, b_scene, background);
BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_rv3d, width, height); BufferParams buffer_params = BlenderSync::get_buffer_params(b_scene, b_rv3d, width, height);
session->reset(buffer_params, session_params.samples); session->reset(buffer_params, session_params.samples);

@ -32,8 +32,10 @@ class Session;
class BlenderSession { class BlenderSession {
public: public:
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene); BlenderSession(BL::RenderEngine b_engine, BL::UserPreferences b_userpref,
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene, BL::BlendData b_data, BL::Scene b_scene);
BlenderSession(BL::RenderEngine b_engine, BL::UserPreferences b_userpref,
BL::BlendData b_data, BL::Scene b_scene,
BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height); BL::SpaceView3D b_v3d, BL::RegionView3D b_rv3d, int width, int height);
~BlenderSession(); ~BlenderSession();
@ -65,6 +67,7 @@ public:
double last_redraw_time; double last_redraw_time;
BL::RenderEngine b_engine; BL::RenderEngine b_engine;
BL::UserPreferences b_userpref;
BL::BlendData b_data; BL::BlendData b_data;
BL::Scene b_scene; BL::Scene b_scene;
BL::SpaceView3D b_v3d; BL::SpaceView3D b_v3d;

@ -248,16 +248,7 @@ bool BlenderSync::get_session_pause(BL::Scene b_scene, bool background)
return (background)? false: get_boolean(cscene, "preview_pause"); return (background)? false: get_boolean(cscene, "preview_pause");
} }
static bool device_type_available(vector<DeviceInfo>& devices, DeviceType dtype) SessionParams BlenderSync::get_session_params(BL::UserPreferences b_userpref, BL::Scene b_scene, bool background)
{
foreach(DeviceInfo& info, devices)
if(info.type == dtype)
return true;
return false;
}
SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
{ {
SessionParams params; SessionParams params;
PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
@ -266,29 +257,26 @@ SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background
params.experimental = (RNA_enum_get(&cscene, "feature_set") != 0); params.experimental = (RNA_enum_get(&cscene, "feature_set") != 0);
/* device type */ /* device type */
vector<DeviceInfo> devices = Device::available_devices(); vector<DeviceInfo>& devices = Device::available_devices();
DeviceType device_type = DEVICE_CPU;
/* device default CPU */
params.device = devices[0];
if(RNA_enum_get(&cscene, "device") != 0) { if(RNA_enum_get(&cscene, "device") != 0) {
/* find GPU device with given id */
if(!params.experimental || RNA_enum_get(&cscene, "gpu_type") == 0) PointerRNA systemptr = b_userpref.system().ptr;
device_type = DEVICE_CUDA; PropertyRNA *deviceprop = RNA_struct_find_property(&systemptr, "compute_device");
else int device_id = b_userpref.system().compute_device();
device_type = DEVICE_OPENCL;
if(device_type_available(devices, device_type)) const char *id;
;
else if(params.experimental && device_type_available(devices, DEVICE_OPENCL)) if(RNA_property_enum_identifier(NULL, &systemptr, deviceprop, device_id, &id)) {
device_type = DEVICE_OPENCL; foreach(DeviceInfo& info, devices)
else if(device_type_available(devices, DEVICE_CUDA)) if(info.id == id)
device_type = DEVICE_CUDA; params.device = info;
}
} }
params.device = devices[0];
foreach(DeviceInfo& info, devices)
if(info.type == device_type)
params.device = info;
/* Background */ /* Background */
params.background = background; params.background = background;
@ -316,6 +304,10 @@ SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background
} }
else else
params.progressive = true; params.progressive = true;
/* todo: multi device only works with single tiles now */
if(params.device.type == DEVICE_MULTI)
params.tile_size = INT_MAX;
return params; return params;
} }

@ -60,7 +60,7 @@ public:
/* get parameters */ /* get parameters */
static SceneParams get_scene_params(BL::Scene b_scene, bool background); static SceneParams get_scene_params(BL::Scene b_scene, bool background);
static SessionParams get_session_params(BL::Scene b_scene, bool background); static SessionParams get_session_params(BL::UserPreferences b_userpref, BL::Scene b_scene, bool background);
static bool get_session_pause(BL::Scene b_scene, bool background); static bool get_session_pause(BL::Scene b_scene, bool background);
static BufferParams get_buffer_params(BL::Scene b_scene, BL::RegionView3D b_rv3d, int width, int height); static BufferParams get_buffer_params(BL::Scene b_scene, BL::RegionView3D b_rv3d, int width, int height);

@ -110,7 +110,7 @@ void Device::pixels_alloc(device_memory& mem)
void Device::pixels_copy_from(device_memory& mem, int y, int w, int h) void Device::pixels_copy_from(device_memory& mem, int y, int w, int h)
{ {
mem_copy_from(mem, sizeof(uint8_t)*4*y*w, sizeof(uint8_t)*4*w*h); mem_copy_from(mem, y, w, h, sizeof(uint8_t)*4);
} }
void Device::pixels_free(device_memory& mem) void Device::pixels_free(device_memory& mem)

@ -111,7 +111,7 @@ public:
virtual void mem_alloc(device_memory& mem, MemoryType type) = 0; virtual void mem_alloc(device_memory& mem, MemoryType type) = 0;
virtual void mem_copy_to(device_memory& mem) = 0; virtual void mem_copy_to(device_memory& mem) = 0;
virtual void mem_copy_from(device_memory& mem, virtual void mem_copy_from(device_memory& mem,
size_t offset, size_t size) = 0; int y, int w, int h, int elem) = 0;
virtual void mem_zero(device_memory& mem) = 0; virtual void mem_zero(device_memory& mem) = 0;
virtual void mem_free(device_memory& mem) = 0; virtual void mem_free(device_memory& mem) = 0;

@ -92,7 +92,7 @@ public:
/* no-op */ /* no-op */
} }
void mem_copy_from(device_memory& mem, size_t offset, size_t size) void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
{ {
/* no-op */ /* no-op */
} }

@ -341,9 +341,11 @@ public:
cuda_pop_context(); cuda_pop_context();
} }
void mem_copy_from(device_memory& mem, size_t offset, size_t size) void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
{ {
/* todo: offset is ignored */ size_t offset = elem*y*w;
size_t size = elem*w*h;
cuda_push_context(); cuda_push_context();
cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset, cuda_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
(CUdeviceptr)((uchar*)mem.device_pointer + offset), size)) (CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
@ -863,6 +865,8 @@ void device_cuda_info(vector<DeviceInfo>& devices)
if(cuDeviceGetCount(&count) != CUDA_SUCCESS) if(cuDeviceGetCount(&count) != CUDA_SUCCESS)
return; return;
vector<DeviceInfo> display_devices;
for(int num = 0; num < count; num++) { for(int num = 0; num < count; num++) {
char name[256]; char name[256];
int attr; int attr;
@ -878,11 +882,16 @@ void device_cuda_info(vector<DeviceInfo>& devices)
info.num = num; info.num = num;
/* if device has a kernel timeout, assume it is used for display */ /* if device has a kernel timeout, assume it is used for display */
if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) {
info.display_device = true; info.display_device = true;
display_devices.push_back(info);
devices.push_back(info); }
else
devices.push_back(info);
} }
if(!display_devices.empty())
devices.insert(devices.end(), display_devices.begin(), display_devices.end());
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

@ -163,15 +163,18 @@ public:
mem.device_pointer = tmp; mem.device_pointer = tmp;
} }
void mem_copy_from(device_memory& mem, size_t offset, size_t size) void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
{ {
device_ptr tmp = mem.device_pointer; device_ptr tmp = mem.device_pointer;
int i = 0, sub_h = h/devices.size();
/* todo: how does this work? */
foreach(SubDevice& sub, devices) { 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]; mem.device_pointer = sub.ptr_map[tmp];
sub.device->mem_copy_from(mem, offset, size); sub.device->mem_copy_from(mem, sy, w, sh, elem);
break; i++;
} }
mem.device_pointer = tmp; mem.device_pointer = tmp;
@ -332,37 +335,39 @@ Device *device_multi_create(DeviceInfo& info, bool background)
return new MultiDevice(info, background); return new MultiDevice(info, background);
} }
static void device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool skip_display, const char *id_fmt, int num) static void device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool with_display, const char *id_fmt, int num)
{ {
DeviceInfo info; DeviceInfo info;
/* create map to find duplicate descriptions */ /* create map to find duplicate descriptions */
map<string, int> dupli_map; map<string, int> dupli_map;
map<string, int>::iterator dt; map<string, int>::iterator dt;
int num_added = 0, num_skipped = 0; int num_added = 0, num_display = 0;
foreach(DeviceInfo& subinfo, devices) { foreach(DeviceInfo& subinfo, devices) {
if(subinfo.type == type) { if(subinfo.type == type) {
if(skip_display && subinfo.display_device) { if(subinfo.display_device) {
num_skipped++; if(with_display)
} num_display++;
else {
string key = subinfo.description;
if(dupli_map.find(key) == dupli_map.end())
dupli_map[key] = 1;
else else
dupli_map[key]++; continue;
info.multi_devices.push_back(subinfo);
if(subinfo.display_device)
info.display_device = true;
num_added++;
} }
string key = subinfo.description;
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++;
} }
} }
if(num_added <= 1 || (skip_display && num_skipped == 0)) if(num_added <= 1 || (with_display && num_display == 0))
return; return;
/* generate string */ /* generate string */
@ -410,20 +415,24 @@ static void device_multi_add(vector<DeviceInfo>& devices, DeviceType type, bool
info.type = DEVICE_MULTI; info.type = DEVICE_MULTI;
info.description = desc.str(); info.description = desc.str();
info.id = string_printf(id_fmt, num); info.id = string_printf(id_fmt, num);
info.display_device = with_display;
info.num = 0; info.num = 0;
devices.push_back(info); if(with_display)
devices.push_back(info);
else
devices.insert(devices.begin(), info);
} }
void device_multi_info(vector<DeviceInfo>& devices) void device_multi_info(vector<DeviceInfo>& devices)
{ {
int num = 0; int num = 0;
device_multi_add(devices, DEVICE_CUDA, true, "CUDA_MULTI_%d", num++);
device_multi_add(devices, DEVICE_CUDA, false, "CUDA_MULTI_%d", num++); device_multi_add(devices, DEVICE_CUDA, false, "CUDA_MULTI_%d", num++);
device_multi_add(devices, DEVICE_CUDA, true, "CUDA_MULTI_%d", num++);
num = 0; num = 0;
device_multi_add(devices, DEVICE_OPENCL, true, "OPENCL_MULTI_%d", num++);
device_multi_add(devices, DEVICE_OPENCL, false, "OPENCL_MULTI_%d", num++); device_multi_add(devices, DEVICE_OPENCL, false, "OPENCL_MULTI_%d", num++);
device_multi_add(devices, DEVICE_OPENCL, true, "OPENCL_MULTI_%d", num++);
} }
CCL_NAMESPACE_END CCL_NAMESPACE_END

@ -103,7 +103,7 @@ public:
#endif #endif
} }
void mem_copy_from(device_memory& mem, size_t offset, size_t size) void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
{ {
#if 0 #if 0
RPCSend snd(socket, "mem_copy_from"); RPCSend snd(socket, "mem_copy_from");

@ -489,8 +489,11 @@ public:
opencl_assert(ciErr); opencl_assert(ciErr);
} }
void mem_copy_from(device_memory& mem, size_t offset, size_t size) void mem_copy_from(device_memory& mem, int y, int w, int h, int elem)
{ {
size_t offset = elem*y*w;
size_t size = elem*w*h;
ciErr = clEnqueueReadBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, offset, size, (uchar*)mem.data_pointer + offset, 0, NULL, NULL); ciErr = clEnqueueReadBuffer(cqCommandQueue, CL_MEM_PTR(mem.device_pointer), CL_TRUE, offset, size, (uchar*)mem.data_pointer + offset, 0, NULL, NULL);
opencl_assert(ciErr); opencl_assert(ciErr);
} }
@ -745,6 +748,8 @@ void device_opencl_info(vector<DeviceInfo>& devices)
info.description = string(name); info.description = string(name);
info.id = string_printf("OPENCL_%d", num); info.id = string_printf("OPENCL_%d", num);
info.num = num; info.num = num;
/* we don't know if it's used for display, but assume it is */
info.display_device = true;
devices.push_back(info); devices.push_back(info);
} }

@ -87,7 +87,7 @@ float4 *RenderBuffers::copy_from_device(float exposure, int sample)
if(!buffer.device_pointer) if(!buffer.device_pointer)
return NULL; return NULL;
device->mem_copy_from(buffer, 0, buffer.memory_size()); device->mem_copy_from(buffer, 0, params.width, params.height, sizeof(float4));
float4 *out = new float4[params.width*params.height]; float4 *out = new float4[params.width*params.height];
float4 *in = (float4*)buffer.data_pointer; float4 *in = (float4*)buffer.data_pointer;

@ -106,7 +106,7 @@ bool MeshManager::displace(Device *device, Scene *scene, Mesh *mesh, Progress& p
device->task_add(task); device->task_add(task);
device->task_wait(); device->task_wait();
device->mem_copy_from(d_output, 0, sizeof(float3)*d_output.size()); device->mem_copy_from(d_output, 0, 1, d_output.size(), sizeof(float3));
device->mem_free(d_input); device->mem_free(d_input);
device->mem_free(d_output); device->mem_free(d_output);

@ -388,11 +388,7 @@ class USERPREF_PT_system(Panel):
col.prop(system, "dpi") col.prop(system, "dpi")
col.prop(system, "frame_server_port") col.prop(system, "frame_server_port")
col.prop(system, "scrollback", text="Console Scrollback") col.prop(system, "scrollback", text="Console Scrollback")
col.prop(system, "author", text="Author")
col.prop(system, "use_scripts_auto_execute")
col.prop(system, "use_tabs_as_spaces")
col.separator()
col.separator() col.separator()
col.separator() col.separator()
@ -406,16 +402,22 @@ class USERPREF_PT_system(Panel):
sub.prop(system, "audio_sample_rate", text="Sample Rate") sub.prop(system, "audio_sample_rate", text="Sample Rate")
sub.prop(system, "audio_sample_format", text="Sample Format") sub.prop(system, "audio_sample_format", text="Sample Format")
col.separator()
col.separator() col.separator()
col.separator() col.separator()
col.label(text="Screencast:") col.label(text="Screencast:")
col.prop(system, "screencast_fps") col.prop(system, "screencast_fps")
col.prop(system, "screencast_wait_time") col.prop(system, "screencast_wait_time")
col.separator() col.separator()
col.separator() col.separator()
col.separator()
if hasattr(system, 'compute_device'):
col.label(text="Compute Device:")
col.row().prop(system, "compute_device_type", expand=True)
sub = col.row()
sub.active = system.compute_device_type != 'CPU'
sub.prop(system, "compute_device", text="")
# 2. Column # 2. Column
column = split.column() column = split.column()
@ -727,6 +729,7 @@ class USERPREF_PT_file(Panel):
userpref = context.user_preferences userpref = context.user_preferences
paths = userpref.filepaths paths = userpref.filepaths
system = userpref.system
split = layout.split(percentage=0.7) split = layout.split(percentage=0.7)
@ -762,6 +765,14 @@ class USERPREF_PT_file(Panel):
subsplit.prop(paths, "animation_player_preset", text="") subsplit.prop(paths, "animation_player_preset", text="")
subsplit.prop(paths, "animation_player", text="") subsplit.prop(paths, "animation_player", text="")
col.separator()
col.separator()
colsplit = col.split(percentage=0.95)
sub = colsplit.column()
sub.label(text="Author:")
sub.prop(system, "author", text="")
col = split.column() col = split.column()
col.label(text="Save & Load:") col.label(text="Save & Load:")
col.prop(paths, "use_relative_paths") col.prop(paths, "use_relative_paths")
@ -784,6 +795,13 @@ class USERPREF_PT_file(Panel):
sub.active = paths.use_auto_save_temporary_files sub.active = paths.use_auto_save_temporary_files
sub.prop(paths, "auto_save_time", text="Timer (mins)") sub.prop(paths, "auto_save_time", text="Timer (mins)")
col.separator()
col.label(text="Scripts:")
col.prop(system, "use_scripts_auto_execute")
col.prop(system, "use_tabs_as_spaces")
from .space_userpref_keymap import InputKeyMapPanel from .space_userpref_keymap import InputKeyMapPanel

@ -413,6 +413,9 @@ typedef struct UserDef {
short pad3; short pad3;
char author[80]; /* author name for file formats supporting it */ char author[80]; /* author name for file formats supporting it */
int compute_device_type;
int compute_device_id;
} UserDef; } UserDef;
extern UserDef U; /* from blenkernel blender.c */ extern UserDef U; /* from blenkernel blender.c */
@ -627,6 +630,10 @@ extern UserDef U; /* from blenkernel blender.c */
#define NDOF_PANY_INVERT_AXIS (1 << 13) #define NDOF_PANY_INVERT_AXIS (1 << 13)
#define NDOF_PANZ_INVERT_AXIS (1 << 14) #define NDOF_PANZ_INVERT_AXIS (1 << 14)
/* compute_device_type */
#define USER_COMPUTE_DEVICE_NONE 0
#define USER_COMPUTE_DEVICE_OPENCL 1
#define USER_COMPUTE_DEVICE_CUDA 2
#ifdef __cplusplus #ifdef __cplusplus
} }

@ -8,7 +8,7 @@ objs += o
incs = '#/intern/guardedalloc #/intern/memutil #/intern/audaspace/intern ../blenkernel ../blenlib ../makesdna intern .' incs = '#/intern/guardedalloc #/intern/memutil #/intern/audaspace/intern ../blenkernel ../blenlib ../makesdna intern .'
incs += ' ../windowmanager ../editors/include ../gpu ../imbuf ../ikplugin ../blenfont ../blenloader' incs += ' ../windowmanager ../editors/include ../gpu ../imbuf ../ikplugin ../blenfont ../blenloader'
incs += ' ../render/extern/include' incs += ' ../render/extern/include #/intern/cycles/blender'
incs += ' ../nodes' incs += ' ../nodes'
incs += ' #/extern/glew/include' incs += ' #/extern/glew/include'
@ -58,6 +58,9 @@ if env['WITH_BF_COLLADA']:
if env['WITH_BF_OCEANSIM']: if env['WITH_BF_OCEANSIM']:
defs.append('WITH_OCEANSIM') defs.append('WITH_OCEANSIM')
if env['WITH_BF_CYCLES']:
defs.append('WITH_CYCLES')
if env['OURPLATFORM'] == 'linux': if env['OURPLATFORM'] == 'linux':
cflags='-pthread' cflags='-pthread'
incs += ' ../../../extern/binreloc/include' incs += ' ../../../extern/binreloc/include'

@ -143,6 +143,9 @@ set(INC_SYS
) )
if(WITH_CYCLES)
add_definitions(-DWITH_CYCLES)
endif()
if(WITH_PYTHON) if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON) add_definitions(-DWITH_PYTHON)
@ -246,6 +249,7 @@ blender_include_dirs(
../../editors/include ../../editors/include
../../render/extern/include ../../render/extern/include
../../../../intern/audaspace/intern ../../../../intern/audaspace/intern
../../../../intern/cycles/blender
../../../../intern/guardedalloc ../../../../intern/guardedalloc
../../../../intern/memutil ../../../../intern/memutil
) )

@ -33,7 +33,7 @@ incs = '#/intern/guardedalloc ../../blenlib ../../blenkernel ../../blenloader'
incs += ' ../../imbuf ../../makesdna ../../makesrna ../../ikplugin' incs += ' ../../imbuf ../../makesdna ../../makesrna ../../ikplugin'
incs += ' ../../windowmanager ../../editors/include ../../blenfont' incs += ' ../../windowmanager ../../editors/include ../../blenfont'
incs += ' ../../render/extern/include' incs += ' ../../render/extern/include'
incs += ' #/intern/audaspace/intern ' incs += ' #/intern/audaspace/intern #/intern/cycles/blender'
incs += ' #/extern/glew/include ' incs += ' #/extern/glew/include '
if env['WITH_BF_OPENEXR']: if env['WITH_BF_OPENEXR']:
@ -91,6 +91,9 @@ if env['WITH_BF_PYTHON']:
if env['WITH_BF_COLLADA']: if env['WITH_BF_COLLADA']:
defs.append('WITH_COLLADA') defs.append('WITH_COLLADA')
if env['WITH_BF_CYCLES']:
defs.append('WITH_CYCLES')
if env['OURPLATFORM'] == 'linux': if env['OURPLATFORM'] == 'linux':
cflags='-pthread' cflags='-pthread'
incs += ' ../../../extern/binreloc/include' incs += ' ../../../extern/binreloc/include'

@ -46,6 +46,14 @@
#include "BKE_sound.h" #include "BKE_sound.h"
#ifdef WITH_CYCLES
static EnumPropertyItem compute_device_type_items[] = {
{USER_COMPUTE_DEVICE_NONE, "NONE", 0, "None", "Don't use compute device"},
{USER_COMPUTE_DEVICE_CUDA, "CUDA", 0, "CUDA", "Use CUDA for GPU acceleration"},
{USER_COMPUTE_DEVICE_OPENCL, "OPENCL", 0, "OpenCL", "Use OpenCL for GPU acceleration"},
{ 0, NULL, 0, NULL, NULL}};
#endif
#ifdef RNA_RUNTIME #ifdef RNA_RUNTIME
#include "DNA_object_types.h" #include "DNA_object_types.h"
@ -65,6 +73,8 @@
#include "UI_interface.h" #include "UI_interface.h"
#include "CCL_api.h"
static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{ {
WM_main_add_notifier(NC_WINDOW, NULL); WM_main_add_notifier(NC_WINDOW, NULL);
@ -302,6 +312,68 @@ static void rna_userdef_text_update(Main *UNUSED(bmain), Scene *UNUSED(scene), P
WM_main_add_notifier(NC_WINDOW, NULL); WM_main_add_notifier(NC_WINDOW, NULL);
} }
#ifdef WITH_CYCLES
static EnumPropertyItem *rna_userdef_compute_device_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
{
EnumPropertyItem *item= NULL;
int totitem= 0;
/* add supported device types */
RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_NONE);
if(CCL_compute_device_list(0))
RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_CUDA);
if(CCL_compute_device_list(1))
RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_OPENCL);
RNA_enum_item_end(&item, &totitem);
*free = 1;
return item;
}
static int rna_userdef_compute_device_get(PointerRNA *UNUSED(ptr))
{
if(U.compute_device_type == USER_COMPUTE_DEVICE_NONE)
return 0;
return U.compute_device_id;
}
static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), int *free)
{
EnumPropertyItem tmp= {0, "", 0, "", ""};
EnumPropertyItem *item= NULL;
int totitem= 0;
if(U.compute_device_type == USER_COMPUTE_DEVICE_NONE) {
/* only add a single CPU device */
tmp.value = 0;
tmp.name = "CPU";
tmp.identifier = "CPU";
RNA_enum_item_add(&item, &totitem, &tmp);
}
else {
/* get device list from cycles. it would be good to make this generic
once we have more subsystems using opencl, for now this is easiest */
int opencl = (U.compute_device_type == USER_COMPUTE_DEVICE_OPENCL);
CCLDeviceInfo *devices = CCL_compute_device_list(opencl);
int a;
for(a = 0; devices[a].name; a++) {
tmp.value = devices[a].value;
tmp.identifier = devices[a].identifier;
tmp.name = devices[a].name;
RNA_enum_item_add(&item, &totitem, &tmp);
}
}
RNA_enum_item_end(&item, &totitem);
*free = 1;
return item;
}
#endif
#else #else
static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
@ -2645,6 +2717,12 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{18, "UKRAINIAN", 0, "Ukrainian (Український)", "uk_UA"}, {18, "UKRAINIAN", 0, "Ukrainian (Український)", "uk_UA"},
{ 0, NULL, 0, NULL, NULL}}; { 0, NULL, 0, NULL, NULL}};
#ifdef WITH_CYCLES
static EnumPropertyItem compute_device_items[] = {
{0, "CPU", 0, "CPU", ""},
{ 0, NULL, 0, NULL, NULL}};
#endif
srna= RNA_def_struct(brna, "UserPreferencesSystem", NULL); srna= RNA_def_struct(brna, "UserPreferencesSystem", NULL);
RNA_def_struct_sdna(srna, "UserDef"); RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "UserPreferences"); RNA_def_struct_nested(brna, srna, "UserPreferences");
@ -2853,14 +2931,20 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased"); RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased");
RNA_def_property_update(prop, 0, "rna_userdef_text_update"); RNA_def_property_update(prop, 0, "rna_userdef_text_update");
#if 0 #ifdef WITH_CYCLES
prop= RNA_def_property(srna, "verse_master", PROP_STRING, PROP_NONE); prop= RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "versemaster"); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
RNA_def_property_ui_text(prop, "Verse Master", "Verse Master-server IP"); RNA_def_property_enum_sdna(prop, NULL, "compute_device_type");
RNA_def_property_enum_items(prop, compute_device_type_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_compute_device_type_itemf");
RNA_def_property_ui_text(prop, "Compute Device Type", "Device to use for computation (rendering with Cycles)");
prop= RNA_def_property(srna, "verse_username", PROP_STRING, PROP_NONE); prop= RNA_def_property(srna, "compute_device", PROP_ENUM, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "verseuser"); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
RNA_def_property_ui_text(prop, "Verse Username", "Verse user name"); RNA_def_property_enum_sdna(prop, NULL, "compute_device_id");
RNA_def_property_enum_items(prop, compute_device_items);
RNA_def_property_enum_funcs(prop, "rna_userdef_compute_device_get", NULL, "rna_userdef_compute_device_itemf");
RNA_def_property_ui_text(prop, "Compute Device", "Device to use for computation");
#endif #endif
} }

@ -6,7 +6,7 @@ Import ('env')
incs = '. ../editors/include ../makesdna ../makesrna ../blenfont ../blenlib ../blenkernel ../nodes' incs = '. ../editors/include ../makesdna ../makesrna ../blenfont ../blenlib ../blenkernel ../nodes'
incs += ' ../imbuf ../blenloader ../gpu ../render/extern/include ../windowmanager' incs += ' ../imbuf ../blenloader ../gpu ../render/extern/include ../windowmanager'
incs += ' #intern/guardedalloc #intern/memutil #extern/glew/include' incs += ' #intern/guardedalloc #intern/memutil #extern/glew/include #intern/cycles/blender'
incs += ' #intern/audaspace/intern ' + env['BF_PYTHON_INC'] incs += ' #intern/audaspace/intern ' + env['BF_PYTHON_INC']
is_debug = (env['OURPLATFORM'] in ('win32-mingw', 'win32-vc','win64-vc') and env['BF_DEBUG']) is_debug = (env['OURPLATFORM'] in ('win32-mingw', 'win32-vc','win64-vc') and env['BF_DEBUG'])

@ -35,6 +35,7 @@ set(INC
../../windowmanager ../../windowmanager
../../gpu ../../gpu
../../../../intern/guardedalloc ../../../../intern/guardedalloc
../../../../intern/cycles/blender
) )
set(INC_SYS set(INC_SYS

@ -57,12 +57,13 @@
#include "BLI_string_utf8.h" #include "BLI_string_utf8.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BKE_context.h" #include "BKE_context.h"
#include "BKE_text.h" #include "BKE_text.h"
#include "BKE_main.h" #include "BKE_main.h"
#include "BKE_global.h" /* only for script checking */ #include "BKE_global.h" /* only for script checking */
#include "CCL_api.h"
#include "BPY_extern.h" #include "BPY_extern.h"
#include "../generic/bpy_internal_import.h" // our own imports #include "../generic/bpy_internal_import.h" // our own imports
@ -176,8 +177,14 @@ void BPY_context_set(bContext *C)
/* defined in AUD_C-API.cpp */ /* defined in AUD_C-API.cpp */
extern PyObject *AUD_initPython(void); extern PyObject *AUD_initPython(void);
/* defined in cycles/blender */
extern PyObject *CYCLES_initPython(void); #ifdef WITH_CYCLES
/* defined in cycles module */
static PyObject *CCL_initPython(void)
{
return (PyObject*)CCL_python_module_init();
}
#endif
static struct _inittab bpy_internal_modules[] = { static struct _inittab bpy_internal_modules[] = {
{(char *)"mathutils", PyInit_mathutils}, {(char *)"mathutils", PyInit_mathutils},
@ -189,7 +196,7 @@ static struct _inittab bpy_internal_modules[] = {
{(char *)"aud", AUD_initPython}, {(char *)"aud", AUD_initPython},
#endif #endif
#ifdef WITH_CYCLES #ifdef WITH_CYCLES
{(char *)"_cycles", CYCLES_initPython}, {(char *)"_cycles", CCL_initPython},
#endif #endif
{(char *)"gpu", GPU_initPython}, {(char *)"gpu", GPU_initPython},
{NULL, NULL} {NULL, NULL}

@ -475,6 +475,9 @@ struct DualConMesh *dualcon(const struct DualConMesh *input_mesh,
float scale, float scale,
int depth) {return 0;} int depth) {return 0;}
/* intern/cycles */
struct CCLDeviceInfo;
struct CCLDeviceInfo *CCL_compute_device_list(int opencl) { return NULL; }
char blender_path[] = ""; char blender_path[] = "";