[Bf-blender-cvs] [8d6a8c543c6] cycles-x: Cycles X: Use GPUDisplay for non-interactive render

Sergey Sharybin noreply at git.blender.org
Tue Sep 7 10:57:22 CEST 2021


Commit: 8d6a8c543c6b61e93ea9f9784fc10c04972a0326
Author: Sergey Sharybin
Date:   Wed Jul 21 17:58:03 2021 +0200
Branches: cycles-x
https://developer.blender.org/rB8d6a8c543c6b61e93ea9f9784fc10c04972a0326

Cycles X: Use GPUDisplay for non-interactive render

This is a part of hi-res image rendering. The goal of this step is to
make it so Cycles takes care of active pass drawing for non-interactive
render, similar to the viewport render. Some top-level overview of the
code side design changes are summarized in T90580.

Benefits and solutions to design limitations which this change brings:

- Allows to lazily allocate render result on Blender side.

- Solves bottleneck of data transfer and color management, which should
  solve issues like T52360.

- Allows a render engine to take advantage of tiled rendering for
  memory saving by saving rendered tiles on disk and only keeping
  display buffer. Leaving display buffer management to an external
  engine allows the engine to implement logic needed for changing
  active display pass (which might involve reading from partial tile
  file).

- Allows to see any pass during rendering.

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

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

M	intern/cycles/blender/addon/__init__.py
M	intern/cycles/blender/addon/engine.py
M	intern/cycles/blender/blender_gpu_display.cpp
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/path_trace.cpp
M	source/blender/draw/engines/eevee/eevee_engine.c
M	source/blender/draw/engines/external/external_engine.c
M	source/blender/draw/engines/external/external_engine.h
M	source/blender/draw/engines/select/select_engine.c
M	source/blender/draw/engines/workbench/workbench_engine.c
M	source/blender/draw/intern/DRW_render.h
M	source/blender/draw/intern/draw_manager.c
M	source/blender/draw/intern/draw_manager_exec.c
M	source/blender/makesrna/intern/rna_render.c
M	source/blender/render/RE_engine.h
M	source/blender/render/intern/engine.c
M	source/blender/windowmanager/WM_api.h
M	source/blender/windowmanager/intern/wm_window.c

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

diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py
index e67dd561ddd..29bb206d3da 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 draw(self, context, depsgraph):
+        engine.draw(self, depsgraph, context.space_data)
+
     def bake(self, depsgraph, obj, pass_type, pass_filter, width, height):
         engine.bake(self, depsgraph, obj, pass_type, pass_filter, width, height)
 
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py
index b724e293567..d7ae8159734 100644
--- a/intern/cycles/blender/addon/engine.py
+++ b/intern/cycles/blender/addon/engine.py
@@ -132,6 +132,18 @@ def render(engine, depsgraph):
         _cycles.render(engine.session, depsgraph.as_pointer())
 
 
+def draw(engine, depsgraph, space_image):
+    if not engine.session:
+        return
+
+    depsgraph_ptr = depsgraph.as_pointer()
+    space_image_ptr = space_image.as_pointer()
+    screen_ptr = space_image.id_data.as_pointer()
+
+    import _cycles
+    _cycles.draw(engine.session, depsgraph_ptr, screen_ptr, space_image_ptr)
+
+
 def bake(engine, depsgraph, obj, pass_type, pass_filter, width, height):
     import _cycles
     session = getattr(engine, "session", None)
diff --git a/intern/cycles/blender/blender_gpu_display.cpp b/intern/cycles/blender/blender_gpu_display.cpp
index 903fb0f0db2..3bcd44f2aa2 100644
--- a/intern/cycles/blender/blender_gpu_display.cpp
+++ b/intern/cycles/blender/blender_gpu_display.cpp
@@ -24,7 +24,7 @@ extern "C" {
 bool DRW_opengl_context_release();
 void DRW_opengl_context_activate(bool drw_state);
 
-void *WM_opengl_context_create();
+void *WM_opengl_context_create_from_thread();
 void WM_opengl_context_activate(void *gl_context);
 void WM_opengl_context_dispose(void *gl_context);
 void WM_opengl_context_release(void *context);
@@ -493,11 +493,12 @@ void BlenderGPUDisplay::gl_context_create()
 {
   const bool drw_state = DRW_opengl_context_release();
 
-  gl_context_ = WM_opengl_context_create();
+  gl_context_ = WM_opengl_context_create_from_thread();
   if (!gl_context_) {
     LOG(ERROR) << "Error creating OpenGL context.";
   }
 
+  WM_opengl_context_release(gl_context_);
   DRW_opengl_context_activate(drw_state);
 }
 
diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp
index 44f3636aff7..996c6e362a8 100644
--- a/intern/cycles/blender/blender_python.cpp
+++ b/intern/cycles/blender/blender_python.cpp
@@ -264,6 +264,30 @@ static PyObject *render_func(PyObject * /*self*/, PyObject *args)
   Py_RETURN_NONE;
 }
 
