Cycles: add cycles.merge_images operator for combing EXR renders.
[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_device.h"
22 #include "blender/blender_sync.h"
23 #include "blender/blender_session.h"
24
25 #include "render/denoising.h"
26 #include "render/merge.h"
27
28 #include "util/util_debug.h"
29 #include "util/util_foreach.h"
30 #include "util/util_logging.h"
31 #include "util/util_md5.h"
32 #include "util/util_opengl.h"
33 #include "util/util_path.h"
34 #include "util/util_string.h"
35 #include "util/util_types.h"
36
37 #ifdef WITH_OSL
38 #include "render/osl.h"
39
40 #include <OSL/oslquery.h>
41 #include <OSL/oslconfig.h>
42 #endif
43
44 #ifdef WITH_OPENCL
45 #include "device/device_intern.h"
46 #endif
47
48 CCL_NAMESPACE_BEGIN
49
50 namespace {
51
52 /* Flag describing whether debug flags were synchronized from scene. */
53 bool debug_flags_set = false;
54
55 void *pylong_as_voidptr_typesafe(PyObject *object)
56 {
57         if(object == Py_None)
58                 return NULL;
59         return PyLong_AsVoidPtr(object);
60 }
61
62 /* Synchronize debug flags from a given Blender scene.
63  * Return truth when device list needs invalidation.
64  */
65 bool debug_flags_sync_from_scene(BL::Scene b_scene)
66 {
67         DebugFlagsRef flags = DebugFlags();
68         PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
69         /* Backup some settings for comparison. */
70         DebugFlags::OpenCL::DeviceType opencl_device_type = flags.opencl.device_type;
71         /* Synchronize shared flags. */
72         flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type");
73         /* Synchronize CPU flags. */
74         flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
75         flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx");
76         flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41");
77         flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
78         flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
79         flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
80         flags.cpu.split_kernel = get_boolean(cscene, "debug_use_cpu_split_kernel");
81         /* Synchronize CUDA flags. */
82         flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
83         flags.cuda.split_kernel = get_boolean(cscene, "debug_use_cuda_split_kernel");
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         flags.opencl.mem_limit = ((size_t)get_int(cscene, "debug_opencl_mem_limit"))*1024*1024;
108         return flags.opencl.device_type != opencl_device_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         flags.reset();
120         return flags.opencl.device_type != opencl_device_type;
121 }
122
123 }  /* namespace */
124
125 void python_thread_state_save(void **python_thread_state)
126 {
127         *python_thread_state = (void*)PyEval_SaveThread();
128 }
129
130 void python_thread_state_restore(void **python_thread_state)
131 {
132         PyEval_RestoreThread((PyThreadState*)*python_thread_state);
133         *python_thread_state = NULL;
134 }
135
136 static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
137 {
138         const char *result = _PyUnicode_AsString(py_str);
139         if(result) {
140                 /* 99% of the time this is enough but we better support non unicode
141                  * chars since blender doesnt limit this.
142                  */
143                 return result;
144         }
145         else {
146                 PyErr_Clear();
147                 if(PyBytes_Check(py_str)) {
148                         return PyBytes_AS_STRING(py_str);
149                 }
150                 else if((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
151                         return PyBytes_AS_STRING(*coerce);
152                 }
153                 else {
154                         /* Clear the error, so Cycles can be at leadt used without
155                          * GPU and OSL support,
156                          */
157                         PyErr_Clear();
158                         return "";
159                 }
160         }
161 }
162
163 static PyObject *init_func(PyObject * /*self*/, PyObject *args)
164 {
165         PyObject *path, *user_path;
166         int headless;
167
168         if(!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) {
169                 return NULL;
170         }
171
172         PyObject *path_coerce = NULL, *user_path_coerce = NULL;
173         path_init(PyC_UnicodeAsByte(path, &path_coerce),
174                   PyC_UnicodeAsByte(user_path, &user_path_coerce));
175         Py_XDECREF(path_coerce);
176         Py_XDECREF(user_path_coerce);
177
178         BlenderSession::headless = headless;
179
180         VLOG(2) << "Debug flags initialized to:\n"
181                 << DebugFlags();
182
183         Py_RETURN_NONE;
184 }
185
186
187 static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
188 {
189         ShaderManager::free_memory();
190         TaskScheduler::free_memory();
191         Device::free_memory();
192         Py_RETURN_NONE;
193 }
194
195 static PyObject *create_func(PyObject * /*self*/, PyObject *args)
196 {
197         PyObject *pyengine, *pyuserpref, *pydata, *pyscene, *pyregion, *pyv3d, *pyrv3d;
198         int preview_osl;
199
200         if(!PyArg_ParseTuple(args, "OOOOOOOi", &pyengine, &pyuserpref, &pydata, &pyscene,
201                              &pyregion, &pyv3d, &pyrv3d, &preview_osl))
202         {
203                 return NULL;
204         }
205
206         /* RNA */
207         PointerRNA engineptr;
208         RNA_pointer_create(NULL, &RNA_RenderEngine, (void*)PyLong_AsVoidPtr(pyengine), &engineptr);
209         BL::RenderEngine engine(engineptr);
210
211         PointerRNA userprefptr;
212         RNA_pointer_create(NULL, &RNA_UserPreferences, (void*)PyLong_AsVoidPtr(pyuserpref), &userprefptr);
213         BL::UserPreferences userpref(userprefptr);
214
215         PointerRNA dataptr;
216         RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
217         BL::BlendData data(dataptr);
218
219         PointerRNA sceneptr;
220         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
221         BL::Scene scene(sceneptr);
222
223         PointerRNA regionptr;
224         RNA_pointer_create(NULL, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
225         BL::Region region(regionptr);
226
227         PointerRNA v3dptr;
228         RNA_pointer_create(NULL, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr);
229         BL::SpaceView3D v3d(v3dptr);
230
231         PointerRNA rv3dptr;
232         RNA_pointer_create(NULL, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr);
233         BL::RegionView3D rv3d(rv3dptr);
234
235         /* create session */
236         BlenderSession *session;
237
238         if(rv3d) {
239                 /* interactive viewport session */
240                 int width = region.width();
241                 int height = region.height();
242
243                 session = new BlenderSession(engine, userpref, data, scene, v3d, rv3d, width, height);
244         }
245         else {
246                 /* override some settings for preview */
247                 if(engine.is_preview()) {
248                         PointerRNA cscene = RNA_pointer_get(&sceneptr, "cycles");
249
250                         RNA_boolean_set(&cscene, "shading_system", preview_osl);
251                         RNA_boolean_set(&cscene, "use_progressive_refine", true);
252                 }
253
254                 /* offline session or preview render */
255                 session = new BlenderSession(engine, userpref, data, scene);
256         }
257
258         python_thread_state_save(&session->python_thread_state);
259
260         session->create();
261
262         python_thread_state_restore(&session->python_thread_state);
263
264         return PyLong_FromVoidPtr(session);
265 }
266
267 static PyObject *free_func(PyObject * /*self*/, PyObject *value)
268 {
269         delete (BlenderSession*)PyLong_AsVoidPtr(value);
270
271         Py_RETURN_NONE;
272 }
273
274 static PyObject *render_func(PyObject * /*self*/, PyObject *value)
275 {
276         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
277
278         python_thread_state_save(&session->python_thread_state);
279
280         session->render();
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, *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, "OOsiiOiiO", &pysession, &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 objectptr;
301         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyobject), &objectptr);
302         BL::Object b_object(objectptr);
303
304         void *b_result = PyLong_AsVoidPtr(pyresult);
305
306         PointerRNA bakepixelptr;
307         RNA_pointer_create(NULL, &RNA_BakePixel, PyLong_AsVoidPtr(pypixel_array), &bakepixelptr);
308         BL::BakePixel b_bake_pixel(bakepixelptr);
309
310         python_thread_state_save(&session->python_thread_state);
311
312         session->bake(b_object, pass_type, pass_filter, object_id, b_bake_pixel, (size_t)num_pixels, depth, (float *)b_result);
313
314         python_thread_state_restore(&session->python_thread_state);
315
316         Py_RETURN_NONE;
317 }
318
319 static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
320 {
321         PyObject *pysession, *pyv3d, *pyrv3d;
322
323         if(!PyArg_ParseTuple(args, "OOO", &pysession, &pyv3d, &pyrv3d))
324                 return NULL;
325
326         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
327
328         if(PyLong_AsVoidPtr(pyrv3d)) {
329                 /* 3d view drawing */
330                 int viewport[4];
331                 glGetIntegerv(GL_VIEWPORT, viewport);
332
333                 session->draw(viewport[2], viewport[3]);
334         }
335
336         Py_RETURN_NONE;
337 }
338
339 static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
340 {
341         PyObject *pysession, *pydata, *pyscene;
342
343         if(!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pyscene))
344                 return NULL;
345
346         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(pysession);
347
348         PointerRNA dataptr;
349         RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
350         BL::BlendData b_data(dataptr);
351
352         PointerRNA sceneptr;
353         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
354         BL::Scene b_scene(sceneptr);
355
356         python_thread_state_save(&session->python_thread_state);
357
358         session->reset_session(b_data, b_scene);
359
360         python_thread_state_restore(&session->python_thread_state);
361
362         Py_RETURN_NONE;
363 }
364
365 static PyObject *sync_func(PyObject * /*self*/, PyObject *value)
366 {
367         BlenderSession *session = (BlenderSession*)PyLong_AsVoidPtr(value);
368
369         python_thread_state_save(&session->python_thread_state);
370
371         session->synchronize();
372
373         python_thread_state_restore(&session->python_thread_state);
374
375         Py_RETURN_NONE;
376 }
377
378 static PyObject *available_devices_func(PyObject * /*self*/, PyObject * args)
379 {
380         const char *type_name;
381         if(!PyArg_ParseTuple(args, "s", &type_name)) {
382                 return NULL;
383         }
384
385         DeviceType type = Device::type_from_string(type_name);
386         uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type);
387         mask |= DEVICE_MASK_CPU;
388
389         vector<DeviceInfo> devices = Device::available_devices(mask);
390         PyObject *ret = PyTuple_New(devices.size());
391
392         for(size_t i = 0; i < devices.size(); i++) {
393                 DeviceInfo& device = devices[i];
394                 string type_name = Device::string_from_type(device.type);
395                 PyObject *device_tuple = PyTuple_New(3);
396                 PyTuple_SET_ITEM(device_tuple, 0, PyUnicode_FromString(device.description.c_str()));
397                 PyTuple_SET_ITEM(device_tuple, 1, PyUnicode_FromString(type_name.c_str()));
398                 PyTuple_SET_ITEM(device_tuple, 2, PyUnicode_FromString(device.id.c_str()));
399                 PyTuple_SET_ITEM(ret, i, device_tuple);
400         }
401
402         return ret;
403 }
404
405 #ifdef WITH_OSL
406
407 static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
408 {
409         PyObject *pydata, *pynodegroup, *pynode;
410         const char *filepath = NULL;
411
412         if(!PyArg_ParseTuple(args, "OOOs", &pydata, &pynodegroup, &pynode, &filepath))
413                 return NULL;
414
415         /* RNA */
416         PointerRNA dataptr;
417         RNA_main_pointer_create((Main*)PyLong_AsVoidPtr(pydata), &dataptr);
418         BL::BlendData b_data(dataptr);
419
420         PointerRNA nodeptr;
421         RNA_pointer_create((ID*)PyLong_AsVoidPtr(pynodegroup), &RNA_ShaderNodeScript, (void*)PyLong_AsVoidPtr(pynode), &nodeptr);
422         BL::ShaderNodeScript b_node(nodeptr);
423
424         /* update bytecode hash */
425         string bytecode = b_node.bytecode();
426
427         if(!bytecode.empty()) {
428                 MD5Hash md5;
429                 md5.append((const uint8_t*)bytecode.c_str(), bytecode.size());
430                 b_node.bytecode_hash(md5.get_hex().c_str());
431         }
432         else
433                 b_node.bytecode_hash("");
434
435         /* query from file path */
436         OSL::OSLQuery query;
437
438         if(!OSLShaderManager::osl_query(query, filepath))
439                 Py_RETURN_FALSE;
440
441         /* add new sockets from parameters */
442         set<void*> used_sockets;
443
444         for(int i = 0; i < query.nparams(); i++) {
445                 const OSL::OSLQuery::Parameter *param = query.getparam(i);
446
447                 /* skip unsupported types */
448                 if(param->varlenarray || param->isstruct || param->type.arraylen > 1)
449                         continue;
450
451                 /* determine socket type */
452                 string socket_type;
453                 BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
454                 float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
455                 float default_float = 0.0f;
456                 int default_int = 0;
457                 string default_string = "";
458
459                 if(param->isclosure) {
460                         socket_type = "NodeSocketShader";
461                         data_type = BL::NodeSocket::type_SHADER;
462                 }
463                 else if(param->type.vecsemantics == TypeDesc::COLOR) {
464                         socket_type = "NodeSocketColor";
465                         data_type = BL::NodeSocket::type_RGBA;
466
467                         if(param->validdefault) {
468                                 default_float4[0] = param->fdefault[0];
469                                 default_float4[1] = param->fdefault[1];
470                                 default_float4[2] = param->fdefault[2];
471                         }
472                 }
473                 else if(param->type.vecsemantics == TypeDesc::POINT ||
474                         param->type.vecsemantics == TypeDesc::VECTOR ||
475                         param->type.vecsemantics == TypeDesc::NORMAL)
476                 {
477                         socket_type = "NodeSocketVector";
478                         data_type = BL::NodeSocket::type_VECTOR;
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.aggregate == TypeDesc::SCALAR) {
487                         if(param->type.basetype == TypeDesc::INT) {
488                                 socket_type = "NodeSocketInt";
489                                 data_type = BL::NodeSocket::type_INT;
490                                 if(param->validdefault)
491                                         default_int = param->idefault[0];
492                         }
493                         else if(param->type.basetype == TypeDesc::FLOAT) {
494                                 socket_type = "NodeSocketFloat";
495                                 data_type = BL::NodeSocket::type_VALUE;
496                                 if(param->validdefault)
497                                         default_float = param->fdefault[0];
498                         }
499                         else if(param->type.basetype == TypeDesc::STRING) {
500                                 socket_type = "NodeSocketString";
501                                 data_type = BL::NodeSocket::type_STRING;
502                                 if(param->validdefault)
503                                         default_string = param->sdefault[0].string();
504                         }
505                         else
506                                 continue;
507                 }
508                 else
509                         continue;
510
511                 /* find socket socket */
512                 BL::NodeSocket b_sock(PointerRNA_NULL);
513                 if(param->isoutput) {
514                         b_sock = b_node.outputs[param->name.string()];
515                         /* remove if type no longer matches */
516                         if(b_sock && b_sock.bl_idname() != socket_type) {
517                                 b_node.outputs.remove(b_data, b_sock);
518                                 b_sock = BL::NodeSocket(PointerRNA_NULL);
519                         }
520                 }
521                 else {
522                         b_sock = b_node.inputs[param->name.string()];
523                         /* remove if type no longer matches */
524                         if(b_sock && b_sock.bl_idname() != socket_type) {
525                                 b_node.inputs.remove(b_data, b_sock);
526                                 b_sock = BL::NodeSocket(PointerRNA_NULL);
527                         }
528                 }
529
530                 if(!b_sock) {
531                         /* create new socket */
532                         if(param->isoutput)
533                                 b_sock = b_node.outputs.create(b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str());
534                         else
535                                 b_sock = b_node.inputs.create(b_data, socket_type.c_str(), param->name.c_str(), param->name.c_str());
536
537                         /* set default value */
538                         if(data_type == BL::NodeSocket::type_VALUE) {
539                                 set_float(b_sock.ptr, "default_value", default_float);
540                         }
541                         else if(data_type == BL::NodeSocket::type_INT) {
542                                 set_int(b_sock.ptr, "default_value", default_int);
543                         }
544                         else if(data_type == BL::NodeSocket::type_RGBA) {
545                                 set_float4(b_sock.ptr, "default_value", default_float4);
546                         }
547                         else if(data_type == BL::NodeSocket::type_VECTOR) {
548                                 set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
549                         }
550                         else if(data_type == BL::NodeSocket::type_STRING) {
551                                 set_string(b_sock.ptr, "default_value", default_string);
552                         }
553                 }
554
555                 used_sockets.insert(b_sock.ptr.data);
556         }
557
558         /* remove unused parameters */
559         bool removed;
560
561         do {
562                 BL::Node::inputs_iterator b_input;
563                 BL::Node::outputs_iterator b_output;
564
565                 removed = false;
566
567                 for(b_node.inputs.begin(b_input); b_input != b_node.inputs.end(); ++b_input) {
568                         if(used_sockets.find(b_input->ptr.data) == used_sockets.end()) {
569                                 b_node.inputs.remove(b_data, *b_input);
570                                 removed = true;
571                                 break;
572                         }
573                 }
574
575                 for(b_node.outputs.begin(b_output); b_output != b_node.outputs.end(); ++b_output) {
576                         if(used_sockets.find(b_output->ptr.data) == used_sockets.end()) {
577                                 b_node.outputs.remove(b_data, *b_output);
578                                 removed = true;
579                                 break;
580                         }
581                 }
582         } while(removed);
583
584         Py_RETURN_TRUE;
585 }
586
587 static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
588 {
589         const char *inputfile = NULL, *outputfile = NULL;
590
591         if(!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile))
592                 return NULL;
593
594         /* return */
595         if(!OSLShaderManager::osl_compile(inputfile, outputfile))
596                 Py_RETURN_FALSE;
597
598         Py_RETURN_TRUE;
599 }
600 #endif
601
602 static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
603 {
604         string system_info = Device::device_capabilities();
605         return PyUnicode_FromString(system_info.c_str());
606 }
607
608 #ifdef WITH_OPENCL
609 static PyObject *opencl_disable_func(PyObject * /*self*/, PyObject * /*value*/)
610 {
611         VLOG(2) << "Disabling OpenCL platform.";
612         DebugFlags().opencl.device_type = DebugFlags::OpenCL::DEVICE_NONE;
613         Py_RETURN_NONE;
614 }
615
616 static PyObject *opencl_compile_func(PyObject * /*self*/, PyObject *args)
617 {
618         PyObject *sequence = PySequence_Fast(args, "Arguments must be a sequence");
619         if(sequence == NULL) {
620                 Py_RETURN_FALSE;
621         }
622
623         vector<string> parameters;
624         for(Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
625                 PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
626                 PyObject *item_as_string = PyObject_Str(item);
627                 const char *parameter_string = PyUnicode_AsUTF8(item_as_string);
628                 parameters.push_back(parameter_string);
629                 Py_DECREF(item_as_string);
630         }
631         Py_DECREF(sequence);
632
633         if (device_opencl_compile_kernel(parameters)) {
634                 Py_RETURN_TRUE;
635         }
636         else {
637                 Py_RETURN_FALSE;
638         }
639 }
640 #endif
641
642 static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string>& filepaths)
643 {
644         if(PyUnicode_Check(pyfilepaths)) {
645                 const char *filepath = PyUnicode_AsUTF8(pyfilepaths);
646                 filepaths.push_back(filepath);
647                 return true;
648         }
649
650         PyObject *sequence = PySequence_Fast(pyfilepaths, "File paths must be a string or sequence of strings");
651         if(sequence == NULL) {
652                 return false;
653         }
654
655         for(Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
656                 PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
657                 const char *filepath = PyUnicode_AsUTF8(item);
658                 if(filepath == NULL) {
659                         PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings.");
660                         Py_DECREF(sequence);
661                         return false;
662                 }
663                 filepaths.push_back(filepath);
664         }
665         Py_DECREF(sequence);
666
667         return true;
668 }
669
670 static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
671 {
672         static const char *keyword_list[] = {"preferences", "scene", "view_layer",
673                                              "input", "output",
674                                              "tile_size", "samples", NULL};
675         PyObject *pypreferences, *pyscene, *pyrenderlayer;
676         PyObject *pyinput, *pyoutput = NULL;
677         int tile_size = 0, samples = 0;
678
679         if (!PyArg_ParseTupleAndKeywords(args, keywords, "OOOO|Oii", (char**)keyword_list,
680                                          &pypreferences, &pyscene, &pyrenderlayer,
681                                                                          &pyinput, &pyoutput,
682                                          &tile_size, &samples)) {
683                 return NULL;
684         }
685
686         /* Get device specification from preferences and scene. */
687         PointerRNA preferencesptr;
688         RNA_pointer_create(NULL, &RNA_UserPreferences, (void*)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
689         BL::UserPreferences b_preferences(preferencesptr);
690
691         PointerRNA sceneptr;
692         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
693         BL::Scene b_scene(sceneptr);
694
695         DeviceInfo device = blender_device_info(b_preferences, b_scene, true);
696
697         /* Get denoising parameters from view layer. */
698         PointerRNA renderlayerptr;
699         RNA_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &RNA_SceneRenderLayer, PyLong_AsVoidPtr(pyrenderlayer), &renderlayerptr);
700         PointerRNA crenderlayer = RNA_pointer_get(&renderlayerptr, "cycles");
701
702         DenoiseParams params;
703         params.radius = get_int(crenderlayer, "denoising_radius");
704         params.strength = get_float(crenderlayer, "denoising_strength");
705         params.feature_strength = get_float(crenderlayer, "denoising_feature_strength");
706         params.relative_pca = get_boolean(crenderlayer, "denoising_relative_pca");
707         params.neighbor_frames = get_int(crenderlayer, "denoising_neighbor_frames");
708
709         /* Parse file paths list. */
710         vector<string> input, output;
711
712         if(!image_parse_filepaths(pyinput, input)) {
713                 return NULL;
714         }
715
716         if(pyoutput) {
717                 if(!image_parse_filepaths(pyoutput, output)) {
718                         return NULL;
719                 }
720         }
721         else {
722                 output = input;
723         }
724
725         if(input.empty()) {
726                 PyErr_SetString(PyExc_ValueError, "No input file paths specified.");
727                 return NULL;
728         }
729         if(input.size() != output.size()) {
730                 PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match.");
731                 return NULL;
732         }
733
734         /* Create denoiser. */
735         Denoiser denoiser(device);
736         denoiser.params = params;
737         denoiser.input = input;
738         denoiser.output = output;
739
740         if (tile_size > 0) {
741                 denoiser.tile_size = make_int2(tile_size, tile_size);
742         }
743         if (samples > 0) {
744                 denoiser.samples_override = samples;
745         }
746
747         /* Run denoiser. */
748         if(!denoiser.run()) {
749                 PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
750                 return NULL;
751         }
752
753         Py_RETURN_NONE;
754 }
755
756 static PyObject *merge_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
757 {
758         static const char *keyword_list[] = {"input", "output", NULL};
759         PyObject *pyinput, *pyoutput = NULL;
760
761         if (!PyArg_ParseTupleAndKeywords(args, keywords, "OO", (char**)keyword_list, &pyinput, &pyoutput)) {
762                 return NULL;
763         }
764
765         /* Parse input list. */
766         vector<string> input;
767         if(!image_parse_filepaths(pyinput, input)) {
768                 return NULL;
769         }
770
771         /* Parse output string. */
772         if(!PyUnicode_Check(pyoutput)) {
773                 PyErr_SetString(PyExc_ValueError, "Output must be a string.");
774                 return NULL;
775         }
776         string output = PyUnicode_AsUTF8(pyoutput);
777
778         /* Merge. */
779         ImageMerger merger;
780         merger.input = input;
781         merger.output = output;
782
783         if(!merger.run()) {
784                 PyErr_SetString(PyExc_ValueError, merger.error.c_str());
785                 return NULL;
786         }
787
788         Py_RETURN_NONE;
789 }
790
791
792 static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
793 {
794         PyObject *pyscene;
795         if(!PyArg_ParseTuple(args, "O", &pyscene)) {
796                 return NULL;
797         }
798
799         PointerRNA sceneptr;
800         RNA_id_pointer_create((ID*)PyLong_AsVoidPtr(pyscene), &sceneptr);
801         BL::Scene b_scene(sceneptr);
802
803         if(debug_flags_sync_from_scene(b_scene)) {
804                 VLOG(2) << "Tagging device list for update.";
805                 Device::tag_update();
806         }
807
808         VLOG(2) << "Debug flags set to:\n"
809                 << DebugFlags();
810
811         debug_flags_set = true;
812
813         Py_RETURN_NONE;
814 }
815
816 static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
817 {
818         if(debug_flags_reset()) {
819                 VLOG(2) << "Tagging device list for update.";
820                 Device::tag_update();
821         }
822         if(debug_flags_set) {
823                 VLOG(2) << "Debug flags reset to:\n"
824                         << DebugFlags();
825                 debug_flags_set = false;
826         }
827         Py_RETURN_NONE;
828 }
829
830 static PyObject *set_resumable_chunk_func(PyObject * /*self*/, PyObject *args)
831 {
832         int num_resumable_chunks, current_resumable_chunk;
833         if(!PyArg_ParseTuple(args, "ii",
834                              &num_resumable_chunks,
835                              &current_resumable_chunk)) {
836                 Py_RETURN_NONE;
837         }
838
839         if(num_resumable_chunks <= 0) {
840                 fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
841                 abort();
842                 Py_RETURN_NONE;
843         }
844         if(current_resumable_chunk < 1 ||
845            current_resumable_chunk > num_resumable_chunks)
846         {
847                 fprintf(stderr, "Cycles: Bad value for current resumable chunk number.\n");
848                 abort();
849                 Py_RETURN_NONE;
850         }
851
852         VLOG(1) << "Initialized resumable render: "
853                 << "num_resumable_chunks=" << num_resumable_chunks << ", "
854                 << "current_resumable_chunk=" << current_resumable_chunk;
855         BlenderSession::num_resumable_chunks = num_resumable_chunks;
856         BlenderSession::current_resumable_chunk = current_resumable_chunk;
857
858         printf("Cycles: Will render chunk %d of %d\n",
859                current_resumable_chunk,
860                num_resumable_chunks);
861
862         Py_RETURN_NONE;
863 }
864
865 static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *args)
866 {
867         int num_chunks, start_chunk, end_chunk;
868         if(!PyArg_ParseTuple(args, "iii",
869                              &num_chunks,
870                              &start_chunk,
871                              &end_chunk)) {
872                 Py_RETURN_NONE;
873         }
874
875         if(num_chunks <= 0) {
876                 fprintf(stderr, "Cycles: Bad value for number of resumable chunks.\n");
877                 abort();
878                 Py_RETURN_NONE;
879         }
880         if(start_chunk < 1 || start_chunk > num_chunks) {
881                 fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
882                 abort();
883                 Py_RETURN_NONE;
884         }
885         if(end_chunk < 1 || end_chunk > num_chunks) {
886                 fprintf(stderr, "Cycles: Bad value for start chunk number.\n");
887                 abort();
888                 Py_RETURN_NONE;
889         }
890         if(start_chunk > end_chunk) {
891                 fprintf(stderr, "Cycles: End chunk should be higher than start one.\n");
892                 abort();
893                 Py_RETURN_NONE;
894         }
895
896         VLOG(1) << "Initialized resumable render: "
897                 << "num_resumable_chunks=" << num_chunks << ", "
898                 << "start_resumable_chunk=" << start_chunk
899                 << "end_resumable_chunk=" << end_chunk;
900         BlenderSession::num_resumable_chunks = num_chunks;
901         BlenderSession::start_resumable_chunk = start_chunk;
902         BlenderSession::end_resumable_chunk = end_chunk;
903
904         printf("Cycles: Will render chunks %d to %d of %d\n",
905                start_chunk,
906                end_chunk,
907                num_chunks);
908
909         Py_RETURN_NONE;
910 }
911
912 static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
913 {
914         BlenderSession::print_render_stats = true;
915         Py_RETURN_NONE;
916 }
917
918 static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
919 {
920         vector<DeviceType> device_types = Device::available_types();
921         bool has_cuda = false, has_opencl = false;
922         foreach(DeviceType device_type, device_types) {
923                 has_cuda   |= (device_type == DEVICE_CUDA);
924                 has_opencl |= (device_type == DEVICE_OPENCL);
925         }
926         PyObject *list = PyTuple_New(2);
927         PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
928         PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_opencl));
929         return list;
930 }
931
932 static PyMethodDef methods[] = {
933         {"init", init_func, METH_VARARGS, ""},
934         {"exit", exit_func, METH_VARARGS, ""},
935         {"create", create_func, METH_VARARGS, ""},
936         {"free", free_func, METH_O, ""},
937         {"render", render_func, METH_O, ""},
938         {"bake", bake_func, METH_VARARGS, ""},
939         {"draw", draw_func, METH_VARARGS, ""},
940         {"sync", sync_func, METH_O, ""},
941         {"reset", reset_func, METH_VARARGS, ""},
942 #ifdef WITH_OSL
943         {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
944         {"osl_compile", osl_compile_func, METH_VARARGS, ""},
945 #endif
946         {"available_devices", available_devices_func, METH_VARARGS, ""},
947         {"system_info", system_info_func, METH_NOARGS, ""},
948 #ifdef WITH_OPENCL
949         {"opencl_disable", opencl_disable_func, METH_NOARGS, ""},
950         {"opencl_compile", opencl_compile_func, METH_VARARGS, ""},
951 #endif
952
953         /* Standalone denoising */
954         {"denoise", (PyCFunction)denoise_func, METH_VARARGS|METH_KEYWORDS, ""},
955         {"merge", (PyCFunction)merge_func, METH_VARARGS|METH_KEYWORDS, ""},
956
957         /* Debugging routines */
958         {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
959         {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
960
961         /* Statistics. */
962         {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
963
964         /* Resumable render */
965         {"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""},
966         {"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""},
967
968         /* Compute Device selection */
969         {"get_device_types", get_device_types_func, METH_VARARGS, ""},
970
971         {NULL, NULL, 0, NULL},
972 };
973
974 static struct PyModuleDef module = {
975         PyModuleDef_HEAD_INIT,
976         "_cycles",
977         "Blender cycles render integration",
978         -1,
979         methods,
980         NULL, NULL, NULL, NULL
981 };
982
983 CCL_NAMESPACE_END
984
985 void *CCL_python_module_init()
986 {
987         PyObject *mod = PyModule_Create(&ccl::module);
988
989 #ifdef WITH_OSL
990         /* TODO(sergey): This gives us library we've been linking against.
991          *               In theory with dynamic OSL library it might not be
992          *               accurate, but there's nothing in OSL API which we
993          *               might use to get version in runtime.
994          */
995         int curversion = OSL_LIBRARY_VERSION_CODE;
996         PyModule_AddObject(mod, "with_osl", Py_True);
997         Py_INCREF(Py_True);
998         PyModule_AddObject(mod, "osl_version",
999                            Py_BuildValue("(iii)",
1000                                           curversion / 10000, (curversion / 100) % 100, curversion % 100));
1001         PyModule_AddObject(mod, "osl_version_string",
1002                            PyUnicode_FromFormat("%2d, %2d, %2d",
1003                                                 curversion / 10000, (curversion / 100) % 100, curversion % 100));
1004 #else
1005         PyModule_AddObject(mod, "with_osl", Py_False);
1006         Py_INCREF(Py_False);
1007         PyModule_AddStringConstant(mod, "osl_version", "unknown");
1008         PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
1009 #endif
1010
1011 #ifdef WITH_CYCLES_DEBUG
1012         PyModule_AddObject(mod, "with_cycles_debug", Py_True);
1013         Py_INCREF(Py_True);
1014 #else
1015         PyModule_AddObject(mod, "with_cycles_debug", Py_False);
1016         Py_INCREF(Py_False);
1017 #endif
1018
1019 #ifdef WITH_NETWORK
1020         PyModule_AddObject(mod, "with_network", Py_True);
1021         Py_INCREF(Py_True);
1022 #else  /* WITH_NETWORK */
1023         PyModule_AddObject(mod, "with_network", Py_False);
1024         Py_INCREF(Py_False);
1025 #endif  /* WITH_NETWORK */
1026
1027 #ifdef WITH_EMBREE
1028         PyModule_AddObject(mod, "with_embree", Py_True);
1029         Py_INCREF(Py_True);
1030 #else  /* WITH_EMBREE */
1031         PyModule_AddObject(mod, "with_embree", Py_False);
1032         Py_INCREF(Py_False);
1033 #endif  /* WITH_EMBREE */
1034
1035         return (void*)mod;
1036 }