tornavis/source/blender/compositor/realtime_compositor/intern/operation.cc

216 lines
6.3 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include <limits>
#include <memory>
#include "BLI_map.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
#include "COM_context.hh"
#include "COM_conversion_operation.hh"
#include "COM_domain.hh"
#include "COM_input_descriptor.hh"
#include "COM_operation.hh"
#include "COM_realize_on_domain_operation.hh"
#include "COM_reduce_to_single_value_operation.hh"
#include "COM_result.hh"
#include "COM_simple_operation.hh"
#include "COM_texture_pool.hh"
namespace blender::realtime_compositor {
Operation::Operation(Context &context) : context_(context) {}
Operation::~Operation() = default;
void Operation::evaluate()
{
evaluate_input_processors();
reset_results();
execute();
compute_preview();
release_inputs();
release_unneeded_results();
}
Result &Operation::get_result(StringRef identifier)
{
return results_.lookup(identifier);
}
void Operation::map_input_to_result(StringRef identifier, Result *result)
{
results_mapped_to_inputs_.add_new(identifier, result);
}
Domain Operation::compute_domain()
{
/* Default to an identity domain in case no domain input was found, most likely because all
* inputs are single values. */
Domain operation_domain = Domain::identity();
int current_domain_priority = std::numeric_limits<int>::max();
/* Go over the inputs and find the domain of the non single value input with the highest domain
* priority. */
for (StringRef identifier : input_descriptors_.keys()) {
const Result &result = get_input(identifier);
const InputDescriptor &descriptor = get_input_descriptor(identifier);
/* A single value input can't be a domain input. */
if (result.is_single_value() || descriptor.expects_single_value) {
continue;
}
/* An input that skips operation domain realization can't be a domain input. */
if (!descriptor.realization_options.realize_on_operation_domain) {
continue;
}
/* Notice that the lower the domain priority value is, the higher the priority is, hence the
* less than comparison. */
if (descriptor.domain_priority < current_domain_priority) {
operation_domain = result.domain();
current_domain_priority = descriptor.domain_priority;
}
}
return operation_domain;
}
void Operation::add_and_evaluate_input_processors()
{
/* Each input processor type is added to all inputs entirely before the next type. This is done
* because the construction of the input processors may depend on the result of previous input
* processors for all inputs. For instance, the realize on domain input processor considers the
* value of all inputs, so previous input processors for all inputs needs to be added and
* evaluated first. */
for (const StringRef &identifier : results_mapped_to_inputs_.keys()) {
SimpleOperation *single_value = ReduceToSingleValueOperation::construct_if_needed(
context(), get_input(identifier));
add_and_evaluate_input_processor(identifier, single_value);
}
for (const StringRef &identifier : results_mapped_to_inputs_.keys()) {
SimpleOperation *conversion = ConversionOperation::construct_if_needed(
context(), get_input(identifier), get_input_descriptor(identifier));
add_and_evaluate_input_processor(identifier, conversion);
}
for (const StringRef &identifier : results_mapped_to_inputs_.keys()) {
SimpleOperation *realize_on_domain = RealizeOnDomainOperation::construct_if_needed(
context(), get_input(identifier), get_input_descriptor(identifier), compute_domain());
add_and_evaluate_input_processor(identifier, realize_on_domain);
}
}
void Operation::add_and_evaluate_input_processor(StringRef identifier, SimpleOperation *processor)
{
/* Allow null inputs to facilitate construct_if_needed pattern of addition. For instance, see the
* implementation of the add_and_evaluate_input_processors method. */
if (!processor) {
return;
}
ProcessorsVector &processors = input_processors_.lookup_or_add_default(identifier);
/* Get the result that should serve as the input for the processor. This is either the result
* mapped to the input or the result of the last processor depending on whether this is the first
* processor or not. */
Result &result = processors.is_empty() ? get_input(identifier) : processors.last()->get_result();
/* Map the input result of the processor and add it to the processors vector. */
processor->map_input_to_result(&result);
processors.append(std::unique_ptr<SimpleOperation>(processor));
/* Switch the result mapped to the input to be the output result of the processor. */
switch_result_mapped_to_input(identifier, &processor->get_result());
processor->evaluate();
}
void Operation::compute_preview(){};
Result &Operation::get_input(StringRef identifier) const
{
return *results_mapped_to_inputs_.lookup(identifier);
}
void Operation::switch_result_mapped_to_input(StringRef identifier, Result *result)
{
results_mapped_to_inputs_.lookup(identifier) = result;
}
void Operation::populate_result(StringRef identifier, Result result)
{
results_.add_new(identifier, result);
}
void Operation::declare_input_descriptor(StringRef identifier, InputDescriptor descriptor)
{
input_descriptors_.add_new(identifier, descriptor);
}
InputDescriptor &Operation::get_input_descriptor(StringRef identifier)
{
return input_descriptors_.lookup(identifier);
}
Context &Operation::context() const
{
return context_;
}
TexturePool &Operation::texture_pool() const
{
return context_.texture_pool();
}
void Operation::evaluate_input_processors()
{
if (!input_processors_added_) {
add_and_evaluate_input_processors();
input_processors_added_ = true;
return;
}
for (const ProcessorsVector &processors : input_processors_.values()) {
for (const std::unique_ptr<SimpleOperation> &processor : processors) {
processor->evaluate();
}
}
}
void Operation::reset_results()
{
for (Result &result : results_.values()) {
result.reset();
}
}
void Operation::release_inputs()
{
for (Result *result : results_mapped_to_inputs_.values()) {
result->release();
}
}
void Operation::release_unneeded_results()
{
for (Result &result : results_.values()) {
if (!result.should_compute() && result.is_allocated()) {
result.release();
}
}
}
} // namespace blender::realtime_compositor