From a5ecde48ae2b26d22df7b6c369bbfe6ad0435a8e Mon Sep 17 00:00:00 2001 From: Omar Emara Date: Thu, 20 Feb 2025 10:38:40 +0100 Subject: [PATCH] Compositor: Add Float4 type The compositor previously overloaded the vector type to represent multiple dimensions that are always stored in a 4D float vector. This patch introduce a dedicated type for float4, leaving the vector type to always represent a 3D vector, which will be done in a later commit. This is not exposed to the user as a separate socket type with a different color, it is only an internal type that uses the same vector socket shape and color. Since the vector socket represents both 4D and 3D vectors, code generally assumes that such sockets represents 3D vectors, and the developer is expected to set it to a 4D vector if needed in the node operation constructor, or use the newly added skip_type_conversion flag for nodes that do not care about types, like the File Output node. Though this should be redundant once we add a dimension property for vector sockets. Pull Request: https://projects.blender.org/blender/blender/pulls/134486 --- .../compositor/COM_input_descriptor.hh | 3 + source/blender/compositor/COM_meta_data.hh | 4 - source/blender/compositor/COM_result.hh | 7 +- .../compositor/algorithms/intern/smaa.cc | 5 + .../intern/symmetric_separable_blur.cc | 3 + .../cached_resources/intern/cached_image.cc | 61 +++++++-- .../compositor/intern/conversion_operation.cc | 120 ++++++++++++++++++ .../intern/input_single_value_operation.cc | 4 + .../multi_function_procedure_operation.cc | 56 ++++++++ .../intern/realize_on_domain_operation.cc | 16 +-- .../reduce_to_single_value_operation.cc | 3 + source/blender/compositor/intern/result.cc | 7 + .../compositor/intern/shader_operation.cc | 28 +++- source/blender/compositor/intern/utilities.cc | 3 + .../shaders/infos/compositor_convert_info.hh | 60 +++++++++ .../infos/compositor_read_input_info.hh | 9 +- .../compositor_realize_on_domain_info.hh | 16 +-- .../gpu_shader_compositor_store_output.glsl | 8 +- ...gpu_shader_compositor_type_conversion.glsl | 44 +++++++ .../COM_utilities_type_conversion.hh | 44 +++++++ .../nodes/node_composite_file_output.cc | 44 +++++-- .../composite/nodes/node_composite_image.cc | 15 ++- .../nodes/node_composite_trackpos.cc | 5 +- .../nodes/node_composite_vec_blur.cc | 45 ++++--- source/blender/render/intern/compositor.cc | 47 ++++--- tests/data | 2 +- 26 files changed, 547 insertions(+), 112 deletions(-) diff --git a/source/blender/compositor/COM_input_descriptor.hh b/source/blender/compositor/COM_input_descriptor.hh index c08e84cd91f..6e13be7247d 100644 --- a/source/blender/compositor/COM_input_descriptor.hh +++ b/source/blender/compositor/COM_input_descriptor.hh @@ -47,6 +47,9 @@ class InputDescriptor { * result that will be discarded anyways. If false, the input can work with both single and * non-single values. */ bool expects_single_value = false; + /* If true, the input will not be implicitly converted to the type of the input and will be + * passed as is. */ + bool skip_type_conversion = false; }; } // namespace blender::compositor diff --git a/source/blender/compositor/COM_meta_data.hh b/source/blender/compositor/COM_meta_data.hh index 3731f61dbef..49b6164750f 100644 --- a/source/blender/compositor/COM_meta_data.hh +++ b/source/blender/compositor/COM_meta_data.hh @@ -28,10 +28,6 @@ struct CryptomatteMetaData { struct MetaData { /* The result stores non color data, which is not to be color-managed. */ bool is_non_color_data = false; - /* The result stores a 4D vector as opposed to a 3D vector. This is the case for things like - * velocity passes, and we need to mark them as 4D in order to write them to file correctly. This - * field can be ignored for results that are not of type Vector. */ - bool is_4d_vector = false; /* Stores Cryptomatte meta data. This will only be initialized for results that represent * Cryptomatte information. See the CryptomatteMetaData structure for more information. */ CryptomatteMetaData cryptomatte; diff --git a/source/blender/compositor/COM_result.hh b/source/blender/compositor/COM_result.hh index b7d1600665d..d264b294ca6 100644 --- a/source/blender/compositor/COM_result.hh +++ b/source/blender/compositor/COM_result.hh @@ -33,14 +33,12 @@ class DerivedResources; /* Make sure to update the format related static methods in the Result class. */ enum class ResultType : uint8_t { /* The following types are user facing and can be used as inputs and outputs of operations. They - * either represent the base type of the result's image or a single value result. The color type - * represents an RGBA color. And the vector type represents a generic 4-component vector, which - * can encode two 2D vectors, one 3D vector with the last component ignored, or other dimensional - * data. */ + * either represent the base type of the result's image or a single value result. */ Float, Int, Vector, Color, + Float4, /* The following types are for internal use only, not user facing, and can't be used as inputs * and outputs of operations. It follows that they needn't be handled in implicit operations like @@ -482,6 +480,7 @@ BLI_INLINE_METHOD int64_t Result::channels_count() const return 3; case ResultType::Vector: case ResultType::Color: + case ResultType::Float4: return 4; } return 4; diff --git a/source/blender/compositor/algorithms/intern/smaa.cc b/source/blender/compositor/algorithms/intern/smaa.cc index 851a0b5c957..9ca9bf3a2a5 100644 --- a/source/blender/compositor/algorithms/intern/smaa.cc +++ b/source/blender/compositor/algorithms/intern/smaa.cc @@ -1417,6 +1417,7 @@ static float3 get_luminance_coefficients(ResultType type) return luminance_coefficients; } case ResultType::Vector: + case ResultType::Float4: return float3(1.0f, 1.0f, 1.0f); case ResultType::Float: return float3(1.0f, 0.0f, 0.0f); @@ -1588,6 +1589,7 @@ static const char *get_blend_shader_name(ResultType type) switch (type) { case ResultType::Color: case ResultType::Vector: + case ResultType::Float4: return "compositor_smaa_neighborhood_blending_float4"; case ResultType::Float2: return "compositor_smaa_neighborhood_blending_float2"; @@ -1667,6 +1669,9 @@ static void compute_single_value(Result &input, Result &output) case ResultType::Vector: output.set_single_value(input.get_single_value()); break; + case ResultType::Float4: + output.set_single_value(input.get_single_value()); + break; case ResultType::Float2: output.set_single_value(input.get_single_value()); break; diff --git a/source/blender/compositor/algorithms/intern/symmetric_separable_blur.cc b/source/blender/compositor/algorithms/intern/symmetric_separable_blur.cc index b5f9f2e68ee..87e9f20f8b5 100644 --- a/source/blender/compositor/algorithms/intern/symmetric_separable_blur.cc +++ b/source/blender/compositor/algorithms/intern/symmetric_separable_blur.cc @@ -79,6 +79,7 @@ static const char *get_blur_shader(const ResultType type) return "compositor_symmetric_separable_blur_float4"; case ResultType::Float2: case ResultType::Float3: + case ResultType::Float4: case ResultType::Int2: case ResultType::Int: /* Not supported. */ @@ -182,6 +183,7 @@ static Result horizontal_pass_cpu(Context &context, break; case ResultType::Float2: case ResultType::Float3: + case ResultType::Float4: case ResultType::Int2: case ResultType::Int: /* Not supported. */ @@ -280,6 +282,7 @@ static void vertical_pass_cpu(Context &context, break; case ResultType::Float2: case ResultType::Float3: + case ResultType::Float4: case ResultType::Int2: case ResultType::Int: /* Not supported. */ diff --git a/source/blender/compositor/cached_resources/intern/cached_image.cc b/source/blender/compositor/cached_resources/intern/cached_image.cc index f13538ea5f3..862d864cbad 100644 --- a/source/blender/compositor/cached_resources/intern/cached_image.cc +++ b/source/blender/compositor/cached_resources/intern/cached_image.cc @@ -201,6 +201,54 @@ static ImBuf *compute_linear_buffer(ImBuf *image_buffer) return linear_image_buffer; } +/* Returns the appropriate result type for the given image buffer, which represents the pass in the + * given render result with the given image user. The type is determined based on the channels + * count of the buffer, except for when the channels count is 4, because it can either be a color + * or a float4 pass, which is determined by inspecting the channels IDs of the pass. */ +static ResultType get_result_type(const RenderResult *render_result, + const ImageUser &image_user, + const ImBuf *image_buffer) +{ + switch (image_buffer->channels) { + case 1: + return ResultType::Float; + case 2: + return ResultType::Float2; + case 3: + return ResultType::Float3; + case 4: + /* The 4 channel case is ambiguous, it can either be a color or a float4, so we need + * to investigate the pass channel IDs outside of the switch to identify its type. */ + break; + default: + BLI_assert_unreachable(); + return ResultType::Float; + } + + if (!render_result) { + /* Not a multi-layer images, 4-channels are always color images. */ + return ResultType::Color; + } + + const RenderLayer *render_layer = get_render_layer(render_result, image_user); + if (!render_layer) { + /* Not a multi-layer images, 4-channels are always color images. */ + return ResultType::Color; + } + + const RenderPass *render_pass = get_render_pass(render_layer, image_user); + if (!render_pass) { + /* Not a multi-layer images, 4-channels are always color images. */ + return ResultType::Color; + } + + if (StringRef(render_pass->chan_id) == "XYZW") { + return ResultType::Float4; + } + + return ResultType::Color; +} + CachedImage::CachedImage(Context &context, Image *image, ImageUser *image_user, @@ -235,11 +283,7 @@ CachedImage::CachedImage(Context &context, const bool use_half_float = linear_image_buffer->flags & IB_halffloat; this->result.set_precision(use_half_float ? ResultPrecision::Half : ResultPrecision::Full); - /* At the user level, vector images are always treated as color, so there are only two possible - * options, float images and color images. 3-channel images should then be converted to 4-channel - * images below. */ - const bool is_single_channel = linear_image_buffer->channels == 1; - this->result.set_type(is_single_channel ? ResultType::Float : ResultType::Color); + this->result.set_type(get_result_type(render_result, image_user_for_pass, linear_image_buffer)); /* For GPU, we wrap the texture returned by IMB module and free it ourselves in destructor. For * CPU, we allocate the result and copy to it from the image buffer. */ @@ -250,8 +294,7 @@ CachedImage::CachedImage(Context &context, } else { const int2 size = int2(image_buffer->x, image_buffer->y); - const int channels_count = linear_image_buffer->channels; - Result buffer_result(context, Result::float_type(channels_count), ResultPrecision::Full); + Result buffer_result(context, this->result.type(), ResultPrecision::Full); buffer_result.wrap_external(linear_image_buffer->float_buffer.data, size); this->result.allocate_texture(size, false); parallel_for(size, [&](const int2 texel) { @@ -320,10 +363,6 @@ void CachedImage::populate_meta_data(const RenderResult *render_result, } }, false); - - if (StringRef(render_pass->chan_id) == "XYZW") { - this->result.meta_data.is_4d_vector = true; - } } CachedImage::~CachedImage() diff --git a/source/blender/compositor/intern/conversion_operation.cc b/source/blender/compositor/intern/conversion_operation.cc index 01cf75cb4c5..553fb846f49 100644 --- a/source/blender/compositor/intern/conversion_operation.cc +++ b/source/blender/compositor/intern/conversion_operation.cc @@ -67,6 +67,10 @@ SimpleOperation *ConversionOperation::construct_if_needed(Context &context, const Result &input_result, const InputDescriptor &input_descriptor) { + if (input_descriptor.skip_type_conversion) { + return nullptr; + } + const ResultType result_type = input_result.type(); const ResultType expected_type = input_descriptor.type; if (result_type != expected_type) { @@ -86,6 +90,8 @@ const char *ConversionOperation::get_conversion_shader_name() return "compositor_convert_float_to_vector"; case ResultType::Color: return "compositor_convert_float_to_color"; + case ResultType::Float4: + return "compositor_convert_float_to_float4"; case ResultType::Float: /* Same type, no conversion needed. */ break; @@ -104,6 +110,8 @@ const char *ConversionOperation::get_conversion_shader_name() return "compositor_convert_int_to_vector"; case ResultType::Color: return "compositor_convert_int_to_color"; + case ResultType::Float4: + return "compositor_convert_int_to_float4"; case ResultType::Int: /* Same type, no conversion needed. */ break; @@ -122,6 +130,8 @@ const char *ConversionOperation::get_conversion_shader_name() return "compositor_convert_vector_to_int"; case ResultType::Color: return "compositor_convert_vector_to_color"; + case ResultType::Float4: + return "compositor_convert_vector_to_float4"; case ResultType::Vector: /* Same type, no conversion needed. */ break; @@ -140,6 +150,8 @@ const char *ConversionOperation::get_conversion_shader_name() return "compositor_convert_color_to_int"; case ResultType::Vector: return "compositor_convert_color_to_vector"; + case ResultType::Float4: + return "compositor_convert_color_to_float4"; case ResultType::Color: /* Same type, no conversion needed. */ break; @@ -150,6 +162,26 @@ const char *ConversionOperation::get_conversion_shader_name() break; } break; + case ResultType::Float4: + switch (this->get_result().type()) { + case ResultType::Float: + return "compositor_convert_float4_to_float"; + case ResultType::Int: + return "compositor_convert_float4_to_int"; + case ResultType::Vector: + return "compositor_convert_float4_to_vector"; + case ResultType::Color: + return "compositor_convert_float4_to_color"; + case ResultType::Float4: + /* Same type, no conversion needed. */ + break; + case ResultType::Float2: + case ResultType::Float3: + case ResultType::Int2: + /* Types are not user facing, so we needn't implement them. */ + break; + } + break; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -175,6 +207,9 @@ void ConversionOperation::execute_single(const Result &input, Result &output) case ResultType::Color: output.set_single_value(float_to_color(input.get_single_value())); return; + case ResultType::Float4: + output.set_single_value(float_to_float4(input.get_single_value())); + return; case ResultType::Float: /* Same type, no conversion needed. */ break; @@ -196,6 +231,9 @@ void ConversionOperation::execute_single(const Result &input, Result &output) case ResultType::Color: output.set_single_value(int_to_color(input.get_single_value())); return; + case ResultType::Float4: + output.set_single_value(int_to_float4(input.get_single_value())); + return; case ResultType::Int: /* Same type, no conversion needed. */ break; @@ -217,6 +255,9 @@ void ConversionOperation::execute_single(const Result &input, Result &output) case ResultType::Color: output.set_single_value(vector_to_color(input.get_single_value())); return; + case ResultType::Float4: + output.set_single_value(vector_to_float4(input.get_single_value())); + return; case ResultType::Vector: /* Same type, no conversion needed. */ break; @@ -238,6 +279,9 @@ void ConversionOperation::execute_single(const Result &input, Result &output) case ResultType::Vector: output.set_single_value(color_to_vector(input.get_single_value())); return; + case ResultType::Float4: + output.set_single_value(color_to_float4(input.get_single_value())); + return; case ResultType::Color: /* Same type, no conversion needed. */ break; @@ -248,6 +292,30 @@ void ConversionOperation::execute_single(const Result &input, Result &output) break; } break; + case ResultType::Float4: + switch (this->get_result().type()) { + case ResultType::Float: + output.set_single_value(float4_to_float(input.get_single_value())); + return; + case ResultType::Int: + output.set_single_value(float4_to_int(input.get_single_value())); + return; + case ResultType::Vector: + output.set_single_value(float4_to_vector(input.get_single_value())); + return; + case ResultType::Color: + output.set_single_value(float4_to_color(input.get_single_value())); + return; + case ResultType::Float4: + /* Same type, no conversion needed. */ + break; + case ResultType::Float2: + case ResultType::Float3: + case ResultType::Int2: + /* Types are not user facing, so we needn't implement them. */ + break; + } + break; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -278,6 +346,11 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) output.store_pixel(texel, float_to_color(input.load_pixel(texel))); }); return; + case ResultType::Float4: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, float_to_float4(input.load_pixel(texel))); + }); + return; case ResultType::Float: /* Same type, no conversion needed. */ break; @@ -305,6 +378,11 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) output.store_pixel(texel, int_to_color(input.load_pixel(texel))); }); return; + case ResultType::Float4: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, int_to_float4(input.load_pixel(texel))); + }); + return; case ResultType::Int: /* Same type, no conversion needed. */ break; @@ -332,6 +410,11 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) output.store_pixel(texel, vector_to_color(input.load_pixel(texel))); }); return; + case ResultType::Float4: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, vector_to_float4(input.load_pixel(texel))); + }); + return; case ResultType::Vector: /* Same type, no conversion needed. */ break; @@ -359,6 +442,11 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) output.store_pixel(texel, color_to_vector(input.load_pixel(texel))); }); return; + case ResultType::Float4: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, color_to_float4(input.load_pixel(texel))); + }); + return; case ResultType::Color: /* Same type, no conversion needed. */ break; @@ -369,6 +457,38 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) break; } break; + case ResultType::Float4: + switch (this->get_result().type()) { + case ResultType::Float: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, float4_to_float(input.load_pixel(texel))); + }); + return; + case ResultType::Int: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, float4_to_int(input.load_pixel(texel))); + }); + return; + case ResultType::Vector: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, float4_to_vector(input.load_pixel(texel))); + }); + return; + case ResultType::Color: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, float4_to_color(input.load_pixel(texel))); + }); + return; + case ResultType::Float4: + /* Same type, no conversion needed. */ + break; + case ResultType::Float2: + case ResultType::Float3: + case ResultType::Int2: + /* Types are not user facing, so we needn't implement them. */ + break; + } + break; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: diff --git a/source/blender/compositor/intern/input_single_value_operation.cc b/source/blender/compositor/intern/input_single_value_operation.cc index 65159786a86..6c555f01979 100644 --- a/source/blender/compositor/intern/input_single_value_operation.cc +++ b/source/blender/compositor/intern/input_single_value_operation.cc @@ -49,6 +49,10 @@ void InputSingleValueOperation::execute() case ResultType::Color: result.set_single_value(float4(bsocket->default_value_typed()->value)); break; + case ResultType::Float4: + result.set_single_value( + float4(float3(bsocket->default_value_typed()->value), 0.0f)); + break; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: diff --git a/source/blender/compositor/intern/multi_function_procedure_operation.cc b/source/blender/compositor/intern/multi_function_procedure_operation.cc index 4e274f68b63..a2dbeb84c6a 100644 --- a/source/blender/compositor/intern/multi_function_procedure_operation.cc +++ b/source/blender/compositor/intern/multi_function_procedure_operation.cc @@ -62,6 +62,8 @@ static const CPPType &get_cpp_type(ResultType type) case ResultType::Vector: case ResultType::Color: return CPPType::get(); + case ResultType::Float4: + return CPPType::get(); case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -91,6 +93,9 @@ static void add_single_value_input_parameter(mf::ParamsBuilder ¶meter_builde case ResultType::Vector: parameter_builder.add_readonly_single_input_value(input.get_single_value()); return; + case ResultType::Float4: + parameter_builder.add_readonly_single_input_value(input.get_single_value()); + return; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -117,6 +122,9 @@ static void add_single_value_output_parameter(mf::ParamsBuilder ¶meter_build case ResultType::Vector: parameter_builder.add_uninitialized_single_output(&output.get_single_value()); return; + case ResultType::Float4: + parameter_builder.add_uninitialized_single_output(&output.get_single_value()); + return; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -143,6 +151,9 @@ static void upload_single_value_output_to_gpu(Result &output) case ResultType::Vector: output.set_single_value(output.get_single_value()); return; + case ResultType::Float4: + output.set_single_value(output.get_single_value()); + return; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -378,6 +389,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type "Float To Vector", float_to_vector, mf::build::exec_presets::AllSpanOrSingle()); static auto float_to_color_function = mf::build::SI1_SO( "Float To Color", float_to_color, mf::build::exec_presets::AllSpanOrSingle()); + static auto float_to_float4_function = mf::build::SI1_SO( + "Float To Float4", float_to_float4, mf::build::exec_presets::AllSpanOrSingle()); static auto int_to_float_function = mf::build::SI1_SO( "Int To Float", int_to_float, mf::build::exec_presets::AllSpanOrSingle()); @@ -385,6 +398,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type "Int To Vector", int_to_vector, mf::build::exec_presets::AllSpanOrSingle()); static auto int_to_color_function = mf::build::SI1_SO( "Int To Color", int_to_color, mf::build::exec_presets::AllSpanOrSingle()); + static auto int_to_float4_function = mf::build::SI1_SO( + "Int To Float4", int_to_float4, mf::build::exec_presets::AllSpanOrSingle()); static auto vector_to_float_function = mf::build::SI1_SO( "Vector To Float", vector_to_float, mf::build::exec_presets::AllSpanOrSingle()); @@ -392,6 +407,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type "Vector To Int", vector_to_int, mf::build::exec_presets::AllSpanOrSingle()); static auto vector_to_color_function = mf::build::SI1_SO( "Vector To Color", vector_to_color, mf::build::exec_presets::AllSpanOrSingle()); + static auto vector_to_float4_function = mf::build::SI1_SO( + "Vector To Float4", vector_to_float4, mf::build::exec_presets::AllSpanOrSingle()); static auto color_to_float_function = mf::build::SI1_SO( "Color To Float", color_to_float, mf::build::exec_presets::AllSpanOrSingle()); @@ -399,6 +416,17 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type "Color To Int", color_to_int, mf::build::exec_presets::AllSpanOrSingle()); static auto color_to_vector_function = mf::build::SI1_SO( "Color To Vector", color_to_vector, mf::build::exec_presets::AllSpanOrSingle()); + static auto color_to_float4_function = mf::build::SI1_SO( + "Color To Float4", color_to_float4, mf::build::exec_presets::AllSpanOrSingle()); + + static auto float4_to_float_function = mf::build::SI1_SO( + "Float4 To Float", float4_to_float, mf::build::exec_presets::AllSpanOrSingle()); + static auto float4_to_int_function = mf::build::SI1_SO( + "Float4 To Int", float4_to_int, mf::build::exec_presets::AllSpanOrSingle()); + static auto float4_to_vector_function = mf::build::SI1_SO( + "Float4 To Vector", float4_to_vector, mf::build::exec_presets::AllSpanOrSingle()); + static auto float4_to_color_function = mf::build::SI1_SO( + "Float4 To Color", float4_to_color, mf::build::exec_presets::AllSpanOrSingle()); switch (variable_type) { case ResultType::Float: @@ -409,6 +437,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type return &float_to_vector_function; case ResultType::Color: return &float_to_color_function; + case ResultType::Float4: + return &float_to_float4_function; case ResultType::Float: /* Same type, no conversion needed. */ return nullptr; @@ -427,6 +457,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type return &int_to_vector_function; case ResultType::Color: return &int_to_color_function; + case ResultType::Float4: + return &int_to_float4_function; case ResultType::Int: /* Same type, no conversion needed. */ return nullptr; @@ -445,6 +477,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type return &vector_to_int_function; case ResultType::Color: return &vector_to_color_function; + case ResultType::Float4: + return &vector_to_float4_function; case ResultType::Vector: /* Same type, no conversion needed. */ return nullptr; @@ -463,6 +497,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type return &color_to_int_function; case ResultType::Vector: return &color_to_vector_function; + case ResultType::Float4: + return &color_to_float4_function; case ResultType::Color: /* Same type, no conversion needed. */ return nullptr; @@ -473,6 +509,26 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type break; } break; + case ResultType::Float4: + switch (expected_type) { + case ResultType::Float: + return &float4_to_float_function; + case ResultType::Int: + return &float4_to_int_function; + case ResultType::Vector: + return &float4_to_vector_function; + case ResultType::Color: + return &float4_to_color_function; + case ResultType::Float4: + /* Same type, no conversion needed. */ + return nullptr; + case ResultType::Float2: + case ResultType::Float3: + case ResultType::Int2: + /* Types are not user facing, so we needn't implement them. */ + break; + } + break; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: diff --git a/source/blender/compositor/intern/realize_on_domain_operation.cc b/source/blender/compositor/intern/realize_on_domain_operation.cc index 2f4c2c50c2e..8af9b0905b6 100644 --- a/source/blender/compositor/intern/realize_on_domain_operation.cc +++ b/source/blender/compositor/intern/realize_on_domain_operation.cc @@ -128,12 +128,12 @@ const char *RealizeOnDomainOperation::get_realization_shader_name() { if (this->get_input().get_realization_options().interpolation == Interpolation::Bicubic) { switch (this->get_input().type()) { - case ResultType::Color: - return "compositor_realize_on_domain_bicubic_color"; - case ResultType::Vector: - return "compositor_realize_on_domain_bicubic_vector"; case ResultType::Float: return "compositor_realize_on_domain_bicubic_float"; + case ResultType::Color: + case ResultType::Vector: + case ResultType::Float4: + return "compositor_realize_on_domain_bicubic_float4"; case ResultType::Int: case ResultType::Int2: case ResultType::Float2: @@ -144,12 +144,12 @@ const char *RealizeOnDomainOperation::get_realization_shader_name() } else { switch (this->get_input().type()) { - case ResultType::Color: - return "compositor_realize_on_domain_color"; - case ResultType::Vector: - return "compositor_realize_on_domain_vector"; case ResultType::Float: return "compositor_realize_on_domain_float"; + case ResultType::Color: + case ResultType::Vector: + case ResultType::Float4: + return "compositor_realize_on_domain_float4"; case ResultType::Int: case ResultType::Int2: case ResultType::Float2: diff --git a/source/blender/compositor/intern/reduce_to_single_value_operation.cc b/source/blender/compositor/intern/reduce_to_single_value_operation.cc index a38204d78c3..cb6133200a5 100644 --- a/source/blender/compositor/intern/reduce_to_single_value_operation.cc +++ b/source/blender/compositor/intern/reduce_to_single_value_operation.cc @@ -50,6 +50,9 @@ void ReduceToSingleValueOperation::execute() case ResultType::Vector: result.set_single_value(float4(static_cast(pixel))); break; + case ResultType::Float4: + result.set_single_value(float4(static_cast(pixel))); + break; case ResultType::Float: result.set_single_value(*static_cast(pixel)); break; diff --git a/source/blender/compositor/intern/result.cc b/source/blender/compositor/intern/result.cc index 62e8e5d15a7..30b735922a3 100644 --- a/source/blender/compositor/intern/result.cc +++ b/source/blender/compositor/intern/result.cc @@ -47,6 +47,7 @@ eGPUTextureFormat Result::gpu_texture_format(ResultType type, ResultPrecision pr return GPU_R16F; case ResultType::Vector: case ResultType::Color: + case ResultType::Float4: return GPU_RGBA16F; case ResultType::Float2: return GPU_RG16F; @@ -64,6 +65,7 @@ eGPUTextureFormat Result::gpu_texture_format(ResultType type, ResultPrecision pr return GPU_R32F; case ResultType::Vector: case ResultType::Color: + case ResultType::Float4: return GPU_RGBA32F; case ResultType::Float2: return GPU_RG32F; @@ -233,6 +235,8 @@ const CPPType &Result::get_cpp_type() const return CPPType::get(); case ResultType::Color: return CPPType::get(); + case ResultType::Float4: + return CPPType::get(); case ResultType::Float2: return CPPType::get(); case ResultType::Float3: @@ -285,6 +289,9 @@ void Result::allocate_single_value() case ResultType::Color: this->set_single_value(float4(0.0f)); break; + case ResultType::Float4: + this->set_single_value(float4(0.0f)); + break; case ResultType::Float2: this->set_single_value(float2(0.0f)); break; diff --git a/source/blender/compositor/intern/shader_operation.cc b/source/blender/compositor/intern/shader_operation.cc index cc9ba74b95e..71de90e0341 100644 --- a/source/blender/compositor/intern/shader_operation.cc +++ b/source/blender/compositor/intern/shader_operation.cc @@ -208,6 +208,8 @@ static const char *get_set_function_name(ResultType type) return "set_rgb"; case ResultType::Color: return "set_rgba"; + case ResultType::Float4: + return "set_rgba"; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -292,6 +294,8 @@ static const char *get_store_function_name(ResultType type) return "node_compositor_store_output_vector"; case ResultType::Color: return "node_compositor_store_output_color"; + case ResultType::Float4: + return "node_compositor_store_output_float4"; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -393,6 +397,8 @@ static const char *glsl_store_expression_from_result_type(ResultType type) return "vec4(vector, 0.0)"; case ResultType::Color: return "color"; + case ResultType::Float4: + return "value"; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -410,6 +416,7 @@ static ImageType gpu_image_type_from_result_type(const ResultType type) case ResultType::Float: case ResultType::Vector: case ResultType::Color: + case ResultType::Float4: return ImageType::FLOAT_2D; case ResultType::Int: return ImageType::INT_2D; @@ -431,16 +438,17 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ const std::string store_int_function_header = "void store_int(const uint id, float value)"; const std::string store_vector_function_header = "void store_vector(const uint id, vec3 vector)"; const std::string store_color_function_header = "void store_color(const uint id, vec4 color)"; + const std::string store_float4_function_header = "void store_float4(const uint id, vec4 value)"; - /* The store functions are used by the node_compositor_store_output_[float|int|vector|color] - * functions but are only defined later as part of the compute source, so they need to be forward - * declared. - * NOTE(Metal): Metal does not require forward declarations. */ + /* The store functions are used by the node_compositor_store_output_[type] functions but are only + * defined later as part of the compute source, so they need to be forward declared. NOTE(Metal): + * Metal does not require forward declarations. */ if (GPU_backend_get_type() != GPU_BACKEND_METAL) { shader_create_info.typedef_source_generated += store_float_function_header + ";\n"; shader_create_info.typedef_source_generated += store_int_function_header + ";\n"; shader_create_info.typedef_source_generated += store_vector_function_header + ";\n"; shader_create_info.typedef_source_generated += store_color_function_header + ";\n"; + shader_create_info.typedef_source_generated += store_float4_function_header + ";\n"; } /* Each of the store functions is essentially a single switch case on the given ID, so start by @@ -450,11 +458,13 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ std::stringstream store_int_function; std::stringstream store_vector_function; std::stringstream store_color_function; + std::stringstream store_float4_function; const std::string store_function_start = "\n{\n switch (id) {\n"; store_float_function << store_float_function_header << store_function_start; store_int_function << store_int_function_header << store_function_start; store_vector_function << store_vector_function_header << store_function_start; store_color_function << store_color_function_header << store_function_start; + store_float4_function << store_float4_function_header << store_function_start; for (StringRefNull output_identifier : output_sockets_to_output_identifiers_map_.values()) { const Result &result = get_result(output_identifier); @@ -489,6 +499,9 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ case ResultType::Color: store_color_function << case_code.str(); break; + case ResultType::Float4: + store_float4_function << case_code.str(); + break; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: @@ -504,11 +517,13 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ store_int_function << store_function_end; store_vector_function << store_function_end; store_color_function << store_function_end; + store_float4_function << store_function_end; shader_create_info.compute_source_generated += store_float_function.str() + store_int_function.str() + store_vector_function.str() + - store_color_function.str(); + store_color_function.str() + + store_float4_function.str(); } static const char *glsl_type_from_result_type(ResultType type) @@ -522,6 +537,7 @@ static const char *glsl_type_from_result_type(ResultType type) case ResultType::Vector: return "vec3"; case ResultType::Color: + case ResultType::Float4: return "vec4"; case ResultType::Float2: case ResultType::Float3: @@ -546,6 +562,8 @@ static const char *glsl_swizzle_from_result_type(ResultType type) return "xyz"; case ResultType::Color: return "rgba"; + case ResultType::Float4: + return "xyzw"; case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: diff --git a/source/blender/compositor/intern/utilities.cc b/source/blender/compositor/intern/utilities.cc index 4b587b8634a..09c005add42 100644 --- a/source/blender/compositor/intern/utilities.cc +++ b/source/blender/compositor/intern/utilities.cc @@ -59,6 +59,9 @@ ResultType get_node_socket_result_type(const bNodeSocket *socket) case SOCK_INT: return ResultType::Int; case SOCK_VECTOR: + /* Vector sockets can also be ResultType::Float4 or ResultType::Float2, but the + * developer is expected to define that manually since there is no way to distinguish them + * from the socket. */ return ResultType::Vector; case SOCK_RGBA: return ResultType::Color; diff --git a/source/blender/compositor/shaders/infos/compositor_convert_info.hh b/source/blender/compositor/shaders/infos/compositor_convert_info.hh index b1579e005d0..2a67ea8aead 100644 --- a/source/blender/compositor/shaders/infos/compositor_convert_info.hh +++ b/source/blender/compositor/shaders/infos/compositor_convert_info.hh @@ -45,6 +45,13 @@ DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float_to_color(value.x))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() +GPU_SHADER_CREATE_INFO(compositor_convert_float_to_float4) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float_to_float4(value.x))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + /* -------------------------------------------------------------------- * Int to other. */ @@ -70,6 +77,13 @@ DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(int_to_color(value.x))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() +GPU_SHADER_CREATE_INFO(compositor_convert_int_to_float4) +ADDITIONAL_INFO(compositor_convert_int_shared) +IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(int_to_float4(value.x))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + /* -------------------------------------------------------------------- * Vector to other. */ @@ -95,6 +109,13 @@ DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(vector_to_color(value))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() +GPU_SHADER_CREATE_INFO(compositor_convert_vector_to_float4) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(vector_to_float4(value))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + /* -------------------------------------------------------------------- * Color to other. */ @@ -124,6 +145,45 @@ DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(color_to_vector(value))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() +GPU_SHADER_CREATE_INFO(compositor_convert_color_to_float4) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(color_to_float4(value))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +/* -------------------------------------------------------------------- + * Float4 to other. + */ + +GPU_SHADER_CREATE_INFO(compositor_convert_float4_to_float) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_R16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float4_to_float(value), vec3(0.0))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_convert_float4_to_int) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_R16I, WRITE, INT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "ivec4(float4_to_int(value), ivec3(0))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_convert_float4_to_vector) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float4_to_vector(value))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_convert_float4_to_color) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float4_to_color(value))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + /* -------------------------------------------------------------------- * Color to channel. */ diff --git a/source/blender/compositor/shaders/infos/compositor_read_input_info.hh b/source/blender/compositor/shaders/infos/compositor_read_input_info.hh index 0aa1be33ff8..3092497b2ce 100644 --- a/source/blender/compositor/shaders/infos/compositor_read_input_info.hh +++ b/source/blender/compositor/shaders/infos/compositor_read_input_info.hh @@ -18,14 +18,7 @@ DEFINE_VALUE("READ_EXPRESSION(input_color)", "vec4(input_color.r, vec3(0.0))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_read_input_vector) -ADDITIONAL_INFO(compositor_read_input_shared) -IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("READ_EXPRESSION(input_color)", "input_color") -DO_STATIC_COMPILATION() -GPU_SHADER_CREATE_END() - -GPU_SHADER_CREATE_INFO(compositor_read_input_color) +GPU_SHADER_CREATE_INFO(compositor_read_input_float4) ADDITIONAL_INFO(compositor_read_input_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) DEFINE_VALUE("READ_EXPRESSION(input_color)", "input_color") diff --git a/source/blender/compositor/shaders/infos/compositor_realize_on_domain_info.hh b/source/blender/compositor/shaders/infos/compositor_realize_on_domain_info.hh index 725ba946b2f..41c09e4f4f4 100644 --- a/source/blender/compositor/shaders/infos/compositor_realize_on_domain_info.hh +++ b/source/blender/compositor/shaders/infos/compositor_realize_on_domain_info.hh @@ -21,13 +21,7 @@ ADDITIONAL_INFO(compositor_realize_on_domain_shared) DEFINE_VALUE("SAMPLER_FUNCTION", "texture_bicubic") GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_color) -ADDITIONAL_INFO(compositor_realize_on_domain_standard_shared) -IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, domain_img) -DO_STATIC_COMPILATION() -GPU_SHADER_CREATE_END() - -GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_vector) +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_float4) ADDITIONAL_INFO(compositor_realize_on_domain_standard_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, domain_img) DO_STATIC_COMPILATION() @@ -39,13 +33,7 @@ IMAGE(0, GPU_R16F, WRITE, FLOAT_2D, domain_img) DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_color) -ADDITIONAL_INFO(compositor_realize_on_domain_bicubic_shared) -IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, domain_img) -DO_STATIC_COMPILATION() -GPU_SHADER_CREATE_END() - -GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_vector) +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_float4) ADDITIONAL_INFO(compositor_realize_on_domain_bicubic_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, domain_img) DO_STATIC_COMPILATION() diff --git a/source/blender/compositor/shaders/library/gpu_shader_compositor_store_output.glsl b/source/blender/compositor/shaders/library/gpu_shader_compositor_store_output.glsl index 8fb51156c0e..fc1c4a5e140 100644 --- a/source/blender/compositor/shaders/library/gpu_shader_compositor_store_output.glsl +++ b/source/blender/compositor/shaders/library/gpu_shader_compositor_store_output.glsl @@ -8,7 +8,7 @@ * used to establish an output link that is then used to track the nodes that contribute to the * output of the compositor node tree. * - * The store_[float|vector|color] functions are dynamically generated in + * The store_[type] functions are dynamically generated in * ShaderOperation::generate_code_for_outputs. */ void node_compositor_store_output_float(const float id, float value, out float out_value) @@ -35,3 +35,9 @@ void node_compositor_store_output_color(const float id, vec4 color, out vec4 out store_color(floatBitsToUint(id), color); out_color = color; } + +void node_compositor_store_output_float4(const float id, vec4 value, out vec4 out_value) +{ + store_float4(floatBitsToUint(id), value); + out_value = value; +} diff --git a/source/blender/compositor/shaders/library/gpu_shader_compositor_type_conversion.glsl b/source/blender/compositor/shaders/library/gpu_shader_compositor_type_conversion.glsl index 26f08de08ee..4bbf5a154b7 100644 --- a/source/blender/compositor/shaders/library/gpu_shader_compositor_type_conversion.glsl +++ b/source/blender/compositor/shaders/library/gpu_shader_compositor_type_conversion.glsl @@ -21,6 +21,11 @@ vec4 float_to_color(float value) return vec4(vec3(value), 1.0); } +vec4 float_to_float4(float value) +{ + return vec4(value); +} + /* -------------------------------------------------------------------- * Int to other. */ @@ -40,6 +45,11 @@ vec4 int_to_color(int value) return float_to_color(int_to_float(value)); } +vec4 int_to_float4(int value) +{ + return float_to_float4(int_to_float(value)); +} + /* -------------------------------------------------------------------- * Vector to other. */ @@ -59,6 +69,11 @@ vec4 vector_to_color(vec4 value) return vec4(value.xyz, 1.0); } +vec4 vector_to_float4(vec4 value) +{ + return value; +} + /* -------------------------------------------------------------------- * Color to other. */ @@ -78,6 +93,35 @@ vec4 color_to_vector(vec4 value) return value; } +vec4 color_to_float4(vec4 value) +{ + return value; +} + +/* -------------------------------------------------------------------- + * Float4 to other. + */ + +float float4_to_float(vec4 value) +{ + return dot(value, vec4(1.0)) / 4.0; +} + +int float4_to_int(vec4 value) +{ + return float_to_int(float4_to_float(value)); +} + +vec4 float4_to_vector(vec4 value) +{ + return value; +} + +vec4 float4_to_color(vec4 value) +{ + return value; +} + /* -------------------------------------------------------------------- * GPUMatrial-specific implicit conversion functions. * diff --git a/source/blender/compositor/utilities/COM_utilities_type_conversion.hh b/source/blender/compositor/utilities/COM_utilities_type_conversion.hh index 64cc81ac6bb..9ca3cee846b 100644 --- a/source/blender/compositor/utilities/COM_utilities_type_conversion.hh +++ b/source/blender/compositor/utilities/COM_utilities_type_conversion.hh @@ -30,6 +30,11 @@ inline float4 float_to_color(const float &value) return float4(float3(value), 1.0f); } +inline float4 float_to_float4(const float &value) +{ + return float4(value); +} + /* -------------------------------------------------------------------- * Int to other. */ @@ -49,6 +54,11 @@ inline float4 int_to_color(const int &value) return float_to_color(int_to_float(value)); } +inline float4 int_to_float4(const int &value) +{ + return float_to_float4(int_to_float(value)); +} + /* -------------------------------------------------------------------- * Vector to other. */ @@ -68,6 +78,11 @@ inline float4 vector_to_color(const float4 &value) return float4(value.xyz(), 1.0f); } +inline float4 vector_to_float4(const float4 &value) +{ + return value; +} + /* -------------------------------------------------------------------- * Color to other. */ @@ -87,4 +102,33 @@ inline float4 color_to_vector(const float4 &value) return value; } +inline float4 color_to_float4(const float4 &value) +{ + return value; +} + +/* -------------------------------------------------------------------- + * Float4 to other. + */ + +inline float float4_to_float(const float4 &value) +{ + return math::reduce_add(value) / 4.0f; +} + +inline int float4_to_int(const float4 &value) +{ + return float_to_int(float4_to_float(value)); +} + +inline float4 float4_to_vector(const float4 &value) +{ + return value; +} + +inline float4 float4_to_color(const float4 &value) +{ + return value; +} + } // namespace blender::compositor diff --git a/source/blender/nodes/composite/nodes/node_composite_file_output.cc b/source/blender/nodes/composite/nodes/node_composite_file_output.cc index fa2cffb14bf..7e6cc9b75b9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_file_output.cc +++ b/source/blender/nodes/composite/nodes/node_composite_file_output.cc @@ -513,6 +513,7 @@ class FileOutputOperation : public NodeOperation { descriptor.realization_mode = this->is_multi_layer() ? InputRealizationMode::OperationDomain : InputRealizationMode::Transforms; + descriptor.skip_type_conversion = true; } } @@ -677,12 +678,13 @@ class FileOutputOperation : public NodeOperation { } break; case ResultType::Vector: - if (result.meta_data.is_4d_vector) { - file_output.add_pass(pass_name, view_name, "XYZW", buffer); - } - else { - file_output.add_pass(pass_name, view_name, "XYZ", float4_to_float3_image(size, buffer)); - } + file_output.add_pass(pass_name, view_name, "XYZ", float4_to_float3_image(size, buffer)); + break; + case ResultType::Float3: + file_output.add_pass(pass_name, view_name, "XYZ", buffer); + break; + case ResultType::Float4: + file_output.add_pass(pass_name, view_name, "XYZW", buffer); break; case ResultType::Float: file_output.add_pass(pass_name, view_name, "V", buffer); @@ -715,14 +717,32 @@ class FileOutputOperation : public NodeOperation { float *buffer = static_cast(MEM_malloc_arrayN( size_t(size.x) * size.y, sizeof(float[4]), "File Output Inflated Buffer.")); - const float4 value = result.type() == ResultType::Color ? - result.get_single_value() : - result.get_single_value(); + const float4 value = result.get_single_value(); parallel_for(size, [&](const int2 texel) { copy_v4_v4(buffer + ((int64_t(texel.y) * size.x + texel.x) * 4), value); }); return buffer; } + case ResultType::Float4: { + float *buffer = static_cast(MEM_malloc_arrayN( + size_t(size.x) * size.y, sizeof(float[4]), "File Output Inflated Buffer.")); + + const float4 value = result.get_single_value(); + parallel_for(size, [&](const int2 texel) { + copy_v4_v4(buffer + ((int64_t(texel.y) * size.x + texel.x) * 4), value); + }); + return buffer; + } + case ResultType::Float3: { + float *buffer = static_cast(MEM_malloc_arrayN( + size_t(size.x) * size.y, sizeof(float[3]), "File Output Inflated Buffer.")); + + const float3 value = result.get_single_value(); + parallel_for(size, [&](const int2 texel) { + copy_v3_v3(buffer + ((int64_t(texel.y) * size.x + texel.x) * 3), value); + }); + return buffer; + } default: /* Other types are internal and needn't be handled by operations. */ break; @@ -752,9 +772,15 @@ class FileOutputOperation : public NodeOperation { case ResultType::Color: file_output.add_view(view_name, 4, buffer); break; + case ResultType::Float4: + file_output.add_view(view_name, 4, buffer); + break; case ResultType::Vector: file_output.add_view(view_name, 3, float4_to_float3_image(size, buffer)); break; + case ResultType::Float3: + file_output.add_view(view_name, 3, buffer); + break; case ResultType::Float: file_output.add_view(view_name, 1, buffer); break; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index fc1abaee01e..8d9347d6415 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -472,6 +472,7 @@ class ImageOperation : public NodeOperation { extract_alpha(context(), cached_image, result); } else { + result.set_type(cached_image.type()); result.set_precision(cached_image.precision()); result.wrap_external(cached_image); } @@ -719,6 +720,13 @@ class RenderLayerOperation : public NodeOperation { return; } + /* Vector sockets are 3D by default, so we need to overwrite the type if the pass turned out to + * be 4D. */ + if (result.type() == ResultType::Vector && pass.type() == ResultType::Float4) { + result.set_type(pass.type()); + } + result.set_precision(pass.precision()); + if (this->context().use_gpu()) { this->execute_pass_gpu(pass, result); } @@ -729,8 +737,6 @@ class RenderLayerOperation : public NodeOperation { void execute_pass_gpu(const Result &pass, Result &result) { - result.set_precision(pass.precision()); - GPUShader *shader = this->context().get_shader(this->get_shader_name(pass, result), result.precision()); GPU_shader_bind(shader); @@ -764,11 +770,10 @@ class RenderLayerOperation : public NodeOperation { case ResultType::Float: return "compositor_read_input_float"; case ResultType::Vector: - return "compositor_read_input_vector"; case ResultType::Color: - return "compositor_read_input_color"; + case ResultType::Float4: case ResultType::Float3: - return "compositor_read_input_vector"; + return "compositor_read_input_float4"; default: /* Other types are internal and needn't be handled by operations. */ break; diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc index 741b28b2772..2de219a6e1f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc +++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc @@ -171,9 +171,11 @@ class TrackPositionOperation : public NodeOperation { const float2 speed_toward_next = current_marker_position - next_marker_position; /* Encode both speeds in a 4D vector. Multiply by the size to get the speed in pixel space. */ - const float4 speed = float4(speed_toward_previous, speed_toward_next) * float4(size, size); + const float4 speed = float4(speed_toward_previous * float2(size), + speed_toward_next * float2(size)); Result &result = get_result("Speed"); + result.set_type(ResultType::Float4); result.allocate_single_value(); result.set_single_value(speed); } @@ -192,6 +194,7 @@ class TrackPositionOperation : public NodeOperation { } if (should_compute_output("Speed")) { Result &result = get_result("Speed"); + result.set_type(ResultType::Float4); result.allocate_single_value(); result.set_single_value(float4(0.0f)); } diff --git a/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc b/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc index ec13a9ea2b2..595af481d88 100644 --- a/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_vec_blur.cc @@ -105,7 +105,7 @@ static float2 max_velocity_approximate(const float2 &a, static Result compute_max_tile_velocity_cpu(Context &context, const Result &velocity_image) { if (velocity_image.is_single_value()) { - Result output = context.create_result(ResultType::Vector); + Result output = context.create_result(ResultType::Float4); output.allocate_single_value(); output.set_single_value(velocity_image.get_single_value()); return output; @@ -114,7 +114,7 @@ static Result compute_max_tile_velocity_cpu(Context &context, const Result &velo const int2 tile_size = int2(MOTION_BLUR_TILE_SIZE); const int2 velocity_size = velocity_image.domain().size; const int2 tiles_count = math::divide_ceil(velocity_size, tile_size); - Result output = context.create_result(ResultType::Vector); + Result output = context.create_result(ResultType::Float4); output.allocate_texture(Domain(tiles_count)); parallel_for(tiles_count, [&](const int2 texel) { @@ -197,14 +197,14 @@ static Result dilate_max_velocity_cpu(Context &context, const float shutter_speed) { if (max_tile_velocity.is_single_value()) { - Result output = context.create_result(ResultType::Vector); + Result output = context.create_result(ResultType::Float4); output.allocate_single_value(); output.set_single_value(max_tile_velocity.get_single_value()); return output; } const int2 size = max_tile_velocity.domain().size; - Result output = context.create_result(ResultType::Vector); + Result output = context.create_result(ResultType::Float4); output.allocate_texture(Domain(size)); parallel_for(size, [&](const int2 texel) { output.store_pixel(texel, float4(0.0f)); }); @@ -213,13 +213,14 @@ static Result dilate_max_velocity_cpu(Context &context, for (const int64_t x : IndexRange(size.x)) { const int2 src_tile = int2(x, y); - float4 max_motion = float4(max_tile_velocity.load_pixel(src_tile)) * - float4(float2(shutter_speed), float2(-shutter_speed)); + const float4 max_motion = max_tile_velocity.load_pixel(src_tile); + const float2 max_previous_velocity = max_motion.xy() * shutter_speed; + const float2 max_next_velocity = max_motion.zw() * -shutter_speed; { /* Rectangular area (in tiles) where the motion vector spreads. */ - MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.xy(), size); - MotionLine motion_line = compute_motion_line(src_tile, max_motion.xy()); + MotionRect motion_rect = compute_motion_rect(src_tile, max_previous_velocity, size); + MotionLine motion_line = compute_motion_line(src_tile, max_previous_velocity); /* Do a conservative rasterization of the line of the motion vector line. */ for (int j = 0; j < motion_rect.extent.y; j++) { for (int i = 0; i < motion_rect.extent.x; i++) { @@ -227,9 +228,9 @@ static Result dilate_max_velocity_cpu(Context &context, if (is_inside_motion_line(tile, motion_line)) { const float4 current_max_velocity = output.load_pixel(tile); const float2 new_max_previous_velocity = max_velocity_approximate( - current_max_velocity.xy(), max_motion.xy(), tile, src_tile); + current_max_velocity.xy(), max_previous_velocity, tile, src_tile); const float2 new_max_next_velocity = max_velocity_approximate( - current_max_velocity.zw(), max_motion.zw(), tile, src_tile); + current_max_velocity.zw(), max_next_velocity, tile, src_tile); output.store_pixel(tile, float4(new_max_previous_velocity, new_max_next_velocity)); } } @@ -238,8 +239,8 @@ static Result dilate_max_velocity_cpu(Context &context, { /* Rectangular area (in tiles) where the motion vector spreads. */ - MotionRect motion_rect = compute_motion_rect(src_tile, max_motion.zw(), size); - MotionLine motion_line = compute_motion_line(src_tile, max_motion.zw()); + MotionRect motion_rect = compute_motion_rect(src_tile, max_next_velocity, size); + MotionLine motion_line = compute_motion_line(src_tile, max_next_velocity); /* Do a conservative rasterization of the line of the motion vector line. */ for (int j = 0; j < motion_rect.extent.y; j++) { for (int i = 0; i < motion_rect.extent.x; i++) { @@ -247,9 +248,9 @@ static Result dilate_max_velocity_cpu(Context &context, if (is_inside_motion_line(tile, motion_line)) { const float4 current_max_velocity = output.load_pixel(tile); const float2 new_max_previous_velocity = max_velocity_approximate( - current_max_velocity.xy(), max_motion.xy(), tile, src_tile); + current_max_velocity.xy(), max_previous_velocity, tile, src_tile); const float2 new_max_next_velocity = max_velocity_approximate( - current_max_velocity.zw(), max_motion.zw(), tile, src_tile); + current_max_velocity.zw(), max_next_velocity, tile, src_tile); output.store_pixel(tile, float4(new_max_previous_velocity, new_max_next_velocity)); } } @@ -436,8 +437,9 @@ static void motion_blur_cpu(const Result &input_image, /* Data of the center pixel of the gather (target). */ float center_depth = input_depth.load_pixel(texel); - float4 center_motion = float4(input_velocity.load_pixel(texel)) * - float4(float2(shutter_speed), float2(-shutter_speed)); + float4 center_motion = input_velocity.load_pixel(texel); + float2 center_previous_motion = center_motion.xy() * shutter_speed; + float2 center_next_motion = center_motion.zw() * -shutter_speed; float4 center_color = input_image.load_pixel(texel); /* Randomize tile boundary to avoid ugly discontinuities. Randomize 1/4th of the tile. @@ -460,7 +462,7 @@ static void motion_blur_cpu(const Result &input_image, input_velocity, size, uv, - center_motion.xy(), + center_previous_motion, center_depth, max_motion.xy(), rand, @@ -474,7 +476,7 @@ static void motion_blur_cpu(const Result &input_image, input_velocity, size, uv, - center_motion.zw(), + center_next_motion, center_depth, max_motion.zw(), rand, @@ -510,7 +512,10 @@ static void motion_blur_cpu(const Result &input_image, class VectorBlurOperation : public NodeOperation { public: - using NodeOperation::NodeOperation; + VectorBlurOperation(Context &context, DNode node) : NodeOperation(context, node) + { + this->get_input_descriptor("Speed").type = ResultType::Float4; + } void execute() override { @@ -550,7 +555,7 @@ class VectorBlurOperation : public NodeOperation { Result &input = get_input("Speed"); input.bind_as_texture(shader, "input_tx"); - Result output = context().create_result(ResultType::Vector); + Result output = context().create_result(ResultType::Float4); const int2 tiles_count = math::divide_ceil(input.domain().size, int2(32)); output.allocate_texture(Domain(tiles_count)); output.bind_as_image(shader, "output_img"); diff --git a/source/blender/render/intern/compositor.cc b/source/blender/render/intern/compositor.cc index 42d7edf26e6..0a966839fcf 100644 --- a/source/blender/render/intern/compositor.cc +++ b/source/blender/render/intern/compositor.cc @@ -259,10 +259,8 @@ class Context : public compositor::Context { return compositor::Result(*this); } - const eGPUTextureFormat format = (render_pass->channels == 1) ? GPU_R32F : - (render_pass->channels == 3) ? GPU_RGB32F : - GPU_RGBA32F; - compositor::Result pass = compositor::Result(*this, format); + compositor::Result pass = compositor::Result( + *this, this->result_type_from_pass(render_pass), compositor::ResultPrecision::Full); if (this->use_gpu()) { GPUTexture *pass_texture = RE_pass_ensure_gpu_texture_cache(render, render_pass); @@ -283,6 +281,30 @@ class Context : public compositor::Context { return pass; } + compositor::ResultType result_type_from_pass(const RenderPass *pass) + { + switch (pass->channels) { + case 1: + return compositor::ResultType::Float; + case 2: + return compositor::ResultType::Float2; + case 3: + return compositor::ResultType::Float3; + case 4: + if (StringRef(pass->chan_id) == "XYZW") { + return compositor::ResultType::Float4; + } + else { + return compositor::ResultType::Color; + } + default: + break; + } + + BLI_assert_unreachable(); + return compositor::ResultType::Float; + } + StringRef get_view_name() const override { return input_data_.view_name; @@ -390,23 +412,6 @@ class Context : public compositor::Context { }, false); - RenderLayer *render_layer = RE_GetRenderLayer(render_result, view_layer->name); - if (!render_layer) { - RE_ReleaseResult(render); - return; - } - - RenderPass *render_pass = RE_pass_find_by_name( - render_layer, pass_name, this->get_view_name().data()); - if (!render_pass) { - RE_ReleaseResult(render); - return; - } - - if (StringRef(render_pass->chan_id) == "XYZW") { - meta_data.is_4d_vector = true; - } - RE_ReleaseResult(render); } diff --git a/tests/data b/tests/data index 60777a2f496..42dabf608f1 160000 --- a/tests/data +++ b/tests/data @@ -1 +1 @@ -Subproject commit 60777a2f496ead8f749c62872e9909d9e2b8fabb +Subproject commit 42dabf608f1e756cc9d84ebda0f1fb6bdcbe639f