diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index e4e5733e864..703eed81e16 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -261,6 +261,7 @@ set(GLSL_SRC shaders/compositor_glare_ghost_accumulate.glsl shaders/compositor_glare_ghost_base.glsl shaders/compositor_glare_highlights.glsl + shaders/compositor_glare_kernel_downsample.glsl shaders/compositor_glare_mix.glsl shaders/compositor_glare_simple_star_anti_diagonal_pass.glsl shaders/compositor_glare_simple_star_diagonal_pass.glsl diff --git a/source/blender/compositor/shaders/compositor_glare_kernel_downsample.glsl b/source/blender/compositor/shaders/compositor_glare_kernel_downsample.glsl new file mode 100644 index 00000000000..dc045287d8d --- /dev/null +++ b/source/blender/compositor/shaders/compositor_glare_kernel_downsample.glsl @@ -0,0 +1,11 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +void main() +{ + int2 texel = int2(gl_GlobalInvocationID.xy); + const float2 normalized_coordinates = (float2(texel) + float2(0.5f)) / + float2(imageSize(output_img)); + imageStore(output_img, texel, texture(input_tx, normalized_coordinates)); +} diff --git a/source/blender/compositor/shaders/infos/compositor_glare_infos.hh b/source/blender/compositor/shaders/infos/compositor_glare_infos.hh index 76b8a1052db..694595d6417 100644 --- a/source/blender/compositor/shaders/infos/compositor_glare_infos.hh +++ b/source/blender/compositor/shaders/infos/compositor_glare_infos.hh @@ -193,3 +193,25 @@ DEFINE("JITTER") PUSH_CONSTANT(float, jitter_factor) DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() + +/* ------ + * Kernel + * ------ */ + +GPU_SHADER_CREATE_INFO(compositor_glare_kernel_downsample_shared) +LOCAL_GROUP_SIZE(16, 16) +SAMPLER(0, sampler2D, input_tx) +COMPUTE_SOURCE("compositor_glare_kernel_downsample.glsl") +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_glare_kernel_downsample_color) +ADDITIONAL_INFO(compositor_glare_kernel_downsample_shared) +IMAGE(0, SFLOAT_16_16_16_16, write, image2D, output_img) +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_glare_kernel_downsample_float) +ADDITIONAL_INFO(compositor_glare_kernel_downsample_shared) +IMAGE(0, SFLOAT_16, write, image2D, output_img) +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc index a71500d5697..15fe5cc63ce 100644 --- a/source/blender/nodes/composite/nodes/node_composite_glare.cc +++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc @@ -2424,10 +2424,83 @@ class GlareOperation : public NodeOperation { } return kernel_result; } - convolve(this->context(), highlights, kernel, kernel_result, true); + + if (this->get_quality() == CMP_NODE_GLARE_QUALITY_HIGH) { + convolve(this->context(), highlights, kernel, kernel_result, true); + } + else { + Result downsampled_kernel = this->downsample_kernel(kernel); + convolve(this->context(), highlights, downsampled_kernel, kernel_result, true); + downsampled_kernel.release(); + } + return kernel_result; } + Result downsample_kernel(const Result &kernel) + { + if (this->context().use_gpu()) { + return this->downsample_kernel_gpu(kernel); + } + + return this->downsample_kernel_cpu(kernel); + } + + Result downsample_kernel_cpu(const Result &kernel) + { + Result downsampled_kernel = this->context().create_result(kernel.type()); + const int2 size = kernel.domain().size / this->get_quality_factor(); + downsampled_kernel.allocate_texture(size); + + if (kernel.type() == ResultType::Float) { + parallel_for(size, [&](const int2 texel) { + const float2 normalized_coordinates = (float2(texel) + float2(0.5f)) / float2(size); + downsampled_kernel.store_pixel(texel, + kernel.sample_bilinear_extended(normalized_coordinates).x); + }); + } + else { + parallel_for(size, [&](const int2 texel) { + const float2 normalized_coordinates = (float2(texel) + float2(0.5f)) / float2(size); + downsampled_kernel.store_pixel(texel, + kernel.sample_bilinear_extended(normalized_coordinates)); + }); + } + + return downsampled_kernel; + } + + Result downsample_kernel_gpu(const Result &kernel) + { + Result downsampled_kernel = this->context().create_result(kernel.type()); + const int2 size = kernel.domain().size / this->get_quality_factor(); + downsampled_kernel.allocate_texture(size); + + gpu::Shader *shader = context().get_shader(this->get_kernel_downsample_shader_name(kernel)); + GPU_shader_bind(shader); + + GPU_texture_filter_mode(kernel, true); + kernel.bind_as_texture(shader, "input_tx"); + + downsampled_kernel.bind_as_image(shader, "output_img"); + + compute_dispatch_threads_at_least(shader, size); + + GPU_shader_unbind(); + kernel.unbind_as_texture(); + downsampled_kernel.unbind_as_image(); + + return downsampled_kernel; + } + + const char *get_kernel_downsample_shader_name(const Result &kernel) + { + if (kernel.type() == ResultType::Float) { + return "compositor_glare_kernel_downsample_float"; + } + return "compositor_glare_kernel_downsample_color"; + } + const Result &get_kernel_input() { switch (this->get_kernel_data_type()) {