+static PyObject *draw_func(PyObject * /*self*/, PyObject *args)
+{
+  PyObject *py_session, *py_graph, *py_screen, *py_space_image;
+
+  if (!PyArg_ParseTuple(args, "OOOO", &py_session, &py_graph, &py_screen, &py_space_image)) {
+    return nullptr;
+  }
+
+  BlenderSession *session = (BlenderSession *)PyLong_AsVoidPtr(py_session);
+
+  ID *b_screen = (ID *)PyLong_AsVoidPtr(py_screen);
+
+  PointerRNA b_space_image_ptr;
+  RNA_pointer_create(b_screen,
+                     &RNA_SpaceImageEditor,
+                     pylong_as_voidptr_typesafe(py_space_image),
+                     &b_space_image_ptr);
+  BL::SpaceImageEditor b_space_image(b_space_image_ptr);
+
+  session->draw(b_space_image);
+
+  Py_RETURN_NONE;
+}
+
 /* pixel_array and result passed as pointers */
 static PyObject *bake_func(PyObject * /*self*/, PyObject *args)
 {
@@ -997,6 +1021,7 @@ static PyMethodDef methods[] = {
     {"create", create_func, METH_VARARGS, ""},
     {"free", free_func, METH_O, ""},
     {"render", render_func, METH_VARARGS, ""},
+    {"draw", draw_func, METH_VARARGS, ""},
     {"bake", bake_func, METH_VARARGS, ""},
     {"view_draw", view_draw_func, METH_VARARGS, ""},
     {"sync", sync_func, METH_VARARGS, ""},
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index 80c56ffff4f..8490f4952ae 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -160,7 +160,7 @@ void BlenderSession::create_session()
   session->reset(buffer_params, session_params.samples);
 
   /* Create GPU display. */
-  if (!background) {
+  if (!b_engine.is_preview()) {
     session->set_gpu_display(make_unique<BlenderGPUDisplay>(b_engine, b_scene));
   }
 
@@ -263,6 +263,11 @@ void BlenderSession::reset_session(BL::BlendData &b_data, BL::Depsgraph &b_depsg
 
   /* reset time */
   start_resize_time = 0.0;
+
+  {
+    thread_scoped_lock lock(draw_state_.mutex);
+    draw_state_.last_pass_index = -1;
+  }
 }
 
 void BlenderSession::free_session()
@@ -273,7 +278,7 @@ void BlenderSession::free_session()
   delete session;
 }
 
-void BlenderSession::do_write_update_render_tile(bool do_update_only)
+void BlenderSession::read_render_tile()
 {
   const int2 tile_offset = session->get_render_tile_offset();
   const int2 tile_size = session->get_render_tile_size();
@@ -300,17 +305,18 @@ void BlenderSession::do_write_update_render_tile(bool do_update_only)
 
   BL::RenderLayer b_rlay = *b_single_rlay;
 
-  if (do_update_only) {
-    update_render_result(b_rlay);
-  }
-  else {
-    write_render_result(b_rlay);
+  vector<float> pixels(tile_size.x * tile_size.y * 4);
+
+  /* Copy each pass.
+   * TODO:copy only the required ones for better performance? */
+  for (BL::RenderPass &b_pass : b_rlay.passes) {
+    session->set_render_tile_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
   }
 
-  b_engine.end_result(b_rr, true, false, true);
+  b_engine.end_result(b_rr, false, false, false);
 }
 
-void BlenderSession::read_render_tile()
+void BlenderSession::write_render_tile()
 {
   const int2 tile_offset = session->get_render_tile_offset();
   const int2 tile_size = session->get_render_tile_size();
@@ -337,32 +343,9 @@ void BlenderSession::read_render_tile()
 
   BL::RenderLayer b_rlay = *b_single_rlay;
 
-  vector<float> pixels(tile_size.x * tile_size.y * 4);
-
-  /* Copy each pass.
-   * TODO:copy only the required ones for better performance? */
-  for (BL::RenderPass &b_pass : b_rlay.passes) {
-    session->set_render_tile_pixels(b_pass.name(), b_pass.channels(), (float *)b_pass.rect());
-  }
-
-  b_engine.end_result(b_rr, false, false, false);
-}
-
-void BlenderSession::write_render_tile()
-{
-  do_write_update_render_tile(false);
-}
+  write_render_result(b_rlay);
 
-void BlenderSession::update_render_tile()
-{
-  /* use final write for preview renders, otherwise render result wouldn't be
-   * be updated in blender side
-   * would need to be investigated a bit further, but for now shall be fine
-   */
-  if (!b_engine.is_preview())
-    do_write_update_render_tile(true);
-  else
-    do_write_update_render_tile(false);
+  b_engine.end_result(b_rr, true, false, true);
 }
 
 static void add_cryptomatte_layer(BL::RenderResult &b_rr, string name, string manifest)
@@ -435,7 +418,13 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
 
   /* set callback to write out render results */
   session->write_render_tile_cb = [&]() { write_render_tile(); };
-  session->update_render_tile_cb = [&]() { update_render_tile(); };
+
+  /* Use final write for preview renders, otherwise render result wouldn't be be updated on Blender
+   * side. */
+  /* TODO(sergey): Investigate whether GPUDisplay can be used for the preview as well. */
+  if (b_engine.is_preview()) {
+    session->update_render_tile_cb = [&]() { write_render_tile(); };
+  }
 
   BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval();
 
@@ -450,7 +439,14 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
   BL::RenderResult::layers_iterator b_single_rlay;
   b_rr.layers.begin(b_single_rlay);
   BL::RenderLayer b_rlay = *b_single_rlay;
-  b_rlay_name = b_view_layer.name();
+
+  {
+    thread_scoped_lock lock(draw_state_.mutex);
+    b_rlay_name = b_view_layer.name();
+
+    /* Signal that the display pass is to be updated. */
+    draw_state_.last_pass_index = -1;
+  }
 
   /* Compute render passes and film settings. */
   sync->sync_render_passes(b_rlay, b_view_layer);
@@ -803,6 +799,40 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_)
   session->start();
 }
 
+void BlenderSession::draw(BL::SpaceImageEditor &space_image)
+{
+  if (!session || !session->scene) {
+    /* Offline render drawing does not force the render engine update, which means it's possible
+     * that the Session is not created yet. */
+    return;
+  }
+
+  thread_scoped_lock lock(draw_state_.mutex);
+
+  const int pass_index = space_image.image_user().multilayer_pass();
+  if (pass_index != draw_state_.last_pass_index) {
+    BL::RenderPass b_display_pass(b_engine.pass_by_index_get(b_rlay_name.c_str(), pass_index));
+    if (!b_display_pass) {
+      return;
+    }
+
+    Scene *scene = session->scene;
+
+    thread_scoped_lock lock(scene->mutex);
+
+    const Pass *pass = Pass::find(scene->passes, b_display_pass.name());
+    if (!pass) {
+      return;
+    }
+
+    scene->film->set_display_pass(pass->type);
+
+    draw_state_.last_pass_index = pass_index;
+  }
+
+  session->draw();
+}
+
 void BlenderSession::view_draw(int w, int h)
 {
   /* pause in redraw in case update is not being called due to final render */
diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h
index c59ea9522d6..e0f61f03ad0 100644
--- a/intern/cycles/blender/blender_session.h
+++ b/intern/cycles/blender/blender_session.h
@@ -73,7 +73,6 @@ class BlenderSession {
   /* 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);
-  void update_render_tile();
 
   /* read functions for baking input */
   void read_render_tile();
@@ -82,6 +81,7 @@ class BlenderSession {
   void synchronize(BL::Depsgraph &b_depsgraph);
 
   /* drawing */
+  void draw(BL::SpaceImageEditor &space_image);
   void view_draw(int w, int h);
   void tag_redraw();
   void tag_update();

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list