diff options
author | Jacques Lucke <jacques@blender.org> | 2022-04-26 18:12:34 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-04-26 18:12:34 +0300 |
commit | ae94e36cfb2f3bc9a99b638782092d9c71d4b3c7 (patch) | |
tree | dc54dc643a2c498af1d3de97b471115607a8d3b4 /source/blender/nodes/shader | |
parent | 9a53599180041cf9501e2ac6150c9f900a3a3fc0 (diff) |
Geometry Nodes: refactor array devirtualization
Goals:
* Better high level control over where devirtualization occurs. There is always
a trade-off between performance and compile-time/binary-size.
* Simplify using array devirtualization.
* Better performance for cases where devirtualization wasn't used before.
Many geometry nodes accept fields as inputs. Internally, that means that the
execution functions have to accept so called "virtual arrays" as inputs. Those
can be e.g. actual arrays, just single values, or lazily computed arrays.
Due to these different possible virtual arrays implementations, access to
individual elements is slower than it would be if everything was just a normal
array (access does through a virtual function call). For more complex execution
functions, this overhead does not matter, but for small functions (like a simple
addition) it very much does. The virtual function call also prevents the compiler
from doing some optimizations (e.g. loop unrolling and inserting simd instructions).
The solution is to "devirtualize" the virtual arrays for small functions where the
overhead is measurable. Essentially, the function is generated many times with
different array types as input. Then there is a run-time dispatch that calls the
best implementation. We have been doing devirtualization in e.g. math nodes
for a long time already. This patch just generalizes the concept and makes it
easier to control. It also makes it easier to investigate the different trade-offs
when it comes to devirtualization.
Nodes that we've optimized using devirtualization before didn't get a speedup.
However, a couple of nodes are using devirtualization now, that didn't before.
Those got a 2-4x speedup in common cases.
* Map Range
* Random Value
* Switch
* Combine XYZ
Differential Revision: https://developer.blender.org/D14628
Diffstat (limited to 'source/blender/nodes/shader')
4 files changed, 234 insertions, 377 deletions
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index 8e7934bf34e..9ba9a279c57 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -223,327 +223,106 @@ static float3 clamp_range(const float3 value, const float3 min, const float3 max clamp_range(value.z, min.z, max.z)); } -static void map_range_vector_signature(fn::MFSignatureBuilder *signature, bool use_steps) +template<bool Clamp> static auto build_float_linear() { - signature->single_input<float3>("Vector"); - signature->single_input<float3>("From Min"); - signature->single_input<float3>("From Max"); - signature->single_input<float3>("To Min"); - signature->single_input<float3>("To Max"); - if (use_steps) { - signature->single_input<float3>("Steps"); - } - signature->single_output<float3>("Vector"); + return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>>{ + Clamp ? "Map Range (clamped)" : "Map Range (unclamped)", + [](float value, float from_min, float from_max, float to_min, float to_max, float *r_value) { + const float factor = safe_divide(value - from_min, from_max - from_min); + float result = to_min + factor * (to_max - to_min); + if constexpr (Clamp) { + result = clamp_range(result, to_min, to_max); + } + *r_value = result; + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; } -class MapRangeVectorFunction : public fn::MultiFunction { - private: - bool clamp_; - - public: - MapRangeVectorFunction(bool clamp) : clamp_(clamp) - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Vector Map Range"}; - map_range_vector_signature(&signature, false); - return signature.build(); - } - - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); - const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); - const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); - const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); - const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); - MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); - - for (int64_t i : mask) { - float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; - } - - if (clamp_) { - for (int64_t i : mask) { - results[i] = clamp_range(results[i], to_min[i], to_max[i]); - } - } - } -}; - -class MapRangeSteppedVectorFunction : public fn::MultiFunction { - private: - bool clamp_; - - public: - MapRangeSteppedVectorFunction(bool clamp) : clamp_(clamp) - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Vector Map Range Stepped"}; - map_range_vector_signature(&signature, true); - return signature.build(); - } - - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); - const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); - const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); - const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); - const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); - const VArray<float3> &steps = params.readonly_single_input<float3>(5, "Steps"); - MutableSpan<float3> results = params.uninitialized_single_output<float3>(6, "Vector"); - - for (int64_t i : mask) { - float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - factor = math::safe_divide(math::floor(factor * (steps[i] + 1.0f)), steps[i]); - results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; - } - - if (clamp_) { - for (int64_t i : mask) { - results[i] = clamp_range(results[i], to_min[i], to_max[i]); - } - } - } -}; - -class MapRangeSmoothstepVectorFunction : public fn::MultiFunction { - public: - MapRangeSmoothstepVectorFunction() - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"}; - map_range_vector_signature(&signature, false); - return signature.build(); - } - - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); - const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); - const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); - const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); - const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); - MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); - - for (int64_t i : mask) { - float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - clamp_v3(factor, 0.0f, 1.0f); - factor = (float3(3.0f) - 2.0f * factor) * (factor * factor); - results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; - } - } -}; - -class MapRangeSmootherstepVectorFunction : public fn::MultiFunction { - public: - MapRangeSmootherstepVectorFunction() - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Vector Map Range Smoothstep"}; - map_range_vector_signature(&signature, false); - return signature.build(); - } - - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float3> &values = params.readonly_single_input<float3>(0, "Vector"); - const VArray<float3> &from_min = params.readonly_single_input<float3>(1, "From Min"); - const VArray<float3> &from_max = params.readonly_single_input<float3>(2, "From Max"); - const VArray<float3> &to_min = params.readonly_single_input<float3>(3, "To Min"); - const VArray<float3> &to_max = params.readonly_single_input<float3>(4, "To Max"); - MutableSpan<float3> results = params.uninitialized_single_output<float3>(5, "Vector"); - - for (int64_t i : mask) { - float3 factor = math::safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - clamp_v3(factor, 0.0f, 1.0f); - factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f); - results[i] = factor * (to_max[i] - to_min[i]) + to_min[i]; - } - } -}; - -static void map_range_signature(fn::MFSignatureBuilder *signature, bool use_steps) +template<bool Clamp> static auto build_float_stepped() { - signature->single_input<float>("Value"); - signature->single_input<float>("From Min"); - signature->single_input<float>("From Max"); - signature->single_input<float>("To Min"); - signature->single_input<float>("To Max"); - if (use_steps) { - signature->single_input<float>("Steps"); - } - signature->single_output<float>("Result"); + return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>>{ + Clamp ? "Map Range Stepped (clamped)" : "Map Range Stepped (unclamped)", + [](float value, + float from_min, + float from_max, + float to_min, + float to_max, + float steps, + float *r_value) { + float factor = safe_divide(value - from_min, from_max - from_min); + factor = safe_divide(floorf(factor * (steps + 1.0f)), steps); + float result = to_min + factor * (to_max - to_min); + if constexpr (Clamp) { + result = clamp_range(result, to_min, to_max); + } + *r_value = result; + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; } -class MapRangeFunction : public fn::MultiFunction { - private: - bool clamp_; - - public: - MapRangeFunction(bool clamp) : clamp_(clamp) - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Map Range"}; - map_range_signature(&signature, false); - return signature.build(); - } - - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float> &values = params.readonly_single_input<float>(0, "Value"); - const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min"); - const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max"); - const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min"); - const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max"); - MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result"); - - for (int64_t i : mask) { - float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - results[i] = to_min[i] + factor * (to_max[i] - to_min[i]); - } - - if (clamp_) { - for (int64_t i : mask) { - results[i] = clamp_range(results[i], to_min[i], to_max[i]); - } - } - } -}; - -class MapRangeSteppedFunction : public fn::MultiFunction { - private: - bool clamp_; - - public: - MapRangeSteppedFunction(bool clamp) : clamp_(clamp) - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Map Range Stepped"}; - map_range_signature(&signature, true); - return signature.build(); - } - - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float> &values = params.readonly_single_input<float>(0, "Value"); - const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min"); - const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max"); - const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min"); - const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max"); - const VArray<float> &steps = params.readonly_single_input<float>(5, "Steps"); - MutableSpan<float> results = params.uninitialized_single_output<float>(6, "Result"); - - for (int64_t i : mask) { - float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - factor = safe_divide(floorf(factor * (steps[i] + 1.0f)), steps[i]); - results[i] = to_min[i] + factor * (to_max[i] - to_min[i]); - } - - if (clamp_) { - for (int64_t i : mask) { - results[i] = clamp_range(results[i], to_min[i], to_max[i]); - } - } - } -}; - -class MapRangeSmoothstepFunction : public fn::MultiFunction { - public: - MapRangeSmoothstepFunction() - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Map Range Smoothstep"}; - map_range_signature(&signature, false); - return signature.build(); - } - - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float> &values = params.readonly_single_input<float>(0, "Value"); - const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min"); - const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max"); - const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min"); - const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max"); - MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result"); - - for (int64_t i : mask) { - float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - factor = std::clamp(factor, 0.0f, 1.0f); - factor = (3.0f - 2.0f * factor) * (factor * factor); - results[i] = to_min[i] + factor * (to_max[i] - to_min[i]); - } - } -}; - -class MapRangeSmootherstepFunction : public fn::MultiFunction { - public: - MapRangeSmootherstepFunction() - { - static fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static fn::MFSignature create_signature() - { - fn::MFSignatureBuilder signature{"Map Range Smoothstep"}; - map_range_signature(&signature, false); - return signature.build(); - } +template<bool Clamp> static auto build_vector_linear() +{ + return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>>{ + Clamp ? "Vector Map Range (clamped)" : "Vector Map Range (unclamped)", + [](const float3 &value, + const float3 &from_min, + const float3 &from_max, + const float3 &to_min, + const float3 &to_max, + float3 *r_value) { + float3 factor = math::safe_divide(value - from_min, from_max - from_min); + float3 result = factor * (to_max - to_min) + to_min; + if constexpr (Clamp) { + result = clamp_range(result, to_min, to_max); + } + *r_value = result; + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; +} - void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override - { - const VArray<float> &values = params.readonly_single_input<float>(0, "Value"); - const VArray<float> &from_min = params.readonly_single_input<float>(1, "From Min"); - const VArray<float> &from_max = params.readonly_single_input<float>(2, "From Max"); - const VArray<float> &to_min = params.readonly_single_input<float>(3, "To Min"); - const VArray<float> &to_max = params.readonly_single_input<float>(4, "To Max"); - MutableSpan<float> results = params.uninitialized_single_output<float>(5, "Result"); - - for (int64_t i : mask) { - float factor = safe_divide(values[i] - from_min[i], from_max[i] - from_min[i]); - factor = std::clamp(factor, 0.0f, 1.0f); - factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f); - results[i] = to_min[i] + factor * (to_max[i] - to_min[i]); - } - } -}; +template<bool Clamp> static auto build_vector_stepped() +{ + return fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>>{ + Clamp ? "Vector Map Range Stepped (clamped)" : "Vector Map Range Stepped (unclamped)", + [](const float3 &value, + const float3 &from_min, + const float3 &from_max, + const float3 &to_min, + const float3 &to_max, + const float3 &steps, + float3 *r_value) { + float3 factor = math::safe_divide(value - from_min, from_max - from_min); + factor = math::safe_divide(math::floor(factor * (steps + 1.0f)), steps); + float3 result = factor * (to_max - to_min) + to_min; + if constexpr (Clamp) { + result = clamp_range(result, to_min, to_max); + } + *r_value = result; + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; +} static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &builder) { @@ -556,34 +335,70 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui switch (interpolation_type) { case NODE_MAP_RANGE_LINEAR: { if (clamp) { - static MapRangeVectorFunction fn_with_clamp{true}; - builder.set_matching_fn(fn_with_clamp); + static auto fn = build_vector_linear<true>(); + builder.set_matching_fn(fn); } else { - static MapRangeVectorFunction fn_without_clamp{false}; - builder.set_matching_fn(fn_without_clamp); + static auto fn = build_vector_linear<false>(); + builder.set_matching_fn(fn); } break; } case NODE_MAP_RANGE_STEPPED: { if (clamp) { - static MapRangeSteppedVectorFunction fn_stepped_with_clamp{true}; - builder.set_matching_fn(fn_stepped_with_clamp); + static auto fn = build_vector_stepped<true>(); + builder.set_matching_fn(fn); } else { - static MapRangeSteppedVectorFunction fn_stepped_without_clamp{false}; - builder.set_matching_fn(fn_stepped_without_clamp); + static auto fn = build_vector_stepped<false>(); + builder.set_matching_fn(fn); } break; } case NODE_MAP_RANGE_SMOOTHSTEP: { - static MapRangeSmoothstepVectorFunction smoothstep; - builder.set_matching_fn(smoothstep); + static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>> + fn{"Vector Map Range Smoothstep", + [](const float3 &value, + const float3 &from_min, + const float3 &from_max, + const float3 &to_min, + const float3 &to_max, + float3 *r_value) { + float3 factor = math::safe_divide(value - from_min, from_max - from_min); + clamp_v3(factor, 0.0f, 1.0f); + factor = (float3(3.0f) - 2.0f * factor) * (factor * factor); + *r_value = factor * (to_max - to_min) + to_min; + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; + builder.set_matching_fn(fn); break; } case NODE_MAP_RANGE_SMOOTHERSTEP: { - static MapRangeSmootherstepVectorFunction smootherstep; - builder.set_matching_fn(smootherstep); + static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float3>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float3>> + fn{"Vector Map Range Smootherstep", + [](const float3 &value, + const float3 &from_min, + const float3 &from_max, + const float3 &to_min, + const float3 &to_max, + float3 *r_value) { + float3 factor = math::safe_divide(value - from_min, from_max - from_min); + clamp_v3(factor, 0.0f, 1.0f); + factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f); + *r_value = factor * (to_max - to_min) + to_min; + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; + builder.set_matching_fn(fn); break; } default: @@ -594,34 +409,70 @@ static void sh_node_map_range_build_multi_function(NodeMultiFunctionBuilder &bui switch (interpolation_type) { case NODE_MAP_RANGE_LINEAR: { if (clamp) { - static MapRangeFunction fn_with_clamp{true}; - builder.set_matching_fn(fn_with_clamp); + static auto fn = build_float_linear<true>(); + builder.set_matching_fn(fn); } else { - static MapRangeFunction fn_without_clamp{false}; - builder.set_matching_fn(fn_without_clamp); + static auto fn = build_float_linear<false>(); + builder.set_matching_fn(fn); } break; } case NODE_MAP_RANGE_STEPPED: { if (clamp) { - static MapRangeSteppedFunction fn_stepped_with_clamp{true}; - builder.set_matching_fn(fn_stepped_with_clamp); + static auto fn = build_float_stepped<true>(); + builder.set_matching_fn(fn); } else { - static MapRangeSteppedFunction fn_stepped_without_clamp{false}; - builder.set_matching_fn(fn_stepped_without_clamp); + static auto fn = build_float_stepped<false>(); + builder.set_matching_fn(fn); } break; } case NODE_MAP_RANGE_SMOOTHSTEP: { - static MapRangeSmoothstepFunction smoothstep; - builder.set_matching_fn(smoothstep); + static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>> + fn{"Map Range Smoothstep", + [](float value, + float from_min, + float from_max, + float to_min, + float to_max, + float *r_value) { + float factor = safe_divide(value - from_min, from_max - from_min); + factor = std::clamp(factor, 0.0f, 1.0f); + factor = (3.0f - 2.0f * factor) * (factor * factor); + *r_value = to_min + factor * (to_max - to_min); + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; + builder.set_matching_fn(fn); break; } case NODE_MAP_RANGE_SMOOTHERSTEP: { - static MapRangeSmootherstepFunction smootherstep; - builder.set_matching_fn(smootherstep); + static fn::CustomMF<fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleInput, float>, + fn::MFParamTag<fn::MFParamCategory::SingleOutput, float>> + fn{"Map Range Smoothstep", + [](float value, + float from_min, + float from_max, + float to_min, + float to_max, + float *r_value) { + float factor = safe_divide(value - from_min, from_max - from_min); + factor = std::clamp(factor, 0.0f, 1.0f); + factor = factor * factor * factor * (factor * (factor * 6.0f - 15.0f) + 10.0f); + *r_value = to_min + factor * (to_max - to_min); + }, + fn::CustomMF_presets::SomeSpanOrSingle<0>()}; + builder.set_matching_fn(fn); break; } default: diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index a828011a3ab..8a2b18d7d76 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -106,28 +106,30 @@ static const fn::MultiFunction *get_base_multi_function(bNode &node) const int mode = node.custom1; const fn::MultiFunction *base_fn = nullptr; - try_dispatch_float_math_fl_to_fl(mode, [&](auto function, const FloatMathOperationInfo &info) { - static fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(), function}; - base_fn = &fn; - }); + try_dispatch_float_math_fl_to_fl( + mode, [&](auto devi_fn, auto function, const FloatMathOperationInfo &info) { + static fn::CustomMF_SI_SO<float, float> fn{ + info.title_case_name.c_str(), function, devi_fn}; + base_fn = &fn; + }); if (base_fn != nullptr) { return base_fn; } - try_dispatch_float_math_fl_fl_to_fl(mode, - [&](auto function, const FloatMathOperationInfo &info) { - static fn::CustomMF_SI_SI_SO<float, float, float> fn{ - info.title_case_name.c_str(), function}; - base_fn = &fn; - }); + try_dispatch_float_math_fl_fl_to_fl( + mode, [&](auto devi_fn, auto function, const FloatMathOperationInfo &info) { + static fn::CustomMF_SI_SI_SO<float, float, float> fn{ + info.title_case_name.c_str(), function, devi_fn}; + base_fn = &fn; + }); if (base_fn != nullptr) { return base_fn; } try_dispatch_float_math_fl_fl_fl_to_fl( - mode, [&](auto function, const FloatMathOperationInfo &info) { + mode, [&](auto devi_fn, auto function, const FloatMathOperationInfo &info) { static fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{ - info.title_case_name.c_str(), function}; + info.title_case_name.c_str(), function, devi_fn}; base_fn = &fn; }); if (base_fn != nullptr) { diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index 0d751157817..94a6febe92e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -106,7 +106,9 @@ static int gpu_shader_combxyz(GPUMaterial *mat, static void sh_node_combxyz_build_multi_function(NodeMultiFunctionBuilder &builder) { static fn::CustomMF_SI_SI_SI_SO<float, float, float, float3> fn{ - "Combine Vector", [](float x, float y, float z) { return float3(x, y, z); }}; + "Combine Vector", + [](float x, float y, float z) { return float3(x, y, z); }, + fn::CustomMF_presets::AllSpanOrSingle()}; builder.set_matching_fn(fn); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 02a3552704e..21f5c44c640 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -231,20 +231,20 @@ static const fn::MultiFunction *get_multi_function(bNode &node) const fn::MultiFunction *multi_fn = nullptr; - try_dispatch_float_math_fl3_fl3_to_fl3(operation, - [&](auto function, const FloatMathOperationInfo &info) { - static fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - info.title_case_name.c_str(), function}; - multi_fn = &fn; - }); + try_dispatch_float_math_fl3_fl3_to_fl3( + operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) { + static fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ + info.title_case_name.c_str(), function, exec_preset}; + multi_fn = &fn; + }); if (multi_fn != nullptr) { return multi_fn; } try_dispatch_float_math_fl3_fl3_fl3_to_fl3( - operation, [&](auto function, const FloatMathOperationInfo &info) { + operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) { static fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ - info.title_case_name.c_str(), function}; + info.title_case_name.c_str(), function, exec_preset}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -252,38 +252,39 @@ static const fn::MultiFunction *get_multi_function(bNode &node) } try_dispatch_float_math_fl3_fl3_fl_to_fl3( - operation, [&](auto function, const FloatMathOperationInfo &info) { + operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) { static fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ - info.title_case_name.c_str(), function}; + info.title_case_name.c_str(), function, exec_preset}; multi_fn = &fn; }); if (multi_fn != nullptr) { return multi_fn; } - try_dispatch_float_math_fl3_fl3_to_fl(operation, - [&](auto function, const FloatMathOperationInfo &info) { - static fn::CustomMF_SI_SI_SO<float3, float3, float> fn{ - info.title_case_name.c_str(), function}; - multi_fn = &fn; - }); + try_dispatch_float_math_fl3_fl3_to_fl( + operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) { + static fn::CustomMF_SI_SI_SO<float3, float3, float> fn{ + info.title_case_name.c_str(), function, exec_preset}; + multi_fn = &fn; + }); if (multi_fn != nullptr) { return multi_fn; } - try_dispatch_float_math_fl3_fl_to_fl3(operation, - [&](auto function, const FloatMathOperationInfo &info) { - static fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ - info.title_case_name.c_str(), function}; - multi_fn = &fn; - }); + try_dispatch_float_math_fl3_fl_to_fl3( + operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) { + static fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ + info.title_case_name.c_str(), function, exec_preset}; + multi_fn = &fn; + }); if (multi_fn != nullptr) { return multi_fn; } try_dispatch_float_math_fl3_to_fl3( - operation, [&](auto function, const FloatMathOperationInfo &info) { - static fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(), function}; + operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) { + static fn::CustomMF_SI_SO<float3, float3> fn{ + info.title_case_name.c_str(), function, exec_preset}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -291,8 +292,9 @@ static const fn::MultiFunction *get_multi_function(bNode &node) } try_dispatch_float_math_fl3_to_fl( - operation, [&](auto function, const FloatMathOperationInfo &info) { - static fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(), function}; + operation, [&](auto exec_preset, auto function, const FloatMathOperationInfo &info) { + static fn::CustomMF_SI_SO<float3, float> fn{ + info.title_case_name.c_str(), function, exec_preset}; multi_fn = &fn; }); if (multi_fn != nullptr) { |