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