[Bf-blender-cvs] [adf85cd552d] cycles-x: Cycles X: Real memory saving when using tiled rendering

Sergey Sharybin noreply at git.blender.org
Fri Sep 17 11:48:47 CEST 2021


Commit: adf85cd552d3d3319b095397f95fecc0c8961bc5
Author: Sergey Sharybin
Date:   Wed Sep 15 16:14:03 2021 +0200
Branches: cycles-x
https://developer.blender.org/rBadf85cd552d3d3319b095397f95fecc0c8961bc5

Cycles X: Real memory saving when using tiled rendering

The general idea is to delay reading EXR files for until after all
view layers are rendered. Once they are all rendered, BlenderSession
frees up as much memory as possible, and initiates processing of the
on-disk files.

The processing includes reading the file, optional denoising of the
full frame (if the denoising is enabled), and writing the result via
the write callback.

The processing is done as a state-machine which routes specific calls
to a full-frame processing, which allows to re-use same tile write
callback in the software integration.

In order to be able to know which view layer and render view is being
written the API has been extended to write layer and view names. Done
via BufferParams, as layer and view concepts are quite typical for the
EXR files.

The BufferParams also contains all fields needed for buffers access
outside of the scene graph.

Differential Revision: https://developer.blender.org/D12503

===================================================================

M	intern/cycles/blender/addon/__init__.py
M	intern/cycles/blender/addon/engine.py
M	intern/cycles/blender/blender_python.cpp
M	intern/cycles/blender/blender_session.cpp
M	intern/cycles/blender/blender_session.h
M	intern/cycles/integrator/pass_accessor.cpp
M	intern/cycles/integrator/pass_accessor.h
M	intern/cycles/integrator/path_trace.cpp
M	intern/cycles/integrator/path_trace.h
M	intern/cycles/integrator/path_trace_work.cpp
M	intern/cycles/integrator/render_scheduler.cpp
M	intern/cycles/integrator/render_scheduler.h
M	intern/cycles/render/buffers.cpp
M	intern/cycles/render/buffers.h
M	intern/cycles/render/session.cpp
M	intern/cycles/render/session.h
M	intern/cycles/render/tile.cpp
M	intern/cycles/render/tile.h

===================================================================

diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index 29bb206d3da..1ce25a253f9 100644
--- a/intern/cycles/blender/addon/__init__.py
+++ b/intern/cycles/blender/addon/__init__.py
@@ -84,6 +84,9 @@ class CyclesRender(bpy.types.RenderEngine):
     def render(self, depsgraph):
         engine.render(self, depsgraph)
 
+    def render_frame_finish(self):
+        engine.render_frame_finish(self)
+
     def draw(self, context, depsgraph):
         engine.draw(self, depsgraph, context.space_data)
 
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index d7ae8159734..097bd32d034 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -132,6 +132,13 @@ def render(engine, depsgraph):
         _cycles.render(engine.session, depsgraph.as_pointer())
 
 
+def render_frame_finish(engine):
+    if not engine.session:
+        return
+
+    import _cycles
+    _cycles.render_frame_finish(engine.session)
+
 def draw(engine, depsgraph, space_image):
     if not engine.session:
         return
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 996c6e362a8..7594c69c5a2 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -264,6 +264,26 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *args)
   Py_RETURN_NONE;
 }
 
