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