diff options
Diffstat (limited to 'intern/cycles/blender/blender_python.cpp')
-rw-r--r-- | intern/cycles/blender/blender_python.cpp | 226 |
1 files changed, 202 insertions, 24 deletions
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 6581d0b997e..ceb9cbf242e 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -37,13 +37,94 @@ CCL_NAMESPACE_BEGIN -static void *pylong_as_voidptr_typesafe(PyObject *object) +namespace { + +/* Device list stored static (used by compute_device_list()). */ +static ccl::vector<CCLDeviceInfo> device_list; +static ccl::DeviceType device_type = DEVICE_NONE; + +/* Flag describing whether debug flags were synchronized from scene. */ +bool debug_flags_set = false; + +void *pylong_as_voidptr_typesafe(PyObject *object) { if(object == Py_None) return NULL; return PyLong_AsVoidPtr(object); } +/* Synchronize debug flags from a given Blender scene. + * Return truth when device list needs invalidation. + */ +bool debug_flags_sync_from_scene(BL::Scene b_scene) +{ + DebugFlagsRef flags = DebugFlags(); + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + /* Backup some settings for comparison. */ + DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type; + DebugFlags::OpenCL::KernelType opencl_kernel_type = flags.opencl.kernel_type; + /* Synchronize CPU flags. */ + flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2"); + flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx"); + flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41"); + flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3"); + flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2"); + flags.cpu.qbvh = get_boolean(cscene, "debug_use_qbvh"); + /* Synchronize OpenCL kernel type. */ + switch(get_enum(cscene, "debug_opencl_kernel_type")) { + case 0: + flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_DEFAULT; + break; + case 1: + flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_MEGA; + break; + case 2: + flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_SPLIT; + break; + } + /* Synchronize OpenCL device type. */ + switch(get_enum(cscene, "debug_opencl_device_type")) { + case 0: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE; + break; + case 1: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ALL; + break; + case 2: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_DEFAULT; + break; + case 3: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_CPU; + break; + case 4: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_GPU; + break; + case 5: + flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR; + break; + } + /* Synchronize other OpenCL flags. */ + flags.opencl.debug = get_boolean(cscene, "debug_use_opencl_debug"); + return flags.opencl.device_type != opencl_device_type || + flags.opencl.kernel_type != opencl_kernel_type; +} + +/* Reset debug flags to default values. + * Return truth when device list needs invalidation. + */ +bool debug_flags_reset() +{ + DebugFlagsRef flags = DebugFlags(); + /* Backup some settings for comparison. */ + DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type; + DebugFlags::OpenCL::KernelType opencl_kernel_type = flags.opencl.kernel_type; + flags.reset(); + return flags.opencl.device_type != opencl_device_type || + flags.opencl.kernel_type != opencl_kernel_type; +} + +} /* namespace */ + void python_thread_state_save(void **python_thread_state) { *python_thread_state = (void*)PyEval_SaveThread(); @@ -57,19 +138,29 @@ void python_thread_state_restore(void **python_thread_state) static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce) { -#ifdef WIN32 - /* bug [#31856] oddly enough, Python3.2 --> 3.3 on Windows will throw an - * exception here this needs to be fixed in python: - * see: bugs.python.org/issue15859 */ - if(!PyUnicode_Check(py_str)) { - PyErr_BadArgument(); - return ""; + const char *result = _PyUnicode_AsString(py_str); + if(result) { + /* 99% of the time this is enough but we better support non unicode + * chars since blender doesnt limit this. + */ + return result; } -#endif - if((*coerce = PyUnicode_EncodeFSDefault(py_str))) { - return PyBytes_AS_STRING(*coerce); + else { + PyErr_Clear(); + if(PyBytes_Check(py_str)) { + return PyBytes_AS_STRING(py_str); + } + else if((*coerce = PyUnicode_EncodeFSDefault(py_str))) { + return PyBytes_AS_STRING(*coerce); + } + else { + /* Clear the error, so Cycles can be at leadt used without + * GPU and OSL support, + */ + PyErr_Clear(); + return ""; + } } - return ""; } static PyObject *init_func(PyObject * /*self*/, PyObject *args) @@ -89,6 +180,19 @@ static PyObject *init_func(PyObject * /*self*/, PyObject *args) BlenderSession::headless = headless; + VLOG(2) << "Debug flags initialized to:\n" + << DebugFlags(); + + Py_RETURN_NONE; +} + + +static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/) +{ + ShaderManager::free_memory(); + TaskScheduler::free_memory(); + Device::free_memory(); + device_list.free_memory(); Py_RETURN_NONE; } @@ -190,9 +294,9 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args) PyObject *pysession, *pyobject; PyObject *pypixel_array, *pyresult; const char *pass_type; - int num_pixels, depth, object_id; + int num_pixels, depth, object_id, pass_filter; - if(!PyArg_ParseTuple(args, "OOsiOiiO", &pysession, &pyobject, &pass_type, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult)) + if(!PyArg_ParseTuple(args, "OOsiiOiiO", &pysession, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult)) return NULL; BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession); @@ -209,7 +313,7 @@ static PyObject *bake_func(PyObject * /*self*/, PyObject *args) python_thread_state_save(&session->python_thread_state); - session->bake(b_object, pass_type, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result); + session->bake(b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result); python_thread_state_restore(&session->python_thread_state); @@ -491,17 +595,87 @@ static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/) static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/) { VLOG(2) << "Disabling OpenCL platform."; -#ifdef WIN32 - putenv("CYCLES_OPENCL_TEST=NONE"); -#else - setenv("CYCLES_OPENCL_TEST", "NONE", 1); -#endif + DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE; Py_RETURN_NONE; } #endif +static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args) +{ + PyObject *pyscene; + if(!PyArg_ParseTuple(args, "O", &pyscene)) { + return NULL; + } + + PointerRNA sceneptr; + RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr); + BL::Scene b_scene(sceneptr); + + if(debug_flags_sync_from_scene(b_scene)) { + VLOG(2) << "Tagging device list for update."; + Device::tag_update(); + } + + VLOG(2) << "Debug flags set to:\n" + << DebugFlags(); + + debug_flags_set = true; + + Py_RETURN_NONE; +} + +static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/) +{ + if(debug_flags_reset()) { + VLOG(2) << "Tagging device list for update."; + Device::tag_update(); + } + if(debug_flags_set) { + VLOG(2) << "Debug flags reset to:\n" + << DebugFlags(); + debug_flags_set = false; + } + Py_RETURN_NONE; +} + +static PyObject *set_resumable_chunks_func(PyObject * /*self*/, PyObject *args) +{ + int num_resumable_chunks, current_resumable_chunk; + if(!PyArg_ParseTuple(args, "ii", + &num_resumable_chunks, + ¤t_resumable_chunk)) { + Py_RETURN_NONE; + } + + if(num_resumable_chunks <= 0) { + fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n"); + abort(); + Py_RETURN_NONE; + } + if(current_resumable_chunk < 1 || + current_resumable_chunk > num_resumable_chunks) + { + fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n"); + abort(); + Py_RETURN_NONE; + } + + VLOG(1) << "Initialized resumable render: " + << "num_resumable_chunks=" << num_resumable_chunks << ", " + << "current_resumable_chunk=" << current_resumable_chunk; + BlenderSession::num_resumable_chunks = num_resumable_chunks; + BlenderSession::current_resumable_chunk = current_resumable_chunk; + + printf("Cycles: Will render chunk %d of %d\n", + current_resumable_chunk, + num_resumable_chunks); + + Py_RETURN_NONE; +} + static PyMethodDef methods[] = { {"init", init_func, METH_VARARGS, ""}, + {"exit", exit_func, METH_VARARGS, ""}, {"create", create_func, METH_VARARGS, ""}, {"free", free_func, METH_O, ""}, {"render", render_func, METH_O, ""}, @@ -518,6 +692,14 @@ static PyMethodDef methods[] = { #ifdef WITH_OPENCL {"opencl_disable", opencl_disable_func, METH_NOARGS, ""}, #endif + + /* Debugging routines */ + {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""}, + {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""}, + + /* Resumable render */ + {"set_resumable_chunks", set_resumable_chunks_func, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL}, }; @@ -532,10 +714,6 @@ static struct PyModuleDef module = { static 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(); |