/* SPDX-FileCopyrightText: 2025 Blender Authors * * SPDX-License-Identifier: GPL-2.0-or-later */ #include "MEM_guardedalloc.h" #include "GPU_compute.hh" #include "GPU_shader.hh" #include "GPU_state.hh" #include "GPU_texture.hh" #include "GPU_texture_pool.hh" #include "COM_context.hh" #include "COM_result.hh" #include "COM_algorithm_sample_pixel.hh" namespace blender::compositor { static char const *get_pixel_sampler_shader_name(const Interpolation &interpolation) { switch (interpolation) { case Interpolation::Anisotropic: case Interpolation::Bicubic: return "compositor_sample_pixel_bicubic"; case Interpolation::Bilinear: case Interpolation::Nearest: return "compositor_sample_pixel"; } BLI_assert_unreachable(); return "compositor_sample_pixel"; } static float4 sample_pixel_gpu(Context &context, const Result &input, const Interpolation &interpolation, const ExtensionMode &extension_mode_x, const ExtensionMode &extension_mode_y, const float2 coordinates) { gpu::Shader *shader = context.get_shader(get_pixel_sampler_shader_name(interpolation)); GPU_shader_bind(shader); GPU_shader_uniform_2fv(shader, "coordinates_u", coordinates); Result output = context.create_result(input.type()); output.allocate_texture(int2(1)); if (interpolation == Interpolation::Anisotropic) { GPU_texture_anisotropic_filter(input, true); GPU_texture_mipmap_mode(input, true, true); } else { const bool use_bilinear = ELEM(interpolation, Interpolation::Bilinear, Interpolation::Bicubic); GPU_texture_filter_mode(input, use_bilinear); } GPU_texture_extend_mode_x(input, map_extension_mode_to_extend_mode(extension_mode_x)); GPU_texture_extend_mode_y(input, map_extension_mode_to_extend_mode(extension_mode_y)); input.bind_as_texture(shader, "input_tx"); output.bind_as_image(shader, "output_img"); GPU_compute_dispatch(shader, 1, 1, 1); input.unbind_as_texture(); output.unbind_as_image(); GPU_shader_unbind(); GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); float *pixel = static_cast(GPU_texture_read(output, GPU_DATA_FLOAT, 0)); output.release(); float4 sampled_value = float4(0.0f, 0.0f, 0.0f, 1.0f); output.get_cpp_type().copy_assign(pixel, sampled_value); MEM_freeN(pixel); return sampled_value; } static float4 sample_pixel_cpu(const Result &input, const Interpolation &interpolation, const ExtensionMode &extension_mode_x, const ExtensionMode &extension_mode_y, const float2 coordinates) { return input.sample(coordinates, interpolation, extension_mode_x, extension_mode_y); } /* Samples a pixel from a result. */ float4 sample_pixel(Context &context, const Result &input, const Interpolation &interpolation, const ExtensionMode &extension_mode_x, const ExtensionMode &extension_mode_y, const float2 coordinates) { if (input.is_single_value()) { switch (input.type()) { case ResultType::Float: return float4(input.get_single_value(), 0.0f, 0.0f, 1.0f); case ResultType::Float2: return float4(input.get_single_value(), 0.0f, 1.0f); case ResultType::Float3: return float4(input.get_single_value(), 1.0f); case ResultType::Float4: case ResultType::Color: return input.get_single_value(); default: break; } BLI_assert_unreachable(); return float4(0.0f); } if (context.use_gpu()) { return sample_pixel_gpu( context, input, interpolation, extension_mode_x, extension_mode_y, coordinates); } else { return sample_pixel_cpu(input, interpolation, extension_mode_x, extension_mode_y, coordinates); } } } // namespace blender::compositor