Blender V5.0
python.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include <Python.h>
6
7#include "blender/CCL_api.h"
8
9#include "blender/device.h"
10#include "blender/session.h"
11#include "blender/sync.h"
12#include "blender/util.h"
13
14#include "session/denoising.h"
15#include "session/merge.h"
16
17#include "util/debug.h"
18
19#include "util/guiding.h"
20#include "util/log.h"
22#include "util/path.h"
23#include "util/string.h"
24#include "util/task.h"
25#include "util/types.h"
26
27#include "GPU_state.hh"
28
29#include "scene/osl.h"
30
31#ifdef WITH_METAL
32# include "device/metal/device.h"
33#endif
34
36
37namespace {
38
39/* Flag describing whether debug flags were synchronized from scene. */
40bool debug_flags_set = false;
41
42void *pylong_as_voidptr_typesafe(PyObject *object)
43{
44 if (object == Py_None) {
45 return nullptr;
46 }
47 return PyLong_AsVoidPtr(object);
48}
49
50PyObject *pyunicode_from_string(const char *str)
51{
52 /* Ignore errors if device API returns invalid UTF8 strings. */
53 return PyUnicode_DecodeUTF8(str, strlen(str), "ignore");
54}
55
56/* Synchronize debug flags from a given Blender scene.
57 * Return truth when device list needs invalidation.
58 */
59void debug_flags_sync_from_scene(BL::Scene b_scene)
60{
61 DebugFlagsRef flags = DebugFlags();
62 PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
63 /* Synchronize CPU flags. */
64 flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
65 flags.cpu.sse42 = get_boolean(cscene, "debug_use_cpu_sse42");
66 flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
67 /* Synchronize CUDA flags. */
68 flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
69 flags.hip.adaptive_compile = get_boolean(cscene, "debug_use_hip_adaptive_compile");
70 flags.metal.adaptive_compile = get_boolean(cscene, "debug_use_metal_adaptive_compile");
71 /* Synchronize OptiX flags. */
72 flags.optix.use_debug = get_boolean(cscene, "debug_use_optix_debug");
73}
74
75/* Reset debug flags to default values.
76 * Return truth when device list needs invalidation.
77 */
79{
80 DebugFlagsRef flags = DebugFlags();
81 flags.reset();
82}
83
84} /* namespace */
85
86void python_thread_state_save(void **python_thread_state)
87{
88 *python_thread_state = (void *)PyEval_SaveThread();
89}
90
91void python_thread_state_restore(void **python_thread_state)
92{
93 PyEval_RestoreThread((PyThreadState *)*python_thread_state);
94 *python_thread_state = nullptr;
95}
96
97static const char *PyC_UnicodeAsBytes(PyObject *py_str, PyObject **coerce)
98{
99 const char *result = PyUnicode_AsUTF8(py_str);
100 if (result) {
101 /* 99% of the time this is enough but we better support non unicode
102 * chars since blender doesn't limit this.
103 */
104 return result;
105 }
106 PyErr_Clear();
107 if (PyBytes_Check(py_str)) {
108 return PyBytes_AS_STRING(py_str);
109 }
110
111 *coerce = PyUnicode_EncodeFSDefault(py_str);
112 if (*coerce) {
113 return PyBytes_AS_STRING(*coerce);
114 }
115 /* Clear the error, so Cycles can be at least used without
116 * GPU and OSL support,
117 */
118 PyErr_Clear();
119 return "";
120}
121
122static PyObject *init_func(PyObject * /*self*/, PyObject *args)
123{
124 PyObject *path;
125 PyObject *user_path;
126 int headless;
127
128 if (!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) {
129 return nullptr;
130 }
131
132 PyObject *path_coerce = nullptr;
133 PyObject *user_path_coerce = nullptr;
134 path_init(PyC_UnicodeAsBytes(path, &path_coerce),
135 PyC_UnicodeAsBytes(user_path, &user_path_coerce));
136 Py_XDECREF(path_coerce);
137 Py_XDECREF(user_path_coerce);
138
139 BlenderSession::headless = headless;
140
141 Py_RETURN_NONE;
142}
143
144static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
145{
146#ifdef WITH_METAL
148#endif
149
154 Py_RETURN_NONE;
155}
156
157static PyObject *create_func(PyObject * /*self*/, PyObject *args)
158{
159 PyObject *pyengine;
160 PyObject *pypreferences;
161 PyObject *pydata;
162 PyObject *pyscreen;
163 PyObject *pyregion;
164 PyObject *pyv3d;
165 PyObject *pyrv3d;
166 int preview_osl;
167
168 if (!PyArg_ParseTuple(args,
169 "OOOOOOOi",
170 &pyengine,
171 &pypreferences,
172 &pydata,
173 &pyscreen,
174 &pyregion,
175 &pyv3d,
176 &pyrv3d,
177 &preview_osl))
178 {
179 return nullptr;
180 }
181
182 /* RNA */
183 ID *bScreen = (ID *)PyLong_AsVoidPtr(pyscreen);
184
185 const PointerRNA engineptr = RNA_pointer_create_discrete(
186 nullptr, &RNA_RenderEngine, PyLong_AsVoidPtr(pyengine));
187 BL::RenderEngine engine(engineptr);
188
189 const PointerRNA preferencesptr = RNA_pointer_create_discrete(
190 nullptr, &RNA_Preferences, PyLong_AsVoidPtr(pypreferences));
191 BL::Preferences preferences(preferencesptr);
192
193 const PointerRNA dataptr = RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata));
194 BL::BlendData data(dataptr);
195
196 const PointerRNA regionptr = RNA_pointer_create_discrete(
197 bScreen, &RNA_Region, pylong_as_voidptr_typesafe(pyregion));
198 BL::Region region(regionptr);
199
201 bScreen, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d));
202 BL::SpaceView3D v3d(v3dptr);
203
205 bScreen, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d));
206 BL::RegionView3D rv3d(rv3dptr);
207
208 /* create session */
209 BlenderSession *session;
210
211 if (rv3d) {
212 /* interactive viewport session */
213 const int width = region.width();
214 const int height = region.height();
215
216 session = new BlenderSession(engine, preferences, data, v3d, rv3d, width, height);
217 }
218 else {
219 /* offline session or preview render */
220 session = new BlenderSession(engine, preferences, data, preview_osl);
221 }
222
223 return PyLong_FromVoidPtr(session);
224}
225
226static PyObject *free_func(PyObject * /*self*/, PyObject *value)
227{
228 delete (BlenderSession *)PyLong_AsVoidPtr(value);
229
230 Py_RETURN_NONE;
231}
232
233static PyObject *render_func(PyObject * /*self*/, PyObject *args)
234{
235 PyObject *pysession;
236 PyObject *pydepsgraph;
237
238 if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) {
239 return nullptr;
240 }
241
242 BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
243
244 const PointerRNA depsgraphptr = RNA_pointer_create_discrete(
245 nullptr, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph));
246 BL::Depsgraph b_depsgraph(depsgraphptr);
247
248 /* Allow Blender to execute other Python scripts. */
250
251 session->render(b_depsgraph);
252
254
255 Py_RETURN_NONE;
256}
257
258static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
259{
260 PyObject *pysession;
261
262 if (!PyArg_ParseTuple(args, "O", &pysession)) {
263 return nullptr;
264 }
265
266 BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
267
268 /* Allow Blender to execute other Python scripts. */
270
271 session->render_frame_finish();
272
274
275 Py_RETURN_NONE;
276}
277
278static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
279{
280 PyObject *py_session;
281 PyObject *py_graph;
282 PyObject *py_screen;
283 PyObject *py_space_image;
284
285 if (!PyArg_ParseTuple(args, "OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
286 return nullptr;
287 }
288
289 BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(py_session);
290
291 ID *b_screen = (ID *)PyLong_AsVoidPtr(py_screen);
292
293 const PointerRNA b_space_image_ptr = RNA_pointer_create_discrete(
294 b_screen, &RNA_SpaceImageEditor, pylong_as_voidptr_typesafe(py_space_image));
295 BL::SpaceImageEditor b_space_image(b_space_image_ptr);
296
297 session->draw(b_space_image);
298
299 Py_RETURN_NONE;
300}
301
302/* pixel_array and result passed as pointers */
303static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
304{
305 PyObject *pysession;
306 PyObject *pydepsgraph;
307 PyObject *pyobject;
308 const char *pass_type;
309 int pass_filter;
310 int width;
311 int height;
312
313 if (!PyArg_ParseTuple(args,
314 "OOOsiii",
315 &pysession,
316 &pydepsgraph,
317 &pyobject,
318 &pass_type,
319 &pass_filter,
320 &width,
321 &height))
322 {
323 return nullptr;
324 }
325
326 BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
327
328 const PointerRNA depsgraphptr = RNA_pointer_create_discrete(
329 nullptr, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph));
330 BL::Depsgraph b_depsgraph(depsgraphptr);
331
332 const PointerRNA objectptr = RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyobject));
333 BL::Object b_object(objectptr);
334
336
337 session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height);
338
340
341 Py_RETURN_NONE;
342}
343
344static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
345{
346 PyObject *pysession;
347 PyObject *pygraph;
348 PyObject *pyv3d;
349 PyObject *pyrv3d;
350
351 if (!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d)) {
352 return nullptr;
353 }
354
355 BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
356
357 if (PyLong_AsVoidPtr(pyrv3d)) {
358 /* 3d view drawing */
359 int viewport[4];
360 GPU_viewport_size_get_i(viewport);
361
362 session->view_draw(viewport[2], viewport[3]);
363 }
364
365 Py_RETURN_NONE;
366}
367
368static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
369{
370 PyObject *pysession;
371 PyObject *pydata;
372 PyObject *pydepsgraph;
373
374 if (!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph)) {
375 return nullptr;
376 }
377
378 BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
379
380 const PointerRNA dataptr = RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata));
381 BL::BlendData b_data(dataptr);
382
383 const PointerRNA depsgraphptr = RNA_pointer_create_discrete(
384 nullptr, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph));
385 BL::Depsgraph b_depsgraph(depsgraphptr);
386
388
389 session->reset_session(b_data, b_depsgraph);
390
392
393 Py_RETURN_NONE;
394}
395
396static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
397{
398 PyObject *pysession;
399 PyObject *pydepsgraph;
400
401 if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph)) {
402 return nullptr;
403 }
404
405 BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
406
407 const PointerRNA depsgraphptr = RNA_pointer_create_discrete(
408 nullptr, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph));
409 BL::Depsgraph b_depsgraph(depsgraphptr);
410
412
413 session->synchronize(b_depsgraph);
414
416
417 Py_RETURN_NONE;
418}
419
420static PyObject *available_devices_func(PyObject * /*self*/, PyObject *args)
421{
422 const char *type_name;
423 if (!PyArg_ParseTuple(args, "s", &type_name)) {
424 return nullptr;
425 }
426
427 const DeviceType type = Device::type_from_string(type_name);
428 /* "NONE" is defined by the add-on, see: `CyclesPreferences.get_device_types`. */
429 if ((type == DEVICE_NONE) && (strcmp(type_name, "NONE") != 0)) {
430 PyErr_Format(PyExc_ValueError, "Device \"%s\" not known.", type_name);
431 return nullptr;
432 }
433
434 uint mask = (type == DEVICE_NONE) ? DEVICE_MASK_ALL : DEVICE_MASK(type);
436
438 PyObject *ret = PyTuple_New(devices.size());
439
440 for (size_t i = 0; i < devices.size(); i++) {
441 const DeviceInfo &device = devices[i];
442 const string type_name = Device::string_from_type(device.type);
443 PyObject *device_tuple = PyTuple_New(8);
444 PyTuple_SET_ITEM(device_tuple, 0, pyunicode_from_string(device.description.c_str()));
445 PyTuple_SET_ITEM(device_tuple, 1, pyunicode_from_string(type_name.c_str()));
446 PyTuple_SET_ITEM(device_tuple, 2, pyunicode_from_string(device.id.c_str()));
447 PyTuple_SET_ITEM(device_tuple, 3, PyBool_FromLong(device.has_peer_memory));
448 PyTuple_SET_ITEM(device_tuple, 4, PyBool_FromLong(device.use_hardware_raytracing));
449 PyTuple_SET_ITEM(
450 device_tuple, 5, PyBool_FromLong(device.denoisers & DENOISER_OPENIMAGEDENOISE));
451 PyTuple_SET_ITEM(device_tuple, 6, PyBool_FromLong(device.denoisers & DENOISER_OPTIX));
452 PyTuple_SET_ITEM(device_tuple, 7, PyBool_FromLong(device.has_execution_optimization));
453 PyTuple_SET_ITEM(ret, i, device_tuple);
454 }
455
456 return ret;
457}
458
459#ifdef WITH_OSL
460
461static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
462{
463 const char *inputfile = nullptr;
464 const char *outputfile = nullptr;
465
466 if (!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile)) {
467 return nullptr;
468 }
469
470 /* return */
471 if (!OSLManager::osl_compile(inputfile, outputfile)) {
472 Py_RETURN_FALSE;
473 }
474
475 Py_RETURN_TRUE;
476}
477#endif
478
479static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
480{
481 const string system_info = Device::device_capabilities();
482 return pyunicode_from_string(system_info.c_str());
483}
484
485static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepaths)
486{
487 if (PyUnicode_Check(pyfilepaths)) {
488 const char *filepath = PyUnicode_AsUTF8(pyfilepaths);
489 filepaths.push_back(filepath);
490 return true;
491 }
492
493 PyObject *sequence = PySequence_Fast(pyfilepaths,
494 "File paths must be a string or sequence of strings");
495 if (sequence == nullptr) {
496 return false;
497 }
498
499 for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
500 PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
501 const char *filepath = PyUnicode_AsUTF8(item);
502 if (filepath == nullptr) {
503 PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings.");
504 Py_DECREF(sequence);
505 return false;
506 }
507 filepaths.push_back(filepath);
508 }
509 Py_DECREF(sequence);
510
511 return true;
512}
513
514static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
515{
516 static const char *keyword_list[] = {
517 "preferences", "scene", "view_layer", "input", "output", nullptr};
518 PyObject *pypreferences;
519 PyObject *pyscene;
520 PyObject *pyviewlayer;
521 PyObject *pyinput;
522 PyObject *pyoutput = nullptr;
523
524 if (!PyArg_ParseTupleAndKeywords(args,
525 keywords,
526 "OOOO|O",
527 (char **)keyword_list,
528 &pypreferences,
529 &pyscene,
530 &pyviewlayer,
531 &pyinput,
532 &pyoutput))
533 {
534 return nullptr;
535 }
536
537 /* Get device specification from preferences and scene. */
538 const PointerRNA preferencesptr = RNA_pointer_create_discrete(
539 nullptr, &RNA_Preferences, PyLong_AsVoidPtr(pypreferences));
540 BL::Preferences b_preferences(preferencesptr);
541
542 const PointerRNA sceneptr = RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene));
543 BL::Scene b_scene(sceneptr);
544
545 DeviceInfo preferences_device;
546 const DeviceInfo pathtrace_device = blender_device_info(
547 b_preferences, b_scene, true, true, preferences_device);
548
549 /* Get denoising parameters from view layer. */
550 const PointerRNA viewlayerptr = RNA_pointer_create_discrete(
551 (ID *)PyLong_AsVoidPtr(pyscene), &RNA_ViewLayer, PyLong_AsVoidPtr(pyviewlayer));
552 BL::ViewLayer b_view_layer(viewlayerptr);
553
555 b_scene, b_view_layer, true, preferences_device);
556 params.use = true;
557
558 /* Parse file paths list. */
561
562 if (!image_parse_filepaths(pyinput, input)) {
563 return nullptr;
564 }
565
566 if (pyoutput) {
567 if (!image_parse_filepaths(pyoutput, output)) {
568 return nullptr;
569 }
570 }
571 else {
572 output = input;
573 }
574
575 if (input.empty()) {
576 PyErr_SetString(PyExc_ValueError, "No input file paths specified.");
577 return nullptr;
578 }
579 if (input.size() != output.size()) {
580 PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match.");
581 return nullptr;
582 }
583
584 /* Create denoiser. */
585 /* We are using preference device here, because path trace device will be identical to it unless
586 * scene is setting CPU render or command line override render device. But both of this options
587 * are for render, not for denoising. */
588 DenoiserPipeline denoiser(preferences_device, params);
589 denoiser.input = input;
590 denoiser.output = output;
591
592 /* Run denoiser. */
593 if (!denoiser.run()) {
594 PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
595 return nullptr;
596 }
597
598 Py_RETURN_NONE;
599}
600
601static PyObject *merge_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
602{
603 static const char *keyword_list[] = {"input", "output", nullptr};
604 PyObject *pyinput;
605 PyObject *pyoutput = nullptr;
606
607 if (!PyArg_ParseTupleAndKeywords(
608 args, keywords, "OO", (char **)keyword_list, &pyinput, &pyoutput))
609 {
610 return nullptr;
611 }
612
613 /* Parse input list. */
615 if (!image_parse_filepaths(pyinput, input)) {
616 return nullptr;
617 }
618
619 /* Parse output string. */
620 if (!PyUnicode_Check(pyoutput)) {
621 PyErr_SetString(PyExc_ValueError, "Output must be a string.");
622 return nullptr;
623 }
624 const string output = PyUnicode_AsUTF8(pyoutput);
625
626 /* Merge. */
627 ImageMerger merger;
628 merger.input = input;
629 merger.output = output;
630
631 if (!merger.run()) {
632 PyErr_SetString(PyExc_ValueError, merger.error.c_str());
633 return nullptr;
634 }
635
636 Py_RETURN_NONE;
637}
638
639static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
640{
641 PyObject *pyscene;
642 if (!PyArg_ParseTuple(args, "O", &pyscene)) {
643 return nullptr;
644 }
645
646 const PointerRNA sceneptr = RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene));
647 const BL::Scene b_scene(sceneptr);
648
649 debug_flags_sync_from_scene(b_scene);
650
651 debug_flags_set = true;
652
653 Py_RETURN_NONE;
654}
655
656static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
657{
658 debug_flags_reset();
659 if (debug_flags_set) {
660 debug_flags_set = false;
661 }
662 Py_RETURN_NONE;
663}
664
665static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
666{
668 Py_RETURN_NONE;
669}
670
671static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
672{
673 const vector<DeviceType> device_types = Device::available_types();
674 bool has_cuda = false;
675 bool has_optix = false;
676 bool has_hip = false;
677 bool has_metal = false;
678 bool has_oneapi = false;
679 bool has_hiprt = false;
680 for (const DeviceType device_type : device_types) {
681 has_cuda |= (device_type == DEVICE_CUDA);
682 has_optix |= (device_type == DEVICE_OPTIX);
683 has_hip |= (device_type == DEVICE_HIP);
684 has_metal |= (device_type == DEVICE_METAL);
685 has_oneapi |= (device_type == DEVICE_ONEAPI);
686 has_hiprt |= (device_type == DEVICE_HIPRT);
687 }
688 PyObject *list = PyTuple_New(6);
689 PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
690 PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
691 PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
692 PyTuple_SET_ITEM(list, 3, PyBool_FromLong(has_metal));
693 PyTuple_SET_ITEM(list, 4, PyBool_FromLong(has_oneapi));
694 PyTuple_SET_ITEM(list, 5, PyBool_FromLong(has_hiprt));
695 return list;
696}
697
698static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
699{
700 PyObject *override_string = PyObject_Str(arg);
701 string override = PyUnicode_AsUTF8(override_string);
702 Py_DECREF(override_string);
703
704 bool include_cpu = false;
705 const string cpu_suffix = "+CPU";
706 if (string_endswith(override, cpu_suffix)) {
707 include_cpu = true;
708 override = override.substr(0, override.length() - cpu_suffix.length());
709 }
710
711 if (override == "CPU") {
713 }
714 else if (override == "CUDA") {
716 }
717 else if (override == "OPTIX") {
719 }
720 else if (override == "HIP") {
722 }
723 else if (override == "METAL") {
725 }
726 else if (override == "ONEAPI") {
728 }
729 else {
730 LOG_ERROR << override << " is not a valid Cycles device.";
731 Py_RETURN_FALSE;
732 }
733
734 if (include_cpu) {
737 }
738
739 Py_RETURN_TRUE;
740}
741
742#ifdef __GNUC__
743# ifdef __clang__
744# pragma clang diagnostic push
745# pragma clang diagnostic ignored "-Wcast-function-type"
746# else
747# pragma GCC diagnostic push
748# pragma GCC diagnostic ignored "-Wcast-function-type"
749# endif
750#endif
751
752static PyMethodDef methods[] = {
753 {"init", init_func, METH_VARARGS, ""},
754 {"exit", exit_func, METH_VARARGS, ""},
755 {"create", create_func, METH_VARARGS, ""},
756 {"free", free_func, METH_O, ""},
757 {"render", render_func, METH_VARARGS, ""},
758 {"render_frame_finish", render_frame_finish_func, METH_VARARGS, ""},
759 {"draw", draw_func, METH_VARARGS, ""},
760 {"bake", bake_func, METH_VARARGS, ""},
761 {"view_draw", view_draw_func, METH_VARARGS, ""},
762 {"sync", sync_func, METH_VARARGS, ""},
763 {"reset", reset_func, METH_VARARGS, ""},
764#ifdef WITH_OSL
765 {"osl_compile", osl_compile_func, METH_VARARGS, ""},
766#endif
767 {"available_devices", available_devices_func, METH_VARARGS, ""},
768 {"system_info", system_info_func, METH_NOARGS, ""},
769
770 /* Standalone denoising */
771 {"denoise", (PyCFunction)denoise_func, METH_VARARGS | METH_KEYWORDS, ""},
772 {"merge", (PyCFunction)merge_func, METH_VARARGS | METH_KEYWORDS, ""},
773
774 /* Debugging routines */
775 {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
776 {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
777
778 /* Statistics. */
779 {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
780
781 /* Compute Device selection */
782 {"get_device_types", get_device_types_func, METH_VARARGS, ""},
783 {"set_device_override", set_device_override_func, METH_O, ""},
784
785 {nullptr, nullptr, 0, nullptr},
786};
787
788#ifdef __GNUC__
789# ifdef __clang__
790# pragma clang diagnostic pop
791# else
792# pragma GCC diagnostic pop
793# endif
794#endif
795
796static struct PyModuleDef module = {
797 /*m_base*/ PyModuleDef_HEAD_INIT,
798 /*m_name*/ "_cycles",
799 /*m_doc*/ "Blender cycles render integration",
800 /*m_size*/ -1,
801 /*m_methods*/ methods,
802 /*m_slots*/ nullptr,
803 /*m_traverse*/ nullptr,
804 /*m_clear*/ nullptr,
805 /*m_free*/ nullptr,
806};
807
809
811{
812 PyObject *mod = PyModule_Create(&ccl::module);
813
814#ifdef WITH_OSL
815 /* TODO(sergey): This gives us library we've been linking against.
816 * In theory with dynamic OSL library it might not be
817 * accurate, but there's nothing in OSL API which we
818 * might use to get version in runtime.
819 */
820 const int curversion = OSL_LIBRARY_VERSION_CODE;
821 PyModule_AddObjectRef(mod, "with_osl", Py_True);
822 PyModule_AddObject(
823 mod,
824 "osl_version",
825 Py_BuildValue("(iii)", curversion / 10000, (curversion / 100) % 100, curversion % 100));
826 PyModule_AddObject(
827 mod,
828 "osl_version_string",
829 PyUnicode_FromFormat(
830 "%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100));
831#else
832 PyModule_AddObjectRef(mod, "with_osl", Py_False);
833 PyModule_AddStringConstant(mod, "osl_version", "unknown");
834 PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
835#endif
836
837 if (ccl::guiding_supported()) {
838 PyModule_AddObjectRef(mod, "with_path_guiding", Py_True);
839 }
840 else {
841 PyModule_AddObjectRef(mod, "with_path_guiding", Py_False);
842 }
843
844#ifdef WITH_EMBREE
845 PyModule_AddObjectRef(mod, "with_embree", Py_True);
846#else /* WITH_EMBREE */
847 PyModule_AddObjectRef(mod, "with_embree", Py_False);
848#endif /* WITH_EMBREE */
849
850#ifdef WITH_EMBREE_GPU
851 PyModule_AddObjectRef(mod, "with_embree_gpu", Py_True);
852#else /* WITH_EMBREE_GPU */
853 PyModule_AddObjectRef(mod, "with_embree_gpu", Py_False);
854#endif /* WITH_EMBREE_GPU */
855
856 if (ccl::openimagedenoise_supported()) {
857 PyModule_AddObjectRef(mod, "with_openimagedenoise", Py_True);
858 }
859 else {
860 PyModule_AddObjectRef(mod, "with_openimagedenoise", Py_False);
861 }
862
863#ifdef WITH_CYCLES_DEBUG
864 PyModule_AddObjectRef(mod, "with_debug", Py_True);
865#else /* WITH_CYCLES_DEBUG */
866 PyModule_AddObjectRef(mod, "with_debug", Py_False);
867#endif /* WITH_CYCLES_DEBUG */
868
869 return (void *)mod;
870}
unsigned int uint
void GPU_viewport_size_get_i(int coords[4])
Definition gpu_state.cc:282
DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scene, bool background, bool preview, DeviceInfo &preferences_device)
BMesh const char void * data
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
Definition btVector3.h:257
static bool headless
static bool print_render_stats
void synchronize(BL::Depsgraph &b_depsgraph)
void bake(BL::Depsgraph &b_depsgraph_, BL::Object &b_object, const string &bake_type, const int bake_filter, const int bake_width, const int bake_height)
void reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph)
void render(BL::Depsgraph &b_depsgraph)
void draw(BL::SpaceImageEditor &space_image)
void view_draw(const int w, const int h)
static DeviceTypeMask device_override
static DenoiseParams get_denoise_params(BL::Scene &b_scene, BL::ViewLayer &b_view_layer, bool background, const DeviceInfo &denoise_device)
Definition sync.cpp:1020
static void free_memory()
CPU cpu
Definition debug.h:120
void reset()
Definition debug.cpp:99
OptiX optix
Definition debug.h:126
CUDA cuda
Definition debug.h:123
HIP hip
Definition debug.h:129
Metal metal
Definition debug.h:132
vector< string > input
Definition denoising.h:39
vector< string > output
Definition denoising.h:43
bool has_execution_optimization
DenoiserTypeMask denoisers
bool has_peer_memory
DeviceType type
string description
bool use_hardware_raytracing
static void free_memory()
static DeviceType type_from_string(const char *name)
static string device_capabilities(const uint device_type_mask=DEVICE_MASK_ALL)
static vector< DeviceType > available_types()
static string string_from_type(DeviceType type)
static vector< DeviceInfo > available_devices(const uint device_type_mask=DEVICE_MASK_ALL)
bool run()
Definition merge.cpp:572
string output
Definition merge.h:25
vector< string > input
Definition merge.h:23
string error
Definition merge.h:20
static void free_memory()
Definition osl.cpp:1618
static void free_memory()
Definition task.cpp:91
static bool get_boolean(PointerRNA &ptr, const char *name)
static int get_enum(PointerRNA &ptr, const char *name, int num_values=-1, int default_value=-1)
DebugFlags & DebugFlagsRef
Definition debug.h:142
DebugFlags & DebugFlags()
Definition debug.h:145
@ DENOISER_OPTIX
Definition denoise.h:12
@ DENOISER_OPENIMAGEDENOISE
Definition denoise.h:13
#define CCL_NAMESPACE_END
#define DEVICE_MASK(type)
DeviceTypeMask
@ DEVICE_MASK_OPTIX
@ DEVICE_MASK_CPU
@ DEVICE_MASK_HIP
@ DEVICE_MASK_ALL
@ DEVICE_MASK_CUDA
@ DEVICE_MASK_METAL
@ DEVICE_MASK_ONEAPI
DeviceType
@ DEVICE_NONE
@ DEVICE_METAL
@ DEVICE_CUDA
@ DEVICE_HIPRT
@ DEVICE_OPTIX
@ DEVICE_HIP
@ DEVICE_ONEAPI
void device_metal_exit()
static KeywordTokenDef keyword_list[]
#define str(s)
#define input
#define output
VecBase< float, D > constexpr mod(VecOp< float, D >, VecOp< float, D >) RET
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define LOG_ERROR
Definition log.h:101
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
void debug_flags_reset()
Definition python.cpp:78
void debug_flags_sync_from_scene(BL::Scene b_scene)
Definition python.cpp:59
void * pylong_as_voidptr_typesafe(PyObject *object)
Definition python.cpp:42
PyObject * pyunicode_from_string(const char *str)
Definition python.cpp:50
KernelBVHLayout BVHLayout
Definition params.h:22
void path_init(const string &path, const string &user_path)
Definition path.cpp:324
static PyObject * init_func(PyObject *, PyObject *args)
Definition python.cpp:122
static PyObject * merge_func(PyObject *, PyObject *args, PyObject *keywords)
Definition python.cpp:601
static PyObject * sync_func(PyObject *, PyObject *args)
Definition python.cpp:396
static PyObject * denoise_func(PyObject *, PyObject *args, PyObject *keywords)
Definition python.cpp:514
void python_thread_state_restore(void **python_thread_state)
Definition python.cpp:91
static PyObject * system_info_func(PyObject *, PyObject *)
Definition python.cpp:479
static PyObject * set_device_override_func(PyObject *, PyObject *arg)
Definition python.cpp:698
static PyObject * free_func(PyObject *, PyObject *value)
Definition python.cpp:226
CCL_NAMESPACE_END void * CCL_python_module_init()
Definition python.cpp:810
static struct PyModuleDef module
Definition python.cpp:796
static bool image_parse_filepaths(PyObject *pyfilepaths, vector< string > &filepaths)
Definition python.cpp:485
static PyMethodDef methods[]
Definition python.cpp:752
static PyObject * available_devices_func(PyObject *, PyObject *args)
Definition python.cpp:420
static PyObject * bake_func(PyObject *, PyObject *args)
Definition python.cpp:303
static PyObject * reset_func(PyObject *, PyObject *args)
Definition python.cpp:368
static PyObject * view_draw_func(PyObject *, PyObject *args)
Definition python.cpp:344
static PyObject * enable_print_stats_func(PyObject *, PyObject *)
Definition python.cpp:665
static PyObject * debug_flags_reset_func(PyObject *, PyObject *)
Definition python.cpp:656
static PyObject * render_func(PyObject *, PyObject *args)
Definition python.cpp:233
static PyObject * debug_flags_update_func(PyObject *, PyObject *args)
Definition python.cpp:639
void python_thread_state_save(void **python_thread_state)
Definition python.cpp:86
static PyObject * draw_func(PyObject *, PyObject *args)
Definition python.cpp:278
static PyObject * get_device_types_func(PyObject *, PyObject *)
Definition python.cpp:671
static const char * PyC_UnicodeAsBytes(PyObject *py_str, PyObject **coerce)
Definition python.cpp:97
static PyObject * render_frame_finish_func(PyObject *, PyObject *args)
Definition python.cpp:258
static PyObject * create_func(PyObject *, PyObject *args)
Definition python.cpp:157
static PyObject * exit_func(PyObject *, PyObject *)
Definition python.cpp:144
Py_DECREF(oname)
return ret
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
PointerRNA RNA_main_pointer_create(Main *main)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
PointerRNA RNA_id_pointer_create(ID *id)
bool string_endswith(const string_view s, const string_view end)
Definition string.cpp:120
BVHLayout bvh_layout
Definition debug.h:47
bool adaptive_compile
Definition debug.h:59
bool adaptive_compile
Definition debug.h:70
bool adaptive_compile
Definition debug.h:93
Definition DNA_ID.h:414
i
Definition text_draw.cc:230