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