Realtime Compositor: Implement ID Mask node

This patch implements the ID Mask node for the realtime compositor.

The node can be implemented as a GPU shader operation when the
anti-aliasing option is disabled, which is something we should do when
the evaluator allows nodes be executed as both standard and GPU shader
operations.

Pull Request: https://projects.blender.org/blender/blender/pulls/106593
This commit is contained in:
Omar Emara 2023-04-20 07:20:58 +02:00 committed by Omar Emara
parent 335d32153e
commit 3d6117994c
4 changed files with 84 additions and 5 deletions

@ -118,6 +118,7 @@ set(GLSL_SRC
shaders/compositor_glare_simple_star_vertical_pass.glsl shaders/compositor_glare_simple_star_vertical_pass.glsl
shaders/compositor_glare_streaks_accumulate.glsl shaders/compositor_glare_streaks_accumulate.glsl
shaders/compositor_glare_streaks_filter.glsl shaders/compositor_glare_streaks_filter.glsl
shaders/compositor_id_mask.glsl
shaders/compositor_image_crop.glsl shaders/compositor_image_crop.glsl
shaders/compositor_map_uv.glsl shaders/compositor_map_uv.glsl
shaders/compositor_morphological_distance.glsl shaders/compositor_morphological_distance.glsl
@ -215,6 +216,7 @@ set(SRC_SHADER_CREATE_INFOS
shaders/infos/compositor_filter_info.hh shaders/infos/compositor_filter_info.hh
shaders/infos/compositor_flip_info.hh shaders/infos/compositor_flip_info.hh
shaders/infos/compositor_glare_info.hh shaders/infos/compositor_glare_info.hh
shaders/infos/compositor_id_mask_info.hh
shaders/infos/compositor_image_crop_info.hh shaders/infos/compositor_image_crop_info.hh
shaders/infos/compositor_map_uv_info.hh shaders/infos/compositor_map_uv_info.hh
shaders/infos/compositor_morphological_distance_feather_info.hh shaders/infos/compositor_morphological_distance_feather_info.hh

@ -0,0 +1,11 @@
#pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl)
void main()
{
ivec2 texel = ivec2(gl_GlobalInvocationID.xy);
float input_mask_value = texture_load(input_mask_tx, texel).x;
float mask = int(round(input_mask_value)) == index ? 1.0 : 0.0;
imageStore(output_mask_img, texel, vec4(mask));
}

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "gpu_shader_create_info.hh"
GPU_SHADER_CREATE_INFO(compositor_id_mask)
.local_group_size(16, 16)
.push_constant(Type::INT, "index")
.sampler(0, ImageType::FLOAT_2D, "input_mask_tx")
.image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_mask_img")
.compute_source("compositor_id_mask.glsl")
.do_static_compilation(true);

@ -5,11 +5,16 @@
* \ingroup cmpnodes * \ingroup cmpnodes
*/ */
#include <cmath>
#include "BLT_translation.h" #include "BLT_translation.h"
#include "UI_interface.h" #include "UI_interface.h"
#include "UI_resources.h" #include "UI_resources.h"
#include "GPU_shader.h"
#include "COM_algorithm_smaa.hh"
#include "COM_node_operation.hh" #include "COM_node_operation.hh"
#include "node_composite_util.hh" #include "node_composite_util.hh"
@ -20,7 +25,11 @@ namespace blender::nodes::node_composite_id_mask_cc {
static void cmp_node_idmask_declare(NodeDeclarationBuilder &b) static void cmp_node_idmask_declare(NodeDeclarationBuilder &b)
{ {
b.add_input<decl::Float>(N_("ID value")).default_value(1.0f).min(0.0f).max(1.0f); b.add_input<decl::Float>(N_("ID value"))
.default_value(1.0f)
.min(0.0f)
.max(1.0f)
.compositor_domain_priority(0);
b.add_output<decl::Float>(N_("Alpha")); b.add_output<decl::Float>(N_("Alpha"));
} }
@ -38,8 +47,56 @@ class IDMaskOperation : public NodeOperation {
void execute() override void execute() override
{ {
get_input("ID value").pass_through(get_result("Alpha")); const Result &input_mask = get_input("ID value");
context().set_info_message("Viewport compositor setup not fully supported"); if (input_mask.is_single_value()) {
execute_single_value();
return;
}
GPUShader *shader = shader_manager().get("compositor_id_mask");
GPU_shader_bind(shader);
GPU_shader_uniform_1i(shader, "index", get_index());
input_mask.bind_as_texture(shader, "input_mask_tx");
/* If anti-aliasing is disabled, write to the output directly, otherwise, write to a temporary
* result to later perform anti-aliasing. */
Result non_anti_aliased_mask = Result::Temporary(ResultType::Float, texture_pool());
Result &output_mask = use_anti_aliasing() ? non_anti_aliased_mask : get_result("Alpha");
const Domain domain = compute_domain();
output_mask.allocate_texture(domain);
output_mask.bind_as_image(shader, "output_mask_img");
compute_dispatch_threads_at_least(shader, domain.size);
input_mask.unbind_as_texture();
output_mask.unbind_as_image();
GPU_shader_unbind();
if (use_anti_aliasing()) {
smaa(context(), non_anti_aliased_mask, get_result("Alpha"));
non_anti_aliased_mask.release();
}
}
void execute_single_value()
{
const float input_mask_value = get_input("ID value").get_float_value();
const float mask = int(round(input_mask_value)) == get_index() ? 1.0f : 0.0f;
get_result("Alpha").allocate_single_value();
get_result("Alpha").set_float_value(mask);
}
int get_index()
{
return bnode().custom1;
}
bool use_anti_aliasing()
{
return bnode().custom2 != 0;
} }
}; };
@ -60,8 +117,6 @@ void register_node_type_cmp_idmask()
ntype.declare = file_ns::cmp_node_idmask_declare; ntype.declare = file_ns::cmp_node_idmask_declare;
ntype.draw_buttons = file_ns::node_composit_buts_id_mask; ntype.draw_buttons = file_ns::node_composit_buts_id_mask;
ntype.get_compositor_operation = file_ns::get_compositor_operation; ntype.get_compositor_operation = file_ns::get_compositor_operation;
ntype.realtime_compositor_unsupported_message = N_(
"Node not supported in the Viewport compositor");
nodeRegisterType(&ntype); nodeRegisterType(&ntype);
} }