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_sync.cpp
CCL_api.h
blender_sync.h
blender_session.h
blender_util.h

@ -35,6 +35,7 @@ def create(engine, data, scene, region=0, v3d=0, rv3d=0):
import _cycles
data = data.as_pointer()
userpref = bpy.context.user_preferences.as_pointer()
scene = scene.as_pointer()
if region:
region = region.as_pointer()
@ -43,7 +44,7 @@ def create(engine, data, scene, region=0, v3d=0, rv3d=0):
if rv3d:
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):

@ -20,29 +20,9 @@
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 = (
("CPU", "CPU", "Processor"),
("GPU", get_gpu_device(), "Graphics card"),
)
gpu_type = (
("CUDA", "CUDA", "NVidia only"),
("OPENCL", "OpenCL", ""),
)
("CPU", "CPU", "Use CPU for rendering"),
("GPU", "GPU Compute", "Use GPU compute device for rendering, configured in user preferences"))
feature_set = (
("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",
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",
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_use_spatial_splits")
class CyclesRender_PT_layers(CyclesButtonsPanel, Panel):
bl_label = "Layers"
bl_options = {'DEFAULT_CLOSED'}
@ -712,19 +711,12 @@ def draw_device(self, context):
cscene = scene.cycles
layout.prop(cscene, "feature_set")
experimental = cscene.feature_set == 'EXPERIMENTAL'
available_devices = engine.available_devices()
available_cuda = 'cuda' in available_devices
available_opencl = experimental and 'opencl' in available_devices
if available_cuda or available_opencl:
device_type = context.user_preferences.system.compute_device_type
if device_type == 'CUDA':
layout.prop(cscene, "device")
elif device_type == 'OPENCL' and cscene.feature_set == 'EXPERIMENTAL':
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):
layout = self.layout

@ -18,9 +18,12 @@
#include <Python.h>
#include "CCL_api.h"
#include "blender_sync.h"
#include "blender_session.h"
#include "util_foreach.h"
#include "util_opengl.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)
{
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;
/* RNA */
@ -50,6 +53,10 @@ static PyObject *create_func(PyObject *self, PyObject *args)
RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
BL::RenderEngine engine(engineptr);
PointerRNA userprefptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyuserpref), &userprefptr);
BL::UserPreferences userpref(userprefptr);
PointerRNA dataptr;
RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pydata), &dataptr);
BL::BlendData data(dataptr);
@ -78,11 +85,11 @@ static PyObject *create_func(PyObject *self, PyObject *args)
int width = region.width();
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 {
/* offline session */
session = new BlenderSession(engine, data, scene);
session = new BlenderSession(engine, userpref, data, scene);
}
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)
{
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 < types.size(); i++) {
string name = Device::string_from_type(types[i]);
PyTuple_SET_ITEM(ret, i, PyUnicode_FromString(name.c_str()));
for(size_t i = 0; i < devices.size(); i++) {
DeviceInfo& device = devices[i];
PyTuple_SET_ITEM(ret, i, PyUnicode_FromString(device.description.c_str()));
}
return ret;
@ -169,11 +175,44 @@ static struct PyModuleDef module = {
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
extern "C" PyObject *CYCLES_initPython();
PyObject *CYCLES_initPython()
void *CCL_python_module_init()
{
PyObject *mod= PyModule_Create(&ccl::module);
@ -185,6 +224,12 @@ PyObject *CYCLES_initPython()
Py_INCREF(Py_False);
#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
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_, BL::Scene b_scene_)
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(PointerRNA_NULL), b_rv3d(PointerRNA_NULL),
BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::UserPreferences b_userpref_,
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)
{
/* offline render */
@ -54,10 +56,11 @@ BlenderSession::BlenderSession(BL::RenderEngine b_engine_, BL::BlendData b_data_
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_)
: b_engine(b_engine_), b_data(b_data_), b_scene(b_scene_), b_v3d(b_v3d_), b_rv3d(b_rv3d_),
b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
: b_engine(b_engine_), b_userpref(b_userpref_), b_data(b_data_), b_scene(b_scene_),
b_v3d(b_v3d_), b_rv3d(b_rv3d_), b_rr(PointerRNA_NULL), b_rlay(PointerRNA_NULL)
{
/* 3d view render */
width = width_;
@ -77,7 +80,7 @@ BlenderSession::~BlenderSession()
void BlenderSession::create_session()
{
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 */
last_status= "";
@ -184,7 +187,7 @@ void BlenderSession::synchronize()
{
/* on session/scene parameter changes, we recreate session entirely */
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) ||
scene->params.modified(scene_params)) {
@ -258,7 +261,7 @@ bool BlenderSession::draw(int w, int h)
/* reset if requested */
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);
session->reset(buffer_params, session_params.samples);

@ -32,8 +32,10 @@ class Session;
class BlenderSession {
public:
BlenderSession(BL::RenderEngine b_engine, BL::BlendData b_data, BL::Scene b_scene);
BlenderSession(BL::RenderEngine b_engine, 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);
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);
~BlenderSession();
@ -65,6 +67,7 @@ public:
double last_redraw_time;
BL::RenderEngine b_engine;
BL::UserPreferences b_userpref;
BL::BlendData b_data;
BL::Scene b_scene;
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");
}
static bool device_type_available(vector<DeviceInfo>& devices, DeviceType dtype)
{
foreach(DeviceInfo& info, devices)
if(info.type == dtype)
return true;
return false;
}
SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background)
SessionParams BlenderSync::get_session_params(BL::UserPreferences b_userpref, BL::Scene b_scene, bool background)
{
SessionParams params;
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);
/* device type */
vector<DeviceInfo> devices = Device::available_devices();
DeviceType device_type = DEVICE_CPU;
vector<DeviceInfo>& devices = Device::available_devices();
/* device default CPU */
params.device = devices[0];
if(RNA_enum_get(&cscene, "device") != 0) {
if(!params.experimental || RNA_enum_get(&cscene, "gpu_type") == 0)
device_type = DEVICE_CUDA;
else
device_type = DEVICE_OPENCL;
/* find GPU device with given id */
PointerRNA systemptr = b_userpref.system().ptr;
PropertyRNA *deviceprop = RNA_struct_find_property(&systemptr, "compute_device");
int device_id = b_userpref.system().compute_device();
if(device_type_available(devices, device_type))
;
else if(params.experimental && device_type_available(devices, DEVICE_OPENCL))
device_type = DEVICE_OPENCL;
else if(device_type_available(devices, DEVICE_CUDA))
device_type = DEVICE_CUDA;
const char *id;
if(RNA_property_enum_identifier(NULL, &systemptr, deviceprop, device_id, &id)) {
foreach(DeviceInfo& info, devices)
if(info.id == id)
params.device = info;
}
}
params.device = devices[0];
foreach(DeviceInfo& info, devices)
if(info.type == device_type)
params.device = info;
/* Background */
params.background = background;
@ -316,6 +304,10 @@ SessionParams BlenderSync::get_session_params(BL::Scene b_scene, bool background
}
else
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;
}

