[Bf-blender-cvs] [bba6fe83e27] blender-v3.0-release: Fix T89204: slow repeated rendering with GPUOffscreen.draw_view3d.

Christian Stolze noreply at git.blender.org
Tue Nov 23 14:08:41 CET 2021


Commit: bba6fe83e27eab7c99bd5bab3eb914189a0793d2
Author: Christian Stolze
Date:   Tue Nov 23 13:55:17 2021 +0100
Branches: blender-v3.0-release
https://developer.blender.org/rBbba6fe83e27eab7c99bd5bab3eb914189a0793d2

Fix T89204: slow repeated rendering with GPUOffscreen.draw_view3d.

Reviewed By: fclem
Differential Revision: D13235

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

M	source/blender/draw/intern/draw_manager.c
M	source/blender/python/gpu/gpu_py_offscreen.c
M	source/blender/python/gpu/gpu_py_offscreen.h

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

diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 1d9bc607590..59ed5316c02 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -1367,6 +1367,61 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx)
   BLI_ticket_mutex_unlock(DST.gl_context_mutex);
 }
 
+/* update a viewport which belongs to a GPUOffscreen */
+void DRW_notify_view_update_offscreen(struct Depsgraph *depsgraph,
+                                      RenderEngineType *engine_type,
+                                      ARegion *region,
+                                      View3D *v3d,
+                                      GPUViewport *viewport)
+{
+
+  if (viewport && GPU_viewport_do_update(viewport)) {
+
+    Scene *scene = DEG_get_evaluated_scene(depsgraph);
+    ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph);
+    RegionView3D *rv3d = region->regiondata;
+
+    const bool gpencil_engine_needed = drw_gpencil_engine_needed(depsgraph, v3d);
+
+    /* Reset before using it. */
+    drw_state_prepare_clean_for_draw(&DST);
+
+    DST.draw_ctx = (DRWContextState){
+        .region = region,
+        .rv3d = rv3d,
+        .v3d = v3d,
+        .scene = scene,
+        .view_layer = view_layer,
+        .obact = OBACT(view_layer),
+        .engine_type = engine_type,
+        .depsgraph = depsgraph,
+    };
+
+    /* Custom lightweight initialize to avoid resetting the memory-pools. */
+    DST.viewport = viewport;
+    DST.vmempool = drw_viewport_data_ensure(DST.viewport);
+
+    /* Separate update for each stereo view. */
+    int view_count = GPU_viewport_is_stereo_get(viewport) ? 2 : 1;
+    for (int view = 0; view < view_count; view++) {
+      DST.view_data_active = DST.vmempool->view_data[view];
+
+      drw_engines_enable(view_layer, engine_type, gpencil_engine_needed);
+      drw_engines_data_validate();
+
+      DRW_ENABLED_ENGINE_ITER (DST.view_data_active, draw_engine, data) {
+        if (draw_engine->view_update) {
+          draw_engine->view_update(data);
+        }
+      }
+
+      drw_engines_disable();
+    }
+
+    drw_manager_exit(&DST);
+  }
+}
+
 /** \} */
 
 /* -------------------------------------------------------------------- */
@@ -1742,11 +1797,14 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph,
                                     GPUOffScreen *ofs,
                                     GPUViewport *viewport)
 {
-  /* Create temporary viewport if needed. */
+  /* Create temporary viewport if needed or update the existing viewport. */
   GPUViewport *render_viewport = viewport;
   if (viewport == NULL) {
     render_viewport = GPU_viewport_create();
   }
+  else {
+    DRW_notify_view_update_offscreen(depsgraph, engine_type, region, v3d, render_viewport);
+  }
 
   GPU_viewport_bind_from_offscreen(render_viewport, ofs);
 
diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c
index 6f23c2213e2..24192780a86 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.c
+++ b/source/blender/python/gpu/gpu_py_offscreen.c
@@ -44,6 +44,7 @@
 #include "GPU_context.h"
 #include "GPU_framebuffer.h"
 #include "GPU_texture.h"
+#include "GPU_viewport.h"
 
 #include "ED_view3d.h"
 #include "ED_view3d_offscreen.h"
@@ -355,6 +356,15 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
 
   GPU_offscreen_bind(self->ofs, true);
 
+  /* Cache the GPUViewport so the framebuffers and associated textures are
+   * not reallocated each time, see: T89204 */
+  if (!self->viewport) {
+    self->viewport = GPU_viewport_create();
+  }
+  else {
+    GPU_viewport_tag_update(self->viewport);
+  }
+
   ED_view3d_draw_offscreen(depsgraph,
                            scene,
                            v3d->shading.type,
@@ -370,7 +380,7 @@ static PyObject *pygpu_offscreen_draw_view3d(BPyGPUOffScreen *self, PyObject *ar
                            do_color_management,
                            true,
                            self->ofs,
-                           NULL);
+                           self->viewport);
 
   GPU_offscreen_unbind(self->ofs, true);
 
@@ -391,6 +401,11 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
 {
   BPY_GPU_OFFSCREEN_CHECK_OBJ(self);
 
+  if (self->viewport) {
+    GPU_viewport_free(self->viewport);
+    self->viewport = NULL;
+  }
+
   GPU_offscreen_free(self->ofs);
   self->ofs = NULL;
   Py_RETURN_NONE;
@@ -399,6 +414,9 @@ static PyObject *pygpu_offscreen_free(BPyGPUOffScreen *self)
 
 static void BPyGPUOffScreen__tp_dealloc(BPyGPUOffScreen *self)
 {
+  if (self->viewport) {
+    GPU_viewport_free(self->viewport);
+  }
   if (self->ofs) {
     GPU_offscreen_free(self->ofs);
   }
@@ -469,6 +487,7 @@ PyObject *BPyGPUOffScreen_CreatePyObject(GPUOffScreen *ofs)
 
   self = PyObject_New(BPyGPUOffScreen, &BPyGPUOffScreen_Type);
   self->ofs = ofs;
+  self->viewport = NULL;
 
   return (PyObject *)self;
 }
diff --git a/source/blender/python/gpu/gpu_py_offscreen.h b/source/blender/python/gpu/gpu_py_offscreen.h
index 309735a6202..78bad595a3d 100644
--- a/source/blender/python/gpu/gpu_py_offscreen.h
+++ b/source/blender/python/gpu/gpu_py_offscreen.h
@@ -26,9 +26,13 @@ extern PyTypeObject BPyGPUOffScreen_Type;
 
 #define BPyGPUOffScreen_Check(v) (Py_TYPE(v) == &BPyGPUOffScreen_Type)
 
+struct GPUOffscreen;
+struct GPUViewport;
+
 typedef struct BPyGPUOffScreen {
   PyObject_HEAD
   struct GPUOffScreen *ofs;
+  struct GPUViewport *viewport;
 } BPyGPUOffScreen;
 
 PyObject *BPyGPUOffScreen_CreatePyObject(struct GPUOffScreen *ofs) ATTR_NONNULL(1);



More information about the Bf-blender-cvs mailing list