WIP: Functions: process multiple elements at once in the lazy-function api #105697

Draft
Jacques Lucke wants to merge 10 commits from JacquesLucke/blender:lazy-function-span-api into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 196 additions and 86 deletions

View File

@ -124,6 +124,8 @@ class Params {
* The #LazyFunction must leave returned object in an initialized state, but can move from it.
*/
void *try_get_input_data_ptr(int index) const;
void try_get_input_data_ptr(IndexRange indices, MutableSpan<void *> r_data) const;
void try_get_input_data_ptr(Span<int> indices, MutableSpan<void *> r_data) const;
/**
* Same as #try_get_input_data_ptr, but if the data is not yet available, request it. This makes
@ -138,12 +140,16 @@ class Params {
* After the output has been initialized to its final value, #output_set has to be called.
*/
void *get_output_data_ptr(int index);
void get_output_data_ptr(IndexRange indices, MutableSpan<void *> r_data);
void get_output_data_ptr(Span<int> indices, MutableSpan<void *> r_data);
/**
* Call this after the output value is initialized. After this is called, the value must not be
* touched anymore. It may be moved or destructed immediately.
*/
void output_set(int index);
void output_set(IndexRange indices);
void output_set(Span<int> indices);
/**
* Allows the #LazyFunction to check whether an output was computed already without keeping
@ -190,13 +196,16 @@ class Params {
* methods above to make it easy to insert additional debugging logic on top of the
* implementations.
*/
virtual void *try_get_input_data_ptr_impl(int index) const = 0;
virtual void *try_get_input_data_ptr_or_request_impl(int index) = 0;
virtual void *get_output_data_ptr_impl(int index) = 0;
virtual void output_set_impl(int index) = 0;
virtual bool output_was_set_impl(int index) const = 0;
virtual ValueUsage get_output_usage_impl(int index) const = 0;
virtual void set_input_unused_impl(int index) = 0;
virtual void try_get_input_data_ptr_impl(Span<int> indices,
MutableSpan<void *> r_data) const = 0;
virtual void try_get_input_data_ptr_or_request_impl(Span<int> indices,
MutableSpan<void *> r_data) = 0;
virtual void get_output_data_ptr_impl(Span<int> indices, MutableSpan<void *> r_data) = 0;
virtual void output_set_impl(Span<int> indices) = 0;
virtual void output_was_set_impl(Span<int> indices, MutableSpan<bool> r_result) const = 0;
virtual void get_output_usage_impl(Span<int> indices,
MutableSpan<ValueUsage> r_result) const = 0;
virtual void set_input_unused_impl(Span<int> indices) = 0;
virtual bool try_enable_multi_threading_impl();
};
@ -365,43 +374,99 @@ inline Params::Params(const LazyFunction &fn,
{
}
inline Array<int, 16> get_indices_array(const IndexRange indices)
{
Array<int, 16> indices_array(indices.size());
for (const int i : IndexRange(indices.size())) {
indices_array[i] = indices[i];
}
return indices_array;
}
inline void *Params::try_get_input_data_ptr(const int index) const
{
return this->try_get_input_data_ptr_impl(index);
void *data;
this->try_get_input_data_ptr_impl({index}, {&data, 1});
return data;
}
inline void Params::get_output_data_ptr(const IndexRange indices, MutableSpan<void *> r_data)
{
Array<int, 16> indices_array = get_indices_array(indices);
this->get_output_data_ptr(indices_array, r_data);
}
inline void Params::get_output_data_ptr(const Span<int> indices, MutableSpan<void *> r_data)
{
BLI_assert(indices.size() == r_data.size());
this->get_output_data_ptr_impl(indices, r_data);
}
inline void Params::output_set(const IndexRange indices)
{
Array<int, 16> indices_array = get_indices_array(indices);
this->output_set(indices_array);
}
inline void Params::output_set(const Span<int> indices)
{
this->output_set_impl(indices);
}
inline void Params::try_get_input_data_ptr(const IndexRange indices,
MutableSpan<void *> r_data) const
{
Array<int, 16> indices_array = get_indices_array(indices);
this->try_get_input_data_ptr(indices_array, r_data);
}
inline void Params::try_get_input_data_ptr(const Span<int> indices,
MutableSpan<void *> r_data) const
{
BLI_assert(indices.size() == r_data.size());
this->try_get_input_data_ptr_impl(indices, r_data);
}
inline void *Params::try_get_input_data_ptr_or_request(const int index)
{
this->assert_valid_thread();
return this->try_get_input_data_ptr_or_request_impl(index);
void *data;
this->try_get_input_data_ptr_or_request_impl({index}, {&data, 1});
return data;
}
inline void *Params::get_output_data_ptr(const int index)
{
this->assert_valid_thread();
return this->get_output_data_ptr_impl(index);
void *data;
this->get_output_data_ptr_impl({index}, {&data, 1});
return data;
}
inline void Params::output_set(const int index)
{
this->assert_valid_thread();
this->output_set_impl(index);
this->output_set_impl({index});
}
inline bool Params::output_was_set(const int index) const
{
return this->output_was_set_impl(index);
bool result;
this->output_was_set_impl({index}, {&result, 1});
return result;
}
inline ValueUsage Params::get_output_usage(const int index) const
{
return this->get_output_usage_impl(index);
ValueUsage result;
this->get_output_usage_impl({index}, {&result, 1});
return result;
}
inline void Params::set_input_unused(const int index)
{
this->assert_valid_thread();
this->set_input_unused_impl(index);
this->set_input_unused_impl({index});
}
template<typename T> inline T Params::extract_input(const int index)

View File

@ -34,13 +34,15 @@ class BasicParams : public Params {
Span<ValueUsage> output_usages,
MutableSpan<bool> set_outputs);
void *try_get_input_data_ptr_impl(const int index) const override;
void *try_get_input_data_ptr_or_request_impl(const int index) override;
void *get_output_data_ptr_impl(const int index) override;
void output_set_impl(const int index) override;
bool output_was_set_impl(const int index) const override;
ValueUsage get_output_usage_impl(const int index) const override;
void set_input_unused_impl(const int index) override;
void try_get_input_data_ptr_impl(Span<int> indices, MutableSpan<void *> r_data) const override;
void try_get_input_data_ptr_or_request_impl(Span<int> indices,
MutableSpan<void *> r_data) override;
void get_output_data_ptr_impl(Span<int> indices, MutableSpan<void *> r_data) override;
void output_set_impl(Span<int> indices) override;
void output_was_set_impl(Span<int> indices, MutableSpan<bool> r_result) const override;
void get_output_usage_impl(const Span<int> indices,
MutableSpan<ValueUsage> r_result) const override;
void set_input_unused_impl(Span<int> indices) override;
bool try_enable_multi_threading_impl() override;
};

