From 85ce4882981943b5a306090f03482bd5397c503d Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Fri, 4 Nov 2022 16:14:22 +0200 Subject: Realtime Compositor: Implement static cache manager This patch introduces the concept of a Cached Resource that can be cached across compositor evaluations as well as used by multiple operations in the same evaluation. Additionally, this patch implements a new structure for the realtime compositor, the Static Cache Manager, that manages all the cached resources and deletes them when they are no longer needed. This improves responsiveness while adjusting compositor node trees and also conserves memory usage. Differential Revision: https://developer.blender.org/D16357 Reviewed By: Clement Foucault --- .../nodes/composite/nodes/node_composite_dilate.cc | 187 ++------------------- 1 file changed, 16 insertions(+), 171 deletions(-) (limited to 'source/blender/nodes/composite/nodes/node_composite_dilate.cc') diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc index d659c46721d..6281ef7990b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc @@ -5,25 +5,20 @@ * \ingroup cmpnodes */ -#include - -#include "BLI_array.hh" #include "BLI_assert.h" #include "BLI_math_base.hh" - -#include "DNA_scene_types.h" +#include "BLI_math_vec_types.hh" #include "RNA_access.h" #include "UI_interface.h" #include "UI_resources.h" -#include "RE_pipeline.h" - #include "GPU_shader.h" #include "GPU_state.h" #include "GPU_texture.h" +#include "COM_morphological_distance_feather_weights.hh" #include "COM_node_operation.hh" #include "COM_utilities.hh" @@ -64,161 +59,7 @@ static void node_composit_buts_dilateerode(uiLayout *layout, bContext * /*C*/, P using namespace blender::realtime_compositor; -/* Computes a falloff that is equal to 1 at an input of zero and decrease to zero at an input of 1, - * with the rate of decrease depending on the falloff type. */ -static float compute_distance_falloff(float x, int falloff_type) -{ - x = 1.0f - x; - - switch (falloff_type) { - case PROP_SMOOTH: - return 3.0f * x * x - 2.0f * x * x * x; - case PROP_SPHERE: - return std::sqrt(2.0f * x - x * x); - case PROP_ROOT: - return std::sqrt(x); - case PROP_SHARP: - return x * x; - case PROP_INVSQUARE: - return x * (2.0f - x); - case PROP_LIN: - return x; - default: - BLI_assert_unreachable(); - return x; - } -} - -/* A helper class that computes and caches 1D GPU textures containing the weights of the separable - * Gaussian filter of the given radius as well as an inverse distance falloff of the given type and - * radius. The weights and falloffs are symmetric, because the Gaussian and falloff functions are - * all even functions. Consequently, only the positive half of the filter is computed and the - * shader takes that into consideration. */ -class SymmetricSeparableMorphologicalDistanceFeatherWeights { - private: - int radius_ = 1; - int falloff_type_ = PROP_SMOOTH; - GPUTexture *weights_texture_ = nullptr; - GPUTexture *distance_falloffs_texture_ = nullptr; - - public: - ~SymmetricSeparableMorphologicalDistanceFeatherWeights() - { - if (weights_texture_) { - GPU_texture_free(weights_texture_); - } - - if (distance_falloffs_texture_) { - GPU_texture_free(distance_falloffs_texture_); - } - } - - /* Check if textures containing the weights and distance falloffs were already computed for the - * given distance falloff type and radius. If such textures exists, do nothing, otherwise, free - * the already computed textures and recompute it with the given distance falloff type and - * radius. */ - void update(int radius, int falloff_type) - { - if (weights_texture_ && distance_falloffs_texture_ && falloff_type == falloff_type_ && - radius == radius_) { - return; - } - - radius_ = radius; - falloff_type_ = falloff_type; - - compute_weights(); - compute_distance_falloffs(); - } - - void compute_weights() - { - if (weights_texture_) { - GPU_texture_free(weights_texture_); - } - - /* The size of filter is double the radius plus 1, but since the filter is symmetric, we only - * compute half of it and no doubling happens. We add 1 to make sure the filter size is always - * odd and there is a center weight. */ - const int size = radius_ + 1; - Array weights(size); - - float sum = 0.0f; - - /* First, compute the center weight. */ - const float center_weight = RE_filter_value(R_FILTER_GAUSS, 0.0f); - weights[0] = center_weight; - sum += center_weight; - - /* Second, compute the other weights in the positive direction, making sure to add double the - * weight to the sum of weights because the filter is symmetric and we only loop over half of - * it. Skip the center weight already computed by dropping the front index. */ - const float scale = radius_ > 0.0f ? 1.0f / radius_ : 0.0f; - for (const int i : weights.index_range().drop_front(1)) { - const float weight = RE_filter_value(R_FILTER_GAUSS, i * scale); - weights[i] = weight; - sum += weight * 2.0f; - } - - /* Finally, normalize the weights. */ - for (const int i : weights.index_range()) { - weights[i] /= sum; - } - - weights_texture_ = GPU_texture_create_1d("Weights", size, 1, GPU_R16F, weights.data()); - } - - void compute_distance_falloffs() - { - if (distance_falloffs_texture_) { - GPU_texture_free(distance_falloffs_texture_); - } - - /* The size of the distance falloffs is double the radius plus 1, but since the falloffs are - * symmetric, we only compute half of them and no doubling happens. We add 1 to make sure the - * falloffs size is always odd and there is a center falloff. */ - const int size = radius_ + 1; - Array falloffs(size); - - /* Compute the distance falloffs in the positive direction only, because the falloffs are - * symmetric. */ - const float scale = radius_ > 0.0f ? 1.0f / radius_ : 0.0f; - for (const int i : falloffs.index_range()) { - falloffs[i] = compute_distance_falloff(i * scale, falloff_type_); - } - - distance_falloffs_texture_ = GPU_texture_create_1d( - "Distance Factors", size, 1, GPU_R16F, falloffs.data()); - } - - void bind_weights_as_texture(GPUShader *shader, const char *texture_name) - { - const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name); - GPU_texture_bind(weights_texture_, texture_image_unit); - } - - void unbind_weights_as_texture() - { - GPU_texture_unbind(weights_texture_); - } - - void bind_distance_falloffs_as_texture(GPUShader *shader, const char *texture_name) - { - const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name); - GPU_texture_bind(distance_falloffs_texture_, texture_image_unit); - } - - void unbind_distance_falloffs_as_texture() - { - GPU_texture_unbind(distance_falloffs_texture_); - } -}; - class DilateErodeOperation : public NodeOperation { - private: - /* Cached symmetric blur weights and distance falloffs for the distance feature method. */ - SymmetricSeparableMorphologicalDistanceFeatherWeights distance_feather_weights_; - public: using NodeOperation::NodeOperation; @@ -414,9 +255,11 @@ class DilateErodeOperation : public NodeOperation { const Result &input_image = get_input("Mask"); input_image.bind_as_texture(shader, "input_tx"); - distance_feather_weights_.update(math::abs(get_distance()), node_storage(bnode()).falloff); - distance_feather_weights_.bind_weights_as_texture(shader, "weights_tx"); - distance_feather_weights_.bind_distance_falloffs_as_texture(shader, "falloffs_tx"); + const MorphologicalDistanceFeatherWeights &weights = + context().cache_manager().get_morphological_distance_feather_weights( + node_storage(bnode()).falloff, math::abs(get_distance())); + weights.bind_weights_as_texture(shader, "weights_tx"); + weights.bind_distance_falloffs_as_texture(shader, "falloffs_tx"); /* We allocate an output image of a transposed size, that is, with a height equivalent to the * width of the input and vice versa. This is done as a performance optimization. The shader @@ -437,8 +280,8 @@ class DilateErodeOperation : public NodeOperation { GPU_shader_unbind(); input_image.unbind_as_texture(); - distance_feather_weights_.unbind_weights_as_texture(); - distance_feather_weights_.unbind_distance_falloffs_as_texture(); + weights.unbind_weights_as_texture(); + weights.unbind_distance_falloffs_as_texture(); GPU_texture_image_unbind(horizontal_pass_result); return horizontal_pass_result; @@ -453,9 +296,11 @@ class DilateErodeOperation : public NodeOperation { const int texture_image_unit = GPU_shader_get_texture_binding(shader, "input_tx"); GPU_texture_bind(horizontal_pass_result, texture_image_unit); - distance_feather_weights_.update(math::abs(get_distance()), node_storage(bnode()).falloff); - distance_feather_weights_.bind_weights_as_texture(shader, "weights_tx"); - distance_feather_weights_.bind_distance_falloffs_as_texture(shader, "falloffs_tx"); + const MorphologicalDistanceFeatherWeights &weights = + context().cache_manager().get_morphological_distance_feather_weights( + node_storage(bnode()).falloff, math::abs(get_distance())); + weights.bind_weights_as_texture(shader, "weights_tx"); + weights.bind_distance_falloffs_as_texture(shader, "falloffs_tx"); const Domain domain = compute_domain(); Result &output_image = get_result("Mask"); @@ -468,8 +313,8 @@ class DilateErodeOperation : public NodeOperation { GPU_shader_unbind(); output_image.unbind_as_image(); - distance_feather_weights_.unbind_weights_as_texture(); - distance_feather_weights_.unbind_distance_falloffs_as_texture(); + weights.unbind_weights_as_texture(); + weights.unbind_distance_falloffs_as_texture(); GPU_texture_unbind(horizontal_pass_result); } -- cgit v1.2.3 From 4ec5a8cbc23311776ad3f5745c52331b4937ddb0 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sat, 5 Nov 2022 16:10:27 +0100 Subject: Cleanup: Remove unnecessary node type registraction functions These functions provided little benefit compared to simply setting the function pointers directly. --- source/blender/nodes/composite/nodes/node_composite_dilate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/nodes/composite/nodes/node_composite_dilate.cc') diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc index 6281ef7990b..cc4e09d4d0d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc @@ -380,7 +380,7 @@ void register_node_type_cmp_dilateerode() cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER); ntype.draw_buttons = file_ns::node_composit_buts_dilateerode; ntype.declare = file_ns::cmp_node_dilate_declare; - node_type_init(&ntype, file_ns::node_composit_init_dilateerode); + ntype.initfunc = file_ns::node_composit_init_dilateerode; node_type_storage( &ntype, "NodeDilateErode", node_free_standard_storage, node_copy_standard_storage); ntype.get_compositor_operation = file_ns::get_compositor_operation; -- cgit v1.2.3