@ -60,7 +60,7 @@ public:
/* get parameters */
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 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)
{
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)

@ -111,7 +111,7 @@ public:
virtual void mem_alloc(device_memory& mem, MemoryType type) = 0;
virtual void mem_copy_to(device_memory& mem) = 0;
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_free(device_memory& mem) = 0;

@ -92,7 +92,7 @@ public:
/* 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 */
}

@ -341,9 +341,11 @@ public:
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_assert(cuMemcpyDtoH((uchar*)mem.data_pointer + offset,
(CUdeviceptr)((uchar*)mem.device_pointer + offset), size))
@ -863,6 +865,8 @@ void device_cuda_info(vector<DeviceInfo>& devices)
if(cuDeviceGetCount(&count) != CUDA_SUCCESS)
return;
vector<DeviceInfo> display_devices;
for(int num = 0; num < count; num++) {
char name[256];
int attr;
@ -878,11 +882,16 @@ void device_cuda_info(vector<DeviceInfo>& devices)
info.num = num;
/* 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;
devices.push_back(info);
display_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

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

@ -103,7 +103,7 @@ public:
#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
RPCSend snd(socket, "mem_copy_from");

@ -489,8 +489,11 @@ public:
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);
opencl_assert(ciErr);
}
@ -745,6 +748,8 @@ void device_opencl_info(vector<DeviceInfo>& devices)
info.description = string(name);
info.id = string_printf("OPENCL_%d", 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);
}

@ -87,7 +87,7 @@ float4 *RenderBuffers::copy_from_device(float exposure, int sample)
if(!buffer.device_pointer)
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 *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_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_output);

@ -388,11 +388,7 @@ class USERPREF_PT_system(Panel):
col.prop(system, "dpi")
col.prop(system, "frame_server_port")
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()
@ -406,16 +402,22 @@ class USERPREF_PT_system(Panel):
sub.prop(system, "audio_sample_rate", text="Sample Rate")
sub.prop(system, "audio_sample_format", text="Sample Format")
col.separator()
col.separator()
col.separator()
col.label(text="Screencast:")
col.prop(system, "screencast_fps")
col.prop(system, "screencast_wait_time")
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
column = split.column()
@ -727,6 +729,7 @@ class USERPREF_PT_file(Panel):
userpref = context.user_preferences
paths = userpref.filepaths
system = userpref.system
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", 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.label(text="Save & Load:")
col.prop(paths, "use_relative_paths")
@ -784,6 +795,13 @@ class USERPREF_PT_file(Panel):
sub.active = paths.use_auto_save_temporary_files
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

@ -413,6 +413,9 @@ typedef struct UserDef {
short pad3;
char author[80]; /* author name for file formats supporting it */
int compute_device_type;
int compute_device_id;
} UserDef;
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_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
}

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

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

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

