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