Cycles: Make all #include statements relative to cycles source directory
[blender.git] / intern / cycles / blender / blender_python.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <Python.h>
18
19 #include "blender/CCL_api.h"
20
21 #include "blender/blender_sync.h"
22 #include "blender/blender_session.h"
23
24 #include "util/util_foreach.h"
25 #include "util/util_logging.h"
26 #include "util/util_md5.h"
27 #include "util/util_opengl.h"
28 #include "util/util_path.h"
29 #include "util/util_string.h"
30 #include "util/util_types.h"
31
32 #ifdef WITH_OSL
33 #include "render/osl.h"
34
35 #include <OSL/oslquery.h>
36 #include <OSL/oslconfig.h>
37 #endif
38
39 CCL_NAMESPACE_BEGIN
40
41 namespace {
42
43 /* Flag describing whether debug flags were synchronized from scene. */
44 bool debug_flags_set = false;
45
46 void *pylong_as_voidptr_typesafe(PyObject *object)
47 {
48         if(object == Py_None)
49                 return NULL;
50         return PyLong_AsVoidPtr(object);
51 }
52
53 /* Synchronize debug flags from a given Blender scene.
54  * Return truth when device list needs invalidation.
55  */
56 bool debug_flags_sync_from_scene(BL::Scene b_scene)
57 {
58         DebugFlagsRef flags = DebugFlags();
59         PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
60         /* Backup some settings for comparison. */
61         DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
62         DebugFlags::OpenCL::KernelType opencl_kernel_type = flags.opencl.kernel_type;
63         /* Synchronize CPU flags. */
64         flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
65         flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx");
66         flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41");
67         flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
68         flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
69         flags.cpu.qbvh = get_boolean(cscene, "debug_use_qbvh");
70         flags.cpu.split_kernel = get_boolean(cscene, "debug_use_cpu_split_kernel");
71         /* Synchronize CUDA flags. */
72         flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
73         flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel");
74         /* Synchronize OpenCL kernel type. */
75         switch(get_enum(cscene, "debug_opencl_kernel_type")) {
76                 case 0:
77                         flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_DEFAULT;
78                         break;
79                 case 1:
80                         flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_MEGA;
81                         break;
82                 case 2:
83                         flags.opencl.kernel_type = DebugFlags::OpenCL::KERNEL_SPLIT;
84                         break;
85         }
86         /* Synchronize OpenCL device type. */
87         switch(get_enum(cscene, "debug_opencl_device_type")) {
88                 case 0:
89                         flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
90                         break;
91                 case 1:
92                         flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ALL;
93                         break;
94                 case 2:
95                         flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_DEFAULT;
96                         break;
97                 case 3:
98                         flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_CPU;
99                         break;
100                 case 4:
101                         flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_GPU;
102                         break;
103                 case 5:
104                         flags.opencl.device_type = DebugFlags::OpenCL::DEVICE_ACCELERATOR;
105                         break;
106         }
107         /* Synchronize other OpenCL flags. */
108         flags.opencl.debug = get_boolean(cscene, "debug_use_opencl_debug");
109         flags.opencl.single_program = get_boolean(cscene, "debug_opencl_kernel_single_program");
110         return flags.opencl.device_type != opencl_device_type ||
111                flags.opencl.kernel_type != opencl_kernel_type;
112 }
113
114 /* Reset debug flags to default values.
115  * Return truth when device list needs invalidation.
116  */
117 bool debug_flags_reset()
118 {
119         DebugFlagsRef flags = DebugFlags();
120         /* Backup some settings for comparison. */
121         DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
122         DebugFlags::OpenCL::KernelType opencl_kernel_type = flags.opencl.kernel_type;
123         flags.reset();
124         return flags.opencl.device_type != opencl_device_type ||
125                flags.opencl.kernel_type != opencl_kernel_type;
126 }
127
128 }  /* namespace */
129
130 void python_thread_state_save(void **python_thread_state)
131 {
132         *python_thread_state = (void*)PyEval_SaveThread();
133 }
134
135 void python_thread_state_restore(void **python_thread_state)
136 {
137         PyEval_RestoreThread((PyThreadState*)*python_thread_state);
138         *python_thread_state = NULL;
139 }
140
141 static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
142 {
143         const char *result = _PyUnicode_AsString(py_str);
144         if(result) {
145                 /* 99% of the time this is enough but we better support non unicode
146                  * chars since blender doesnt limit this.
147                  */
148                 return result;
149         }
150         else {
151                 PyErr_Clear();
152                 if(PyBytes_Check(py_str)) {
153                         return PyBytes_AS_STRING(py_str);
154                 }
155                 else if((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
156                         return PyBytes_AS_STRING(*coerce);
157                 }
158                 else {
159                         /* Clear the error, so Cycles can be at leadt used without
160                          * GPU and OSL support,
161                          */
162                         PyErr_Clear();
163                         return "";
164                 }
165         }
166 }
167
168 static PyObject *init_func(PyObject * /*self*/, PyObject *args)
169 {
170         PyObject *path, *user_path;
171         int headless;
172
173         if(!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) {
174                 return NULL;
175         }
176
177         PyObject *path_coerce = NULL, *user_path_coerce = NULL;
178         path_init(PyC_UnicodeAsByte(path, &path_coerce),
179                   PyC_UnicodeAsByte(user_path, &user_path_coerce));
180         Py_XDECREF(path_coerce);
181         Py_XDECREF(user_path_coerce);
182
183         BlenderSession::headless = headless;
184
185         VLOG(2) << "Debug flags initialized to:\n"
186                 << DebugFlags();
187
188         Py_RETURN_NONE;
189 }
190
191
192 static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
193 {
194         ShaderManager::free_memory();
195         TaskScheduler::free_memory();
196         Device::free_memory();
197         Py_RETURN_NONE;
198 }
199
200 static PyObject *create_func(PyObject * /*self*/, PyObject *args)
201 {
202         PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
203         int preview_osl;
204
205         if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene,
206                              &pyregion, &pyv3d, &pyrv3d, &preview_osl))
207         {
208                 return NULL;
209         }
210
211         /* RNA */
212         PointerRNA engineptr;
213         RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
214         BL::RenderEngine engine(engineptr);
215
216         PointerRNA userprefptr;
217         RNA_pointer_create(NULL, &RNA_UserPreferences, (void*)PyLong_AsVoidPtr(pyuserpref), &userprefptr);
218         BL::UserPreferences userpref(userprefptr);
219
220         PointerRNA dataptr;
221         RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
222         BL::BlendData data(dataptr);
223
224         PointerRNA sceneptr;
225         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
226         BL::Scene scene(sceneptr);
227
228         PointerRNA regionptr;
229         RNA_pointer_create(NULL, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
230         BL::Region region(regionptr);
231
232         PointerRNA v3dptr;
233         RNA_pointer_create(NULL, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr);
234         BL::SpaceView3D v3d(v3dptr);
235
236         PointerRNA rv3dptr;
237         RNA_pointer_create(NULL, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr);
238         BL::RegionView3D rv3d(rv3dptr);
239
240         /* create session */
241         BlenderSession *session;
242
243         if(rv3d) {
244                 /* interactive viewport session */
245                 int width = region.width();
246                 int height = region.height();
247
248                 session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height);
249         }
250         else {
251                 /* override some settings for preview */
252                 if(engine.is_preview()) {
253                         PointerRNA cscene = RNA_pointer_get(&sceneptr, "cycles");
254
255                         RNA_boolean_set(&cscene, "shading_system", preview_osl);
256                         RNA_boolean_set(&cscene, "use_progressive_refine", true);
257                 }
258
259                 /* offline session or preview render */
260                 session = new BlenderSession(engine, userpref, data, scene);
261         }
262
263         python_thread_state_save(&session->python_thread_state);
264
265         session->create();
266
267         python_thread_state_restore(&session->python_thread_state);
268
269         return PyLong_FromVoidPtr(session);
270 }
271
272 static PyObject *free_func(PyObject * /*self*/, PyObject *value)
273 {
274         delete (BlenderSession*)PyLong_AsVoidPtr(value);
275
276         Py_RETURN_NONE;
277 }
278
279 static PyObject *render_func(PyObject * /*self*/, PyObject *value)
280 {
281         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
282
283         python_thread_state_save(&session->python_thread_state);
284
285         session->render();
286
287         python_thread_state_restore(&session->python_thread_state);
288
289         Py_RETURN_NONE;
290 }
291
292 /* pixel_array and result passed as pointers */
293 static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
294 {
295         PyObject *pysession, *pyobject;
296         PyObject *pypixel_array, *pyresult;
297         const char *pass_type;
298         int num_pixels, depth, object_id, pass_filter;
299
300         if(!PyArg_ParseTuple(args, "OOsiiOiiO", &pysession, &pyobject, &pass_type, &pass_filter, &object_id, &pypixel_array, &num_pixels, &depth, &pyresult))
301                 return NULL;
302
303         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
304
305         PointerRNA objectptr;
306         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyobject), &objectptr);
307         BL::Object b_object(objectptr);
308
309         void *b_result = PyLong_AsVoidPtr(pyresult);
310
311         PointerRNA bakepixelptr;
312         RNA_pointer_create(NULL, &RNA_BakePixel, PyLong_AsVoidPtr(pypixel_array), &bakepixelptr);
313         BL::BakePixel b_bake_pixel(bakepixelptr);
314
315         python_thread_state_save(&session->python_thread_state);
316
317         session->bake(b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
318
319         python_thread_state_restore(&session->python_thread_state);
320
321         Py_RETURN_NONE;
322 }
323
324 static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
325 {
326         PyObject *pysession, *pyv3d, *pyrv3d;
327
328         if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
329                 return NULL;
330         
331         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
332
333         if(PyLong_AsVoidPtr(pyrv3d)) {
334                 /* 3d view drawing */
335                 int viewport[4];
336                 glGetIntegerv(GL_VIEWPORT, viewport);
337
338                 session->draw(viewport[2], viewport[3]);
339         }
340
341         Py_RETURN_NONE;
342 }
343
344 static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
345 {
346         PyObject *pysession, *pydata, *pyscene;
347
348         if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pyscene))
349                 return NULL;
350
351         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
352
353         PointerRNA dataptr;
354         RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
355         BL::BlendData b_data(dataptr);
356
357         PointerRNA sceneptr;
358         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
359         BL::Scene b_scene(sceneptr);
360
361         python_thread_state_save(&session->python_thread_state);
362
363         session->reset_session(b_data, b_scene);
364
365         python_thread_state_restore(&session->python_thread_state);
366
367         Py_RETURN_NONE;
368 }
369
370 static PyObject *sync_func(PyObject * /*self*/, PyObject *value)
371 {
372         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
373
374         python_thread_state_save(&session->python_thread_state);
375
376         session->synchronize();
377
378         python_thread_state_restore(&session->python_thread_state);
379
380         Py_RETURN_NONE;
381 }
382
383 static PyObject *available_devices_func(PyObject * /*self*/, PyObject * /*args*/)
384 {
385         vector<DeviceInfo>& devices = Device::available_devices();
386         PyObject *ret = PyTuple_New(devices.size());
387
388         for(size_t i = 0; i < devices.size(); i++) {
389                 DeviceInfo& device = devices[i];
390                 string type_name = Device::string_from_type(device.type);
391                 PyObject *device_tuple = PyTuple_New(3);
392                 PyTuple_SET_ITEM(device_tuple, 0, PyUnicode_FromString(device.description.c_str()));
393                 PyTuple_SET_ITEM(device_tuple, 1, PyUnicode_FromString(type_name.c_str()));
394                 PyTuple_SET_ITEM(device_tuple, 2, PyUnicode_FromString(device.id.c_str()));
395                 PyTuple_SET_ITEM(ret, i, device_tuple);
396         }
397
398         return ret;
399 }
400
401 #ifdef WITH_OSL
402
403 static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
404 {
405         PyObject *pynodegroup, *pynode;
406         const char *filepath = NULL;
407
408         if(!PyArg_ParseTuple(args, "OOs", &pynodegroup, &pynode, &filepath))
409                 return NULL;
410
411         /* RNA */
412         PointerRNA nodeptr;
413         RNA_pointer_create((ID*)PyLong_AsVoidPtr(pynodegroup), &RNA_ShaderNodeScript, (void*)PyLong_AsVoidPtr(pynode), &nodeptr);
414         BL::ShaderNodeScript b_node(nodeptr);
415
416         /* update bytecode hash */
417         string bytecode = b_node.bytecode();
418
419         if(!bytecode.empty()) {
420                 MD5Hash md5;
421                 md5.append((const uint8_t*)bytecode.c_str(), bytecode.size());
422                 b_node.bytecode_hash(md5.get_hex().c_str());
423         }
424         else
425                 b_node.bytecode_hash("");
426
427         /* query from file path */
428         OSL::OSLQuery query;
429
430         if(!OSLShaderManager::osl_query(query, filepath))
431                 Py_RETURN_FALSE;
432
433         /* add new sockets from parameters */
434         set<void*> used_sockets;
435
436         for(int i = 0; i < query.nparams(); i++) {
437                 const OSL::OSLQuery::Parameter *param = query.getparam(i);
438
439                 /* skip unsupported types */
440                 if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
441                         continue;
442
443                 /* determine socket type */
444                 string socket_type;
445                 BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
446                 float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
447                 float default_float = 0.0f;
448                 int default_int = 0;
449                 string default_string = "";
450
451                 if(param->isclosure) {
452                         socket_type = "NodeSocketShader";
453                         data_type = BL::NodeSocket::type_SHADER;
454                 }
455                 else if(param->type.vecsemantics == TypeDesc::COLOR) {
456                         socket_type = "NodeSocketColor";
457                         data_type = BL::NodeSocket::type_RGBA;
458
459                         if(param->validdefault) {
460                                 default_float4[0] = param->fdefault[0];
461                                 default_float4[1] = param->fdefault[1];
462                                 default_float4[2] = param->fdefault[2];
463                         }
464                 }
465                 else if(param->type.vecsemantics == TypeDesc::POINT ||
466                         param->type.vecsemantics == TypeDesc::VECTOR ||
467                         param->type.vecsemantics == TypeDesc::NORMAL)
468                 {
469                         socket_type = "NodeSocketVector";
470                         data_type = BL::NodeSocket::type_VECTOR;
471
472                         if(param->validdefault) {
473                                 default_float4[0] = param->fdefault[0];
474                                 default_float4[1] = param->fdefault[1];
475                                 default_float4[2] = param->fdefault[2];
476                         }
477                 }
478                 else if(param->type.aggregate == TypeDesc::SCALAR) {
479                         if(param->type.basetype == TypeDesc::INT) {
480                                 socket_type = "NodeSocketInt";
481                                 data_type = BL::NodeSocket::type_INT;
482                                 if(param->validdefault)
483                                         default_int = param->idefault[0];
484                         }
485                         else if(param->type.basetype == TypeDesc::FLOAT) {
486                                 socket_type = "NodeSocketFloat";
487                                 data_type = BL::NodeSocket::type_VALUE;
488                                 if(param->validdefault)
489                                         default_float = param->fdefault[0];
490                         }
491                         else if(param->type.basetype == TypeDesc::STRING) {
492                                 socket_type = "NodeSocketString";
493                                 data_type = BL::NodeSocket::type_STRING;
494                                 if(param->validdefault)
495                                         default_string = param->sdefault[0];
496                         }
497                         else
498                                 continue;
499                 }
500                 else
501                         continue;
502
503                 /* find socket socket */
504                 BL::NodeSocket b_sock(PointerRNA_NULL);
505                 if(param->isoutput) {
506                         b_sock = b_node.outputs[param->name.string()];
507                         /* remove if type no longer matches */
508                         if(b_sock && b_sock.bl_idname() != socket_type) {
509                                 b_node.outputs.remove(b_sock);
510                                 b_sock = BL::NodeSocket(PointerRNA_NULL);
511                         }
512                 }
513                 else {
514                         b_sock = b_node.inputs[param->name.string()];
515                         /* remove if type no longer matches */
516                         if(b_sock && b_sock.bl_idname() != socket_type) {
517                                 b_node.inputs.remove(b_sock);
518                                 b_sock = BL::NodeSocket(PointerRNA_NULL);
519                         }
520                 }
521
522                 if(!b_sock) {
523                         /* create new socket */
524                         if(param->isoutput)
525                                 b_sock = b_node.outputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
526                         else
527                                 b_sock = b_node.inputs.create(socket_type.c_str(), param->name.c_str(), param->name.c_str());
528
529                         /* set default value */
530                         if(data_type == BL::NodeSocket::type_VALUE) {
531                                 set_float(b_sock.ptr, "default_value", default_float);
532                         }
533                         else if(data_type == BL::NodeSocket::type_INT) {
534                                 set_int(b_sock.ptr, "default_value", default_int);
535                         }
536                         else if(data_type == BL::NodeSocket::type_RGBA) {
537                                 set_float4(b_sock.ptr, "default_value", default_float4);
538                         }
539                         else if(data_type == BL::NodeSocket::type_VECTOR) {
540                                 set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
541                         }
542                         else if(data_type == BL::NodeSocket::type_STRING) {
543                                 set_string(b_sock.ptr, "default_value", default_string);
544                         }
545                 }
546
547                 used_sockets.insert(b_sock.ptr.data);
548         }
549
550         /* remove unused parameters */
551         bool removed;
552
553         do {
554                 BL::Node::inputs_iterator b_input;
555                 BL::Node::outputs_iterator b_output;
556
557                 removed = false;
558
559                 for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
560                         if(used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
561                                 b_node.inputs.remove(*b_input);
562                                 removed = true;
563                                 break;
564                         }
565                 }
566
567                 for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
568                         if(used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
569                                 b_node.outputs.remove(*b_output);
570                                 removed = true;
571                                 break;
572                         }
573                 }
574         } while(removed);
575
576         Py_RETURN_TRUE;
577 }
578
579 static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
580 {
581         const char *inputfile = NULL, *outputfile = NULL;
582
583         if(!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile))
584                 return NULL;
585         
586         /* return */
587         if(!OSLShaderManager::osl_compile(inputfile, outputfile))
588                 Py_RETURN_FALSE;
589
590         Py_RETURN_TRUE;
591 }
592 #endif
593
594 static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
595 {
596         string system_info = Device::device_capabilities();
597         return PyUnicode_FromString(system_info.c_str());
598 }
599
600 #ifdef WITH_OPENCL
601 static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/)
602 {
603         VLOG(2) << "Disabling OpenCL platform.";
604         DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
605         Py_RETURN_NONE;
606 }
607 #endif
608
609 static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
610 {
611         PyObject *pyscene;
612         if(!PyArg_ParseTuple(args, "O", &pyscene)) {
613                 return NULL;
614         }
615
616         PointerRNA sceneptr;
617         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
618         BL::Scene b_scene(sceneptr);
619
620         if(debug_flags_sync_from_scene(b_scene)) {
621                 VLOG(2) << "Tagging device list for update.";
622                 Device::tag_update();
623         }
624
625         VLOG(2) << "Debug flags set to:\n"
626                 << DebugFlags();
627
628         debug_flags_set = true;
629
630         Py_RETURN_NONE;
631 }
632
633 static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
634 {
635         if(debug_flags_reset()) {
636                 VLOG(2) << "Tagging device list for update.";
637                 Device::tag_update();
638         }
639         if(debug_flags_set) {
640                 VLOG(2) << "Debug flags reset to:\n"
641                         << DebugFlags();
642                 debug_flags_set = false;
643         }
644         Py_RETURN_NONE;
645 }
646
647 static PyObject *set_resumable_chunk_func(PyObject * /*self*/, PyObject *args)
648 {
649         int num_resumable_chunks, current_resumable_chunk;
650         if(!PyArg_ParseTuple(args, "ii",
651                              &num_resumable_chunks,
652                              &current_resumable_chunk)) {
653                 Py_RETURN_NONE;
654         }
655
656         if(num_resumable_chunks <= 0) {
657                 fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
658                 abort();
659                 Py_RETURN_NONE;
660         }
661         if(current_resumable_chunk < 1 ||
662            current_resumable_chunk > num_resumable_chunks)
663         {
664                 fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n");
665                 abort();
666                 Py_RETURN_NONE;
667         }
668
669         VLOG(1) << "Initialized resumable render: "
670                 << "num_resumable_chunks=" << num_resumable_chunks << ", "
671                 << "current_resumable_chunk=" << current_resumable_chunk;
672         BlenderSession::num_resumable_chunks = num_resumable_chunks;
673         BlenderSession::current_resumable_chunk = current_resumable_chunk;
674
675         printf("Cycles: Will render chunk %d of %d\n",
676                current_resumable_chunk,
677                num_resumable_chunks);
678
679         Py_RETURN_NONE;
680 }
681
682 static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *args)
683 {
684         int num_chunks, start_chunk, end_chunk;
685         if(!PyArg_ParseTuple(args, "iii",
686                              &num_chunks,
687                              &start_chunk,
688                              &end_chunk)) {
689                 Py_RETURN_NONE;
690         }
691
692         if(num_chunks <= 0) {
693                 fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
694                 abort();
695                 Py_RETURN_NONE;
696         }
697         if(start_chunk < 1 || start_chunk > num_chunks) {
698                 fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
699                 abort();
700                 Py_RETURN_NONE;
701         }
702         if(end_chunk < 1 || end_chunk > num_chunks) {
703                 fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
704                 abort();
705                 Py_RETURN_NONE;
706         }
707         if(start_chunk > end_chunk) {
708                 fprintf(stderr, "Cycles: End chunk should be higher than start one.\n");
709                 abort();
710                 Py_RETURN_NONE;
711         }
712
713         VLOG(1) << "Initialized resumable render: "
714                 << "num_resumable_chunks=" << num_chunks << ", "
715                 << "start_resumable_chunk=" << start_chunk
716                 << "end_resumable_chunk=" << end_chunk;
717         BlenderSession::num_resumable_chunks = num_chunks;
718         BlenderSession::start_resumable_chunk = start_chunk;
719         BlenderSession::end_resumable_chunk = end_chunk;
720
721         printf("Cycles: Will render chunks %d to %d of %d\n",
722                start_chunk,
723                end_chunk,
724                num_chunks);
725
726         Py_RETURN_NONE;
727 }
728
729 static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
730 {
731         vector<DeviceInfo>& devices = Device::available_devices();
732         bool has_cuda = false, has_opencl = false;
733         for(int i = 0; i < devices.size(); i++) {
734                 has_cuda   |= (devices[i].type == DEVICE_CUDA);
735                 has_opencl |= (devices[i].type == DEVICE_OPENCL);
736         }
737         PyObject *list = PyTuple_New(2);
738         PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
739         PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_opencl));
740         return list;
741 }
742
743 static PyMethodDef methods[] = {
744         {"init", init_func, METH_VARARGS, ""},
745         {"exit", exit_func, METH_VARARGS, ""},
746         {"create", create_func, METH_VARARGS, ""},
747         {"free", free_func, METH_O, ""},
748         {"render", render_func, METH_O, ""},
749         {"bake", bake_func, METH_VARARGS, ""},
750         {"draw", draw_func, METH_VARARGS, ""},
751         {"sync", sync_func, METH_O, ""},
752         {"reset", reset_func, METH_VARARGS, ""},
753 #ifdef WITH_OSL
754         {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
755         {"osl_compile", osl_compile_func, METH_VARARGS, ""},
756 #endif
757         {"available_devices", available_devices_func, METH_NOARGS, ""},
758         {"system_info", system_info_func, METH_NOARGS, ""},
759 #ifdef WITH_OPENCL
760         {"opencl_disable", opencl_disable_func, METH_NOARGS, ""},
761 #endif
762
763         /* Debugging routines */
764         {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
765         {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
766
767         /* Resumable render */
768         {"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""},
769         {"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""},
770
771         /* Compute Device selection */
772         {"get_device_types", get_device_types_func, METH_VARARGS, ""},
773
774         {NULL, NULL, 0, NULL},
775 };
776
777 static struct PyModuleDef module = {
778         PyModuleDef_HEAD_INIT,
779         "_cycles",
780         "Blender cycles render integration",
781         -1,
782         methods,
783         NULL, NULL, NULL, NULL
784 };
785
786 CCL_NAMESPACE_END
787
788 void *CCL_python_module_init()
789 {
790         PyObject *mod = PyModule_Create(&ccl::module);
791
792 #ifdef WITH_OSL
793         /* TODO(sergey): This gives us library we've been linking against.
794          *               In theory with dynamic OSL library it might not be
795          *               accurate, but there's nothing in OSL API which we
796          *               might use to get version in runtime.
797          */
798         int curversion = OSL_LIBRARY_VERSION_CODE;
799         PyModule_AddObject(mod, "with_osl", Py_True);
800         Py_INCREF(Py_True);
801         PyModule_AddObject(mod, "osl_version",
802                            Py_BuildValue("(iii)",
803                                           curversion / 10000, (curversion / 100) % 100, curversion % 100));
804         PyModule_AddObject(mod, "osl_version_string",
805                            PyUnicode_FromFormat("%2d, %2d, %2d",
806                                                 curversion / 10000, (curversion / 100) % 100, curversion % 100));
807 #else
808         PyModule_AddObject(mod, "with_osl", Py_False);
809         Py_INCREF(Py_False);
810         PyModule_AddStringConstant(mod, "osl_version", "unknown");
811         PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
812 #endif
813
814 #ifdef WITH_NETWORK
815         PyModule_AddObject(mod, "with_network", Py_True);
816         Py_INCREF(Py_True);
817 #else /* WITH_NETWORK */
818         PyModule_AddObject(mod, "with_network", Py_False);
819         Py_INCREF(Py_False);
820 #endif /* WITH_NETWORK */
821
822         return (void*)mod;
823 }