Blender V4.3
COM_result.hh
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#pragma once
6
9
10#include "GPU_shader.hh"
11#include "GPU_texture.hh"
12
13#include "COM_domain.hh"
14#include "COM_meta_data.hh"
15
17
18class Context;
19
20/* Make sure to update the format related static methods in the Result class. */
21enum class ResultType : uint8_t {
22 /* The following types are user facing and can be used as inputs and outputs of operations. They
23 * either represent the base type of the result texture or a single value result. The color type
24 * represents an RGBA color. And the vector type represents a generic 4-component vector, which
25 * can encode two 2D vectors, one 3D vector with the last component ignored, or other dimensional
26 * data. */
27 Float,
28 Vector,
29 Color,
30
31 /* The following types are for internal use only, not user facing, and can't be used as inputs
32 * and outputs of operations. It follows that they needn't be handled in implicit operations like
33 * type conversion, shader, or single value reduction operations. */
34 Float2,
35 Float3,
36 Int2,
37};
38
39/* The precision of the data. CPU data is always stored using full precision at the moment. */
41 Full,
42 Half,
43};
44
45/* The type of storage used to hold the result data. */
47 /* Stored as a GPUTexture on the GPU. */
48 GPU,
49 /* Stored as a contiguous float buffer the CPU. */
51 /* Stored as a contiguous integer buffer the CPU. */
53};
54
55/* ------------------------------------------------------------------------------------------------
56 * Result
57 *
58 * A result represents the computed value of an output of an operation. A result can either
59 * represent an image or a single value. A result is typed, and can be of types like color, vector,
60 * or float. Single value results are stored in 1x1 textures to make them easily accessible in
61 * shaders. But the same value is also stored in the value union member of the result for any
62 * host-side processing. The GPU texture of the result can either be allocated from the texture
63 * pool of the context referenced by the result or it can be allocated directly from the GPU
64 * module, see the allocation method for more information.
65 *
66 * Results are reference counted and their textures are released once their reference count reaches
67 * zero. After constructing a result, the set_initial_reference_count method is called to declare
68 * the number of operations that needs this result. Once each operation that needs the result no
69 * longer needs it, the release method is called and the reference count is decremented, until it
70 * reaches zero, where the result's texture is then released. Since results are eventually
71 * decremented to zero by the end of every evaluation, the reference count is restored before every
72 * evaluation to its initial reference count by calling the reset method, which is why a separate
73 * member initial_reference_count_ is stored to keep track of the initial value.
74 *
75 * A result not only represents an image, but also the area it occupies in the virtual compositing
76 * space. This area is called the Domain of the result, see the discussion in COM_domain.hh for
77 * more information.
78 *
79 * A result can be a proxy result that merely wraps another master result, in which case, it shares
80 * its values and delegates all reference counting to it. While a proxy result shares the value of
81 * the master result, it can have a different domain. Consequently, transformation operations are
82 * implemented using proxy results, where their results are proxy results of their inputs but with
83 * their domains transformed based on their options. Moreover, proxy results can also be used as
84 * the results of identity operations, that is, operations that do nothing to their inputs in
85 * certain configurations. In which case, the proxy result is left as is with no extra
86 * transformation on its domain whatsoever. Proxy results can be created by calling the
87 * pass_through method, see that method for more details.
88 *
89 * A result can wrap an external texture that is not allocated nor managed by the result. This is
90 * set up by a call to the wrap_external method. In that case, when the reference count eventually
91 * reach zero, the texture will not be freed. */
92class Result {
93 private:
94 /* The context that the result was created within, this should be initialized during
95 * construction. */
96 Context *context_ = nullptr;
97 /* The base type of the result's texture or single value. */
99 /* The precision of the result's texture, host-side single values are always stored using full
100 * precision. */
102 /* If true, the result is a single value, otherwise, the result is a texture. */
103 bool is_single_value_ = false;
104 /* The type of storage used to hold the data. Used to correctly interpret the data union. */
106 /* A texture storing the result pixel data, either stored in a GPU texture or a raw contagious
107 * array on CPU. This will be a 1x1 texture if the result is a single value, the value of which
108 * will be identical to that of the value member. See class description for more information. */
109 union {
110 GPUTexture *gpu_texture_ = nullptr;
113 };
114 /* The number of operations that currently needs this result. At the time when the result is
115 * computed, this member will have a value that matches initial_reference_count_. Once each
116 * operation that needs the result no longer needs it, the release method is called and the
117 * reference count is decremented, until it reaches zero, where the result's texture is then
118 * released. If this result have a master result, then this reference count is irrelevant and
119 * shadowed by the reference count of the master result. */
120 int reference_count_ = 1;
121 /* The number of operations that reference and use this result at the time when it was initially
122 * computed. Since reference_count_ is decremented and always becomes zero at the end of the
123 * evaluation, this member is used to reset the reference count of the results for later
124 * evaluations by calling the reset method. This member is also used to determine if this result
125 * should be computed by calling the should_compute method. */
126 int initial_reference_count_ = 1;
127 /* If the result is a single value, this member stores the value of the result, the value of
128 * which will be identical to that stored in the texture member. The active union member depends
129 * on the type of the result. This member is uninitialized and should not be used if the result
130 * is a texture. */
131 union {
138 };
139 /* The domain of the result. This only matters if the result was a texture. See the discussion in
140 * COM_domain.hh for more information. */
141 Domain domain_ = Domain::identity();
142 /* If not nullptr, then this result wraps and shares the value of another master result. In this
143 * case, calls to texture-related methods like increment_reference_count and release should
144 * operate on the master result as opposed to this result. This member is typically set upon
145 * calling the pass_through method, which sets this result to be the master of a target result.
146 * See that method for more information. */
147 Result *master_ = nullptr;
148 /* If true, then the result wraps an external texture that is not allocated nor managed by the
149 * result. This is set up by a call to the wrap_external method. In that case, when the reference
150 * count eventually reach zero, the texture will not be freed. */
151 bool is_external_ = false;
152 /* If true, the GPU texture that holds the data was allocated from the texture pool of the
153 * context and should be released back into the pool instead of being freed. For CPU storage,
154 * this is irrelevant. */
155 bool is_from_pool_ = false;
156
157 public:
158 /* Stores extra information about the result such as image meta data that can eventually be
159 * written to file. */
161
162 public:
163 /* Construct a result within the given context. */
164 Result(Context &context);
165
166 /* Construct a result of the given type and precision within the given context. */
168
169 /* Returns the appropriate GPU texture format based on the given result type and precision. */
171
172 /* Returns the GPU texture format that corresponds to the give one, but whose precision is the
173 * given precision. */
175
176 /* Returns the precision of the given GPU texture format. */
178
179 /* Returns the type of the given GPU texture format. */
181
182 /* Returns the float type of the result given the channels count. */
183 static ResultType float_type(const int channels_count);
184
185 /* Implicit conversion to the internal GPU texture. */
186 operator GPUTexture *() const;
187
188 /* Returns the appropriate texture format based on the result's type and precision. */
190
191 /* Declare the result to be a texture result, allocate a texture of an appropriate type with
192 * the size of the given domain, and set the domain of the result to the given domain.
193 *
194 * If from_pool is true, the texture will be allocated from the texture pool of the context,
195 * otherwise, a new texture will be allocated. Pooling should not be be used for persistent
196 * results that might span more than one evaluation, like cached resources. While pooling should
197 * be used for most other cases where the result will be allocated then later released in the
198 * same evaluation.
199 *
200 * If the context of the result uses GPU, then GPU allocation will be done, otherwise, CPU
201 * allocation will be done.
202 *
203 * If the result should not be computed, that is, should_compute() returns false, yet this method
204 * is called, that means the result is only being allocated because the shader that computes it
205 * also computes another result that is actually needed, and shaders needs to have a texture
206 * bound to all their images units for a correct invocation, even if some of those textures are
207 * not needed and will eventually be discarded. In that case, since allocating the full texture
208 * is not needed, allocate_single_value() is called instead and the reference count is set to 1.
209 * This essentially allocates a dummy 1x1 texture, which works because out of bound shader writes
210 * to images are safe. Since this result is not referenced by any other operation, it should be
211 * manually released after the operation is evaluated, which is implemented by calling the
212 * Operation::release_unneeded_results() method. */
213 void allocate_texture(Domain domain, bool from_pool = true);
214
215 /* Declare the result to be a single value result, allocate a texture of an appropriate type with
216 * size 1x1 from the texture pool, and set the domain to be an identity domain. See class
217 * description for more information. */
219
220 /* Allocate a single value result and set its value to zero. This is called for results whose
221 * value can't be computed and are considered invalid. */
222 void allocate_invalid();
223
224 /* Bind the GPU texture of the result to the texture image unit with the given name in the
225 * currently bound given shader. This also inserts a memory barrier for texture fetches to ensure
226 * any prior writes to the texture are reflected before reading from it. */
227 void bind_as_texture(GPUShader *shader, const char *texture_name) const;
228
229 /* Bind the GPU texture of the result to the image unit with the given name in the currently
230 * bound given shader. If read is true, a memory barrier will be inserted for image reads to
231 * ensure any prior writes to the images are reflected before reading from it. */
232 void bind_as_image(GPUShader *shader, const char *image_name, bool read = false) const;
233
234 /* Unbind the GPU texture which was previously bound using bind_as_texture. */
235 void unbind_as_texture() const;
236
237 /* Unbind the GPU texture which was previously bound using bind_as_image. */
238 void unbind_as_image() const;
239
240 /* Pass this result through to a target result, in which case, the target result becomes a proxy
241 * result with this result as its master result. This is done by making the target result a copy
242 * of this result, essentially having identical values between the two and consequently sharing
243 * the underlying texture. An exception is the initial reference count, whose value is retained
244 * and not copied, because it is a property of the original result and is needed for correctly
245 * resetting the result before the next evaluation. Additionally, this result is set to be the
246 * master of the target result, by setting the master member of the target. Finally, the
247 * reference count of the result is incremented by the reference count of the target result. See
248 * the discussion above for more information. */
249 void pass_through(Result &target);
250
251 /* Steal the allocated data from the given source result and assign it to this result, then
252 * remove any references to the data from the source result. It is assumed that:
253 *
254 * - Both results are of the same type.
255 * - This result is not allocated but the source result is allocated.
256 * - Neither of the results is a proxy one, that is, has a master result.
257 *
258 * This is different from proxy results and the pass_through mechanism in that it can be used on
259 * temporary results. This is most useful in multi-step compositor operations where some steps
260 * can be optional, in that case, intermediate results can be temporary results that can
261 * eventually be stolen by the actual output of the operation. See the uses of the method for
262 * a practical example of use. */
263 void steal_data(Result &source);
264
265 /* Set up the result to wrap an external GPU texture that is not allocated nor managed by the
266 * result. The is_external_ member will be set to true, the domain will be set to have the same
267 * size as the texture, and the texture will be set to the given texture. See the is_external_
268 * member for more information. The given texture should have the same format as the result and
269 * is assumed to have a lifetime that covers the evaluation of the compositor. */
270 void wrap_external(GPUTexture *texture);
271
272 /* Identical to GPU variant of wrap_external but wraps a float buffer instead. */
273 void wrap_external(float *texture, int2 size);
274
275 /* Identical to GPU variant of wrap_external but wraps an integer buffer instead. */
276 void wrap_external(int *texture, int2 size);
277
278 /* Sets the transformation of the domain of the result to the given transformation. */
279 void set_transformation(const float3x3 &transformation);
280
281 /* Transform the result by the given transformation. This effectively pre-multiply the given
282 * transformation by the current transformation of the domain of the result. */
283 void transform(const float3x3 &transformation);
284
285 /* Get a reference to the realization options of this result. See the RealizationOptions struct
286 * for more information. */
288
289 /* Returns the single value of the result. */
290 float get_float_value() const;
291 float4 get_vector_value() const;
292 float4 get_color_value() const;
293 float2 get_float2_value() const;
294 float3 get_float3_value() const;
295 int2 get_int2_value() const;
296
297 /* Returns the single value of the result, but returns a default value if the result is not a
298 * single value result. */
299 float get_float_value_default(float default_value) const;
300 float4 get_vector_value_default(const float4 &default_value) const;
301 float4 get_color_value_default(const float4 &default_value) const;
302 float2 get_float2_value_default(const float2 &default_value) const;
303 float3 get_float3_value_default(const float3 &default_value) const;
304 int2 get_int2_value_default(const int2 &default_value) const;
305
306 /* Set the single value of the result to the given value, which also involves setting the single
307 * pixel in the texture to that value. See the class description for more information. */
308 void set_float_value(float value);
309 void set_vector_value(const float4 &value);
310 void set_color_value(const float4 &value);
311 void set_float2_value(const float2 &value);
312 void set_float3_value(const float3 &value);
313 void set_int2_value(const int2 &value);
314
315 /* Set the value of initial_reference_count_, see that member for more details. This should be
316 * called after constructing the result to declare the number of operations that needs it. */
318
319 /* Reset the result to prepare it for a new evaluation. This should be called before evaluating
320 * the operation that computes this result. Keep the type, precision, context, and initial
321 * reference count, and rest all other members to their default value. Finally, set the value of
322 * reference_count_ to the value of initial_reference_count_ since reference_count_ may have
323 * already been decremented to zero in a previous evaluation. */
324 void reset();
325
326 /* Increment the reference count of the result by the given count. If this result have a master
327 * result, the reference count of the master result is incremented instead. */
328 void increment_reference_count(int count = 1);
329
330 /* Decrement the reference count of the result and free its texture if the reference count
331 * reaches zero. This should be called when an operation that used this result no longer needs
332 * it. If this result have a master result, the master result is released instead. */
333 void release();
334
335 /* Returns true if this result should be computed and false otherwise. The result should be
336 * computed if its reference count is not zero, that is, its result is used by at least one
337 * operation. */
338 bool should_compute();
339
340 /* Returns the type of the result. */
341 ResultType type() const;
342
343 /* Returns the precision of the result. */
345
346 /* Sets the type of the result. */
347 void set_type(ResultType type);
348
349 /* Sets the precision of the result. */
351
352 /* Returns true if the result is a single value and false of it is a texture. */
353 bool is_single_value() const;
354
355 /* Returns true if the result is allocated. */
356 bool is_allocated() const;
357
358 /* Returns the reference count of the result. If this result have a master result, then the
359 * reference count of the master result is returned instead. */
360 int reference_count() const;
361
362 /* Returns a reference to the domain of the result. See the Domain class. */
363 const Domain &domain() const;
364
365 /* Returns a reference to the allocate float data. */
366 float *float_texture();
367
368 /* Loads the float pixel at the given texel coordinates and returns it in a float4. If the number
369 * of channels in the result are less than 4, then the rest of the returned float4 will have its
370 * vales initialized as follows: float4(0, 0, 0, 1). This is similar to how the texelFetch
371 * function in GLSL works. If the result is a single value result, then that single value is
372 * returned for all texel coordinates. */
373 float4 load_pixel(const int2 &texel) const;
374
375 /* Stores the given pixel value in the float pixel at the given texel coordinates. While a float4
376 * is given, only the number of channels of the result will be written, while the rest of the
377 * float4 will be ignored. This is similar to how the imageStore function in GLSL works. */
378 void store_pixel(const int2 &texel, const float4 &pixel_value);
379
380 private:
381 /* Allocates the texture data for the given size, either on the GPU or CPU based on the result's
382 * context. See the allocate_texture method for information about the from_pool argument. */
383 void allocate_data(int2 size, bool from_pool);
384
385 /* Computes the number of channels of the result based on its type. */
386 int64_t channels_count() const;
387
388 /* Get a pointer to the float pixel at the given texel position. */
389 float *get_float_pixel(const int2 &texel) const;
390
391 /* Copy the float pixel from the source pointer to the target pointer. */
392 void copy_pixel(float *target, const float *source) const;
393};
394
395} // namespace blender::realtime_compositor
eGPUTextureFormat
struct GPUShader GPUShader
float get_float_value_default(float default_value) const
Definition result.cc:413
float4 load_pixel(const int2 &texel) const
Definition result.cc:723
void set_int2_value(const int2 &value)
Definition result.cc:567
void wrap_external(GPUTexture *texture)
Definition result.cc:321
ResultPrecision precision() const
Definition result.cc:665
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
Definition result.cc:264
void pass_through(Result &target)
Definition result.cc:289
void set_float3_value(const float3 &value)
Definition result.cc:547
eGPUTextureFormat get_gpu_texture_format() const
Definition result.cc:199
float3 get_float3_value_default(const float3 &default_value) const
Definition result.cc:449
const Domain & domain() const
Definition result.cc:712
void set_precision(ResultPrecision precision)
Definition result.cc:677
float4 get_vector_value_default(const float4 &default_value) const
Definition result.cc:422
void transform(const float3x3 &transformation)
Definition result.cc:361
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:29
void set_transformation(const float3x3 &transformation)
Definition result.cc:356
float4 get_color_value_default(const float4 &default_value) const
Definition result.cc:431
float2 get_float2_value_default(const float2 &default_value) const
Definition result.cc:440
void store_pixel(const int2 &texel, const float4 &pixel_value)
Definition result.cc:735
void set_float_value(float value)
Definition result.cc:467
void set_float2_value(const float2 &value)
Definition result.cc:527
void increment_reference_count(int count=1)
Definition result.cc:600
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:204
void set_type(ResultType type)
Definition result.cc:670
int2 get_int2_value_default(const int2 &default_value) const
Definition result.cc:458
void set_vector_value(const float4 &value)
Definition result.cc:487
void steal_data(Result &source)
Definition result.cc:304
void set_initial_reference_count(int count)
Definition result.cc:587
void set_color_value(const float4 &value)
Definition result.cc:507
RealizationOptions & get_realization_options()
Definition result.cc:366
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:253
static ResultType float_type(const int channels_count)
Definition result.cc:174
int count
format
VecBase< float, 4 > float4
__int64 int64_t
Definition stdint.h:89
unsigned char uint8_t
Definition stdint.h:78