+static PyObject *render_frame_finish_func(PyObject * /*self*/, PyObject *args)
+{
+  PyObject *pysession;
+
+  if (!PyArg_ParseTuple(args, "O", &pysession)) {
+    return nullptr;
+  }
+
+  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(pysession);
+
+  /* Allow Blender to execute other Python scripts. */
+  python_thread_state_save(&session->python_thread_state);
+
+  session->render_frame_finish();
+
+  python_thread_state_restore(&session->python_thread_state);
+
+  Py_RETURN_NONE;
+}
+
 static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
 {
   PyObject *py_session, *py_graph, *py_screen, *py_space_image;
@@ -1021,6 +1041,7 @@ static PyMethodDef methods[] = {
     {"create", create_func, METH_VARARGS, ""},
     {"free", free_func, METH_O, ""},
     {"render", render_func, METH_VARARGS, ""},
+    {"render_frame_finish", render_frame_finish_func, METH_VARARGS, ""},
     {"draw", draw_func, METH_VARARGS, ""},
     {"bake", bake_func, METH_VARARGS, ""},
     {"view_draw", view_draw_func, METH_VARARGS, ""},
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index ea365617590..6fd731555fd 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -38,6 +38,7 @@
 #include "util/util_hash.h"
 #include "util/util_logging.h"
 #include "util/util_murmurhash.h"
+#include "util/util_path.h"
 #include "util/util_progress.h"
 #include "util/util_time.h"
 
@@ -269,10 +270,15 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
 
 void BlenderSession::free_session()
 {
-  session->cancel(true);
+  if (session) {
+    session->cancel(true);
+  }
 
   delete sync;
+  sync = nullptr;
+
   delete session;
+  session = nullptr;
 }
 
 void BlenderSession::read_render_tile()
@@ -316,13 +322,16 @@ void BlenderSession::write_render_tile()
   const int2 tile_offset = session->get_render_tile_offset();
   const int2 tile_size = session->get_render_tile_size();
 
+  const string_view render_layer_name = session->get_render_tile_layer();
+  const string_view render_view_name = session->get_render_tile_view();
+
   /* get render result */
   BL::RenderResult b_rr = b_engine.begin_result(tile_offset.x,
                                                 tile_offset.y,
                                                 tile_size.x,
                                                 tile_size.y,
-                                                b_rlay_name.c_str(),
-                                                b_rview_name.c_str());
+                                                render_layer_name.c_str(),
+                                                render_view_name.c_str());
 
   /* can happen if the intersected rectangle gives 0 width or height */
   if (b_rr.ptr.data == NULL) {
@@ -333,8 +342,9 @@ void BlenderSession::write_render_tile()
   b_rr.layers.begin(b_single_rlay);
 
   /* layer will be missing if it was disabled in the UI */
-  if (b_single_rlay == b_rr.layers.end())
+  if (b_single_rlay == b_rr.layers.end()) {
     return;
+  }
 
   BL::RenderLayer b_rlay = *b_single_rlay;
 
@@ -343,6 +353,11 @@ void BlenderSession::write_render_tile()
   b_engine.end_result(b_rr, true, false, true);
 }
 
+void BlenderSession::full_buffer_written(string_view filename)
+{
+  full_buffer_files_.emplace_back(filename);
+}
+
 static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest)
 {
   string identifier = string_printf("%08x", util_murmur_hash3(name.c_str(), name.length(), 0));
@@ -421,6 +436,8 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
     session->update_render_tile_cb = [&]() { write_render_tile(); };
   }
 
+  session->full_buffer_written_cb = [&](string_view filename) { full_buffer_written(filename); };
+
   BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
 
   /* get buffer parameters */
