From fa96497999433d78e633852a0a4f625d0cb5b815 Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Wed, 29 Nov 2023 16:30:15 +0200 Subject: [PATCH] Realtime Compositor: Implement zero cost external images This patch implements a new mechanism for compositor results to wrap external images, such as those cached in the static cache manager. Thereby enabling zero cost use of those resources, which previously needed a copy at each evaluation. --- .../realtime_compositor/COM_result.hh | 17 ++++++++++++++++- .../realtime_compositor/intern/result.cc | 17 ++++++++++++++++- .../nodes/node_composite_keyingscreen.cc | 4 +--- .../composite/nodes/node_composite_mask.cc | 3 +-- .../composite/nodes/node_composite_texture.cc | 6 ++---- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/source/blender/compositor/realtime_compositor/COM_result.hh b/source/blender/compositor/realtime_compositor/COM_result.hh index dee2d88bdeb..0f930f6e7ae 100644 --- a/source/blender/compositor/realtime_compositor/COM_result.hh +++ b/source/blender/compositor/realtime_compositor/COM_result.hh @@ -72,7 +72,11 @@ enum class ResultPrecision : uint8_t { * the results of identity operations, that is, operations that do nothing to their inputs in * certain configurations. In which case, the proxy result is left as is with no extra * transformation on its domain whatsoever. Proxy results can be created by calling the - * pass_through method, see that method for more details. */ + * pass_through method, see that method for more details. + * + * A result can wrap an external texture that is not allocated nor managed by the result. This is + * set up by a call to the wrap_external method. In that case, when the reference count eventually + * reach zero, the texture will not be freed. */ class Result { private: /* The base type of the result's texture or single value. */ @@ -120,6 +124,10 @@ class Result { * calling the pass_through method, which sets this result to be the master of a target result. * See that method for more information. */ Result *master_ = nullptr; + /* If true, then the result wraps an external texture that is not allocated nor managed by the + * result. This is set up by a call to the wrap_external method. In that case, when the reference + * count eventually reach zero, the texture will not be freed. */ + bool is_external_ = false; public: /* Construct a result of the given type and precision with the given texture pool that will be @@ -203,6 +211,13 @@ class Result { * a practical example of use. */ void steal_data(Result &source); + /* Set up the result to wrap an external texture that is not allocated nor managed by the result. + * The is_external_ member will be set to true, the domain will be set to have the same size as + * the texture, and the texture will be set to the given texture. See the is_external_ member for + * more information. The given texture should have the same format as the result and is assumed + * to have a lifetime that covers the evaluation of the compositor. */ + void wrap_external(GPUTexture *texture); + /* Sets the transformation of the domain of the result to the given transformation. */ void set_transformation(const float3x3 &transformation); diff --git a/source/blender/compositor/realtime_compositor/intern/result.cc b/source/blender/compositor/realtime_compositor/intern/result.cc index 1abfc434b8d..3648431f060 100644 --- a/source/blender/compositor/realtime_compositor/intern/result.cc +++ b/source/blender/compositor/realtime_compositor/intern/result.cc @@ -192,6 +192,19 @@ void Result::steal_data(Result &source) source.texture_pool_ = nullptr; } +void Result::wrap_external(GPUTexture *texture) +{ + const eGPUTextureFormat texture_format = GPU_texture_format(texture); + BLI_assert(texture_format == get_texture_format()); + BLI_assert(!is_allocated()); + BLI_assert(!master_); + + texture_ = texture; + is_external_ = true; + is_single_value_ = false; + domain_ = Domain(int2(GPU_texture_width(texture), GPU_texture_height(texture))); +} + void Result::set_transformation(const float3x3 &transformation) { domain_.transformation = transformation; @@ -298,7 +311,9 @@ void Result::release() * texture pool. */ reference_count_--; if (reference_count_ == 0) { - texture_pool_->release(texture_); + if (!is_external_) { + texture_pool_->release(texture_); + } texture_ = nullptr; } } diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc index 73efe665801..90f7ceb91f5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc +++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc @@ -108,9 +108,7 @@ class KeyingScreenOperation : public NodeOperation { KeyingScreen &cached_keying_screen = context().cache_manager().keying_screens.get( context(), get_movie_clip(), movie_tracking_object, get_smoothness()); - const Domain domain = compute_domain(); - keying_screen.allocate_texture(domain); - GPU_texture_copy(keying_screen.texture(), cached_keying_screen.texture()); + keying_screen.wrap_external(cached_keying_screen.texture()); } Domain compute_domain() override diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc index bd661a66600..8c9a4f10cf7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc @@ -101,8 +101,7 @@ class MaskOperation : public NodeOperation { get_motion_blur_samples(), get_motion_blur_shutter()); - output_mask.allocate_texture(domain); - GPU_texture_copy(output_mask.texture(), cached_mask.texture()); + output_mask.wrap_external(cached_mask.texture()); } Domain compute_domain() override diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc index 369e4f46df3..4d0391f228c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_texture.cc +++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc @@ -63,13 +63,11 @@ class TextureOperation : public NodeOperation { get_input("Scale").get_vector_value_default(float4(0.0f)).xy()); if (color_result.should_compute()) { - color_result.allocate_texture(domain); - GPU_texture_copy(color_result.texture(), cached_texture.color_texture()); + color_result.wrap_external(cached_texture.color_texture()); } if (value_result.should_compute()) { - value_result.allocate_texture(domain); - GPU_texture_copy(value_result.texture(), cached_texture.value_texture()); + value_result.wrap_external(cached_texture.value_texture()); } } -- 2.30.2