Cycles: multi GPU rendering support.
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 9 Jan 2012 16:58:01 +0000 (16:58 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Mon, 9 Jan 2012 16:58:01 +0000 (16:58 +0000)
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.

30 files changed:
intern/cycles/blender/CCL_api.h [new file with mode: 0644]
intern/cycles/blender/CMakeLists.txt
intern/cycles/blender/addon/engine.py
intern/cycles/blender/addon/enums.py
intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_python.cpp
intern/cycles/blender/blender_session.cpp
intern/cycles/blender/blender_session.h
intern/cycles/blender/blender_sync.cpp
intern/cycles/blender/blender_sync.h
intern/cycles/device/device.cpp
intern/cycles/device/device.h
intern/cycles/device/device_cpu.cpp
intern/cycles/device/device_cuda.cpp
intern/cycles/device/device_multi.cpp
intern/cycles/device/device_network.cpp
intern/cycles/device/device_opencl.cpp
intern/cycles/render/buffers.cpp
intern/cycles/render/mesh_displace.cpp
release/scripts/startup/bl_ui/space_userpref.py
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/SConscript
source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/SConscript
source/blender/makesrna/intern/rna_userdef.c
source/blender/python/SConscript
source/blender/python/intern/CMakeLists.txt
source/blender/python/intern/bpy_interface.c
source/blenderplayer/bad_level_call_stubs/stubs.c

diff --git a/intern/cycles/blender/CCL_api.h b/intern/cycles/blender/CCL_api.h
new file mode 100644 (file)
index 0000000..469d63d
--- /dev/null
@@ -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 */
+
index 3b685346791c8b2ceb419925abd64c9b86c95361..003c6c84f8f9192befff0f11abf3e25a42abb45a 100644 (file)
@@ -27,6 +27,7 @@ set(SRC
        blender_shader.cpp
        blender_sync.cpp
 
+       CCL_api.h
        blender_sync.h
        blender_session.h
        blender_util.h
index 3d71c25d7ade46c9fcad252a73e6aae1ec378195..05b1f88359433f761b919106524e670c5623d873 100644 (file)
@@ -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):
index a11f5ca0f87fadfd3be9517a0caed51ea895ff98..da4c73a5d3be89d438bdf2ab48cba825c9151155 100644 (file)
 
 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"),
index 0ea7396f9c2e3599587069a6070aea176e44f65a..0b096c529b89c7ff1d2dbce099bb80d4361d5415 100644 (file)
@@ -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")
 
index 6e73795666e9952e4ac376b85e5f10bb4a8e639b..ea23e2b56a5681169daf3d1d979e1ed67b53afe8 100644 (file)
@@ -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
index 90dab298dc303bc998ce78b348ae15ec691dab96..6e892095387a3b4e7f2967e15c72f664ebf6bfe6 100644 (file)
 
 #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
 };
 
-CCL_NAMESPACE_END
+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);
+               }
+       }
 
-extern "C" PyObject *CYCLES_initPython();
+       return (device_list.empty())? NULL: &device_list[0];
+}
 
-PyObject *CYCLES_initPython()
+
+CCL_NAMESPACE_END
+
+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);
 }
 
index c7c35b537bd89a5f155b083ebc24636a7aadbe99..b052fb3e195a742b7907e310e53cfae4dad619a4 100644 (file)
 
 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);
index 26fffcf3aff9a20603fdd3f8dffe2a212b8f43fb..b98e3ffed54fc3c618fef57765364d2158b2189d 100644 (file)
@@ -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;
index 8f54f291cfba78b2251638f817af98340bac0029..c00320f009462794f03466326164005fac935195 100644 (file)
@@ -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;
-
-               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;
+               /* 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();
+
+               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;
 }
index 60fdd7c386b143c48afabc9e43fce40dd392c5d2..7b65376bd846eb46d44d253a89e7ec2207db1810 100644 (file)
@@ -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);
 
index 83600120fdd4717e1925646552b06b388996fcc2..1f0be1599bfbec2ab33a474ad8ee3a684550fa61 100644 (file)
@@ -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)
index 51505aa9cb924d6189bb523ac51843d980f11f89..b8fea4c4c6900f512d5ca4592d2cef981a8ce34b 100644 (file)
@@ -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;
 
index c93c6ff17da468bfc85489dd7e5ec25bdf6b6e2e..e29266b0a7dae2cec4af8cf4b80813f53bf8a1d8 100644 (file)
@@ -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 */
        }