@ -46,6 +46,14 @@
#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
#include "DNA_object_types.h"
@ -65,6 +73,8 @@
#include "UI_interface.h"
#include "CCL_api.h"
static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
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);
}
#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
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"},
{ 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);
RNA_def_struct_sdna(srna, "UserDef");
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_update(prop, 0, "rna_userdef_text_update");
#if 0
prop= RNA_def_property(srna, "verse_master", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "versemaster");
RNA_def_property_ui_text(prop, "Verse Master", "Verse Master-server IP");
#ifdef WITH_CYCLES
prop= RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
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);
RNA_def_property_string_sdna(prop, NULL, "verseuser");
RNA_def_property_ui_text(prop, "Verse Username", "Verse user name");
prop= RNA_def_property(srna, "compute_device", PROP_ENUM, PROP_NONE);
RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
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
}

@ -6,7 +6,7 @@ Import ('env')
incs = '. ../editors/include ../makesdna ../makesrna ../blenfont ../blenlib ../blenkernel ../nodes'
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']
is_debug = (env['OURPLATFORM'] in ('win32-mingw', 'win32-vc','win64-vc') and env['BF_DEBUG'])

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

@ -57,12 +57,13 @@
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
#include "BKE_text.h"
#include "BKE_main.h"
#include "BKE_global.h" /* only for script checking */
#include "CCL_api.h"
#include "BPY_extern.h"
#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 */
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[] = {
{(char *)"mathutils", PyInit_mathutils},
@ -189,7 +196,7 @@ static struct _inittab bpy_internal_modules[] = {
{(char *)"aud", AUD_initPython},
#endif
#ifdef WITH_CYCLES
{(char *)"_cycles", CYCLES_initPython},
{(char *)"_cycles", CCL_initPython},
#endif
{(char *)"gpu", GPU_initPython},
{NULL, NULL}

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