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