From 2cf8b5c4e1fc0e1d97cc2ecb5d4036acd24bcef7 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Tue, 16 Apr 2024 09:10:36 +0200 Subject: [PATCH] Compositor: Improve interactivity for GPU compositing This patch improves the interactivity of the GPU compositor for interactive node tree edits by waiting on GPU work to finish to support more granular canceling. This does have a performance penalty, but it does not affect final rendering and it seems worth it because even though it is slower it will feel faster for users. Pull Request: https://projects.blender.org/blender/blender/pulls/120656 --- .../compositor/realtime_compositor/COM_context.hh | 4 ++++ .../realtime_compositor/intern/context.cc | 2 ++ .../realtime_compositor/intern/operation.cc | 2 ++ source/blender/render/intern/compositor.cc | 15 +++++++++++++++ 4 files changed, 23 insertions(+) diff --git a/source/blender/compositor/realtime_compositor/COM_context.hh b/source/blender/compositor/realtime_compositor/COM_context.hh index 296b4aae0d9..438da5533aa 100644 --- a/source/blender/compositor/realtime_compositor/COM_context.hh +++ b/source/blender/compositor/realtime_compositor/COM_context.hh @@ -112,6 +112,10 @@ class Context { * render pipeline. */ virtual RenderContext *render_context() const; + /* Gets called after the evaluation of each compositor operation. See overrides for possible + * uses. */ + virtual void evaluate_operation_post() const; + /* Returns true if the compositor evaluation is canceled and that the evaluator should stop * executing as soon as possible. */ virtual bool is_canceled() const; diff --git a/source/blender/compositor/realtime_compositor/intern/context.cc b/source/blender/compositor/realtime_compositor/intern/context.cc index 8421455003a..df7c1e93ce7 100644 --- a/source/blender/compositor/realtime_compositor/intern/context.cc +++ b/source/blender/compositor/realtime_compositor/intern/context.cc @@ -26,6 +26,8 @@ RenderContext *Context::render_context() const return nullptr; } +void Context::evaluate_operation_post() const {} + bool Context::is_canceled() const { if (!this->get_node_tree().runtime->test_break) { diff --git a/source/blender/compositor/realtime_compositor/intern/operation.cc b/source/blender/compositor/realtime_compositor/intern/operation.cc index d8f9f7ab508..795d45d083e 100644 --- a/source/blender/compositor/realtime_compositor/intern/operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/operation.cc @@ -39,6 +39,8 @@ void Operation::evaluate() release_inputs(); release_unneeded_results(); + + context().evaluate_operation_post(); } Result &Operation::get_result(StringRef identifier) diff --git a/source/blender/render/intern/compositor.cc b/source/blender/render/intern/compositor.cc index 117d3940acb..fa49ba71688 100644 --- a/source/blender/render/intern/compositor.cc +++ b/source/blender/render/intern/compositor.cc @@ -453,6 +453,21 @@ class Context : public realtime_compositor::Context { { return input_data_.render_context; } + + void evaluate_operation_post() const override + { + /* If no render context exist, that means this is an interactive compositor evaluation due to + * the user editing the node tree. In that case, we wait until the operation finishes executing + * on the GPU before we continue to improve interactivity. The improvement comes from the fact + * that the user might be rapidly changing values, so we need to cancel previous evaluations to + * make editing faster, but we can't do that if all operations are submitted to the GPU all at + * once, and we can't cancel work that was already submitted to the GPU. This does have a + * performance penalty, but in practice, the improved interactivity is worth it according to + * user feedback. */ + if (!this->render_context()) { + GPU_finish(); + } + } }; /* Render Realtime Compositor */