Blender V5.0
conversion_operation.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <fmt/format.h>
6
7#include "BLI_color.hh"
8#include "BLI_cpp_type.hh"
9#include "BLI_generic_span.hh"
11#include "BLI_utildefines.h"
12
13#include "GPU_shader.hh"
14
16
18
19#include "COM_context.hh"
22#include "COM_result.hh"
23#include "COM_utilities.hh"
24
25namespace blender::compositor {
26
28 const ResultType input_type,
29 const ResultType expected_type)
31{
33 this->populate_result(context.create_result(expected_type));
34}
35
36/* Returns true if conversion between the given from and to types is supported. This should be
37 * consistent and up to date with the compositor node tree's validate_link fallback. */
38static bool is_conversion_supported(const ResultType from_type, const ResultType to_type)
39{
40 switch (from_type) {
45 case ResultType::Int:
49 switch (to_type) {
54 case ResultType::Int:
58 return true;
61 return false;
62 }
63 break;
66 return to_type == from_type;
67 }
68
70 return false;
71}
72
74{
75 Result &result = this->get_result();
76 const Result &input = this->get_input();
77
78 if (!is_conversion_supported(input.type(), result.type())) {
79 result.allocate_invalid();
80 return;
81 }
82
83 if (input.is_single_value()) {
84 result.allocate_single_value();
85 this->execute_single(input, result);
86 return;
87 }
88
89 result.allocate_texture(input.domain());
90 if (this->context().use_gpu()) {
91 const std::string shader_name = fmt::format("compositor_convert_{}_to_{}",
92 Result::type_name(this->get_input().type()),
93 Result::type_name(this->get_result().type()));
94 gpu::Shader *shader = this->context().get_shader(shader_name.c_str());
95 GPU_shader_bind(shader);
96
97 if (this->get_input().type() == ResultType::Color &&
99 {
100 float luminance_coefficients[3];
102 GPU_shader_uniform_3fv(shader, "luminance_coefficients_u", luminance_coefficients);
103 }
104
105 input.bind_as_texture(shader, "input_tx");
106 result.bind_as_image(shader, "output_img");
107
108 compute_dispatch_threads_at_least(shader, input.domain().size);
109
110 input.unbind_as_texture();
111 result.unbind_as_image();
113 }
114 else {
115 this->execute_cpu(input, result);
116 }
117}
118
120 const Result &input_result,
121 const InputDescriptor &input_descriptor)
122{
123 if (input_descriptor.skip_type_conversion) {
124 return nullptr;
125 }
126
127 const ResultType result_type = input_result.type();
128 const ResultType expected_type = input_descriptor.type;
129 if (result_type != expected_type) {
130 return new ConversionOperation(context, result_type, expected_type);
131 }
132 return nullptr;
133}
134
135/* Gets the single value of the given result as a single element GSpan. This calls the underlying
136 * single_value method to construct a GSpan from the GPointer, however, it has an exception for
137 * color types, since colors are stored as float4 internally, while their semantic type is
138 * ColorSceneLinear4f<eAlpha::Premultiplied> during conversion. */
140{
141 if (result.type() == ResultType::Color) {
142 return GSpan(
144 }
145
146 return GSpan(result.single_value().type(), result.single_value().get(), 1);
147}
148
150{
151 if (result.type() == ResultType::Color) {
152 return GMutableSpan(
154 }
155
156 return GMutableSpan(result.single_value().type(), result.single_value().get(), 1);
157}
158
159void ConversionOperation::execute_single(const Result &input, Result &output)
160{
164 output.update_single_value_data();
165}
166
167/* Gets the CPU data of the given result as a GSpan. This calls the underlying cpu_data method,
168 * however, it has an exception for color types, since colors are stored as float4 internally,
169 * while their semantic type is ColorSceneLinear4f<eAlpha::Premultiplied> during conversion. */
171{
172 if (result.type() == ResultType::Color) {
174 result.cpu_data().data(),
175 result.cpu_data().size());
176 }
177
178 return result.cpu_data();
179}
180
181/* Same as get_result_data but takes non-const result and returns a GMutableSpan. */
183{
184 if (result.type() == ResultType::Color) {
186 result.cpu_data().data(),
187 result.cpu_data().size());
188 }
189
190 return result.cpu_data();
191}
192
193void ConversionOperation::execute_cpu(const Result &input, Result &output)
194{
197}
198
199} // namespace blender::compositor
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define ELEM(...)
void GPU_shader_uniform_3fv(blender::gpu::Shader *sh, const char *name, const float data[3])
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_unbind()
BLI_INLINE void IMB_colormanagement_get_luminance_coefficients(float r_rgb[3])
static const CPPType & get()
void convert_to_initialized_n(GSpan from_span, GMutableSpan to_span) const
Result create_result(ResultType type, ResultPrecision precision)
gpu::Shader * get_shader(const char *info_name, ResultPrecision precision)
static SimpleOperation * construct_if_needed(Context &context, const Result &input_result, const InputDescriptor &input_descriptor)
ConversionOperation(Context &context, const ResultType input_type, const ResultType expected_type)
static const char * type_name(const ResultType type)
Definition result.cc:340
static ResultType type(blender::gpu::TextureFormat format)
Definition result.cc:261
void declare_input_descriptor(InputDescriptor descriptor)
#define input
#define output
const DataTypeConversions & get_implicit_type_conversions()
void compute_dispatch_threads_at_least(gpu::Shader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:196
static GSpan get_result_data(const Result &result)
static GSpan get_result_single_value(const Result &result)
static bool is_conversion_supported(const ResultType from_type, const ResultType to_type)
static Type to_type(const GPUType type)