Blender  V3.3
python.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include <Python.h>
5 
6 #include "blender/CCL_api.h"
7 
8 #include "blender/device.h"
9 #include "blender/session.h"
10 #include "blender/sync.h"
11 #include "blender/util.h"
12 
13 #include "session/denoising.h"
14 #include "session/merge.h"
15 
16 #include "util/debug.h"
17 #include "util/foreach.h"
18 #include "util/log.h"
19 #include "util/md5.h"
20 #include "util/opengl.h"
21 #include "util/openimagedenoise.h"
22 #include "util/path.h"
23 #include "util/string.h"
24 #include "util/task.h"
25 #include "util/tbb.h"
26 #include "util/types.h"
27 
28 #ifdef WITH_OSL
29 # include "scene/osl.h"
30 
31 # include <OSL/oslconfig.h>
32 # include <OSL/oslquery.h>
33 #endif
34 
36 
37 namespace {
38 
39 /* Flag describing whether debug flags were synchronized from scene. */
40 bool debug_flags_set = false;
41 
42 void *pylong_as_voidptr_typesafe(PyObject *object)
43 {
44  if (object == Py_None)
45  return NULL;
46  return PyLong_AsVoidPtr(object);
47 }
48 
49 PyObject *pyunicode_from_string(const char *str)
50 {
51  /* Ignore errors if device API returns invalid UTF-8 strings. */
52  return PyUnicode_DecodeUTF8(str, strlen(str), "ignore");
53 }
54 
55 /* Synchronize debug flags from a given Blender scene.
56  * Return truth when device list needs invalidation.
57  */
59 {
60  DebugFlagsRef flags = DebugFlags();
61  PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
62  /* Synchronize shared flags. */
63  flags.viewport_static_bvh = get_enum(cscene, "debug_bvh_type");
64  /* Synchronize CPU flags. */
65  flags.cpu.avx2 = get_boolean(cscene, "debug_use_cpu_avx2");
66  flags.cpu.avx = get_boolean(cscene, "debug_use_cpu_avx");
67  flags.cpu.sse41 = get_boolean(cscene, "debug_use_cpu_sse41");
68  flags.cpu.sse3 = get_boolean(cscene, "debug_use_cpu_sse3");
69  flags.cpu.sse2 = get_boolean(cscene, "debug_use_cpu_sse2");
70  flags.cpu.bvh_layout = (BVHLayout)get_enum(cscene, "debug_bvh_layout");
71  /* Synchronize CUDA flags. */
72  flags.cuda.adaptive_compile = get_boolean(cscene, "debug_use_cuda_adaptive_compile");
73  /* Synchronize OptiX flags. */
74  flags.optix.use_debug = get_boolean(cscene, "debug_use_optix_debug");
75 }
76 
77 /* Reset debug flags to default values.
78  * Return truth when device list needs invalidation.
79  */
80 static void debug_flags_reset()
81 {
82  DebugFlagsRef flags = DebugFlags();
83  flags.reset();
84 }
85 
86 } /* namespace */
87 
88 void python_thread_state_save(void **python_thread_state)
89 {
90  *python_thread_state = (void *)PyEval_SaveThread();
91 }
92 
93 void python_thread_state_restore(void **python_thread_state)
94 {
95  PyEval_RestoreThread((PyThreadState *)*python_thread_state);
96  *python_thread_state = NULL;
97 }
98 
99 static const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
100 {
101  const char *result = PyUnicode_AsUTF8(py_str);
102  if (result) {
103  /* 99% of the time this is enough but we better support non unicode
104  * chars since blender doesn't limit this.
105  */
106  return result;
107  }
108  else {
109  PyErr_Clear();
110  if (PyBytes_Check(py_str)) {
111  return PyBytes_AS_STRING(py_str);
112  }
113  else if ((*coerce = PyUnicode_EncodeFSDefault(py_str))) {
114  return PyBytes_AS_STRING(*coerce);
115  }
116  else {
117  /* Clear the error, so Cycles can be at least used without
118  * GPU and OSL support,
119  */
120  PyErr_Clear();
121  return "";
122  }
123  }
124 }
125 
126 static PyObject *init_func(PyObject * /*self*/, PyObject *args)
127 {
128  PyObject *path, *user_path;
129  int headless;
130 
131  if (!PyArg_ParseTuple(args, "OOi", &path, &user_path, &headless)) {
132  return nullptr;
133  }
134 
135  PyObject *path_coerce = nullptr, *user_path_coerce = nullptr;
136  path_init(PyC_UnicodeAsByte(path, &path_coerce),
137  PyC_UnicodeAsByte(user_path, &user_path_coerce));
138  Py_XDECREF(path_coerce);
139  Py_XDECREF(user_path_coerce);
140 
141  BlenderSession::headless = headless;
142 
144 
145  Py_RETURN_NONE;
146 }
147 
148 static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/)
149 {
153  Py_RETURN_NONE;
154 }
155 
156 static PyObject *create_func(PyObject * /*self*/, PyObject *args)
157 {
158  PyObject *pyengine, *pypreferences, *pydata, *pyscreen, *pyregion, *pyv3d, *pyrv3d;
159  int preview_osl;
160 
161  if (!PyArg_ParseTuple(args,
162  "OOOOOOOi",
163  &pyengine,
164  &pypreferences,
165  &pydata,
166  &pyscreen,
167  &pyregion,
168  &pyv3d,
169  &pyrv3d,
170  &preview_osl)) {
171  return NULL;
172  }
173 
174  /* RNA */
175  ID *bScreen = (ID *)PyLong_AsVoidPtr(pyscreen);
176 
177  PointerRNA engineptr;
178  RNA_pointer_create(NULL, &RNA_RenderEngine, (void *)PyLong_AsVoidPtr(pyengine), &engineptr);
179  BL::RenderEngine engine(engineptr);
180 
181  PointerRNA preferencesptr;
183  NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
184  BL::Preferences preferences(preferencesptr);
185 
186  PointerRNA dataptr;
187  RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
188  BL::BlendData data(dataptr);
189 
190  PointerRNA regionptr;
191  RNA_pointer_create(bScreen, &RNA_Region, pylong_as_voidptr_typesafe(pyregion), &regionptr);
192  BL::Region region(regionptr);
193 
194  PointerRNA v3dptr;
195  RNA_pointer_create(bScreen, &RNA_SpaceView3D, pylong_as_voidptr_typesafe(pyv3d), &v3dptr);
196  BL::SpaceView3D v3d(v3dptr);
197 
198  PointerRNA rv3dptr;
199  RNA_pointer_create(bScreen, &RNA_RegionView3D, pylong_as_voidptr_typesafe(pyrv3d), &rv3dptr);
200  BL::RegionView3D rv3d(rv3dptr);
201 
202  /* create session */
203  BlenderSession *session;
204 
205  if (rv3d) {
206  /* interactive viewport session */
207  int width = region.width();
208  int height = region.height();
209 
210  session = new BlenderSession(engine, preferences, data, v3d, rv3d, width, height);
211  }
212  else {
213  /* offline session or preview render */
214  session = new BlenderSession(engine, preferences, data, preview_osl);
215  }
216 
217  return PyLong_FromVoidPtr(session);
218 }
219 
220 static PyObject *free_func(PyObject * /*self*/, PyObject *value)
221 {
222  delete (BlenderSession *)PyLong_AsVoidPtr(value);
223 
224  Py_RETURN_NONE;
225 }
226 
227 static PyObject *render_func(PyObject * /*self*/, PyObject *args)
228 {
229  PyObject *pysession, *pydepsgraph;
230 
231  if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
232  return NULL;
233 
234  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
235 
236  PointerRNA depsgraphptr;
237  RNA_pointer_create(NULL, &RNA_Depsgraph, (ID *)PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
238  BL::Depsgraph b_depsgraph(depsgraphptr);
239 
240  /* Allow Blender to execute other Python scripts. */
242 
243  session->render(b_depsgraph);
244 
246 
247  Py_RETURN_NONE;
248 }
249 
250 static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
251 {
252  PyObject *pysession;
253 
254  if (!PyArg_ParseTuple(args, "O", &pysession)) {
255  return nullptr;
256  }
257 
258  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
259 
260  /* Allow Blender to execute other Python scripts. */
262 
263  session->render_frame_finish();
264 
266 
267  Py_RETURN_NONE;
268 }
269 
270 static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
271 {
272  PyObject *py_session, *py_graph, *py_screen, *py_space_image;
273 
274  if (!PyArg_ParseTuple(args, "OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
275  return nullptr;
276  }
277 
278  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(py_session);
279 
280  ID *b_screen = (ID *)PyLong_AsVoidPtr(py_screen);
281 
282  PointerRNA b_space_image_ptr;
283  RNA_pointer_create(b_screen,
284  &RNA_SpaceImageEditor,
285  pylong_as_voidptr_typesafe(py_space_image),
286  &b_space_image_ptr);
287  BL::SpaceImageEditor b_space_image(b_space_image_ptr);
288 
289  session->draw(b_space_image);
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  const char *pass_type;
299  int pass_filter, width, height;
300 
301  if (!PyArg_ParseTuple(args,
302  "OOOsiii",
303  &pysession,
304  &pydepsgraph,
305  &pyobject,
306  &pass_type,
307  &pass_filter,
308  &width,
309  &height))
310  return NULL;
311 
312  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
313 
314  PointerRNA depsgraphptr;
315  RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
316  BL::Depsgraph b_depsgraph(depsgraphptr);
317 
318  PointerRNA objectptr;
319  RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyobject), &objectptr);
320  BL::Object b_object(objectptr);
321 
323 
324  session->bake(b_depsgraph, b_object, pass_type, pass_filter, width, height);
325 
327 
328  Py_RETURN_NONE;
329 }
330 
331 static PyObject *view_draw_func(PyObject * /*self*/, PyObject *args)
332 {
333  PyObject *pysession, *pygraph, *pyv3d, *pyrv3d;
334 
335  if (!PyArg_ParseTuple(args, "OOOO", &pysession, &pygraph, &pyv3d, &pyrv3d))
336  return NULL;
337 
338  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
339 
340  if (PyLong_AsVoidPtr(pyrv3d)) {
341  /* 3d view drawing */
342  int viewport[4];
343  glGetIntegerv(GL_VIEWPORT, viewport);
344 
345  session->view_draw(viewport[2], viewport[3]);
346  }
347 
348  Py_RETURN_NONE;
349 }
350 
351 static PyObject *reset_func(PyObject * /*self*/, PyObject *args)
352 {
353  PyObject *pysession, *pydata, *pydepsgraph;
354 
355  if (!PyArg_ParseTuple(args, "OOO", &pysession, &pydata, &pydepsgraph))
356  return NULL;
357 
358  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
359 
360  PointerRNA dataptr;
361  RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
362  BL::BlendData b_data(dataptr);
363 
364  PointerRNA depsgraphptr;
365  RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
366  BL::Depsgraph b_depsgraph(depsgraphptr);
367 
369 
370  session->reset_session(b_data, b_depsgraph);
371 
373 
374  Py_RETURN_NONE;
375 }
376 
377 static PyObject *sync_func(PyObject * /*self*/, PyObject *args)
378 {
379  PyObject *pysession, *pydepsgraph;
380 
381  if (!PyArg_ParseTuple(args, "OO", &pysession, &pydepsgraph))
382  return NULL;
383 
384  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
385 
386  PointerRNA depsgraphptr;
387  RNA_pointer_create(NULL, &RNA_Depsgraph, PyLong_AsVoidPtr(pydepsgraph), &depsgraphptr);
388  BL::Depsgraph b_depsgraph(depsgraphptr);
389 
391 
392  session->synchronize(b_depsgraph);
393 
395 
396  Py_RETURN_NONE;
397 }
398 
399 static PyObject *available_devices_func(PyObject * /*self*/, PyObject *args)
400 {
401  const char *type_name;
402  if (!PyArg_ParseTuple(args, "s", &type_name)) {
403  return NULL;
404  }
405 
407  /* "NONE" is defined by the add-on, see: `CyclesPreferences.get_device_types`. */
408  if ((type == DEVICE_NONE) && (strcmp(type_name, "NONE") != 0)) {
409  PyErr_Format(PyExc_ValueError, "Device \"%s\" not known.", type_name);
410  return NULL;
411  }
412 
415 
417  PyObject *ret = PyTuple_New(devices.size());
418 
419  for (size_t i = 0; i < devices.size(); i++) {
420  DeviceInfo &device = devices[i];
421  string type_name = Device::string_from_type(device.type);
422  PyObject *device_tuple = PyTuple_New(4);
423  PyTuple_SET_ITEM(device_tuple, 0, pyunicode_from_string(device.description.c_str()));
424  PyTuple_SET_ITEM(device_tuple, 1, pyunicode_from_string(type_name.c_str()));
425  PyTuple_SET_ITEM(device_tuple, 2, pyunicode_from_string(device.id.c_str()));
426  PyTuple_SET_ITEM(device_tuple, 3, PyBool_FromLong(device.has_peer_memory));
427  PyTuple_SET_ITEM(ret, i, device_tuple);
428  }
429 
430  return ret;
431 }
432 
433 #ifdef WITH_OSL
434 
435 static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args)
436 {
437  PyObject *pydata, *pynodegroup, *pynode;
438  const char *filepath = NULL;
439 
440  if (!PyArg_ParseTuple(args, "OOOs", &pydata, &pynodegroup, &pynode, &filepath))
441  return NULL;
442 
443  /* RNA */
444  PointerRNA dataptr;
445  RNA_main_pointer_create((Main *)PyLong_AsVoidPtr(pydata), &dataptr);
446  BL::BlendData b_data(dataptr);
447 
448  PointerRNA nodeptr;
449  RNA_pointer_create((ID *)PyLong_AsVoidPtr(pynodegroup),
450  &RNA_ShaderNodeScript,
451  (void *)PyLong_AsVoidPtr(pynode),
452  &nodeptr);
453  BL::ShaderNodeScript b_node(nodeptr);
454 
455  /* update bytecode hash */
456  string bytecode = b_node.bytecode();
457 
458  if (!bytecode.empty()) {
459  MD5Hash md5;
460  md5.append((const uint8_t *)bytecode.c_str(), bytecode.size());
461  b_node.bytecode_hash(md5.get_hex().c_str());
462  }
463  else
464  b_node.bytecode_hash("");
465 
466  /* query from file path */
467  OSL::OSLQuery query;
468 
469  if (!OSLShaderManager::osl_query(query, filepath))
470  Py_RETURN_FALSE;
471 
472  /* add new sockets from parameters */
473  set<void *> used_sockets;
474 
475  for (int i = 0; i < query.nparams(); i++) {
476  const OSL::OSLQuery::Parameter *param = query.getparam(i);
477 
478  /* skip unsupported types */
479  if (param->varlenarray || param->isstruct || param->type.arraylen > 1)
480  continue;
481 
482  /* Read metadata. */
483  bool is_bool_param = false;
484  ustring param_label = param->name;
485 
486  for (const OSL::OSLQuery::Parameter &metadata : param->metadata) {
487  if (metadata.type == TypeDesc::STRING) {
488  if (metadata.name == "widget") {
489  /* Boolean socket. */
490  if (metadata.sdefault[0] == "boolean" || metadata.sdefault[0] == "checkBox") {
491  is_bool_param = true;
492  }
493  }
494  else if (metadata.name == "label") {
495  /* Socket label. */
496  param_label = metadata.sdefault[0];
497  }
498  }
499  }
500  /* determine socket type */
501  string socket_type;
502  BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE;
503  float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
504  float default_float = 0.0f;
505  int default_int = 0;
506  string default_string = "";
507  bool default_boolean = false;
508 
509  if (param->isclosure) {
510  socket_type = "NodeSocketShader";
511  data_type = BL::NodeSocket::type_SHADER;
512  }
513  else if (param->type.vecsemantics == TypeDesc::COLOR) {
514  socket_type = "NodeSocketColor";
515  data_type = BL::NodeSocket::type_RGBA;
516 
517  if (param->validdefault) {
518  default_float4[0] = param->fdefault[0];
519  default_float4[1] = param->fdefault[1];
520  default_float4[2] = param->fdefault[2];
521  }
522  }
523  else if (param->type.vecsemantics == TypeDesc::POINT ||
524  param->type.vecsemantics == TypeDesc::VECTOR ||
525  param->type.vecsemantics == TypeDesc::NORMAL) {
526  socket_type = "NodeSocketVector";
527  data_type = BL::NodeSocket::type_VECTOR;
528 
529  if (param->validdefault) {
530  default_float4[0] = param->fdefault[0];
531  default_float4[1] = param->fdefault[1];
532  default_float4[2] = param->fdefault[2];
533  }
534  }
535  else if (param->type.aggregate == TypeDesc::SCALAR) {
536  if (param->type.basetype == TypeDesc::INT) {
537  if (is_bool_param) {
538  socket_type = "NodeSocketBool";
539  data_type = BL::NodeSocket::type_BOOLEAN;
540  if (param->validdefault) {
541  default_boolean = (bool)param->idefault[0];
542  }
543  }
544  else {
545  socket_type = "NodeSocketInt";
546  data_type = BL::NodeSocket::type_INT;
547  if (param->validdefault)
548  default_int = param->idefault[0];
549  }
550  }
551  else if (param->type.basetype == TypeDesc::FLOAT) {
552  socket_type = "NodeSocketFloat";
553  data_type = BL::NodeSocket::type_VALUE;
554  if (param->validdefault)
555  default_float = param->fdefault[0];
556  }
557  else if (param->type.basetype == TypeDesc::STRING) {
558  socket_type = "NodeSocketString";
559  data_type = BL::NodeSocket::type_STRING;
560  if (param->validdefault)
561  default_string = param->sdefault[0].string();
562  }
563  else
564  continue;
565  }
566  else
567  continue;
568 
569  /* Update existing socket. */
570  bool found_existing = false;
571  if (param->isoutput) {
572  for (BL::NodeSocket &b_sock : b_node.outputs) {
573  if (b_sock.identifier() == param->name) {
574  if (b_sock.bl_idname() != socket_type) {
575  /* Remove if type no longer matches. */
576  b_node.outputs.remove(b_data, b_sock);
577  }
578  else {
579  /* Reuse and update label. */
580  if (b_sock.name() != param_label) {
581  b_sock.name(param_label.string());
582  }
583  used_sockets.insert(b_sock.ptr.data);
584  found_existing = true;
585  }
586  break;
587  }
588  }
589  }
590  else {
591  for (BL::NodeSocket &b_sock : b_node.inputs) {
592  if (b_sock.identifier() == param->name) {
593  if (b_sock.bl_idname() != socket_type) {
594  /* Remove if type no longer matches. */
595  b_node.inputs.remove(b_data, b_sock);
596  }
597  else {
598  /* Reuse and update label. */
599  if (b_sock.name() != param_label) {
600  b_sock.name(param_label.string());
601  }
602  used_sockets.insert(b_sock.ptr.data);
603  found_existing = true;
604  }
605  break;
606  }
607  }
608  }
609 
610  if (!found_existing) {
611  /* Create new socket. */
612  BL::NodeSocket b_sock = (param->isoutput) ? b_node.outputs.create(b_data,
613  socket_type.c_str(),
614  param_label.c_str(),
615  param->name.c_str()) :
616  b_node.inputs.create(b_data,
617  socket_type.c_str(),
618  param_label.c_str(),
619  param->name.c_str());
620 
621  /* set default value */
622  if (data_type == BL::NodeSocket::type_VALUE) {
623  set_float(b_sock.ptr, "default_value", default_float);
624  }
625  else if (data_type == BL::NodeSocket::type_INT) {
626  set_int(b_sock.ptr, "default_value", default_int);
627  }
628  else if (data_type == BL::NodeSocket::type_RGBA) {
629  set_float4(b_sock.ptr, "default_value", default_float4);
630  }
631  else if (data_type == BL::NodeSocket::type_VECTOR) {
632  set_float3(b_sock.ptr, "default_value", float4_to_float3(default_float4));
633  }
634  else if (data_type == BL::NodeSocket::type_STRING) {
635  set_string(b_sock.ptr, "default_value", default_string);
636  }
637  else if (data_type == BL::NodeSocket::type_BOOLEAN) {
638  set_boolean(b_sock.ptr, "default_value", default_boolean);
639  }
640 
641  used_sockets.insert(b_sock.ptr.data);
642  }
643  }
644 
645  /* remove unused parameters */
646  bool removed;
647 
648  do {
649  removed = false;
650 
651  for (BL::NodeSocket &b_input : b_node.inputs) {
652  if (used_sockets.find(b_input.ptr.data) == used_sockets.end()) {
653  b_node.inputs.remove(b_data, b_input);
654  removed = true;
655  break;
656  }
657  }
658 
659  for (BL::NodeSocket &b_output : b_node.outputs) {
660  if (used_sockets.find(b_output.ptr.data) == used_sockets.end()) {
661  b_node.outputs.remove(b_data, b_output);
662  removed = true;
663  break;
664  }
665  }
666  } while (removed);
667 
668  Py_RETURN_TRUE;
669 }
670 
671 static PyObject *osl_compile_func(PyObject * /*self*/, PyObject *args)
672 {
673  const char *inputfile = NULL, *outputfile = NULL;
674 
675  if (!PyArg_ParseTuple(args, "ss", &inputfile, &outputfile))
676  return NULL;
677 
678  /* return */
679  if (!OSLShaderManager::osl_compile(inputfile, outputfile))
680  Py_RETURN_FALSE;
681 
682  Py_RETURN_TRUE;
683 }
684 #endif
685 
686 static PyObject *system_info_func(PyObject * /*self*/, PyObject * /*value*/)
687 {
688  string system_info = Device::device_capabilities();
689  return pyunicode_from_string(system_info.c_str());
690 }
691 
692 static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepaths)
693 {
694  if (PyUnicode_Check(pyfilepaths)) {
695  const char *filepath = PyUnicode_AsUTF8(pyfilepaths);
696  filepaths.push_back(filepath);
697  return true;
698  }
699 
700  PyObject *sequence = PySequence_Fast(pyfilepaths,
701  "File paths must be a string or sequence of strings");
702  if (sequence == NULL) {
703  return false;
704  }
705 
706  for (Py_ssize_t i = 0; i < PySequence_Fast_GET_SIZE(sequence); i++) {
707  PyObject *item = PySequence_Fast_GET_ITEM(sequence, i);
708  const char *filepath = PyUnicode_AsUTF8(item);
709  if (filepath == NULL) {
710  PyErr_SetString(PyExc_ValueError, "File paths must be a string or sequence of strings.");
711  Py_DECREF(sequence);
712  return false;
713  }
714  filepaths.push_back(filepath);
715  }
716  Py_DECREF(sequence);
717 
718  return true;
719 }
720 
721 static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
722 {
723  static const char *keyword_list[] = {
724  "preferences", "scene", "view_layer", "input", "output", NULL};
725  PyObject *pypreferences, *pyscene, *pyviewlayer;
726  PyObject *pyinput, *pyoutput = NULL;
727 
728  if (!PyArg_ParseTupleAndKeywords(args,
729  keywords,
730  "OOOO|O",
731  (char **)keyword_list,
732  &pypreferences,
733  &pyscene,
734  &pyviewlayer,
735  &pyinput,
736  &pyoutput)) {
737  return NULL;
738  }
739 
740  /* Get device specification from preferences and scene. */
741  PointerRNA preferencesptr;
743  NULL, &RNA_Preferences, (void *)PyLong_AsVoidPtr(pypreferences), &preferencesptr);
744  BL::Preferences b_preferences(preferencesptr);
745 
746  PointerRNA sceneptr;
747  RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
748  BL::Scene b_scene(sceneptr);
749 
750  DeviceInfo device = blender_device_info(b_preferences, b_scene, true);
751 
752  /* Get denoising parameters from view layer. */
753  PointerRNA viewlayerptr;
754  RNA_pointer_create((ID *)PyLong_AsVoidPtr(pyscene),
755  &RNA_ViewLayer,
756  PyLong_AsVoidPtr(pyviewlayer),
757  &viewlayerptr);
758  BL::ViewLayer b_view_layer(viewlayerptr);
759 
760  DenoiseParams params = BlenderSync::get_denoise_params(b_scene, b_view_layer, true);
761  params.use = true;
762 
763  /* Parse file paths list. */
765 
766  if (!image_parse_filepaths(pyinput, input)) {
767  return NULL;
768  }
769 
770  if (pyoutput) {
771  if (!image_parse_filepaths(pyoutput, output)) {
772  return NULL;
773  }
774  }
775  else {
776  output = input;
777  }
778 
779  if (input.empty()) {
780  PyErr_SetString(PyExc_ValueError, "No input file paths specified.");
781  return NULL;
782  }
783  if (input.size() != output.size()) {
784  PyErr_SetString(PyExc_ValueError, "Number of input and output file paths does not match.");
785  return NULL;
786  }
787 
788  /* Create denoiser. */
789  DenoiserPipeline denoiser(device, params);
790  denoiser.input = input;
791  denoiser.output = output;
792 
793  /* Run denoiser. */
794  if (!denoiser.run()) {
795  PyErr_SetString(PyExc_ValueError, denoiser.error.c_str());
796  return NULL;
797  }
798 
799  Py_RETURN_NONE;
800 }
801 
802 static PyObject *merge_func(PyObject * /*self*/, PyObject *args, PyObject *keywords)
803 {
804  static const char *keyword_list[] = {"input", "output", NULL};
805  PyObject *pyinput, *pyoutput = NULL;
806 
807  if (!PyArg_ParseTupleAndKeywords(
808  args, keywords, "OO", (char **)keyword_list, &pyinput, &pyoutput)) {
809  return NULL;
810  }
811 
812  /* Parse input list. */
814  if (!image_parse_filepaths(pyinput, input)) {
815  return NULL;
816  }
817 
818  /* Parse output string. */
819  if (!PyUnicode_Check(pyoutput)) {
820  PyErr_SetString(PyExc_ValueError, "Output must be a string.");
821  return NULL;
822  }
823  string output = PyUnicode_AsUTF8(pyoutput);
824 
825  /* Merge. */
826  ImageMerger merger;
827  merger.input = input;
828  merger.output = output;
829 
830  if (!merger.run()) {
831  PyErr_SetString(PyExc_ValueError, merger.error.c_str());
832  return NULL;
833  }
834 
835  Py_RETURN_NONE;
836 }
837 
838 static PyObject *debug_flags_update_func(PyObject * /*self*/, PyObject *args)
839 {
840  PyObject *pyscene;
841  if (!PyArg_ParseTuple(args, "O", &pyscene)) {
842  return NULL;
843  }
844 
845  PointerRNA sceneptr;
846  RNA_id_pointer_create((ID *)PyLong_AsVoidPtr(pyscene), &sceneptr);
847  BL::Scene b_scene(sceneptr);
848 
850 
851  debug_flags_set = true;
852 
853  Py_RETURN_NONE;
854 }
855 
856 static PyObject *debug_flags_reset_func(PyObject * /*self*/, PyObject * /*args*/)
857 {
859  if (debug_flags_set) {
860  debug_flags_set = false;
861  }
862  Py_RETURN_NONE;
863 }
864 
865 static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/)
866 {
868  Py_RETURN_NONE;
869 }
870 
871 static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/)
872 {
874  bool has_cuda = false, has_optix = false, has_hip = false, has_metal = false, has_oneapi = false;
875  foreach (DeviceType device_type, device_types) {
876  has_cuda |= (device_type == DEVICE_CUDA);
877  has_optix |= (device_type == DEVICE_OPTIX);
878  has_hip |= (device_type == DEVICE_HIP);
879  has_metal |= (device_type == DEVICE_METAL);
880  has_oneapi |= (device_type == DEVICE_ONEAPI);
881  }
882  PyObject *list = PyTuple_New(5);
883  PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda));
884  PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_optix));
885  PyTuple_SET_ITEM(list, 2, PyBool_FromLong(has_hip));
886  PyTuple_SET_ITEM(list, 3, PyBool_FromLong(has_metal));
887  PyTuple_SET_ITEM(list, 4, PyBool_FromLong(has_oneapi));
888  return list;
889 }
890 
891 static PyObject *set_device_override_func(PyObject * /*self*/, PyObject *arg)
892 {
893  PyObject *override_string = PyObject_Str(arg);
894  string override = PyUnicode_AsUTF8(override_string);
895  Py_DECREF(override_string);
896 
897  bool include_cpu = false;
898  const string cpu_suffix = "+CPU";
899  if (string_endswith(override, cpu_suffix)) {
900  include_cpu = true;
901  override = override.substr(0, override.length() - cpu_suffix.length());
902  }
903 
904  if (override == "CPU") {
906  }
907  else if (override == "CUDA") {
909  }
910  else if (override == "OPTIX") {
912  }
913  else if (override == "HIP") {
915  }
916  else if (override == "METAL") {
918  }
919  else if (override == "ONEAPI") {
921  }
922  else {
923  printf("\nError: %s is not a valid Cycles device.\n", override.c_str());
924  Py_RETURN_FALSE;
925  }
926 
927  if (include_cpu) {
930  }
931 
932  Py_RETURN_TRUE;
933 }
934 
935 static PyMethodDef methods[] = {
936  {"init", init_func, METH_VARARGS, ""},
937  {"exit", exit_func, METH_VARARGS, ""},
938  {"create", create_func, METH_VARARGS, ""},
939  {"free", free_func, METH_O, ""},
940  {"render", render_func, METH_VARARGS, ""},
941  {"render_frame_finish", render_frame_finish_func, METH_VARARGS, ""},
942  {"draw", draw_func, METH_VARARGS, ""},
943  {"bake", bake_func, METH_VARARGS, ""},
944  {"view_draw", view_draw_func, METH_VARARGS, ""},
945  {"sync", sync_func, METH_VARARGS, ""},
946  {"reset", reset_func, METH_VARARGS, ""},
947 #ifdef WITH_OSL
948  {"osl_update_node", osl_update_node_func, METH_VARARGS, ""},
949  {"osl_compile", osl_compile_func, METH_VARARGS, ""},
950 #endif
951  {"available_devices", available_devices_func, METH_VARARGS, ""},
952  {"system_info", system_info_func, METH_NOARGS, ""},
953 
954  /* Standalone denoising */
955  {"denoise", (PyCFunction)denoise_func, METH_VARARGS | METH_KEYWORDS, ""},
956  {"merge", (PyCFunction)merge_func, METH_VARARGS | METH_KEYWORDS, ""},
957 
958  /* Debugging routines */
959  {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""},
960  {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""},
961 
962  /* Statistics. */
963  {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""},
964 
965  /* Compute Device selection */
966  {"get_device_types", get_device_types_func, METH_VARARGS, ""},
967  {"set_device_override", set_device_override_func, METH_O, ""},
968 
969  {NULL, NULL, 0, NULL},
970 };
971 
972 static struct PyModuleDef module = {
973  PyModuleDef_HEAD_INIT,
974  "_cycles",
975  "Blender cycles render integration",
976  -1,
977  methods,
978  NULL,
979  NULL,
980  NULL,
981  NULL,
982 };
983 
985 
987 {
988  PyObject *mod = PyModule_Create(&ccl::module);
989 
990 #ifdef WITH_OSL
991  /* TODO(sergey): This gives us library we've been linking against.
992  * In theory with dynamic OSL library it might not be
993  * accurate, but there's nothing in OSL API which we
994  * might use to get version in runtime.
995  */
996  int curversion = OSL_LIBRARY_VERSION_CODE;
997  PyModule_AddObject(mod, "with_osl", Py_True);
998  Py_INCREF(Py_True);
999  PyModule_AddObject(
1000  mod,
1001  "osl_version",
1002  Py_BuildValue("(iii)", curversion / 10000, (curversion / 100) % 100, curversion % 100));
1003  PyModule_AddObject(
1004  mod,
1005  "osl_version_string",
1006  PyUnicode_FromFormat(
1007  "%2d, %2d, %2d", curversion / 10000, (curversion / 100) % 100, curversion % 100));
1008 #else
1009  PyModule_AddObject(mod, "with_osl", Py_False);
1010  Py_INCREF(Py_False);
1011  PyModule_AddStringConstant(mod, "osl_version", "unknown");
1012  PyModule_AddStringConstant(mod, "osl_version_string", "unknown");
1013 #endif
1014 
1015 #ifdef WITH_EMBREE
1016  PyModule_AddObject(mod, "with_embree", Py_True);
1017  Py_INCREF(Py_True);
1018 #else /* WITH_EMBREE */
1019  PyModule_AddObject(mod, "with_embree", Py_False);
1020  Py_INCREF(Py_False);
1021 #endif /* WITH_EMBREE */
1022 
1024  PyModule_AddObject(mod, "with_openimagedenoise", Py_True);
1025  Py_INCREF(Py_True);
1026  }
1027  else {
1028  PyModule_AddObject(mod, "with_openimagedenoise", Py_False);
1029  Py_INCREF(Py_False);
1030  }
1031 
1032 #ifdef WITH_CYCLES_DEBUG
1033  PyModule_AddObject(mod, "with_debug", Py_True);
1034  Py_INCREF(Py_True);
1035 #else /* WITH_CYCLES_DEBUG */
1036  PyModule_AddObject(mod, "with_debug", Py_False);
1037  Py_INCREF(Py_False);
1038 #endif /* WITH_CYCLES_DEBUG */
1039 
1040  return (void *)mod;
1041 }
unsigned int uint
Definition: BLI_sys_types.h:67
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct ViewLayer ViewLayer
struct Object Object
struct Scene Scene
struct RegionView3D RegionView3D
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum query
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei width
float float4[4]
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value NORMAL
struct RenderEngine RenderEngine
DeviceInfo blender_device_info(BL::Preferences &b_preferences, BL::Scene &b_scene, bool background)
static bool headless
static bool print_render_stats
void synchronize(BL::Depsgraph &b_depsgraph)
void * python_thread_state
void view_draw(int w, int h)
void reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph)
void bake(BL::Depsgraph &b_depsgrah, BL::Object &b_object, const string &pass_type, const int custom_flag, const int bake_width, const int bake_height)
void render(BL::Depsgraph &b_depsgraph)
void draw(BL::SpaceImageEditor &space_image)
static DeviceTypeMask device_override
static DenoiseParams get_denoise_params(BL::Scene &b_scene, BL::ViewLayer &b_view_layer, bool background)
Definition: sync.cpp:955
CPU cpu
Definition: debug.h:128
void reset()
Definition: debug.cpp:92
OptiX optix
Definition: debug.h:134
CUDA cuda
Definition: debug.h:131
bool running_inside_blender
Definition: debug.h:23
bool viewport_static_bvh
Definition: debug.h:21
vector< string > input
Definition: denoising.h:36
vector< string > output
Definition: denoising.h:40
bool has_peer_memory
Definition: device/device.h:70
DeviceType type
Definition: device/device.h:62
string description
Definition: device/device.h:63
static void free_memory()
static vector< DeviceInfo > available_devices(uint device_type_mask=DEVICE_MASK_ALL)
static DeviceType type_from_string(const char *name)
static string device_capabilities(uint device_type_mask=DEVICE_MASK_ALL)
static vector< DeviceType > available_types()
static string string_from_type(DeviceType type)
bool run()
Definition: merge.cpp:569
string output
Definition: merge.h:25
vector< string > input
Definition: merge.h:23
string error
Definition: merge.h:20
Definition: md5.h:20
string get_hex()
Definition: md5.cpp:348
void append(const uint8_t *data, int size)
Definition: md5.cpp:256
static void free_memory()
static void free_memory()
Definition: task.cpp:94
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
static void set_boolean(PointerRNA &ptr, const char *name, bool value)
static bool get_boolean(PointerRNA &ptr, const char *name)
static void set_float3(PointerRNA &ptr, const char *name, float3 value)
static int get_enum(PointerRNA &ptr, const char *name, int num_values=-1, int default_value=-1)
static void set_float4(PointerRNA &ptr, const char *name, float4 value)
static void set_int(PointerRNA &ptr, const char *name, int value)
static void set_float(PointerRNA &ptr, const char *name, float value)
static void set_string(PointerRNA &ptr, const char *name, const string &value)
DebugFlags & DebugFlags()
Definition: debug.h:159
#define DEVICE_MASK(type)
Definition: device/device.h:58
DeviceTypeMask
Definition: device/device.h:48
@ DEVICE_MASK_OPTIX
Definition: device/device.h:51
@ DEVICE_MASK_CPU
Definition: device/device.h:49
@ DEVICE_MASK_HIP
Definition: device/device.h:52
@ DEVICE_MASK_ALL
Definition: device/device.h:55
@ DEVICE_MASK_CUDA
Definition: device/device.h:50
@ DEVICE_MASK_METAL
Definition: device/device.h:53
@ DEVICE_MASK_ONEAPI
Definition: device/device.h:54
DeviceType
Definition: device/device.h:36
@ DEVICE_NONE
Definition: device/device.h:37
@ DEVICE_METAL
Definition: device/device.h:43
@ DEVICE_CUDA
Definition: device/device.h:39
@ DEVICE_OPTIX
Definition: device/device.h:41
@ DEVICE_HIP
Definition: device/device.h:42
@ DEVICE_ONEAPI
Definition: device/device.h:44
static KeywordTokenDef keyword_list[]
#define str(s)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
#define make_float4(x, y, z, w)
Definition: metal/compat.h:205
static void debug_flags_reset()
Definition: python.cpp:80
static void debug_flags_sync_from_scene(BL::Scene b_scene)
Definition: python.cpp:58
void * pylong_as_voidptr_typesafe(PyObject *object)
Definition: python.cpp:42
PyObject * pyunicode_from_string(const char *str)
Definition: python.cpp:49
static const VertexNature POINT
Definition: Nature.h:20
Vector< CPUDevice > devices
list of all CPUDevices. for every hardware thread an instance of CPUDevice is created
T length(const vec_base< T, Size > &a)
static CCL_NAMESPACE_BEGIN bool openimagedenoise_supported()
CCL_NAMESPACE_BEGIN typedef KernelBVHLayout BVHLayout
Definition: params.h:19
void path_init(const string &path, const string &user_path)
Definition: path.cpp:325
static PyObject * available_devices_func(PyObject *, PyObject *args)
Definition: python.cpp:399
CCL_NAMESPACE_END void * CCL_python_module_init()
Definition: python.cpp:986
void python_thread_state_restore(void **python_thread_state)
Definition: python.cpp:93
static PyObject * draw_func(PyObject *, PyObject *args)
Definition: python.cpp:270
static PyObject * create_func(PyObject *, PyObject *args)
Definition: python.cpp:156
static PyObject * debug_flags_reset_func(PyObject *, PyObject *)
Definition: python.cpp:856
static PyObject * view_draw_func(PyObject *, PyObject *args)
Definition: python.cpp:331
static PyObject * set_device_override_func(PyObject *, PyObject *arg)
Definition: python.cpp:891
static PyObject * sync_func(PyObject *, PyObject *args)
Definition: python.cpp:377
static struct PyModuleDef module
Definition: python.cpp:972
static PyObject * debug_flags_update_func(PyObject *, PyObject *args)
Definition: python.cpp:838
static bool image_parse_filepaths(PyObject *pyfilepaths, vector< string > &filepaths)
Definition: python.cpp:692
static PyMethodDef methods[]
Definition: python.cpp:935
static PyObject * merge_func(PyObject *, PyObject *args, PyObject *keywords)
Definition: python.cpp:802
static PyObject * render_func(PyObject *, PyObject *args)
Definition: python.cpp:227
static PyObject * enable_print_stats_func(PyObject *, PyObject *)
Definition: python.cpp:865
static PyObject * system_info_func(PyObject *, PyObject *)
Definition: python.cpp:686
static PyObject * exit_func(PyObject *, PyObject *)
Definition: python.cpp:148
static const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
Definition: python.cpp:99
void python_thread_state_save(void **python_thread_state)
Definition: python.cpp:88
static PyObject * get_device_types_func(PyObject *, PyObject *)
Definition: python.cpp:871
static PyObject * denoise_func(PyObject *, PyObject *args, PyObject *keywords)
Definition: python.cpp:721
static PyObject * free_func(PyObject *, PyObject *value)
Definition: python.cpp:220
static PyObject * reset_func(PyObject *, PyObject *args)
Definition: python.cpp:351
static PyObject * render_frame_finish_func(PyObject *, PyObject *args)
Definition: python.cpp:250
static PyObject * bake_func(PyObject *, PyObject *args)
Definition: python.cpp:295
static PyObject * init_func(PyObject *, PyObject *args)
Definition: python.cpp:126
return ret
void RNA_pointer_create(ID *id, StructRNA *type, void *data, PointerRNA *r_ptr)
Definition: rna_access.c:136
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5167
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
void RNA_main_pointer_create(struct Main *main, PointerRNA *r_ptr)
Definition: rna_access.c:105
@ FLOAT
unsigned char uint8_t
Definition: stdint.h:78
bool string_endswith(const string_view s, const string_view end)
Definition: string.cpp:111
bool avx
Definition: debug.h:34
bool sse2
Definition: debug.h:37
bool avx2
Definition: debug.h:33
bool sse3
Definition: debug.h:36
BVHLayout bvh_layout
Definition: debug.h:68
bool sse41
Definition: debug.h:35
bool adaptive_compile
Definition: debug.h:80
bool use_debug
Definition: debug.h:103
Definition: DNA_ID.h:368
Definition: BKE_main.h:121
ccl_device_inline int mod(int x, int m)
Definition: util/math.h:490
ccl_device_inline float3 float4_to_float3(const float4 a)
Definition: util/math.h:500