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