Blender  V3.3
blender/session.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include <stdlib.h>
5 
6 #include "device/device.h"
7 #include "scene/background.h"
8 #include "scene/camera.h"
9 #include "scene/colorspace.h"
10 #include "scene/film.h"
11 #include "scene/integrator.h"
12 #include "scene/light.h"
13 #include "scene/mesh.h"
14 #include "scene/object.h"
15 #include "scene/scene.h"
16 #include "scene/shader.h"
17 #include "scene/stats.h"
18 #include "session/buffers.h"
19 #include "session/session.h"
20 
21 #include "util/algorithm.h"
22 #include "util/color.h"
23 #include "util/foreach.h"
24 #include "util/function.h"
25 #include "util/hash.h"
26 #include "util/log.h"
27 #include "util/murmurhash.h"
28 #include "util/path.h"
29 #include "util/progress.h"
30 #include "util/time.h"
31 
32 #include "blender/display_driver.h"
33 #include "blender/output_driver.h"
34 #include "blender/session.h"
35 #include "blender/sync.h"
36 #include "blender/util.h"
37 
39 
41 bool BlenderSession::headless = false;
43 
45  BL::Preferences &b_userpref,
46  BL::BlendData &b_data,
47  bool preview_osl)
48  : session(NULL),
49  scene(NULL),
50  sync(NULL),
51  b_engine(b_engine),
52  b_userpref(b_userpref),
53  b_data(b_data),
54  b_render(b_engine.render()),
55  b_depsgraph(PointerRNA_NULL),
56  b_scene(PointerRNA_NULL),
57  b_v3d(PointerRNA_NULL),
58  b_rv3d(PointerRNA_NULL),
59  width(0),
60  height(0),
61  preview_osl(preview_osl),
62  python_thread_state(NULL),
63  use_developer_ui(false)
64 {
65  /* offline render */
66  background = true;
67  last_redraw_time = 0.0;
68  start_resize_time = 0.0;
69  last_status_time = 0.0;
70 }
71 
73  BL::Preferences &b_userpref,
74  BL::BlendData &b_data,
75  BL::SpaceView3D &b_v3d,
76  BL::RegionView3D &b_rv3d,
77  int width,
78  int height)
79  : session(NULL),
80  scene(NULL),
81  sync(NULL),
82  b_engine(b_engine),
83  b_userpref(b_userpref),
84  b_data(b_data),
85  b_render(b_engine.render()),
86  b_depsgraph(PointerRNA_NULL),
87  b_scene(PointerRNA_NULL),
88  b_v3d(b_v3d),
89  b_rv3d(b_rv3d),
90  width(width),
91  height(height),
92  preview_osl(false),
93  python_thread_state(NULL),
94  use_developer_ui(b_userpref.experimental().use_cycles_debug() &&
95  b_userpref.view().show_developer_ui())
96 {
97  /* 3d view render */
98  background = false;
99  last_redraw_time = 0.0;
100  start_resize_time = 0.0;
101  last_status_time = 0.0;
102 }
103 
105 {
106  free_session();
107 }
108 
110 {
111  const SessionParams session_params = BlenderSync::get_session_params(
114  const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
115 
116  /* reset status/progress */
117  last_status = "";
118  last_error = "";
119  last_progress = -1.0;
120  start_resize_time = 0.0;
121 
122  /* create session */
123  session = new Session(session_params, scene_params);
126  session->set_pause(session_pause);
127 
128  /* create scene */
129  scene = session->scene;
130  scene->name = b_scene.name();
131 
132  /* create sync */
133  sync = new BlenderSync(
135  BL::Object b_camera_override(b_engine.camera_override());
136  if (b_v3d) {
138  }
139  else {
140  sync->sync_camera(b_render, b_camera_override, width, height, "");
141  }
142 
143  /* set buffer parameters */
144  const BufferParams buffer_params = BlenderSync::get_buffer_params(
146  session->reset(session_params, buffer_params);
147 
148  /* Viewport and preview (as in, material preview) does not do tiled rendering, so can inform
149  * engine that no tracking of the tiles state is needed.
150  * The offline rendering will make a decision when tile is being written. The penalty of asking
151  * the engine to keep track of tiles state is minimal, so there is nothing to worry about here
152  * about possible single-tiled final render. */
153  if (!b_engine.is_preview() && !b_v3d) {
154  b_engine.use_highlight_tiles(true);
155  }
156 }
157 
158 void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsgraph)
159 {
160  /* Update data, scene and depsgraph pointers. These can change after undo. */
161  this->b_data = b_data;
162  this->b_depsgraph = b_depsgraph;
163  this->b_scene = b_depsgraph.scene_eval();
164  if (sync) {
165  sync->reset(this->b_data, this->b_scene);
166  }
167 
168  if (preview_osl) {
169  PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
170  RNA_boolean_set(&cscene, "shading_system", preview_osl);
171  }
172 
173  if (b_v3d) {
174  this->b_render = b_scene.render();
175  }
176  else {
177  this->b_render = b_engine.render();
180  }
181 
182  bool is_new_session = (session == NULL);
183  if (is_new_session) {
184  /* Initialize session and remember it was just created so not to
185  * re-create it below.
186  */
187  create_session();
188  }
189 
190  if (b_v3d) {
191  /* NOTE: We need to create session, but all the code from below
192  * will make viewport render to stuck on initialization.
193  */
194  return;
195  }
196 
197  const SessionParams session_params = BlenderSync::get_session_params(
200 
201  if (scene->params.modified(scene_params) || session->params.modified(session_params) ||
202  !this->b_render.use_persistent_data()) {
203  /* if scene or session parameters changed, it's easier to simply re-create
204  * them rather than trying to distinguish which settings need to be updated
205  */
206  if (!is_new_session) {
207  free_session();
208  create_session();
209  }
210  return;
211  }
212 
214 
215  /* peak memory usage should show current render peak, not peak for all renders
216  * made by this render session
217  */
219 
220  if (is_new_session) {
221  /* Sync object should be re-created for new scene. */
222  delete sync;
223  sync = new BlenderSync(
225  }
226  else {
227  /* Sync recalculations to do just the required updates. */
229  }
230 
231  BL::Object b_camera_override(b_engine.camera_override());
232  sync->sync_camera(b_render, b_camera_override, width, height, "");
233 
234  BL::SpaceView3D b_null_space_view3d(PointerRNA_NULL);
235  BL::RegionView3D b_null_region_view3d(PointerRNA_NULL);
236  const BufferParams buffer_params = BlenderSync::get_buffer_params(
237  b_null_space_view3d, b_null_region_view3d, scene->camera, width, height);
238  session->reset(session_params, buffer_params);
239 
240  /* reset time */
241  start_resize_time = 0.0;
242 
243  {
245  draw_state_.last_pass_index = -1;
246  }
247 }
248 
250 {
251  if (session) {
252  session->cancel(true);
253  }
254 
255  delete sync;
256  sync = nullptr;
257 
258  delete session;
259  session = nullptr;
260 
261  display_driver_ = nullptr;
262 }
263 
264 void BlenderSession::full_buffer_written(string_view filename)
265 {
266  full_buffer_files_.emplace_back(filename);
267 }
268 
269 static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest)
270 {
271  string identifier = string_printf("%08x", util_murmur_hash3(name.c_str(), name.length(), 0));
272  string prefix = "cryptomatte/" + identifier.substr(0, 7) + "/";
273 
274  render_add_metadata(b_rr, prefix + "name", name);
275  render_add_metadata(b_rr, prefix + "hash", "MurmurHash3_32");
276  render_add_metadata(b_rr, prefix + "conversion", "uint32_to_float32");
277  render_add_metadata(b_rr, prefix + "manifest", manifest);
278 }
279 
280 void BlenderSession::stamp_view_layer_metadata(Scene *scene, const string &view_layer_name)
281 {
282  BL::RenderResult b_rr = b_engine.get_result();
283  string prefix = "cycles." + view_layer_name + ".";
284 
285  /* Configured number of samples for the view layer. */
286  b_rr.stamp_data_add_field((prefix + "samples").c_str(),
287  to_string(session->params.samples).c_str());
288 
289  /* Store ranged samples information. */
290  /* TODO(sergey): Need to bring this information back. */
291 #if 0
292  if (session->tile_manager.range_num_samples != -1) {
293  b_rr.stamp_data_add_field((prefix + "range_start_sample").c_str(),
294  to_string(session->tile_manager.range_start_sample).c_str());
295  b_rr.stamp_data_add_field((prefix + "range_num_samples").c_str(),
296  to_string(session->tile_manager.range_num_samples).c_str());
297  }
298 #endif
299 
300  /* Write cryptomatte metadata. */
301  if (scene->film->get_cryptomatte_passes() & CRYPT_OBJECT) {
303  view_layer_name + ".CryptoObject",
305  }
306  if (scene->film->get_cryptomatte_passes() & CRYPT_MATERIAL) {
308  view_layer_name + ".CryptoMaterial",
310  }
311  if (scene->film->get_cryptomatte_passes() & CRYPT_ASSET) {
313  view_layer_name + ".CryptoAsset",
315  }
316 
317  /* Store synchronization and bare-render times. */
318  double total_time, render_time;
319  session->progress.get_time(total_time, render_time);
320  b_rr.stamp_data_add_field((prefix + "total_time").c_str(),
321  time_human_readable_from_seconds(total_time).c_str());
322  b_rr.stamp_data_add_field((prefix + "render_time").c_str(),
323  time_human_readable_from_seconds(render_time).c_str());
324  b_rr.stamp_data_add_field((prefix + "synchronization_time").c_str(),
325  time_human_readable_from_seconds(total_time - render_time).c_str());
326 }
327 
329 {
330  b_depsgraph = b_depsgraph_;
331 
332  if (session->progress.get_cancel()) {
334  return;
335  }
336 
337  /* Create driver to write out render results. */
339  session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
340 
341  session->full_buffer_written_cb = [&](string_view filename) { full_buffer_written(filename); };
342 
343  BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
344 
345  /* get buffer parameters */
346  const SessionParams session_params = BlenderSync::get_session_params(
350 
351  /* temporary render result to find needed passes and views */
352  BL::RenderResult b_rr = b_engine.begin_result(0, 0, 1, 1, b_view_layer.name().c_str(), NULL);
353  BL::RenderResult::layers_iterator b_single_rlay;
354  b_rr.layers.begin(b_single_rlay);
355  BL::RenderLayer b_rlay = *b_single_rlay;
356 
357  {
359  b_rlay_name = b_view_layer.name();
360 
361  /* Signal that the display pass is to be updated. */
362  draw_state_.last_pass_index = -1;
363  }
364 
365  /* Compute render passes and film settings. */
366  sync->sync_render_passes(b_rlay, b_view_layer);
367 
368  BL::RenderResult::views_iterator b_view_iter;
369 
370  int num_views = 0;
371  for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) {
372  num_views++;
373  }
374 
375  int view_index = 0;
376  for (b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end();
377  ++b_view_iter, ++view_index) {
378  b_rview_name = b_view_iter->name();
379 
380  buffer_params.layer = b_view_layer.name();
381  buffer_params.view = b_rview_name;
382 
383  /* set the current view */
384  b_engine.active_view_set(b_rview_name.c_str());
385 
386  /* Force update in this case, since the camera transform on each frame changes
387  * in different views. This could be optimized by somehow storing the animated
388  * camera transforms separate from the fixed stereo transform. */
389  if ((scene->need_motion() != Scene::MOTION_NONE) && view_index > 0) {
390  sync->tag_update();
391  }
392 
393  /* update scene */
394  BL::Object b_camera_override(b_engine.camera_override());
395  sync->sync_camera(b_render, b_camera_override, width, height, b_rview_name.c_str());
396  sync->sync_data(
397  b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
399 
400  /* Attempt to free all data which is held by Blender side, since at this
401  * point we know that we've got everything to render current view layer.
402  */
403  /* At the moment we only free if we are not doing multi-view
404  * (or if we are rendering the last view). See T58142/D4239 for discussion.
405  */
406  if (view_index == num_views - 1) {
408  }
409 
410  /* Make sure all views have different noise patterns. - hardcoded value just to make it random
411  */
412  if (view_index != 0) {
413  int seed = scene->integrator->get_seed();
414  seed += hash_uint2(seed, hash_uint2(view_index * 0xdeadbeef, 0));
415  scene->integrator->set_seed(seed);
416  }
417 
418  /* Update number of samples per layer. */
419  const int samples = sync->get_layer_samples();
420  const bool bound_samples = sync->get_layer_bound_samples();
421 
422  SessionParams effective_session_params = session_params;
423  if (samples != 0 && (!bound_samples || (samples < session_params.samples))) {
424  effective_session_params.samples = samples;
425  }
426 
427  /* Update session itself. */
428  session->reset(effective_session_params, buffer_params);
429 
430  /* render */
431  if (!b_engine.is_preview() && background && print_render_stats) {
433  }
434 
435  session->start();
436  session->wait();
437 
438  if (!b_engine.is_preview() && background && print_render_stats) {
439  RenderStats stats;
440  session->collect_statistics(&stats);
441  printf("Render statistics:\n%s\n", stats.full_report().c_str());
442  }
443 
444  if (session->progress.get_cancel())
445  break;
446  }
447 
448  /* add metadata */
450 
451  /* free result without merging */
452  b_engine.end_result(b_rr, true, false, false);
453 
454  /* When tiled rendering is used there will be no "write" done for the tile. Forcefully clear
455  * highlighted tiles now, so that the highlight will be removed while processing full frame from
456  * file. */
457  b_engine.tile_highlight_clear_all();
458 
459  double total_time, render_time;
460  session->progress.get_time(total_time, render_time);
461  VLOG_INFO << "Total render time: " << total_time;
462  VLOG_INFO << "Render time (without synchronization): " << render_time;
463 }
464 
466 {
467  /* Processing of all layers and views is done. Clear the strings so that we can communicate
468  * progress about reading files and denoising them. */
469  b_rlay_name = "";
470  b_rview_name = "";
471 
472  if (!b_render.use_persistent_data()) {
473  /* Free the sync object so that it can properly dereference nodes from the scene graph before
474  * the graph is freed. */
475  delete sync;
476  sync = nullptr;
477 
478  session->device_free();
479  }
480 
481  for (string_view filename : full_buffer_files_) {
484  break;
485  }
486  }
487 
488  for (string_view filename : full_buffer_files_) {
489  path_remove(filename);
490  }
491 
492  /* Clear output driver. */
493  session->set_output_driver(nullptr);
495 
496  /* The display driver is the source of drawing context for both drawing and possible graphics
497  * interop objects in the path trace. Once the frame is finished the OpenGL context might be
498  * freed form Blender side. Need to ensure that all GPU resources are freed prior to that
499  * point.
500  * Ideally would only do this when OpenGL context is actually destroyed, but there is no way to
501  * know when this happens (at least in the code at the time when this comment was written).
502  * The penalty of re-creating resources on every frame is unlikely to be noticed. */
503  display_driver_ = nullptr;
504  session->set_display_driver(nullptr);
505 
506  /* All the files are handled.
507  * Clear the list so that this session can be re-used by Persistent Data. */
508  full_buffer_files_.clear();
509 }
510 
511 static bool bake_setup_pass(Scene *scene, const string &bake_type_str, const int bake_filter)
512 {
513  Integrator *integrator = scene->integrator;
514  const char *bake_type = bake_type_str.c_str();
515 
517  bool use_direct_light = false;
518  bool use_indirect_light = false;
519  bool include_albedo = false;
520 
521  /* Data passes. */
522  if (strcmp(bake_type, "POSITION") == 0) {
524  }
525  else if (strcmp(bake_type, "NORMAL") == 0) {
526  type = PASS_NORMAL;
527  }
528  else if (strcmp(bake_type, "UV") == 0) {
529  type = PASS_UV;
530  }
531  else if (strcmp(bake_type, "ROUGHNESS") == 0) {
533  }
534  else if (strcmp(bake_type, "EMIT") == 0) {
536  }
537  /* Environment pass. */
538  else if (strcmp(bake_type, "ENVIRONMENT") == 0) {
540  }
541  /* AO passes. */
542  else if (strcmp(bake_type, "AO") == 0) {
543  type = PASS_AO;
544  }
545  /* Combined pass. */
546  else if (strcmp(bake_type, "COMBINED") == 0) {
548 
549  use_direct_light = (bake_filter & BL::BakeSettings::pass_filter_DIRECT) != 0;
550  use_indirect_light = (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) != 0;
551  include_albedo = (bake_filter & BL::BakeSettings::pass_filter_COLOR);
552 
553  integrator->set_use_diffuse((bake_filter & BL::BakeSettings::pass_filter_DIFFUSE) != 0);
554  integrator->set_use_glossy((bake_filter & BL::BakeSettings::pass_filter_GLOSSY) != 0);
555  integrator->set_use_transmission((bake_filter & BL::BakeSettings::pass_filter_TRANSMISSION) !=
556  0);
557  integrator->set_use_emission((bake_filter & BL::BakeSettings::pass_filter_EMIT) != 0);
558  }
559  /* Shadow pass. */
560  else if (strcmp(bake_type, "SHADOW") == 0) {
561  type = PASS_SHADOW;
562  use_direct_light = true;
563  }
564  /* Light component passes. */
565  else if (strcmp(bake_type, "DIFFUSE") == 0) {
566  if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
567  bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
568  type = PASS_DIFFUSE;
569  use_direct_light = true;
570  use_indirect_light = true;
571  }
572  else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
574  use_direct_light = true;
575  }
576  else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
578  use_indirect_light = true;
579  }
580  else {
582  }
583 
584  include_albedo = (bake_filter & BL::BakeSettings::pass_filter_COLOR);
585  }
586  else if (strcmp(bake_type, "GLOSSY") == 0) {
587  if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
588  bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
589  type = PASS_GLOSSY;
590  use_direct_light = true;
591  use_indirect_light = true;
592  }
593  else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
595  use_direct_light = true;
596  }
597  else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
599  use_indirect_light = true;
600  }
601  else {
603  }
604 
605  include_albedo = (bake_filter & BL::BakeSettings::pass_filter_COLOR);
606  }
607  else if (strcmp(bake_type, "TRANSMISSION") == 0) {
608  if ((bake_filter & BL::BakeSettings::pass_filter_DIRECT) &&
609  bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
611  use_direct_light = true;
612  use_indirect_light = true;
613  }
614  else if (bake_filter & BL::BakeSettings::pass_filter_DIRECT) {
616  use_direct_light = true;
617  }
618  else if (bake_filter & BL::BakeSettings::pass_filter_INDIRECT) {
620  use_indirect_light = true;
621  }
622  else {
624  }
625 
626  include_albedo = (bake_filter & BL::BakeSettings::pass_filter_COLOR);
627  }
628 
629  if (type == PASS_NONE) {
630  return false;
631  }
632 
633  /* Create pass. */
634  Pass *pass = scene->create_node<Pass>();
635  pass->set_name(ustring("Combined"));
636  pass->set_type(type);
637  pass->set_include_albedo(include_albedo);
638 
639  /* Disable direct indirect light for performance when not needed. */
640  integrator->set_use_direct_light(use_direct_light);
641  integrator->set_use_indirect_light(use_indirect_light);
642 
643  return true;
644 }
645 
647  BL::Object &b_object,
648  const string &bake_type,
649  const int bake_filter,
650  const int bake_width,
651  const int bake_height)
652 {
653  b_depsgraph = b_depsgraph_;
654 
655  /* Initialize bake manager, before we load the baking kernels. */
656  scene->bake_manager->set(scene, b_object.name());
657 
658  session->set_display_driver(nullptr);
659  session->set_output_driver(make_unique<BlenderOutputDriver>(b_engine));
660  session->full_buffer_written_cb = [&](string_view filename) { full_buffer_written(filename); };
661 
662  /* Sync scene. */
663  BL::Object b_camera_override(b_engine.camera_override());
664  sync->sync_camera(b_render, b_camera_override, width, height, "");
665  sync->sync_data(
666  b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
667 
668  /* Add render pass that we want to bake, and name it Combined so that it is
669  * used as that on the Blender side. */
670  if (!bake_setup_pass(scene, bake_type, bake_filter)) {
671  session->cancel(true);
672  }
673 
674  /* Always use transparent background for baking. */
675  scene->background->set_transparent(true);
676 
677  if (!session->progress.get_cancel()) {
678  /* Load built-in images from Blender. */
680  }
681 
682  /* Object might have been disabled for rendering or excluded in some
683  * other way, in that case Blender will report a warning afterwards. */
684  bool object_found = false;
685  if (!session->progress.get_cancel()) {
686  foreach (Object *ob, scene->objects) {
687  if (ob->name == b_object.name()) {
688  object_found = true;
689  break;
690  }
691  }
692  }
693 
694  if (object_found && !session->progress.get_cancel()) {
695  /* Get session and buffer parameters. */
696  const SessionParams session_params = BlenderSync::get_session_params(
698 
699  BufferParams buffer_params;
700  buffer_params.width = bake_width;
701  buffer_params.height = bake_height;
702  buffer_params.window_width = bake_width;
703  buffer_params.window_height = bake_height;
704  /* Unique layer name for multi-image baking. */
705  buffer_params.layer = string_printf("bake_%d\n", bake_id++);
706 
707  /* Update session. */
708  session->reset(session_params, buffer_params);
709 
712  }
713 
714  /* Perform bake. Check cancel to avoid crash with incomplete scene data. */
715  if (object_found && !session->progress.get_cancel()) {
716  session->start();
717  session->wait();
718  }
719 }
720 
722 {
723  /* only used for viewport render */
724  if (!b_v3d)
725  return;
726 
727  /* on session/scene parameter changes, we recreate session entirely */
728  const SessionParams session_params = BlenderSync::get_session_params(
731  const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
732 
733  if (session->params.modified(session_params) || scene->params.modified(scene_params)) {
734  free_session();
735  create_session();
736  }
737 
739 
740  /* increase samples and render time, but never decrease */
741  session->set_samples(session_params.samples);
742  session->set_time_limit(session_params.time_limit);
743  session->set_pause(session_pause);
744 
745  /* copy recalc flags, outside of mutex so we can decide to do the real
746  * synchronization at a later time to not block on running updates */
747  sync->sync_recalc(b_depsgraph_, b_v3d);
748 
749  /* don't do synchronization if on pause */
750  if (session_pause) {
751  tag_update();
752  return;
753  }
754 
755  /* try to acquire mutex. if we don't want to or can't, come back later */
756  if (!session->ready_to_reset() || !session->scene->mutex.try_lock()) {
757  tag_update();
758  return;
759  }
760 
761  /* data and camera synchronize */
762  b_depsgraph = b_depsgraph_;
763 
764  BL::Object b_camera_override(b_engine.camera_override());
765  sync->sync_data(
766  b_render, b_depsgraph, b_v3d, b_camera_override, width, height, &python_thread_state);
767 
768  if (b_rv3d)
770  else
771  sync->sync_camera(b_render, b_camera_override, width, height, "");
772 
773  /* get buffer parameters */
774  const BufferParams buffer_params = BlenderSync::get_buffer_params(
776 
777  /* reset if needed */
778  if (scene->need_reset()) {
779  session->reset(session_params, buffer_params);
780 
781  /* After session reset, so device is not accessing image data anymore. */
783 
784  /* reset time */
785  start_resize_time = 0.0;
786  }
787 
788  /* unlock */
789  session->scene->mutex.unlock();
790 
791  /* Start rendering thread, if it's not running already. Do this
792  * after all scene data has been synced at least once. */
793  session->start();
794 }
795 
796 void BlenderSession::draw(BL::SpaceImageEditor &space_image)
797 {
798  if (!session || !session->scene) {
799  /* Offline render drawing does not force the render engine update, which means it's possible
800  * that the Session is not created yet. */
801  return;
802  }
803 
805 
806  const int pass_index = space_image.image_user().multilayer_pass();
807  if (pass_index != draw_state_.last_pass_index) {
808  BL::RenderPass b_display_pass(b_engine.pass_by_index_get(b_rlay_name.c_str(), pass_index));
809  if (!b_display_pass) {
810  return;
811  }
812 
813  Scene *scene = session->scene;
814 
816 
817  const Pass *pass = Pass::find(scene->passes, b_display_pass.name());
818  if (!pass) {
819  return;
820  }
821 
822  scene->film->set_display_pass(pass->get_type());
823 
824  draw_state_.last_pass_index = pass_index;
825  }
826 
827  if (display_driver_) {
828  BL::Array<float, 2> zoom = space_image.zoom();
829  display_driver_->set_zoom(zoom[0], zoom[1]);
830  }
831 
832  session->draw();
833 }
834 
835 void BlenderSession::view_draw(int w, int h)
836 {
837  /* pause in redraw in case update is not being called due to final render */
839 
840  /* before drawing, we verify camera and viewport size changes, because
841  * we do not get update callbacks for those, we must detect them here */
842  if (session->ready_to_reset()) {
843  bool reset = false;
844 
845  /* if dimensions changed, reset */
846  if (width != w || height != h) {
847  if (start_resize_time == 0.0) {
848  /* don't react immediately to resizes to avoid flickery resizing
849  * of the viewport, and some window managers changing the window
850  * size temporarily on unminimize */
852  tag_redraw();
853  }
854  else if (time_dt() - start_resize_time < 0.2) {
855  tag_redraw();
856  }
857  else {
858  width = w;
859  height = h;
860  reset = true;
861  }
862  }
863 
864  /* try to acquire mutex. if we can't, come back later */
865  if (!session->scene->mutex.try_lock()) {
866  tag_update();
867  }
868  else {
869  /* update camera from 3d view */
870 
872 
873  if (scene->camera->is_modified())
874  reset = true;
875 
876  session->scene->mutex.unlock();
877  }
878 
879  /* reset if requested */
880  if (reset) {
881  const SessionParams session_params = BlenderSync::get_session_params(
883  const BufferParams buffer_params = BlenderSync::get_buffer_params(
885  const bool session_pause = BlenderSync::get_session_pause(b_scene, background);
886 
887  if (session_pause == false) {
888  session->reset(session_params, buffer_params);
889  start_resize_time = 0.0;
890  }
891  }
892  }
893  else {
894  tag_update();
895  }
896 
897  /* update status and progress for 3d view draw */
899 
900  /* draw */
901  session->draw();
902 }
903 
904 void BlenderSession::get_status(string &status, string &substatus)
905 {
906  session->progress.get_status(status, substatus);
907 }
908 
909 void BlenderSession::get_progress(double &progress, double &total_time, double &render_time)
910 {
911  session->progress.get_time(total_time, render_time);
912  progress = session->progress.get_progress();
913 }
914 
916 {
917  double progress = session->progress.get_progress();
918 
919  if (progress != last_progress) {
920  b_engine.update_progress((float)progress);
921  last_progress = progress;
922  }
923 }
924 
926 {
927  string timestatus, status, substatus;
928  string scene_status = "";
929  double progress;
930  double total_time, remaining_time = 0, render_time;
931  float mem_used = (float)session->stats.mem_used / 1024.0f / 1024.0f;
932  float mem_peak = (float)session->stats.mem_peak / 1024.0f / 1024.0f;
933 
934  get_status(status, substatus);
935  get_progress(progress, total_time, render_time);
936 
937  if (progress > 0) {
938  remaining_time = session->get_estimated_remaining_time();
939  }
940 
941  if (background) {
942  if (scene)
943  scene_status += " | " + scene->name;
944  if (b_rlay_name != "")
945  scene_status += ", " + b_rlay_name;
946 
947  if (b_rview_name != "")
948  scene_status += ", " + b_rview_name;
949 
950  if (remaining_time > 0) {
951  timestatus += "Remaining:" + time_human_readable_from_seconds(remaining_time) + " | ";
952  }
953 
954  timestatus += string_printf("Mem:%.2fM, Peak:%.2fM", (double)mem_used, (double)mem_peak);
955 
956  if (status.size() > 0)
957  status = " | " + status;
958  if (substatus.size() > 0)
959  status += " | " + substatus;
960  }
961 
962  double current_time = time_dt();
963  /* When rendering in a window, redraw the status at least once per second to keep the elapsed
964  * and remaining time up-to-date. For headless rendering, only report when something
965  * significant changes to keep the console output readable. */
966  if (status != last_status || (!headless && (current_time - last_status_time) > 1.0)) {
967  b_engine.update_stats("", (timestatus + scene_status + status).c_str());
968  b_engine.update_memory_stats(mem_used, mem_peak);
969  last_status = status;
970  last_status_time = current_time;
971  }
972  if (progress != last_progress) {
973  b_engine.update_progress((float)progress);
974  last_progress = progress;
975  }
976 
978 }
979 
981 {
982  if (!session->progress.get_error()) {
983  return false;
984  }
985 
986  const string error = session->progress.get_error_message();
987  if (error != last_error) {
988  /* TODO(sergey): Currently C++ RNA API doesn't let us to use mnemonic name for the variable.
989  * Would be nice to have this figured out.
990  *
991  * For until then, 1 << 5 means RPT_ERROR. */
992  b_engine.report(1 << 5, error.c_str());
993  b_engine.error_set(error.c_str());
994  last_error = error;
995  }
996 
997  return true;
998 }
999 
1001 {
1002  /* tell blender that we want to get another update callback */
1003  b_engine.tag_update();
1004 }
1005 
1007 {
1008  if (background) {
1009  /* update stats and progress, only for background here because
1010  * in 3d view we do it in draw for thread safety reasons */
1012 
1013  /* offline render, redraw if timeout passed */
1014  if (time_dt() - last_redraw_time > 1.0) {
1015  b_engine.tag_redraw();
1017  }
1018  }
1019  else {
1020  /* tell blender that we want to redraw */
1021  b_engine.tag_redraw();
1022  }
1023 }
1024 
1026 {
1027  /* test if we need to cancel rendering */
1028  if (background)
1029  if (b_engine.test_break())
1030  session->progress.set_cancel("Cancelled");
1031 }
1032 
1034 {
1035  if (!background) {
1036  /* During interactive render we can not free anything: attempts to save
1037  * memory would cause things to be allocated and evaluated for every
1038  * updated sample.
1039  */
1040  return;
1041  }
1042  b_engine.free_blender_memory();
1043 }
1044 
1046 {
1047  if (display_driver_) {
1048  /* Driver is already created. */
1049  return;
1050  }
1051 
1052  if (headless) {
1053  /* No display needed for headless. */
1054  return;
1055  }
1056 
1057  if (b_engine.is_preview()) {
1058  /* TODO(sergey): Investigate whether DisplayDriver can be used for the preview as well. */
1059  return;
1060  }
1061 
1062  unique_ptr<BlenderDisplayDriver> display_driver = make_unique<BlenderDisplayDriver>(b_engine,
1063  b_scene);
1064  display_driver_ = display_driver.get();
1065  session->set_display_driver(move(display_driver));
1066 }
1067 
typedef float(TangentPoint)[2]
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
struct ViewLayer ViewLayer
struct Object Object
struct RegionView3D RegionView3D
static AppView * view
_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
struct RenderEngine RenderEngine
struct RenderLayer RenderLayer
struct RenderResult RenderResult
struct RenderPass RenderPass
volatile int lock
static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest)
static bool bake_setup_pass(Scene *scene, const string &bake_type_str, const int bake_filter)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition: btQuadWord.h:119
static unsigned long seed
Definition: btSoftBody.h:39
void set(Scene *scene, const std::string &object_name)
Definition: bake.cpp:30
void set_zoom(float zoom_x, float zoom_y)
void stamp_view_layer_metadata(Scene *scene, const string &view_layer_name)
BL::RenderSettings b_render
static bool headless
static bool print_render_stats
BL::RegionView3D b_rv3d
bool check_and_report_session_error()
double start_resize_time
BL::RenderEngine b_engine
void full_buffer_written(string_view filename)
void synchronize(BL::Depsgraph &b_depsgraph)
vector< string > full_buffer_files_
void ensure_display_driver_if_needed()
void builtin_images_load()
void update_status_progress()
void * python_thread_state
void free_blender_memory_if_possible()
void view_draw(int w, int h)
struct BlenderSession::@1229 draw_state_
BL::Preferences b_userpref
BlenderSync * sync
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)
BlenderDisplayDriver * display_driver_
BL::BlendData b_data
Session * session
void render(BL::Depsgraph &b_depsgraph)
void draw(BL::SpaceImageEditor &space_image)
BL::SpaceView3D b_v3d
BlenderSession(BL::RenderEngine &b_engine, BL::Preferences &b_userpref, BL::BlendData &b_data, bool preview_osl)
double last_redraw_time
void get_status(string &status, string &substatus)
void get_progress(double &progress, double &total_time, double &render_time)
BL::Depsgraph b_depsgraph
BL::Scene b_scene
double last_status_time
static DeviceTypeMask device_override
static bool get_session_pause(BL::Scene &b_scene, bool background)
Definition: sync.cpp:857
void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d)
Definition: sync.cpp:92
void tag_update()
Definition: sync.cpp:85
static SceneParams get_scene_params(BL::Scene &b_scene, bool background)
Definition: sync.cpp:808
void sync_camera(BL::RenderSettings &b_render, BL::Object &b_override, int width, int height, const char *viewname)
void sync_render_passes(BL::RenderLayer &b_render_layer, BL::ViewLayer &b_view_layer)
Definition: sync.cpp:631
int get_layer_bound_samples()
Definition: sync.h:81
static BufferParams get_buffer_params(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height)
void sync_view(BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, int width, int height)
void sync_data(BL::RenderSettings &b_render, BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, BL::Object &b_override, int width, int height, void **python_thread_state)
Definition: sync.cpp:241
void reset(BL::BlendData &b_data, BL::Scene &b_scene)
Definition: sync.cpp:75
int get_layer_samples()
Definition: sync.h:77
static SessionParams get_session_params(BL::RenderEngine &b_engine, BL::Preferences &b_userpref, BL::Scene &b_scene, bool background)
Definition: sync.cpp:863
ustring view
Definition: buffers.h:98
ustring layer
Definition: buffers.h:97
int height
Definition: buffers.h:72
int window_height
Definition: buffers.h:81
int window_width
Definition: buffers.h:80
NODE_DECLARE int width
Definition: buffers.h:71
string get_cryptomatte_objects(Scene *scene)
string get_cryptomatte_assets(Scene *scene)
Definition: pass.h:48
static const Pass * find(const vector< Pass * > &passes, const string &name)
Definition: pass.cpp:362
void set_cancel_callback(function< void()> function)
Definition: progress.h:104
void get_status(string &status_, string &substatus_) const
Definition: progress.h:290
void set_cancel(const string &cancel_message_)
Definition: progress.h:83
void get_time(double &total_time_, double &render_time_) const
Definition: progress.h:158
bool get_cancel() const
Definition: progress.h:90
void reset()
Definition: progress.h:62
double get_progress() const
Definition: progress.h:190
bool get_error() const
Definition: progress.h:120
string get_error_message() const
Definition: progress.h:125
void set_update_callback(function< void()> function)
Definition: progress.h:314
bool modified(const SceneParams &params) const
Definition: scene.h:174
bool modified(const SessionParams &params) const
void collect_statistics(RenderStats *stats)
void set_pause(bool pause)
void process_full_buffer_from_disk(string_view filename)
void set_display_driver(unique_ptr< DisplayDriver > driver)
bool ready_to_reset()
void set_time_limit(double time_limit)
void cancel(bool quick=false)
void start()
Progress progress
double get_estimated_remaining_time() const
SessionParams params
function< void(string_view)> full_buffer_written_cb
void reset(const SessionParams &session_params, const BufferParams &buffer_params)
void device_free()
Scene * scene
void set_output_driver(unique_ptr< OutputDriver > driver)
void set_samples(int samples)
string get_cryptomatte_materials(Scene *scene)
size_t mem_used
Definition: util/stats.h:35
size_t mem_peak
Definition: util/stats.h:36
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
static int render_resolution_x(BL::RenderSettings &b_render)
static int render_resolution_y(BL::RenderSettings &b_render)
static void render_add_metadata(BL::RenderResult &b_rr, string name, string value)
Scene scene
#define function_bind
DeviceTypeMask
Definition: device/device.h:48
@ DEVICE_MASK_ALL
Definition: device/device.h:55
#define function_null
Definition: function.h:12
static const char * to_string(const Interpolation &interp)
Definition: gl_shader.cc:63
ccl_device_inline uint hash_uint2(uint kx, uint ky)
Definition: hash.h:70
ccl_gpu_kernel_postfix ccl_global float int int int int float bool reset
clear internal cached data and reset random seed
@ CRYPT_ASSET
Definition: kernel/types.h:411
@ CRYPT_OBJECT
Definition: kernel/types.h:409
@ CRYPT_MATERIAL
Definition: kernel/types.h:410
PassType
Definition: kernel/types.h:334
@ PASS_EMISSION
Definition: kernel/types.h:339
@ PASS_POSITION
Definition: kernel/types.h:359
@ PASS_BACKGROUND
Definition: kernel/types.h:340
@ PASS_TRANSMISSION_DIRECT
Definition: kernel/types.h:350
@ PASS_UV
Definition: kernel/types.h:362
@ PASS_TRANSMISSION_COLOR
Definition: kernel/types.h:374
@ PASS_TRANSMISSION_INDIRECT
Definition: kernel/types.h:351
@ PASS_ROUGHNESS
Definition: kernel/types.h:361
@ PASS_DIFFUSE_DIRECT
Definition: kernel/types.h:344
@ PASS_AO
Definition: kernel/types.h:341
@ PASS_COMBINED
Definition: kernel/types.h:338
@ PASS_DIFFUSE
Definition: kernel/types.h:343
@ PASS_DIFFUSE_INDIRECT
Definition: kernel/types.h:345
@ PASS_GLOSSY
Definition: kernel/types.h:346
@ PASS_NONE
Definition: kernel/types.h:335
@ PASS_TRANSMISSION
Definition: kernel/types.h:349
@ PASS_NORMAL
Definition: kernel/types.h:360
@ PASS_DIFFUSE_COLOR
Definition: kernel/types.h:372
@ PASS_GLOSSY_DIRECT
Definition: kernel/types.h:347
@ PASS_GLOSSY_COLOR
Definition: kernel/types.h:373
@ PASS_SHADOW
Definition: kernel/types.h:342
@ PASS_GLOSSY_INDIRECT
Definition: kernel/types.h:348
#define VLOG_INFO
Definition: log.h:77
static void error(const char *str)
Definition: meshlaplacian.c:51
uint32_t util_murmur_hash3(const void *key, int len, uint32_t seed)
Definition: murmurhash.cpp:49
bool path_remove(const string &path)
Definition: path.cpp:724
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5167
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
Definition: rna_access.c:4874
const PointerRNA PointerRNA_NULL
Definition: rna_access.c:61
CCL_NAMESPACE_BEGIN string string_printf(const char *format,...)
Definition: string.cpp:22
ustring name
Definition: graph/node.h:174
bool is_modified() const
Definition: graph/node.cpp:804
string full_report()
Definition: stats.cpp:300
BakeManager * bake_manager
Definition: scene.h:228
Film * film
Definition: scene.h:208
string name
Definition: scene.h:198
T * create_node(Args &&...args)
Definition: scene.h:284
MotionType need_motion() const
Definition: scene.cpp:387
vector< Pass * > passes
Definition: scene.h:218
SceneParams params
Definition: scene.h:243
void enable_update_stats()
Definition: scene.cpp:479
vector< Object * > objects
Definition: scene.h:213
ObjectManager * object_manager
Definition: scene.h:226
Background * background
Definition: scene.h:209
@ MOTION_NONE
Definition: scene.h:259
ShaderManager * shader_manager
Definition: scene.h:224
Integrator * integrator
Definition: scene.h:210
thread_mutex mutex
Definition: scene.h:246
struct Object * camera
bool need_reset()
Definition: scene.cpp:443
std::unique_lock< std::mutex > thread_scoped_lock
Definition: thread.h:28
string time_human_readable_from_seconds(const double seconds)
Definition: time.cpp:65
CCL_NAMESPACE_BEGIN double time_dt()
Definition: time.cpp:35