index 73d87ae4a2e209e893895780948a80ad637836e8..55b467fc856ab98a76c47952a2bd5517e42a37c0 100644 (file)
@@ -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
index f8b512f209c80269215d71efbf7dbf422ecf6396..41d0e268526e1ba4bb7132331c075a51db28ca50 100644 (file)
@@ -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++;
+                       if(subinfo.display_device) {
+                               if(with_display)
+                                       num_display++;
+                               else
+                                       continue;
                        }
-                       else {
-                               string key = subinfo.description;
 
-                               if(dupli_map.find(key) == dupli_map.end())
-                                       dupli_map[key] = 1;
-                               else
-                                       dupli_map[key]++;
+                       string key = subinfo.description;
 
-                               info.multi_devices.push_back(subinfo);
-                               if(subinfo.display_device)
-                                       info.display_device = true;
-                               num_added++;
-                       }
+                       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
index 4347d7eecd822534b382980e85a430badb7fa4f5..14518b1507ec82b84f1271f846f3dd6541596ad9 100644 (file)
@@ -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");
index 41844d37f502c725cd4d0fad72a7b2aa9afe2589..ccfd854436261f0de34c2ebdb4d82a937ba61da9 100644 (file)
@@ -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);
        }
index dd78ccd8f32211fb5fe06332d87ee6bd18122f16..a6bbbc91901e536db3bc759fa582e9dfe7788e85 100644 (file)
@@ -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;
index f0ddf4e8d7bfdbbcaaa29bcd6b86c6a51b4b2a2e..c4f3e43bfba4e7ef109d6b894609cd8fc9c9c019 100644 (file)
@@ -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);
 
index 046026a3b6e2e0b5fe2d123b6d827e6933c9c7be..544fc92e8a4a3e9fb1ca66843254241fbb081190 100644 (file)
@@ -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
 
 
index b33984605009c9acea32629317354d88b3d76815..fc418069c5c86d4e55ecfe25ebecb8cad147e82b 100644 (file)
@@ -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
 }
index 9eea6d83cb97975247a7cfa00ada4397bdff861e..7eb5d042dd7dc812c32b9a2227f9134f6ac34f02 100644 (file)
@@ -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'
index fd9cd26cbfae40cdec5e1ea8408a82812fecfeb7..5bbdac646a790ca8178c1645b3631ff7bed892d4 100644 (file)
@@ -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
 )
index d710dd06a17680753a27e5375e13a074997cee2e..1fc6ed0f1308cd981ab4649d877e879f5e4bffd6 100644 (file)
@@ -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'
index 164f8e4f0d097e4735b3f61573a37640a8ae3ffe..4564b9f29468ea3f993806695a63ad03cb561336 100644 (file)
 
 #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");
-
-       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");
+#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, "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
 }
 
index cd1666d0eed6c17578c482fbbb6622b0871d7425..2a47c2dcb96be360aff9520a8a920c82d846b2ae 100644 (file)
@@ -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'])
index f110576a297f484bbf1fadb4b82216d738b192c2..05583e133dc0840eab6672b97eba85fd4f64ab76 100644 (file)
@@ -35,6 +35,7 @@ set(INC
        ../../windowmanager
        ../../gpu
        ../../../../intern/guardedalloc
+       ../../../../intern/cycles/blender
 )
 
 set(INC_SYS
index 7d91438e4f704c1e9cb5b81d437ea99d7bcea8fe..6c961d8e6a8ed4e4858ae89f16bc84d139ebe61a 100644 (file)
 #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}
index 75d1f182189d938ae81ae4088d58105b0708424c..9efb8114cbdee201816c713926ed553050f862fb 100644 (file)
@@ -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[] = "";