Compositor: Implement Morphological Blurring for CPU

Reference #125968.
This commit is contained in:
Omar Emara
2024-11-25 16:19:51 +02:00
parent 140e5de1f5
commit c7d58d8dbc
2 changed files with 54 additions and 18 deletions

View File

@@ -30,11 +30,12 @@ enum class MorphologicalBlurOperation : uint8_t {
* and blurred input depending on the chosen operation, see the MorphologicalBlurOperation enum for
* more information. The output is written to the given output result, which will be allocated
* internally and is thus expected not to be previously allocated. */
void morphological_blur(Context &context,
Result &input,
Result &output,
float2 radius,
MorphologicalBlurOperation operation = MorphologicalBlurOperation::Erode,
int filter_type = R_FILTER_GAUSS);
void morphological_blur(
Context &context,
const Result &input,
Result &output,
const float2 &radius,
const MorphologicalBlurOperation operation = MorphologicalBlurOperation::Erode,
const int filter_type = R_FILTER_GAUSS);
} // namespace blender::realtime_compositor

View File

@@ -3,6 +3,7 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_assert.h"
#include "BLI_math_base.hh"
#include "BLI_math_vector_types.hh"
#include "GPU_shader.hh"
@@ -23,20 +24,16 @@ static const char *get_shader(MorphologicalBlurOperation operation)
return "compositor_morphological_blur_dilate";
case MorphologicalBlurOperation::Erode:
return "compositor_morphological_blur_erode";
default:
break;
}
BLI_assert_unreachable();
return nullptr;
}
/* Apply the morphological operator (minimum or maximum) on the input and the blurred input. The
* output is written to the blurred_input in-place. */
static void apply_morphological_operator(Context &context,
Result &input,
Result &blurred_input,
MorphologicalBlurOperation operation)
static void apply_morphological_operator_gpu(Context &context,
const Result &input,
Result &blurred_input,
const MorphologicalBlurOperation operation)
{
GPUShader *shader = context.get_shader(get_shader(operation));
GPU_shader_bind(shader);
@@ -53,12 +50,50 @@ static void apply_morphological_operator(Context &context,
blurred_input.unbind_as_image();
}
static void apply_morphological_operator_cpu(const Result &input,
Result &blurred_input,
const MorphologicalBlurOperation operation)
{
Domain domain = input.domain();
switch (operation) {
case MorphologicalBlurOperation::Dilate:
parallel_for(domain.size, [&](const int2 texel) {
float input_value = input.load_pixel(texel).x;
float blurred_value = blurred_input.load_pixel(texel).x;
blurred_input.store_pixel(texel, float4(math::max(input_value, blurred_value)));
});
break;
case MorphologicalBlurOperation::Erode:
parallel_for(domain.size, [&](const int2 texel) {
float input_value = input.load_pixel(texel).x;
float blurred_value = blurred_input.load_pixel(texel).x;
blurred_input.store_pixel(texel, float4(math::min(input_value, blurred_value)));
});
break;
}
}
/* Apply the morphological operator (minimum or maximum) on the input and the blurred input. The
* output is written to the blurred_input in-place. */
static void apply_morphological_operator(Context &context,
const Result &input,
Result &blurred_input,
const MorphologicalBlurOperation operation)
{
if (context.use_gpu()) {
apply_morphological_operator_gpu(context, input, blurred_input, operation);
}
else {
apply_morphological_operator_cpu(input, blurred_input, operation);
}
}
void morphological_blur(Context &context,
Result &input,
const Result &input,
Result &output,
float2 radius,
MorphologicalBlurOperation operation,
int filter_type)
const float2 &radius,
const MorphologicalBlurOperation operation,
const int filter_type)
{
BLI_assert(input.type() == ResultType::Float);