From bba6fe83e27eab7c99bd5bab3eb914189a0793d2 Mon Sep 17 00:00:00 2001 From: Christian Stolze Date: Tue, 23 Nov 2021 13:55:17 +0100 Subject: Fix T89204: slow repeated rendering with GPUOffscreen.draw_view3d. Reviewed By: fclem Differential Revision: D13235 --- source/blender/draw/intern/draw_manager.c | 60 +++++++++++++++++++++++++++- source/blender/python/gpu/gpu_py_offscreen.c | 21 +++++++++- source/blender/python/gpu/gpu_py_offscreen.h | 4 ++ 3 files changed, 83 insertions(+), 2 deletions(-) (limited to 'source/blender') 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); -- cgit v1.2.3