CaptureMoment 0.1.0
Free and open-source non-destructive photo editor
Loading...
Searching...
No Matches
operation_pipeline_executor.cpp
Go to the documentation of this file.
1
11#include "config/app_config.h"
12
13#include <spdlog/spdlog.h>
14
16
18
20 m_factory(nullptr),
21 m_chain_built(false)
22{
23 m_input.dim(0).set_stride(4);
24 m_input.dim(2).set_stride(1);
25
26 spdlog::debug("[OperationPipelineExecutor]: Constructed. Input set to Float(32), 3 dimensions. Backend: {}",
27 static_cast<int>(Config::AppConfig::instance().getProcessingBackend()));
28}
29
31 std::vector<Operations::OperationDescriptor>&& operations,
32 const Operations::OperationFactory& factory)
33{
34 spdlog::debug("[OperationPipelineExecutor::init (Move)]: Initializing with {} operations.", operations.size());
35
36 m_operations = std::move(operations);
37 m_factory = &factory;
38
39 if (!m_operations.empty()) {
41 } else {
42 m_chain_built = false;
43 m_pipeline = Halide::Pipeline();
44 m_pipeline_params.clear();
45 }
46}
47
48void OperationPipelineExecutor::updateRuntimeParams(std::vector<Operations::OperationDescriptor>&& operations)
49{
50 // Move the input vector into the member variable. This updates our internal state
51 // with the latest values without any memory allocation or copying of the data structure.
52 m_operations = std::move(operations);
53
54 // FAST PATH: Iterate over the updated operations and sync the Halide Parameters.
55 for (const auto& desc : m_operations)
56 {
57 if (!desc.enabled) continue;
58
59 auto it = m_pipeline_params.find(desc.id);
60 if (it != m_pipeline_params.end())
61 {
62 // Parameter exists in cache, update its value
63 if (auto val_res = desc.getParam<float>("value")) {
64 it->second.set(val_res.value());
65 }
66 } else {
67 // If we reach here, the structure changed (new operation added) but init() wasn't called.
68 // This indicates a logic error in the caller (should have called init instead).
69 spdlog::warn("[OperationPipelineExecutor::updateRuntimeParams]: Param '{}' not found in cache. Structure changed? Call init().", desc.name);
70 }
71 }
72}
73
74Halide::Func OperationPipelineExecutor::applyOperations(const Halide::Func& input, const Halide::Var& x, const Halide::Var& y, const Halide::Var& c)
75{
76 Halide::Func current_stage("current_stage");
77 current_stage(x, y, c) = input(x, y, c);
78
79 m_pipeline_params.clear();
80
81 for (const auto& desc : m_operations)
82 {
83 if (!desc.enabled) continue;
84
85 if (!m_factory) {
86 spdlog::error("[OperationPipelineExecutor::applyOperations]: Factory is null.");
87 return current_stage;
88 }
89
90 auto op_impl_expected { m_factory->create(desc) };
91 if (!op_impl_expected) continue;
92
93 auto op_impl { std::move(op_impl_expected.value()) };
94 auto* fusion_logic { dynamic_cast<const Operations::IOperationFusionLogic*>(op_impl.get()) };
95
96 if (fusion_logic)
97 {
98 auto& param_ref { m_pipeline_params[desc.id] };
99 if (auto val_res = desc.getParam<float>("value")) {
100 param_ref.set(val_res.value());
101 }
102 current_stage = fusion_logic->appendToFusedPipeline(current_stage, x, y, c, param_ref);
103 }
104 }
105 return current_stage;
106}
107
108bool OperationPipelineExecutor::executeOnHalideBuffer(Halide::Buffer<float>& input_buffer, Halide::Buffer<float>& output_buffer)
109{
110 if (!m_chain_built || !m_pipeline.defined()) {
111 return true;
112 }
113
114 try {
115 // 1. Bind the actual C++ buffer memory to the Halide ImageParam
116 // This is extremely fast (pointer copy), no data duplication.
117 m_input.set(input_buffer);
118 // 2. Get the target for execution
119 // CRITICAL: For GPU execution, realize() MUST receive the target parameter
120 Halide::Target target { Config::AppConfig::getHalideTarget() };
121
122 spdlog::debug("[OperationPipelineExecutor::executeOnHalideBuffer]: Halide Target Architecture: {}",
123 target.to_string());
124
125 // 3. Execute the pipeline on the correct device (CPU or GPU)
126 m_pipeline.realize(output_buffer, target);
127 return true;
128 }
129 catch (const Halide::RuntimeError& e) {
130 spdlog::critical("[OperationPipelineExecutor::executeOnHalideBuffer]: Halide Runtime Error: {}", e.what());
131 return false;
132 }
133 catch (const std::exception& e) {
134 spdlog::critical("[OperationPipelineExecutor::executeOnHalideBuffer]: Unexpected exception: {}", e.what());
135 return false;
136 }
137}
138
139} // namespace CaptureMoment::Core::Pipeline
Application-wide configuration singleton.
static AppConfig & instance()
Gets the singleton instance of AppConfig.
static const Halide::Target & getHalideTarget()
Gets the configured Halide Target object.
Interface for providing the Halide fusion logic of an operation.
Factory Pattern - creates operations from OperationDescriptor.
std::expected< std::unique_ptr< IOperation >, ErrorHandling::CoreError > create(const OperationDescriptor &descriptor) const
Create an operation instance from descriptor.
Base class for Halide executors providing shared 4-channel input parameter.
Halide::ImageParam m_input
The shared Halide Input Parameter.
virtual void buildOperationChain()=0
Builds the Halide function graph based on m_operations.
bool m_chain_built
Flag indicating if the pipeline has been successfully built and compiled.
Halide::Func applyOperations(const Halide::Func &input, const Halide::Var &x, const Halide::Var &y, const Halide::Var &c)
Applies all operations to the input function.
void init(std::vector< Operations::OperationDescriptor > &&operations, const Operations::OperationFactory &factory)
Initializes the executor with a moved list of operations (Optimized).
bool executeOnHalideBuffer(Halide::Buffer< float > &input_buffer, Halide::Buffer< float > &output_buffer) override
Executes the compiled pipeline directly on a Halide buffer.
void updateRuntimeParams(std::vector< Operations::OperationDescriptor > &&operations)
Updates the runtime values of the cached parameters WITHOUT recompiling.
Halide::Pipeline m_pipeline
The compiled Halide pipeline object.
Interface for providing the Halide fusion logic of an operation.
Factory for creating operations (Dependency Injection)
Declaration of OperationPipelineExecutor (Fused Adjustment Pipeline).
CaptureMoment — footer