@@ -458,6 +475,9 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
        ++b_view_iter, ++view_index) {
     b_rview_name = b_view_iter->name();
 
+    buffer_params.layer = b_view_layer.name();
+    buffer_params.view = b_rview_name;
+
     /* set the current view */
     b_engine.active_view_set(b_rview_name.c_str());
 
@@ -529,10 +549,28 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
   session->progress.get_time(total_time, render_time);
   VLOG(1) << "Total render time: " << total_time;
   VLOG(1) << "Render time (without synchronization): " << render_time;
+}
+
+void BlenderSession::render_frame_finish()
+{
+  if (!b_render.use_persistent_data()) {
+    /* Free the sync object so that it can properly dereference nodes from the scene graph before
+     * the graph is freed. */
+    delete sync;
+    sync = nullptr;
+
+    session->device_free();
+  }
+
+  for (string_view filename : full_buffer_files_) {
+    session->process_full_buffer_from_disk(filename);
+    path_remove(filename);
+  }
 
   /* clear callback */
   session->write_render_tile_cb = function_null;
   session->update_render_tile_cb = function_null;
+  session->full_buffer_written_cb = function_null;
 }
 
 static PassType bake_type_to_pass(const string &bake_type_str, const int bake_filter)
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index e0f61f03ad0..dce313a0ad4 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -60,6 +60,8 @@ class BlenderSession {
   /* offline render */
   void render(BL::Depsgraph &b_depsgraph);
 
+  void render_frame_finish();
+
   void bake(BL::Depsgraph &b_depsgrah,
             BL::Object &b_object,
             const string &pass_type,
@@ -70,6 +72,8 @@ class BlenderSession {
   void write_render_result(BL::RenderLayer &b_rlay);
   void write_render_tile();
 
+  void full_buffer_written(string_view filename);
+
   /* update functions are used to update display buffer only after sample was rendered
    * only needed for better visual feedback */
   void update_render_result(BL::RenderLayer &b_rlay);
@@ -167,6 +171,8 @@ class BlenderSession {
     thread_mutex mutex;
     int last_pass_index = -1;
   } draw_state_;
+
+  vector<string> full_buffer_files_;
 };
 
 CCL_NAMESPACE_END
diff --git a/intern/cycles/integrator/pass_accessor.cpp b/intern/cycles/integrator/pass_accessor.cpp
index 5c91d5651bf..87c048b1fa5 100644
--- a/intern/cycles/integrator/pass_accessor.cpp
+++ b/intern/cycles/integrator/pass_accessor.cpp
@@ -16,9 +16,7 @@
 
 #include "integrator/pass_accessor.h"
 
-#include "render/background.h"
 #include "render/buffers.h"
-#include "render/film.h"
 #include "util/util_logging.h"
 
 // clang-format off
@@ -32,16 +30,8 @@ CCL_NAMESPACE_BEGIN
  * Pass input information.
  */
 
-PassAccessor::PassAccessInfo::PassAccessInfo(const BufferPass &pass,
-                                             const Film &film,
-                                             const Background &background)
-    : type(pass.type),
-      mode(pass.mode),
-      include_albedo(pass.include_albedo),
-      offset(pass.offset),
-      use_approximate_shadow_catcher(film.get_use_approximate_shadow_catcher()),
-      use_approximate_shadow_catcher_background(use_approximate_shadow_catcher &&
-                                                !background.get_transparent())
+PassAccessor::PassAccessInfo::PassAccessInfo(const BufferPass &pass)
+    : type(pass.type), mode(pass.mode), include_albedo(pass.include_albedo), offset(pass.offset)
 {
 }
 
diff --git a/intern/cycles/integrator/pass_accessor.h b/intern/cycles/integrator/pass_accessor.h
index 0298b0f40d9..624bf7d0b2c 100644
--- a/intern/cycles/integrator/pass_accessor.h
+++ b/intern/cycles/integrator/pass_accessor.h
@@ -23,8 +23,6 @@
 
 CCL_NAMESPACE_BEGIN
 
-class Background;
-class Film;
 class RenderBuffers;
 class BufferPass;
 class BufferParams;
@@ -38,7 +36,7 @@ class PassAccessor {
   class PassAccessInfo {
    public:
     PassAccessInfo() = default;
-    PassAccessInfo(const BufferPass &pass, const Film &film, const Background &background);
+    explicit PassAccessInfo(const BufferPass &pass);
 
     PassType type = PASS_NONE;
     PassMode mode = PassMode::NOISY;
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index c69921c8394..b5ab7768c4f 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -134,7 +134,18 @@ void PathTrace::reset(const BufferParams &full_params, const BufferParams &big_t
   render_state_.tile_written = false;
 
   did_draw_after_reset_ = false;
-  full_frame_buffers_ = nullptr;
+}
+
+void PathTrace::device_free()
+{
+  /* Free render buffers used by the path trace work to reduce 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list