/* SPDX-License-Identifier: GPL-2.0-or-later */ #include #include "BLI_array.hh" #include "BLI_hash.hh" #include "BLI_index_range.hh" #include "BLI_math_base.hh" #include "RE_pipeline.h" #include "GPU_shader.h" #include "GPU_texture.h" #include "COM_symmetric_separable_blur_weights.hh" namespace blender::realtime_compositor { /* -------------------------------------------------------------------- * Symmetric Separable Blur Weights Key. */ SymmetricSeparableBlurWeightsKey::SymmetricSeparableBlurWeightsKey(int type, float radius) : type(type), radius(radius) { } uint64_t SymmetricSeparableBlurWeightsKey::hash() const { return get_default_hash_2(type, radius); } bool operator==(const SymmetricSeparableBlurWeightsKey &a, const SymmetricSeparableBlurWeightsKey &b) { return a.type == b.type && a.radius == b.radius; } /* -------------------------------------------------------------------- * Symmetric Separable Blur Weights. */ SymmetricSeparableBlurWeights::SymmetricSeparableBlurWeights(int type, float radius) { /* 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 = math::ceil(radius) + 1; Array weights(size); float sum = 0.0f; /* First, compute the center weight. */ const float center_weight = RE_filter_value(type, 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(type, i * scale); weights[i] = weight; sum += weight * 2.0f; } /* Finally, normalize the weights. */ for (const int i : weights.index_range()) { weights[i] /= sum; } texture_ = GPU_texture_create_1d("Weights", size, 1, GPU_R16F, weights.data()); } SymmetricSeparableBlurWeights::~SymmetricSeparableBlurWeights() { GPU_texture_free(texture_); } void SymmetricSeparableBlurWeights::bind_as_texture(GPUShader *shader, const char *texture_name) const { const int texture_image_unit = GPU_shader_get_texture_binding(shader, texture_name); GPU_texture_bind(texture_, texture_image_unit); } void SymmetricSeparableBlurWeights::unbind_as_texture() const { GPU_texture_unbind(texture_); } } // namespace blender::realtime_compositor