diff --git a/source/blender/compositor/COM_result.hh b/source/blender/compositor/COM_result.hh index 51ed794bdfc..3de33a5f4e9 100644 --- a/source/blender/compositor/COM_result.hh +++ b/source/blender/compositor/COM_result.hh @@ -33,6 +33,7 @@ enum class ResultType : uint8_t { * can encode two 2D vectors, one 3D vector with the last component ignored, or other dimensional * data. */ Float, + Int, Vector, Color, @@ -142,6 +143,7 @@ class Result { float4 color_value_ = float4(0.0f); float2 float2_value_; float3 float3_value_; + int int_value_; int2 int2_value_; }; /* The domain of the result. This only matters if the result was a texture. See the discussion in @@ -364,6 +366,10 @@ class Result { /* Returns a reference to the allocate integer data. */ int *integer_texture() const; + /* Returns a reference to the allocated CPU data. The returned data is untyped, use the + * float_texture() or the integer_texture() methods for typed data. */ + void *data() const; + /* Gets the single value stored in the result. Assumes the result stores a value of the given * template type. */ template T get_single_value() const; @@ -501,6 +507,7 @@ inline int64_t Result::channels_count() const { switch (type_) { case ResultType::Float: + case ResultType::Int: return 1; case ResultType::Float2: case ResultType::Int2: @@ -526,6 +533,21 @@ inline int *Result::integer_texture() const return integer_texture_; } +inline void *Result::data() const +{ + switch (storage_type_) { + case ResultStorageType::FloatCPU: + return this->float_texture(); + case ResultStorageType::IntegerCPU: + return this->integer_texture(); + case ResultStorageType::GPU: + break; + } + + BLI_assert_unreachable(); + return nullptr; +} + template inline T Result::get_single_value() const { BLI_assert(this->is_single_value()); @@ -535,6 +557,10 @@ template inline T Result::get_single_value() const BLI_assert(type_ == ResultType::Float); return float_value_; } + else if constexpr (std::is_same_v) { + BLI_assert(type_ == ResultType::Int); + return int_value_; + } else if constexpr (std::is_same_v) { BLI_assert(type_ == ResultType::Float2); return float2_value_; @@ -574,6 +600,10 @@ template inline void Result::set_single_value(const T &value) BLI_assert(type_ == ResultType::Float); float_value_ = value; } + else if constexpr (std::is_same_v) { + BLI_assert(type_ == ResultType::Int); + int_value_ = value; + } else if constexpr (std::is_same_v) { BLI_assert(type_ == ResultType::Float2); float2_value_ = value; @@ -987,7 +1017,7 @@ template constexpr int Result::get_type_channels_count() template constexpr bool Result::is_supported_type() { - return is_same_any_v; + return is_same_any_v; } template inline int64_t Result::get_pixel_index(const int2 &texel) const @@ -1059,6 +1089,9 @@ inline void Result::copy_pixel(float *target, const float *source, const int cha inline void Result::copy_pixel(int *target, const int *source, const int channels_count) { switch (channels_count) { + case 1: + *target = *source; + break; case 2: copy_v2_v2_int(target, source); break; @@ -1084,6 +1117,7 @@ inline void Result::copy_pixel(float *target, const float *source) const case ResultType::Color: copy_v4_v4(target, source); break; + case ResultType::Int: case ResultType::Int2: BLI_assert_unreachable(); break; diff --git a/source/blender/compositor/algorithms/intern/realize_on_domain.cc b/source/blender/compositor/algorithms/intern/realize_on_domain.cc index c91ea1a22d2..bb30579df44 100644 --- a/source/blender/compositor/algorithms/intern/realize_on_domain.cc +++ b/source/blender/compositor/algorithms/intern/realize_on_domain.cc @@ -34,6 +34,7 @@ static const char *get_realization_shader(Result &input, return "compositor_realize_on_domain_bicubic_vector"; case ResultType::Float: return "compositor_realize_on_domain_bicubic_float"; + case ResultType::Int: case ResultType::Int2: case ResultType::Float2: case ResultType::Float3: @@ -49,6 +50,7 @@ static const char *get_realization_shader(Result &input, return "compositor_realize_on_domain_vector"; case ResultType::Float: return "compositor_realize_on_domain_float"; + case ResultType::Int: case ResultType::Int2: case ResultType::Float2: case ResultType::Float3: diff --git a/source/blender/compositor/algorithms/intern/smaa.cc b/source/blender/compositor/algorithms/intern/smaa.cc index 72d9db07e68..04e77d879fc 100644 --- a/source/blender/compositor/algorithms/intern/smaa.cc +++ b/source/blender/compositor/algorithms/intern/smaa.cc @@ -1426,6 +1426,7 @@ static float3 get_luminance_coefficients(ResultType type) case ResultType::Float3: /* GPU module does not support float3 outputs. */ break; + case ResultType::Int: case ResultType::Int2: /* SMAA does not support integer types. */ break; @@ -1596,6 +1597,7 @@ static const char *get_blend_shader_name(ResultType type) case ResultType::Float3: /* GPU module does not support float3 outputs. */ break; + case ResultType::Int: case ResultType::Int2: /* SMAA does not support integer types. */ break; @@ -1675,6 +1677,9 @@ static void compute_single_value(Result &input, Result &output) case ResultType::Float3: output.set_single_value(input.get_single_value()); break; + case ResultType::Int: + output.set_single_value(input.get_single_value()); + break; case ResultType::Int2: 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 707d401f922..6318434d0aa 100644 --- a/source/blender/compositor/algorithms/intern/symmetric_separable_blur.cc +++ b/source/blender/compositor/algorithms/intern/symmetric_separable_blur.cc @@ -84,6 +84,7 @@ static const char *get_blur_shader(const ResultType type) case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: + case ResultType::Int: /* Not supported. */ break; } @@ -176,6 +177,7 @@ static Result horizontal_pass_cpu(Context &context, case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: + case ResultType::Int: /* Not supported. */ BLI_assert_unreachable(); break; @@ -263,6 +265,7 @@ static void vertical_pass_cpu(Context &context, case ResultType::Float2: case ResultType::Float3: case ResultType::Int2: + case ResultType::Int: /* Not supported. */ BLI_assert_unreachable(); break; diff --git a/source/blender/compositor/intern/conversion_operation.cc b/source/blender/compositor/intern/conversion_operation.cc index f41d1b3a4e4..257cb6e61b8 100644 --- a/source/blender/compositor/intern/conversion_operation.cc +++ b/source/blender/compositor/intern/conversion_operation.cc @@ -71,6 +71,8 @@ const char *ConversionOperation::get_conversion_shader_name() switch (this->get_input().type()) { case ResultType::Float: switch (this->get_result().type()) { + case ResultType::Int: + return "compositor_convert_float_to_int"; case ResultType::Vector: return "compositor_convert_float_to_vector"; case ResultType::Color: @@ -85,10 +87,30 @@ const char *ConversionOperation::get_conversion_shader_name() break; } break; + case ResultType::Int: + switch (this->get_result().type()) { + case ResultType::Float: + return "compositor_convert_int_to_float"; + case ResultType::Vector: + return "compositor_convert_int_to_vector"; + case ResultType::Color: + return "compositor_convert_int_to_color"; + case ResultType::Int: + /* 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::Vector: switch (this->get_result().type()) { case ResultType::Float: return "compositor_convert_vector_to_float"; + case ResultType::Int: + return "compositor_convert_vector_to_int"; case ResultType::Color: return "compositor_convert_vector_to_color"; case ResultType::Vector: @@ -105,6 +127,8 @@ const char *ConversionOperation::get_conversion_shader_name() switch (this->get_result().type()) { case ResultType::Float: return "compositor_convert_color_to_float"; + case ResultType::Int: + return "compositor_convert_color_to_int"; case ResultType::Vector: return "compositor_convert_color_to_vector"; case ResultType::Color: @@ -133,6 +157,9 @@ void ConversionOperation::execute_single(const Result &input, Result &output) switch (this->get_input().type()) { case ResultType::Float: switch (this->get_result().type()) { + case ResultType::Int: + output.set_single_value(float_to_int(input.get_single_value())); + return; case ResultType::Vector: output.set_single_value(float_to_vector(input.get_single_value())); return; @@ -149,11 +176,35 @@ void ConversionOperation::execute_single(const Result &input, Result &output) break; } break; + case ResultType::Int: + switch (this->get_result().type()) { + case ResultType::Float: + output.set_single_value(int_to_float(input.get_single_value())); + return; + case ResultType::Vector: + output.set_single_value(int_to_vector(input.get_single_value())); + return; + case ResultType::Color: + output.set_single_value(int_to_color(input.get_single_value())); + return; + case ResultType::Int: + /* 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::Vector: switch (this->get_result().type()) { case ResultType::Float: output.set_single_value(vector_to_float(input.get_single_value())); return; + case ResultType::Int: + output.set_single_value(vector_to_int(input.get_single_value())); + return; case ResultType::Color: output.set_single_value(vector_to_color(input.get_single_value())); return; @@ -172,6 +223,9 @@ void ConversionOperation::execute_single(const Result &input, Result &output) case ResultType::Float: output.set_single_value(color_to_float(input.get_single_value())); return; + case ResultType::Int: + output.set_single_value(color_to_int(input.get_single_value())); + return; case ResultType::Vector: output.set_single_value(color_to_vector(input.get_single_value())); return; @@ -200,6 +254,11 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) switch (this->get_input().type()) { case ResultType::Float: switch (this->get_result().type()) { + case ResultType::Int: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, float_to_int(input.load_pixel(texel))); + }); + return; case ResultType::Vector: parallel_for(input.domain().size, [&](const int2 texel) { output.store_pixel(texel, float_to_vector(input.load_pixel(texel))); @@ -220,6 +279,33 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) break; } break; + case ResultType::Int: + switch (this->get_result().type()) { + case ResultType::Float: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, int_to_float(input.load_pixel(texel))); + }); + return; + case ResultType::Vector: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, int_to_vector(input.load_pixel(texel))); + }); + return; + case ResultType::Color: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, int_to_color(input.load_pixel(texel))); + }); + return; + case ResultType::Int: + /* 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::Vector: switch (this->get_result().type()) { case ResultType::Float: @@ -227,6 +313,11 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) output.store_pixel(texel, vector_to_float(input.load_pixel(texel))); }); return; + case ResultType::Int: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, vector_to_int(input.load_pixel(texel))); + }); + return; case ResultType::Color: parallel_for(input.domain().size, [&](const int2 texel) { output.store_pixel(texel, vector_to_color(input.load_pixel(texel))); @@ -249,6 +340,11 @@ void ConversionOperation::execute_cpu(const Result &input, Result &output) output.store_pixel(texel, color_to_float(input.load_pixel(texel))); }); return; + case ResultType::Int: + parallel_for(input.domain().size, [&](const int2 texel) { + output.store_pixel(texel, color_to_int(input.load_pixel(texel))); + }); + return; case ResultType::Vector: parallel_for(input.domain().size, [&](const int2 texel) { output.store_pixel(texel, color_to_vector(input.load_pixel(texel))); diff --git a/source/blender/compositor/intern/input_single_value_operation.cc b/source/blender/compositor/intern/input_single_value_operation.cc index cc7f2fd8077..65159786a86 100644 --- a/source/blender/compositor/intern/input_single_value_operation.cc +++ b/source/blender/compositor/intern/input_single_value_operation.cc @@ -39,6 +39,9 @@ void InputSingleValueOperation::execute() case ResultType::Float: result.set_single_value(bsocket->default_value_typed()->value); break; + case ResultType::Int: + result.set_single_value(bsocket->default_value_typed()->value); + break; case ResultType::Vector: result.set_single_value( float4(float3(bsocket->default_value_typed()->value), 0.0f)); diff --git a/source/blender/compositor/intern/multi_function_procedure_operation.cc b/source/blender/compositor/intern/multi_function_procedure_operation.cc index 02c6f9a98e7..f498d853297 100644 --- a/source/blender/compositor/intern/multi_function_procedure_operation.cc +++ b/source/blender/compositor/intern/multi_function_procedure_operation.cc @@ -58,6 +58,8 @@ static const CPPType &get_cpp_type(ResultType type) switch (type) { case ResultType::Float: return CPPType::get(); + case ResultType::Int: + return CPPType::get(); case ResultType::Vector: case ResultType::Color: return CPPType::get(); @@ -80,6 +82,9 @@ static void add_single_value_parameter(mf::ParamsBuilder ¶meter_builder, con case ResultType::Float: parameter_builder.add_readonly_single_input_value(input.get_single_value()); return; + case ResultType::Int: + parameter_builder.add_readonly_single_input_value(input.get_single_value()); + return; case ResultType::Color: parameter_builder.add_readonly_single_input_value(input.get_single_value()); return; @@ -111,14 +116,14 @@ void MultiFunctionProcedureOperation::execute() add_single_value_parameter(parameter_builder, input); } else { - const GSpan span{get_cpp_type(input.type()), input.float_texture(), size}; + const GSpan span{get_cpp_type(input.type()), input.data(), size}; parameter_builder.add_readonly_single_input(span); } } else { Result &result = get_result(parameter_identifiers_[i]); result.allocate_texture(domain); - const GMutableSpan span{get_cpp_type(result.type()), result.float_texture(), size}; + const GMutableSpan span{get_cpp_type(result.type()), result.data(), size}; parameter_builder.add_uninitialized_single_output(span); } } @@ -217,6 +222,11 @@ mf::Variable *MultiFunctionProcedureOperation::get_constant_input_variable(DInpu constant_function = &procedure_.construct_function>(value); break; } + case SOCK_INT: { + const int value = input->default_value_typed()->value; + constant_function = &procedure_.construct_function>(value); + break; + } case SOCK_VECTOR: { const float3 value = float3(input->default_value_typed()->value); constant_function = &procedure_.construct_function>( @@ -295,22 +305,39 @@ mf::Variable *MultiFunctionProcedureOperation::get_multi_function_input_variable static mf::MultiFunction *get_conversion_function(const ResultType variable_type, const ResultType expected_type) { + static auto float_to_int_function = mf::build::SI1_SO( + "Float To Int", float_to_int, mf::build::exec_presets::AllSpanOrSingle()); static auto float_to_vector_function = mf::build::SI1_SO( "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 int_to_float_function = mf::build::SI1_SO( + "Int To Float", int_to_float, mf::build::exec_presets::AllSpanOrSingle()); + static auto int_to_vector_function = mf::build::SI1_SO( + "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 vector_to_float_function = mf::build::SI1_SO( "Vector To Float", vector_to_float, mf::build::exec_presets::AllSpanOrSingle()); + static auto vector_to_int_function = mf::build::SI1_SO( + "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 color_to_float_function = mf::build::SI1_SO( "Color To Float", color_to_float, mf::build::exec_presets::AllSpanOrSingle()); + static auto color_to_int_function = mf::build::SI1_SO( + "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()); switch (variable_type) { case ResultType::Float: switch (expected_type) { + case ResultType::Int: + return &float_to_int_function; case ResultType::Vector: return &float_to_vector_function; case ResultType::Color: @@ -325,10 +352,30 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type break; } break; + case ResultType::Int: + switch (expected_type) { + case ResultType::Float: + return &int_to_float_function; + case ResultType::Vector: + return &int_to_vector_function; + case ResultType::Color: + return &int_to_color_function; + case ResultType::Int: + /* 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::Vector: switch (expected_type) { case ResultType::Float: return &vector_to_float_function; + case ResultType::Int: + return &vector_to_int_function; case ResultType::Color: return &vector_to_color_function; case ResultType::Vector: @@ -345,6 +392,8 @@ static mf::MultiFunction *get_conversion_function(const ResultType variable_type switch (expected_type) { case ResultType::Float: return &color_to_float_function; + case ResultType::Int: + return &color_to_int_function; case ResultType::Vector: return &color_to_vector_function; case ResultType::Color: 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 b97a6190a48..d4181e6a1c7 100644 --- a/source/blender/compositor/intern/reduce_to_single_value_operation.cc +++ b/source/blender/compositor/intern/reduce_to_single_value_operation.cc @@ -29,12 +29,12 @@ void ReduceToSingleValueOperation::execute() { Result &input = get_input(); - float *pixel = nullptr; + void *pixel = nullptr; bool need_to_free_pixel = false; if (context().use_gpu()) { /* Make sure any prior writes to the texture are reflected before downloading it. */ GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); - pixel = static_cast(GPU_texture_read(input, GPU_DATA_FLOAT, 0)); + pixel = GPU_texture_read(input, GPU_DATA_FLOAT, 0); need_to_free_pixel = true; } else { @@ -45,13 +45,16 @@ void ReduceToSingleValueOperation::execute() result.allocate_single_value(); switch (result.type()) { case ResultType::Color: - result.set_single_value(float4(pixel)); + result.set_single_value(float4(static_cast(pixel))); break; case ResultType::Vector: - result.set_single_value(float4(pixel)); + result.set_single_value(float4(static_cast(pixel))); break; case ResultType::Float: - result.set_single_value(*pixel); + result.set_single_value(*static_cast(pixel)); + break; + case ResultType::Int: + result.set_single_value(*static_cast(pixel)); break; case ResultType::Float2: case ResultType::Float3: diff --git a/source/blender/compositor/intern/result.cc b/source/blender/compositor/intern/result.cc index 6325038821f..587b1a1ba5f 100644 --- a/source/blender/compositor/intern/result.cc +++ b/source/blender/compositor/intern/result.cc @@ -45,6 +45,8 @@ eGPUTextureFormat Result::gpu_texture_format(ResultType type, ResultPrecision pr return GPU_RG16F; case ResultType::Float3: return GPU_RGB16F; + case ResultType::Int: + return GPU_R16I; case ResultType::Int2: return GPU_RG16I; } @@ -60,6 +62,8 @@ eGPUTextureFormat Result::gpu_texture_format(ResultType type, ResultPrecision pr return GPU_RG32F; case ResultType::Float3: return GPU_RGB32F; + case ResultType::Int: + return GPU_R32I; case ResultType::Int2: return GPU_RG32I; } @@ -80,6 +84,7 @@ eGPUTextureFormat Result::gpu_texture_format(eGPUTextureFormat format, ResultPre case GPU_RG16F: case GPU_RGB16F: case GPU_RGBA16F: + case GPU_R16I: case GPU_RG16I: return format; @@ -91,6 +96,8 @@ eGPUTextureFormat Result::gpu_texture_format(eGPUTextureFormat format, ResultPre return GPU_RGB16F; case GPU_RGBA32F: return GPU_RGBA16F; + case GPU_R32I: + return GPU_R16I; case GPU_RG32I: return GPU_RG16I; default: @@ -104,6 +111,7 @@ eGPUTextureFormat Result::gpu_texture_format(eGPUTextureFormat format, ResultPre case GPU_RG32F: case GPU_RGB32F: case GPU_RGBA32F: + case GPU_R32I: case GPU_RG32I: return format; @@ -115,6 +123,8 @@ eGPUTextureFormat Result::gpu_texture_format(eGPUTextureFormat format, ResultPre return GPU_RGB32F; case GPU_RGBA16F: return GPU_RGBA32F; + case GPU_R16I: + return GPU_R32I; case GPU_RG16I: return GPU_RG32I; default: @@ -134,12 +144,14 @@ ResultPrecision Result::precision(eGPUTextureFormat format) case GPU_RG16F: case GPU_RGB16F: case GPU_RGBA16F: + case GPU_R16I: case GPU_RG16I: return ResultPrecision::Half; case GPU_R32F: case GPU_RG32F: case GPU_RGB32F: case GPU_RGBA32F: + case GPU_R32I: case GPU_RG32I: return ResultPrecision::Full; default: @@ -165,6 +177,9 @@ ResultType Result::type(eGPUTextureFormat format) case GPU_RGBA16F: case GPU_RGBA32F: return ResultType::Color; + case GPU_R16I: + case GPU_R32I: + return ResultType::Int; case GPU_RG16I: case GPU_RG32I: return ResultType::Int2; @@ -249,6 +264,9 @@ void Result::allocate_invalid() case ResultType::Float3: set_single_value(float3(0.0f)); break; + case ResultType::Int: + set_single_value(0); + break; case ResultType::Int2: set_single_value(int2(0)); break; @@ -553,6 +571,7 @@ void Result::allocate_data(int2 size, bool from_pool) int64_t(size.x) * int64_t(size.y), this->channels_count() * sizeof(float), __func__)); storage_type_ = ResultStorageType::FloatCPU; break; + case ResultType::Int: case ResultType::Int2: integer_texture_ = static_cast(MEM_malloc_arrayN( int64_t(size.x) * int64_t(size.y), this->channels_count() * sizeof(int), __func__)); diff --git a/source/blender/compositor/intern/shader_node.cc b/source/blender/compositor/intern/shader_node.cc index 7ab3741184c..0598a52a308 100644 --- a/source/blender/compositor/intern/shader_node.cc +++ b/source/blender/compositor/intern/shader_node.cc @@ -14,6 +14,7 @@ #include "COM_shader_node.hh" #include "COM_utilities.hh" +#include "COM_utilities_type_conversion.hh" namespace blender::compositor { @@ -69,6 +70,9 @@ static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) switch (type) { case SOCK_FLOAT: return GPU_FLOAT; + case SOCK_INT: + /* GPUMaterial doesn't support int, so it is passed as a float. */ + return GPU_FLOAT; case SOCK_VECTOR: return GPU_VEC3; case SOCK_RGBA: @@ -84,63 +88,100 @@ static eGPUType gpu_type_from_socket_type(eNodeSocketDatatype type) * conversion if needed. */ static void gpu_stack_vector_from_socket(GPUNodeStack &stack, const bNodeSocket *socket) { - switch (socket->type) { + const eNodeSocketDatatype input_type = static_cast(socket->type); + const eNodeSocketDatatype expected_type = static_cast(stack.sockettype); + + switch (input_type) { case SOCK_FLOAT: { const float value = socket->default_value_typed()->value; - switch (stack.sockettype) { + switch (expected_type) { case SOCK_FLOAT: stack.vec[0] = value; return; + case SOCK_INT: + /* GPUMaterial doesn't support int, so it is passed as a float. */ + stack.vec[0] = float(float_to_int(value)); + return; case SOCK_VECTOR: - copy_v3_fl(stack.vec, value); + copy_v4_v4(stack.vec, float_to_vector(value)); return; case SOCK_RGBA: - copy_v4_fl(stack.vec, value); - stack.vec[3] = 1.0f; + copy_v4_v4(stack.vec, float_to_color(value)); return; default: - BLI_assert_unreachable(); - return; + break; } + break; + } + case SOCK_INT: { + const int value = socket->default_value_typed()->value; + switch (expected_type) { + case SOCK_FLOAT: + stack.vec[0] = int_to_float(value); + return; + case SOCK_INT: + /* GPUMaterial doesn't support int, so it is passed as a float. */ + stack.vec[0] = float(value); + return; + case SOCK_VECTOR: + copy_v4_v4(stack.vec, int_to_vector(value)); + return; + case SOCK_RGBA: + copy_v4_v4(stack.vec, int_to_color(value)); + return; + default: + break; + } + break; } case SOCK_VECTOR: { - const float *value = socket->default_value_typed()->value; - switch (stack.sockettype) { + const float4 value = float4( + float3(socket->default_value_typed()->value), 0.0f); + switch (expected_type) { case SOCK_FLOAT: - stack.vec[0] = (value[0] + value[1] + value[2]) / 3.0f; + stack.vec[0] = vector_to_float(value); + return; + case SOCK_INT: + /* GPUMaterial doesn't support int, so it is passed as a float. */ + stack.vec[0] = float(vector_to_int(value)); return; case SOCK_VECTOR: copy_v3_v3(stack.vec, value); return; case SOCK_RGBA: - copy_v3_v3(stack.vec, value); - stack.vec[3] = 1.0f; + copy_v4_v4(stack.vec, vector_to_color(value)); return; default: - BLI_assert_unreachable(); - return; + break; } + break; } case SOCK_RGBA: { - const float *value = socket->default_value_typed()->value; - switch (stack.sockettype) { + const float4 value = socket->default_value_typed()->value; + switch (expected_type) { case SOCK_FLOAT: - stack.vec[0] = (value[0] + value[1] + value[2]) / 3.0f; + stack.vec[0] = color_to_float(value); + return; + case SOCK_INT: + /* GPUMaterial doesn't support int, so it is passed as a float. */ + stack.vec[0] = float(color_to_int(value)); return; case SOCK_VECTOR: - copy_v3_v3(stack.vec, value); + copy_v4_v4(stack.vec, color_to_vector(value)); return; case SOCK_RGBA: copy_v4_v4(stack.vec, value); return; default: - BLI_assert_unreachable(); - return; + break; } + break; } default: - BLI_assert_unreachable(); + break; } + + BLI_assert_unreachable(); } static void populate_gpu_node_stack(DSocket socket, GPUNodeStack &stack) diff --git a/source/blender/compositor/intern/shader_operation.cc b/source/blender/compositor/intern/shader_operation.cc index 68f1a19e632..dd192c4c7cc 100644 --- a/source/blender/compositor/intern/shader_operation.cc +++ b/source/blender/compositor/intern/shader_operation.cc @@ -204,6 +204,9 @@ static const char *get_set_function_name(ResultType type) switch (type) { case ResultType::Float: return "set_value"; + case ResultType::Int: + /* GPUMaterial doesn't support int, so it is passed as a float. */ + return "set_value"; case ResultType::Vector: return "set_rgb"; case ResultType::Color: @@ -286,6 +289,8 @@ static const char *get_store_function_name(ResultType type) switch (type) { case ResultType::Float: return "node_compositor_store_output_float"; + case ResultType::Int: + return "node_compositor_store_output_int"; case ResultType::Vector: return "node_compositor_store_output_vector"; case ResultType::Color: @@ -376,13 +381,17 @@ void ShaderOperation::generate_code(void *thunk, shader_create_info.compute_source_generated += "}\n"; } -/* Texture storers in the shader always take a vec4 as an argument, so encode each type in a vec4 - * appropriately. */ +/* Texture storers in the shader always take a [i]vec4 as an argument, so encode each type in an + * [i]vec4 appropriately. */ static const char *glsl_store_expression_from_result_type(ResultType type) { switch (type) { case ResultType::Float: return "vec4(value)"; + case ResultType::Int: + /* GPUMaterial doesn't support int, so it is passed as a float, and we need to convert it + * back to int before writing it. */ + return "ivec4(int(value))"; case ResultType::Vector: return "vec4(vector, 0.0)"; case ResultType::Color: @@ -398,18 +407,41 @@ static const char *glsl_store_expression_from_result_type(ResultType type) return nullptr; } +static ImageType gpu_image_type_from_result_type(const ResultType type) +{ + switch (type) { + case ResultType::Float: + case ResultType::Vector: + case ResultType::Color: + return ImageType::FLOAT_2D; + case ResultType::Int: + return ImageType::INT_2D; + case ResultType::Float2: + case ResultType::Float3: + case ResultType::Int2: + /* Those types are internal and needn't be handled by operations. */ + break; + } + + BLI_assert_unreachable(); + return ImageType::FLOAT_2D; +} + void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_info) { const std::string store_float_function_header = "void store_float(const uint id, float value)"; + /* GPUMaterial doesn't support int, so it is passed as a float. */ + 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)"; - /* The store functions are used by the node_compositor_store_output_[float|vector|color] + /* 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. */ 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"; } @@ -418,10 +450,12 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ * opening the function with a curly bracket followed by opening a switch statement in each of * the functions. */ std::stringstream store_float_function; + std::stringstream store_int_function; std::stringstream store_vector_function; std::stringstream store_color_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; @@ -432,7 +466,7 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ shader_create_info.image(0, result.get_gpu_texture_format(), Qualifier::WRITE, - ImageType::FLOAT_2D, + gpu_image_type_from_result_type(result.type()), output_identifier, Frequency::PASS); @@ -449,6 +483,9 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ case ResultType::Float: store_float_function << case_code.str(); break; + case ResultType::Int: + store_int_function << case_code.str(); + break; case ResultType::Vector: store_vector_function << case_code.str(); break; @@ -467,10 +504,12 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_ /* Close the previously opened switch statement as well as the function itself. */ const std::string store_function_end = " }\n}\n\n"; store_float_function << store_function_end; + store_int_function << store_function_end; store_vector_function << store_function_end; store_color_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(); } @@ -480,6 +519,9 @@ static const char *glsl_type_from_result_type(ResultType type) switch (type) { case ResultType::Float: return "float"; + case ResultType::Int: + /* GPUMaterial doesn't support int, so it is passed as a float. */ + return "float"; case ResultType::Vector: return "vec3"; case ResultType::Color: @@ -495,12 +537,13 @@ static const char *glsl_type_from_result_type(ResultType type) return nullptr; } -/* Texture loaders in the shader always return a vec4, so a swizzle is needed to retrieve the +/* Texture loaders in the shader always return an [i]vec4, so a swizzle is needed to retrieve the * actual value for each type. */ static const char *glsl_swizzle_from_result_type(ResultType type) { switch (type) { case ResultType::Float: + case ResultType::Int: return "x"; case ResultType::Vector: return "xyz"; @@ -529,7 +572,11 @@ void ShaderOperation::generate_code_for_inputs(GPUMaterial *material, /* Add a texture sampler for each of the inputs with the same name as the attribute. */ LISTBASE_FOREACH (GPUMaterialAttribute *, attribute, &attributes) { - shader_create_info.sampler(0, ImageType::FLOAT_2D, attribute->name, Frequency::PASS); + const InputDescriptor &input_descriptor = get_input_descriptor(attribute->name); + shader_create_info.sampler(0, + gpu_image_type_from_result_type(input_descriptor.type), + attribute->name, + Frequency::PASS); } /* Declare a struct called var_attrs that includes an appropriately typed member for each of the @@ -551,14 +598,16 @@ void ShaderOperation::generate_code_for_inputs(GPUMaterial *material, shader_create_info.typedef_source("gpu_shader_compositor_texture_utilities.glsl"); /* Initialize each member of the previously declared struct by loading its corresponding texture - * with an appropriate swizzle for its type. */ + * with an appropriate swizzle and cast for its type. */ std::stringstream initialize_attributes; LISTBASE_FOREACH (GPUMaterialAttribute *, attribute, &attributes) { const InputDescriptor &input_descriptor = get_input_descriptor(attribute->name); const std::string swizzle = glsl_swizzle_from_result_type(input_descriptor.type); - initialize_attributes << "var_attrs.v" << attribute->id << " = " + const std::string type = glsl_type_from_result_type(input_descriptor.type); + initialize_attributes << "var_attrs.v" << attribute->id << " = " << type << "(" << "texture_load(" << attribute->name - << ", ivec2(gl_GlobalInvocationID.xy))." << swizzle << ";\n"; + << ", ivec2(gl_GlobalInvocationID.xy))." << swizzle << ")" + << ";\n"; } initialize_attributes << "\n"; diff --git a/source/blender/compositor/intern/utilities.cc b/source/blender/compositor/intern/utilities.cc index f42ee770df9..99c9967958e 100644 --- a/source/blender/compositor/intern/utilities.cc +++ b/source/blender/compositor/intern/utilities.cc @@ -58,6 +58,8 @@ ResultType get_node_socket_result_type(const bNodeSocket *socket) switch (socket->type) { case SOCK_FLOAT: return ResultType::Float; + case SOCK_INT: + return ResultType::Int; case SOCK_VECTOR: return ResultType::Vector; case SOCK_RGBA: diff --git a/source/blender/compositor/shaders/compositor_convert.glsl b/source/blender/compositor/shaders/compositor_convert.glsl index 9cccaa29966..b256ce1a953 100644 --- a/source/blender/compositor/shaders/compositor_convert.glsl +++ b/source/blender/compositor/shaders/compositor_convert.glsl @@ -7,6 +7,5 @@ void main() { ivec2 texel = ivec2(gl_GlobalInvocationID.xy); - vec4 value = texture_load(input_tx, texel); - imageStore(output_img, texel, CONVERT_EXPRESSION(value)); + imageStore(output_img, texel, CONVERT_EXPRESSION(texture_load(input_tx, texel))); } diff --git a/source/blender/compositor/shaders/infos/compositor_convert_info.hh b/source/blender/compositor/shaders/infos/compositor_convert_info.hh index d42fb8e3731..2c7dbd6593e 100644 --- a/source/blender/compositor/shaders/infos/compositor_convert_info.hh +++ b/source/blender/compositor/shaders/infos/compositor_convert_info.hh @@ -6,76 +6,126 @@ GPU_SHADER_CREATE_INFO(compositor_convert_shared) LOCAL_GROUP_SIZE(16, 16) -SAMPLER(0, FLOAT_2D, input_tx) TYPEDEF_SOURCE("gpu_shader_compositor_type_conversion.glsl") COMPUTE_SOURCE("compositor_convert.glsl") GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_convert_float_to_float) +GPU_SHADER_CREATE_INFO(compositor_convert_float_shared) ADDITIONAL_INFO(compositor_convert_shared) -IMAGE(0, GPU_R16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "value") +SAMPLER(0, FLOAT_2D, input_tx) +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_convert_int_shared) +ADDITIONAL_INFO(compositor_convert_shared) +SAMPLER(0, INT_2D, input_tx) +GPU_SHADER_CREATE_END() + +/* -------------------------------------------------------------------- + * Float to other. + */ + +GPU_SHADER_CREATE_INFO(compositor_convert_float_to_int) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_R16I, WRITE, INT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "ivec4(float_to_int(value.x), ivec3(0))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() GPU_SHADER_CREATE_INFO(compositor_convert_float_to_vector) -ADDITIONAL_INFO(compositor_convert_shared) +ADDITIONAL_INFO(compositor_convert_float_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(vec3_from_float(value.x), 1.0)") +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float_to_vector(value.x))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() GPU_SHADER_CREATE_INFO(compositor_convert_float_to_color) -ADDITIONAL_INFO(compositor_convert_shared) +ADDITIONAL_INFO(compositor_convert_float_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4_from_float(value.x)") +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float_to_color(value.x))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_convert_color_to_float) -ADDITIONAL_INFO(compositor_convert_shared) +/* -------------------------------------------------------------------- + * Int to other. + */ + +GPU_SHADER_CREATE_INFO(compositor_convert_int_to_float) +ADDITIONAL_INFO(compositor_convert_int_shared) IMAGE(0, GPU_R16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float_from_vec4(value), vec3(0.0))") +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(int_to_float(value.x), vec3(0.0))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_convert_color_to_vector) -ADDITIONAL_INFO(compositor_convert_shared) +GPU_SHADER_CREATE_INFO(compositor_convert_int_to_vector) +ADDITIONAL_INFO(compositor_convert_int_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "value") +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(int_to_vector(value.x))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_convert_color_to_color) -ADDITIONAL_INFO(compositor_convert_shared) +GPU_SHADER_CREATE_INFO(compositor_convert_int_to_color) +ADDITIONAL_INFO(compositor_convert_int_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "value") +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(int_to_color(value.x))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() +/* -------------------------------------------------------------------- + * Vector to other. + */ + GPU_SHADER_CREATE_INFO(compositor_convert_vector_to_float) -ADDITIONAL_INFO(compositor_convert_shared) +ADDITIONAL_INFO(compositor_convert_float_shared) IMAGE(0, GPU_R16F, WRITE, FLOAT_2D, output_img) DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(float_from_vec3(value.xyz), vec3(0.0))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() -GPU_SHADER_CREATE_INFO(compositor_convert_vector_to_vector) -ADDITIONAL_INFO(compositor_convert_shared) -IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "value") +GPU_SHADER_CREATE_INFO(compositor_convert_vector_to_int) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_R16I, WRITE, INT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "ivec4(vector_to_int(value), ivec3(0.0))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() GPU_SHADER_CREATE_INFO(compositor_convert_vector_to_color) -ADDITIONAL_INFO(compositor_convert_shared) +ADDITIONAL_INFO(compositor_convert_float_shared) IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) -DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4_from_vec3(value.xyz)") +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(vector_to_color(value))") DO_STATIC_COMPILATION() GPU_SHADER_CREATE_END() +/* -------------------------------------------------------------------- + * Color to other. + */ + +GPU_SHADER_CREATE_INFO(compositor_convert_color_to_float) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_R16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(color_to_float(value), vec3(0.0))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_convert_color_to_int) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_R16I, WRITE, INT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "ivec4(color_to_int(value), ivec3(0))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +GPU_SHADER_CREATE_INFO(compositor_convert_color_to_vector) +ADDITIONAL_INFO(compositor_convert_float_shared) +IMAGE(0, GPU_RGBA16F, WRITE, FLOAT_2D, output_img) +DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(color_to_vector(value))") +DO_STATIC_COMPILATION() +GPU_SHADER_CREATE_END() + +/* -------------------------------------------------------------------- + * Color to channel. + */ + GPU_SHADER_CREATE_INFO(compositor_convert_color_to_alpha) -ADDITIONAL_INFO(compositor_convert_shared) +ADDITIONAL_INFO(compositor_convert_float_shared) IMAGE(0, GPU_R16F, WRITE, FLOAT_2D, output_img) DEFINE_VALUE("CONVERT_EXPRESSION(value)", "vec4(value.a)") 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 c65280943dc..8fb51156c0e 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 @@ -17,6 +17,13 @@ void node_compositor_store_output_float(const float id, float value, out float o out_value = value; } +/* GPUMaterial doesn't support int, so it is passed as a float. */ +void node_compositor_store_output_int(const float id, float value, out float out_value) +{ + store_int(floatBitsToUint(id), value); + out_value = value; +} + void node_compositor_store_output_vector(const float id, vec3 vector, out vec3 out_vector) { store_vector(floatBitsToUint(id), vector); 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 8d54d7b84a0..eaa344916e1 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 @@ -2,6 +2,88 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +/* -------------------------------------------------------------------- + * Float to other. + */ + +int float_to_int(float value) +{ + return int(value); +} + +vec4 float_to_vector(float value) +{ + return vec4(vec3(value), 1.0); +} + +vec4 float_to_color(float value) +{ + return vec4(vec3(value), 1.0); +} + +/* -------------------------------------------------------------------- + * Int to other. + */ + +float int_to_float(int value) +{ + return float(value); +} + +vec4 int_to_vector(int value) +{ + return float_to_vector(int_to_float(value)); +} + +vec4 int_to_color(int value) +{ + return float_to_color(int_to_float(value)); +} + +/* -------------------------------------------------------------------- + * Vector to other. + */ + +float vector_to_float(vec4 value) +{ + return dot(value.xyz, vec3(1.0)) / 3.0; +} + +int vector_to_int(vec4 value) +{ + return float_to_int(vector_to_float(value)); +} + +vec4 vector_to_color(vec4 value) +{ + return vec4(value.xyz, 1.0); +} + +/* -------------------------------------------------------------------- + * Color to other. + */ + +float color_to_float(vec4 value) +{ + return dot(value.rgb, vec3(1.0)) / 3.0; +} + +int color_to_int(vec4 value) +{ + return float_to_int(color_to_float(value)); +} + +vec4 color_to_vector(vec4 value) +{ + return value; +} + +/* -------------------------------------------------------------------- + * GPUMatrial-specific implicit conversion functions. + * + * Those should have the same interface and names as the macros in gpu_shader_codegen_lib.glsl + * since the GPUMaterial compiler inserts those hard coded names. */ + float float_from_vec4(vec4 vector) { return dot(vector.rgb, vec3(1.0)) / 3.0; diff --git a/source/blender/compositor/utilities/COM_utilities_type_conversion.hh b/source/blender/compositor/utilities/COM_utilities_type_conversion.hh index d0ceda2648c..20b6f12ccbc 100644 --- a/source/blender/compositor/utilities/COM_utilities_type_conversion.hh +++ b/source/blender/compositor/utilities/COM_utilities_type_conversion.hh @@ -9,34 +9,80 @@ namespace blender::compositor { -inline float4 float_to_vector(const float &input) +/* -------------------------------------------------------------------- + * Float to other. + */ + +inline int float_to_int(const float &value) { - return float4(float3(input), 1.0f); + return int(value); } -inline float4 float_to_color(const float &input) +inline float4 float_to_vector(const float &value) { - return float4(float3(input), 1.0f); + return float4(float3(value), 1.0f); } -inline float vector_to_float(const float4 &input) +inline float4 float_to_color(const float &value) { - return math::reduce_add(input.xyz()) / 3.0f; + return float4(float3(value), 1.0f); } -inline float4 vector_to_color(const float4 &input) +/* -------------------------------------------------------------------- + * Int to other. + */ + +inline float int_to_float(const int &value) { - return float4(input.xyz(), 1.0f); + return float(value); } -inline float color_to_float(const float4 &input) +inline float4 int_to_vector(const int &value) { - return math::reduce_add(input.xyz()) / 3.0f; + return float_to_vector(int_to_float(value)); } -inline float4 color_to_vector(const float4 &input) +inline float4 int_to_color(const int &value) { - return input; + return float_to_color(int_to_float(value)); +} + +/* -------------------------------------------------------------------- + * Vector to other. + */ + +inline float vector_to_float(const float4 &value) +{ + return math::reduce_add(value.xyz()) / 3.0f; +} + +inline int vector_to_int(const float4 &value) +{ + return float_to_int(vector_to_float(value)); +} + +inline float4 vector_to_color(const float4 &value) +{ + return float4(value.xyz(), 1.0f); +} + +/* -------------------------------------------------------------------- + * Vector to other. + */ + +inline float color_to_float(const float4 &value) +{ + return math::reduce_add(value.xyz()) / 3.0f; +} + +inline int color_to_int(const float4 &value) +{ + return float_to_int(color_to_float(value)); +} + +inline float4 color_to_vector(const float4 &value) +{ + return value; } } // namespace blender::compositor diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index f16fe3d3460..835879b3f7d 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -143,7 +143,7 @@ static bool composite_node_tree_socket_type_valid(blender::bke::bNodeTreeType * blender::bke::bNodeSocketType *socket_type) { return blender::bke::node_is_static_socket_type(socket_type) && - ELEM(socket_type->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA); + ELEM(socket_type->type, SOCK_FLOAT, SOCK_INT, SOCK_VECTOR, SOCK_RGBA); } blender::bke::bNodeTreeType *ntreeType_Composite; diff --git a/tests/python/bl_node_group_interface.py b/tests/python/bl_node_group_interface.py index a7b8635cfd9..d9e9d49df28 100644 --- a/tests/python/bl_node_group_interface.py +++ b/tests/python/bl_node_group_interface.py @@ -446,7 +446,7 @@ class CompositorNodeGroupInterfaceTest(AbstractNodeGroupInterfaceTest, NodeGroup self.do_test_socket_type("NodeSocketFloat") self.do_test_invalid_socket_type("NodeSocketGeometry") self.do_test_invalid_socket_type("NodeSocketImage") - self.do_test_invalid_socket_type("NodeSocketInt") + self.do_test_socket_type("NodeSocketInt") self.do_test_invalid_socket_type("NodeSocketMaterial") self.do_test_invalid_socket_type("NodeSocketObject") self.do_test_invalid_socket_type("NodeSocketRotation")