View File

@ -23,43 +23,65 @@ BasicParams::BasicParams(const LazyFunction &fn,
{
}
void *BasicParams::try_get_input_data_ptr_impl(const int index) const
void BasicParams::try_get_input_data_ptr_impl(const Span<int> indices,
MutableSpan<void *> r_data) const
{
return inputs_[index].get();
}
void *BasicParams::try_get_input_data_ptr_or_request_impl(const int index)
{
void *value = inputs_[index].get();
if (value == nullptr) {
input_usages_[index] = ValueUsage::Used;
for (const int i : indices.index_range()) {
const int index = indices[i];
r_data[i] = inputs_[index].get();
}
return value;
}
void *BasicParams::get_output_data_ptr_impl(const int index)
void BasicParams::try_get_input_data_ptr_or_request_impl(const Span<int> indices,
MutableSpan<void *> r_data)
{
return outputs_[index].get();
for (const int i : indices.index_range()) {
const int index = indices[i];
void *value = inputs_[index].get();
if (value == nullptr) {
input_usages_[index] = ValueUsage::Used;
}
r_data[i] = value;
}
}
void BasicParams::output_set_impl(const int index)
void BasicParams::get_output_data_ptr_impl(const Span<int> indices, MutableSpan<void *> r_data)
{
set_outputs_[index] = true;
for (const int i : indices.index_range()) {
const int index = indices[i];
r_data[i] = outputs_[index].get();
}
}
bool BasicParams::output_was_set_impl(const int index) const
void BasicParams::output_set_impl(const Span<int> indices)
{
return set_outputs_[index];
for (const int index : indices) {
set_outputs_[index] = true;
}
}
ValueUsage BasicParams::get_output_usage_impl(const int index) const
void BasicParams::output_was_set_impl(const Span<int> indices, MutableSpan<bool> r_result) const
{
return output_usages_[index];
for (const int i : indices.index_range()) {
const int index = indices[i];
r_result[i] = set_outputs_[index];
}
}
void BasicParams::set_input_unused_impl(const int index)
void BasicParams::get_output_usage_impl(const Span<int> indices,
MutableSpan<ValueUsage> r_result) const
{
input_usages_[index] = ValueUsage::Unused;
for (const int i : indices.index_range()) {
const int index = indices[i];
r_result[i] = output_usages_[index];
}
}
void BasicParams::set_input_unused_impl(const Span<int> indices)
{
for (const int index : indices) {
input_usages_[index] = ValueUsage::Unused;
}
}
bool BasicParams::try_enable_multi_threading_impl()

View File

@ -1223,63 +1223,90 @@ class GraphExecutorLFParams final : public Params {
}
private:
void *try_get_input_data_ptr_impl(const int index) const override
void try_get_input_data_ptr_impl(const Span<int> indices,
MutableSpan<void *> r_data) const override
{
const InputState &input_state = node_state_.inputs[index];
if (input_state.was_ready_for_execution) {
return input_state.value;
for (const int i : indices.index_range()) {
const int index = indices[i];
const InputState &input_state = node_state_.inputs[index];
if (input_state.was_ready_for_execution) {
r_data[i] = input_state.value;
}
else {
r_data[i] = nullptr;
}
}
return nullptr;
}
void *try_get_input_data_ptr_or_request_impl(const int index) override
void try_get_input_data_ptr_or_request_impl(const Span<int> indices,
MutableSpan<void *> r_data) override
{
const InputState &input_state = node_state_.inputs[index];
if (input_state.was_ready_for_execution) {
return input_state.value;
for (const int i : indices.index_range()) {
const int index = indices[i];
const InputState &input_state = node_state_.inputs[index];
if (input_state.was_ready_for_execution) {
r_data[i] = input_state.value;
}
else {
r_data[i] = executor_.set_input_required_during_execution(
node_, node_state_, index, current_task_);
}
}
return executor_.set_input_required_during_execution(node_, node_state_, index, current_task_);
}
void *get_output_data_ptr_impl(const int index) override
void get_output_data_ptr_impl(const Span<int> indices, MutableSpan<void *> r_data) override
{
OutputState &output_state = node_state_.outputs[index];
BLI_assert(!output_state.has_been_computed);
if (output_state.value == nullptr) {
LinearAllocator<> &allocator = executor_.get_main_or_local_allocator();
const CPPType &type = node_.output(index).type();
output_state.value = allocator.allocate(type.size(), type.alignment());
for (const int i : indices.index_range()) {
const int index = indices[i];
OutputState &output_state = node_state_.outputs[index];
BLI_assert(!output_state.has_been_computed);
if (output_state.value == nullptr) {
LinearAllocator<> &allocator = executor_.get_main_or_local_allocator();
const CPPType &type = node_.output(index).type();
output_state.value = allocator.allocate(type.size(), type.alignment());
}
r_data[i] = output_state.value;
}
return output_state.value;
}
void output_set_impl(const int index) override
void output_set_impl(const Span<int> indices) override
{
OutputState &output_state = node_state_.outputs[index];
BLI_assert(!output_state.has_been_computed);
BLI_assert(output_state.value != nullptr);
const OutputSocket &output_socket = node_.output(index);
executor_.forward_value_to_linked_inputs(
output_socket, {output_socket.type(), output_state.value}, current_task_);
output_state.value = nullptr;
output_state.has_been_computed = true;
for (const int index : indices) {
OutputState &output_state = node_state_.outputs[index];
BLI_assert(!output_state.has_been_computed);
BLI_assert(output_state.value != nullptr);
const OutputSocket &output_socket = node_.output(index);
executor_.forward_value_to_linked_inputs(
output_socket, {output_socket.type(), output_state.value}, current_task_);
output_state.value = nullptr;
output_state.has_been_computed = true;
}
}
bool output_was_set_impl(const int index) const override
void output_was_set_impl(const Span<int> indices, MutableSpan<bool> r_result) const override
{
const OutputState &output_state = node_state_.outputs[index];
return output_state.has_been_computed;
for (const int i : indices.index_range()) {
const int index = indices[i];
const OutputState &output_state = node_state_.outputs[index];
r_result[i] = output_state.has_been_computed;
}
}
ValueUsage get_output_usage_impl(const int index) const override
void get_output_usage_impl(const Span<int> indices,
MutableSpan<ValueUsage> r_result) const override
{
const OutputState &output_state = node_state_.outputs[index];
return output_state.usage_for_execution;
for (const int i : indices.index_range()) {
const int index = indices[i];
const OutputState &output_state = node_state_.outputs[index];
r_result[i] = output_state.usage_for_execution;
}
}
void set_input_unused_impl(const int index) override
void set_input_unused_impl(const Span<int> indices) override
{
executor_.set_input_unused_during_execution(node_, node_state_, index, current_task_);
for (const int index : indices) {
executor_.set_input_unused_during_execution(node_, node_state_, index, current_task_);
}
}
bool try_enable_multi_threading_impl() override

View File

@ -521,19 +521,13 @@ class LazyFunctionForMultiFunctionNode : public LazyFunction {
void execute_impl(lf::Params &params, const lf::Context & /*context*/) const override
{
Vector<const void *> input_values(inputs_.size());
Vector<void *> input_values(inputs_.size());
Vector<void *> output_values(outputs_.size());
for (const int i : inputs_.index_range()) {
input_values[i] = params.try_get_input_data_ptr(i);
}
for (const int i : outputs_.index_range()) {
output_values[i] = params.get_output_data_ptr(i);
}
params.try_get_input_data_ptr(inputs_.index_range(), input_values);
params.get_output_data_ptr(outputs_.index_range(), output_values);
execute_multi_function_on_value_or_field(
*fn_item_.fn, fn_item_.owned_fn, input_types_, output_types_, input_values, output_values);
for (const int i : outputs_.index_range()) {
params.output_set(i);
}
params.output_set(outputs_.index_range());
}
};