Blender V4.5
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
7#include <cstdint>
8#include <type_traits>
9#include <utility>
10#include <variant>
11
12#include "BLI_assert.h"
13#include "BLI_cpp_type.hh"
15#include "BLI_generic_span.hh"
16#include "BLI_math_interp.hh"
18#include "BLI_math_vector.h"
19#include "BLI_math_vector.hh"
21#include "BLI_memory_utils.hh"
22#include "BLI_utildefines.h"
23
24#include "GPU_shader.hh"
25#include "GPU_texture.hh"
26
27#include "COM_domain.hh"
28#include "COM_meta_data.hh"
29
30namespace blender::compositor {
31
32class Context;
34
35/* Make sure to update the format related static methods in the Result class. */
46
47/* The precision of the data. CPU data is always stored using full precision at the moment. */
48enum class ResultPrecision : uint8_t {
51};
52
53/* The type of storage used to hold the result data. */
54enum class ResultStorageType : uint8_t {
55 /* Stored as a GPUTexture on the GPU. */
57 /* Stored as a buffer on the CPU and wrapped in a GMutableSpan. */
59};
60
61/* ------------------------------------------------------------------------------------------------
62 * Result
63 *
64 * A result represents the computed value of an output of an operation. A result can either
65 * represent an image or a single value. A result is typed, and can be of types like color, vector,
66 * or float. Single value results are stored in 1x1 textures to make them easily accessible in
67 * shaders. But the same value is also stored in the value union member of the result for any
68 * host-side processing. The GPU texture of the result can either be allocated from the texture
69 * pool of the context referenced by the result or it can be allocated directly from the GPU
70 * module, see the allocation method for more information.
71 *
72 * Results are reference counted and their data are released once their reference count reaches
73 * zero. After constructing a result, the set_reference_count method is called to declare the
74 * number of operations that needs this result. Once each operation that needs the result no longer
75 * needs it, the release method is called and the reference count is decremented, until it reaches
76 * zero, where the result's data is then released.
77 *
78 * A result not only represents an image, but also the area it occupies in the virtual compositing
79 * space. This area is called the Domain of the result, see the discussion in COM_domain.hh for
80 * more information.
81 *
82 * Allocated data of results can be shared by multiple results, this is achieved by tracking an
83 * extra reference count for data data_reference_count_, which is heap allocated along with the
84 * data, and shared by all results that share the same data. This reference count is incremented
85 * every time the data is shared by a call to the share_data method, and decremented during
86 * freeing, where the data is only freed if the reference count is 1, that is, no longer shared.
87 *
88 * A result can wrap external data that is not allocated nor managed by the result. This is set up
89 * by a call to the wrap_external method. In that case, when the reference count eventually reach
90 * zero, the data will not be freed.
91 *
92 * A result may store resources that are computed and cached in case they are needed by multiple
93 * operations. Those are called Derived Resources and can be accessed using the derived_resources
94 * method. */
95class Result {
96 private:
97 /* The context that the result was created within, this should be initialized during
98 * construction. */
99 Context *context_ = nullptr;
100 /* The base type of the result's image or single value. */
102 /* The precision of the result's data. Only relevant for GPU textures. CPU buffers and single
103 * values are always stored using full precision. */
105 /* If true, the result is a single value, otherwise, the result is an image. */
106 bool is_single_value_ = false;
107 /* The type of storage used to hold the data. Used to correctly interpret the data union. */
109 /* Stores the result's pixel data, either stored in a GPU texture or a buffer that is wrapped in
110 * a GMutableSpan on CPU. This will represent a 1x1 image if the result is a single value, the
111 * value of which will be identical to that of the value member. See class description for more
112 * information. */
113 union {
114 GPUTexture *gpu_texture_ = nullptr;
116 };
117 /* The number of users that currently needs this result. Operations initializes this by calling
118 * the set_reference_count method before evaluation. Once each operation that needs the result no
119 * longer needs it, the release method is called and the reference count is decremented, until it
120 * reaches zero, where the result's data is then released. */
121 int reference_count_ = 1;
122 /* Allocated result data can be shared by multiple results by calling the share_data method. This
123 * member stores the number of results that share the data. This is heap allocated and have the
124 * same lifetime as allocated data, that's because this reference count is shared by all results
125 * that share the same data. Unlike the result's reference count, the data is freed if the count
126 * becomes 1, that is, data is no longer shared with some other result. This is nullptr if the
127 * data is external. */
128 int *data_reference_count_ = nullptr;
129 /* If the result is a single value, this member stores the value of the result, the value of
130 * which will be identical to that stored in the data_ member. The active variant member depends
131 * on the type of the result. This member is uninitialized and should not be used if the result
132 * is not a single value. */
133 std::variant<float, float2, float3, float4, int32_t, int2, bool> single_value_ = 0.0f;
134 /* The domain of the result. This only matters if the result was not a single value. See the
135 * discussion in COM_domain.hh for more information. */
136 Domain domain_ = Domain::identity();
137 /* If true, then the result wraps external data that is not allocated nor managed by the result.
138 * This is set up by a call to the wrap_external method. In that case, when the reference count
139 * eventually reach zero, the data will not be freed. */
140 bool is_external_ = false;
141 /* If true, the GPU texture that holds the data was allocated from the texture pool of the
142 * context and should be released back into the pool instead of being freed. For CPU storage,
143 * this is irrelevant. */
144 bool is_from_pool_ = false;
145 /* Stores resources that are derived from this result. Lazily allocated if needed. See the class
146 * description for more information. */
147 DerivedResources *derived_resources_ = nullptr;
148
149 public:
150 /* Stores extra information about the result such as image meta data that can eventually be
151 * written to file. */
153
154 /* Construct a result within the given context. */
155 Result(Context &context);
156
157 /* Construct a result of the given type and precision within the given context. */
159
160 /* Construct a result of an appropriate type and precision based on the given GPU texture format
161 * within the given context. */
163
164 /* Returns the appropriate GPU texture format based on the given result type and precision. A
165 * special case is given to ResultType::Float3, because 3-component textures can't be used as
166 * write targets in shaders, so we need to allocate 4-component textures for them, and ignore the
167 * fourth channel during processing. */
169
170 /* Returns the GPU texture format that corresponds to the give one, but whose precision is the
171 * given precision. */
173
174 /* Returns the precision of the given GPU texture format. */
176
177 /* Returns the type of the given GPU texture format. */
179
180 /* Returns the float type of the result given the channels count. */
181 static ResultType float_type(const int channels_count);
182
183 /* Returns the CPP type corresponding to the given result type. */
184 static const CPPType &cpp_type(const ResultType type);
185
186 /* Returns a string representation of the given result type. */
187 static const char *type_name(const ResultType type);
188
189 /* Implicit conversion to the internal GPU texture. */
190 operator GPUTexture *() const;
191
192 /* Returns the CPP type of the result. */
193 const CPPType &get_cpp_type() const;
194
195 /* Returns the appropriate texture format based on the result's type and precision. This is
196 * identical to the gpu_texture_format static method. This will match the format of the allocated
197 * texture, with one exception. Results of type ResultType::Float3 that wrap external textures
198 * might hold a 3-component texture as opposed to a 4-component one, which would have been
199 * created by uploading data from CPU. */
201
202 /* Declare the result to be a texture result, allocate a texture of an appropriate type with
203 * the size of the given domain, and set the domain of the result to the given domain.
204 *
205 * If from_pool is true, the texture will be allocated from the texture pool of the context,
206 * otherwise, a new texture will be allocated. Pooling should not be used for persistent
207 * results that might span more than one evaluation, like cached resources. While pooling should
208 * be used for most other cases where the result will be allocated then later released in the
209 * same evaluation.
210 *
211 * If the context of the result uses GPU, then GPU allocation will be done, otherwise, CPU
212 * allocation will be done. */
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. The value is zero
217 * initialized. See class description for more information. */
219
220 /* Allocate a single value result whose value is zero. This is called for results whose value
221 * 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 /* Share the data of the given source result. For a source that wraps external results, this just
241 * shallow copies the data since it can be transparency shared. Otherwise, the data is also
242 * shallow copied and the data_reference_count_ is incremented to denote sharing. The source data
243 * is expect to be allocated and have the same type and precision as this result. */
244 void share_data(const Result &source);
245
246 /* Steal the allocated data from the given source result and assign it to this result, then
247 * remove any references to the data from the source result. It is assumed that:
248 *
249 * - Both results are of the same type.
250 * - This result is not allocated but the source result is allocated.
251 *
252 * This is most useful in multi-step compositor operations where some steps can be optional, in
253 * that case, intermediate results can be temporary results that can eventually be stolen by the
254 * actual output of the operation. See the uses of the method for a practical example of use. */
255 void steal_data(Result &source);
256
257 /* Set up the result to wrap an external GPU texture that is not allocated nor managed by the
258 * result. The is_external_ member will be set to true, the domain will be set to have the same
259 * size as the texture, and the texture will be set to the given texture. See the is_external_
260 * member for more information. The given texture should have the same format as the result and
261 * is assumed to have a lifetime that covers the evaluation of the compositor. */
262 void wrap_external(GPUTexture *texture);
263
264 /* Identical to GPU variant of wrap_external but wraps a CPU buffer instead. */
265 void wrap_external(void *data, int2 size);
266
267 /* Identical to GPU variant of wrap_external but wraps whatever the given result has instead. */
268 void wrap_external(const Result &result);
269
270 /* Sets the transformation of the domain of the result to the given transformation. */
271 void set_transformation(const float3x3 &transformation);
272
273 /* Transform the result by the given transformation. This effectively pre-multiply the given
274 * transformation by the current transformation of the domain of the result. */
275 void transform(const float3x3 &transformation);
276
277 /* Get a reference to the realization options of this result. See the RealizationOptions struct
278 * for more information. */
281
282 /* Set the value of reference_count_, see that member for more details. This should be called
283 * after constructing the result to declare the number of operations that needs it. */
284 void set_reference_count(int count);
285
286 /* Increment the reference count of the result by the given count. */
287 void increment_reference_count(int count = 1);
288
289 /* Decrement the reference count of the result by the given count. */
290 void decrement_reference_count(int count = 1);
291
292 /* Decrement the reference count of the result and free its data if it reaches zero. */
293 void release();
294
295 /* Frees the result data. If the result is not allocated, wraps external data, or shares data
296 * with some other result, then this does nothing. */
297 void free();
298
299 /* Returns true if this result should be computed and false otherwise. The result should be
300 * computed if its reference count is not zero, that is, its result is used by at least one
301 * operation. */
302 bool should_compute();
303
304 /* Returns a reference to the derived resources of the result, which is allocated if it was not
305 * allocated already. */
307
308 /* Returns the type of the result. */
309 ResultType type() const;
310
311 /* Returns the precision of the result. */
313
314 /* Sets the type of the result. */
316
317 /* Sets the precision of the result. */
319
320 /* Returns true if the result is a single value and false of it is an image. */
321 bool is_single_value() const;
322
323 /* Returns true if the result is allocated. */
324 bool is_allocated() const;
325
326 /* Returns the reference count of the result. */
327 int reference_count() const;
328
329 /* Returns a reference to the domain of the result. See the Domain class. */
330 const Domain &domain() const;
331
332 /* Computes the number of channels of the result based on its type. */
333 int64_t channels_count() const;
334
335 GPUTexture *gpu_texture() const;
336
337 GSpan cpu_data() const;
339
340 /* It is important to call update_single_value_data after adjusting the single value. See that
341 * method for more information. */
342 GPointer single_value() const;
344
345 /* Gets the single value stored in the result. Assumes the result stores a value of the given
346 * template type. */
347 template<typename T> const T &get_single_value() const;
348
349 /* Gets the single value stored in the result, if the result is not a single value, the given
350 * default value is returned. Assumes the result stores a value of the same type as the template
351 * type. */
352 template<typename T> T get_single_value_default(const T &default_value) const;
353
354 /* Sets the single value of the result to the given value, which also involves setting the single
355 * pixel in the image to that value. See the class description for more information. Assumes
356 * the result stores a value of the given template type. */
357 template<typename T> void set_single_value(const T &value);
358
359 /* Updates the single pixel in the image to the current single value in the result. This is
360 * called implicitly in the set_single_value method, but calling this explicitly is useful when
361 * the single value was adjusted through its data pointer returned by the single_value method.
362 * See the class description for more information. */
364
365 /* Loads the pixel at the given texel coordinates. Assumes the result stores a value of the given
366 * template type. If the CouldBeSingleValue template argument is true and the result is a single
367 * value result, then that single value is returned for all texel coordinates. */
368 template<typename T, bool CouldBeSingleValue = false> T load_pixel(const int2 &texel) const;
369
370 /* Identical to load_pixel but with extended boundary condition. */
371 template<typename T, bool CouldBeSingleValue = false>
372 T load_pixel_extended(const int2 &texel) const;
373
374 /* Identical to load_pixel but with a fallback value for out of bound access. */
375 template<typename T, bool CouldBeSingleValue = false>
376 T load_pixel_fallback(const int2 &texel, const T &fallback) const;
377
378 /* Identical to load_pixel but with zero boundary condition. */
379 template<typename T, bool CouldBeSingleValue = false> T load_pixel_zero(const int2 &texel) const;
380
381 /* Similar to load_pixel, but can load a result whose type is not known at compile time. If the
382 * number of channels in the result are less than 4, then the rest of the returned float4 will
383 * have its vales initialized as follows: float4(0, 0, 0, 1). This is similar to how the
384 * texelFetch function in GLSL works. */
385 float4 load_pixel_generic_type(const int2 &texel) const;
386
387 /* Stores the given pixel value in the pixel at the given texel coordinates. Assumes the result
388 * stores a value of the given template type. */
389 template<typename T> void store_pixel(const int2 &texel, const T &pixel_value);
390
391 /* Similar to store_pixel, but can write to a result whose types is not known at compile time.
392 * While a float4 is given, only the number of channels of the result will be written, while the
393 * rest of the float4 will be ignored. This is similar to how the imageStore function in GLSL
394 * works. */
395 void store_pixel_generic_type(const int2 &texel, const float4 &pixel_value);
396
397 /* Equivalent to the GLSL texture() function with nearest interpolation and zero boundary
398 * condition. The coordinates are thus expected to have half-pixels offsets. A float4 is always
399 * returned regardless of the number of channels of the buffer, the remaining channels will be
400 * initialized with the template float4(0, 0, 0, 1). */
401 float4 sample_nearest_zero(const float2 &coordinates) const;
402
403 /* Identical to sample_nearest_zero but with bilinear interpolation. */
404 float4 sample_bilinear_zero(const float2 &coordinates) const;
405
406 /* Identical to sample_nearest_zero but with extended boundary condition. */
407 float4 sample_nearest_extended(const float2 &coordinates) const;
408
409 /* Identical to sample_nearest_extended but with bilinear interpolation. */
410 float4 sample_bilinear_extended(const float2 &coordinates) const;
411
412 /* Identical to sample_nearest_extended but with cubic interpolation. */
413 float4 sample_cubic_extended(const float2 &coordinates) const;
414
415 float4 sample_nearest_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const;
416 float4 sample_bilinear_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const;
417 float4 sample_cubic_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const;
418
419 /* Equivalent to the GLSL textureGrad() function with EWA filtering and extended boundary
420 * condition. Note that extended boundaries only cover areas touched by the ellipses whose
421 * center is inside the image, other areas will be zero. The coordinates are thus expected to
422 * have half-pixels offsets. Only supports ResultType::Color. */
423 float4 sample_ewa_extended(const float2 &coordinates,
424 const float2 &x_gradient,
425 const float2 &y_gradient) const;
426
427 /* Identical to sample_ewa_extended but with zero boundary condition. */
428 float4 sample_ewa_zero(const float2 &coordinates,
429 const float2 &x_gradient,
430 const float2 &y_gradient) const;
431
432 private:
433 /* Allocates the image data for the given size, either on the GPU or CPU based on the result's
434 * context. See the allocate_texture method for information about the from_pool argument. */
435 void allocate_data(int2 size, bool from_pool);
436
437 /* Same as get_pixel_index but can be used when the type of the result is not known at compile
438 * time. */
439 int64_t get_pixel_index(const int2 &texel) const;
440};
441
442/* -------------------------------------------------------------------- */
443/* Inline Methods.
444 */
445
447{
448 return domain_;
449}
450
452{
453 switch (type_) {
455 case ResultType::Int:
456 case ResultType::Bool:
457 return 1;
459 case ResultType::Int2:
460 return 2;
462 return 3;
465 return 4;
466 }
467 return 4;
468}
469
471{
472 BLI_assert(storage_type_ == ResultStorageType::GPU);
473 return gpu_texture_;
474}
475
477{
478 BLI_assert(storage_type_ == ResultStorageType::CPU);
479 return cpu_data_;
480}
481
487
488template<typename T> BLI_INLINE_METHOD const T &Result::get_single_value() const
489{
491
492 return std::get<T>(single_value_);
493}
494
495template<typename T>
497{
498 if (this->is_single_value()) {
499 return this->get_single_value<T>();
500 }
501 return default_value;
502}
503
504template<typename T> BLI_INLINE_METHOD void Result::set_single_value(const T &value)
505{
506 BLI_assert(this->is_allocated());
508
509 single_value_ = value;
511}
512
513template<typename T, bool CouldBeSingleValue>
515{
516 if constexpr (CouldBeSingleValue) {
517 if (is_single_value_) {
518 return this->get_single_value<T>();
519 }
520 }
521 else {
522 BLI_assert(!this->is_single_value());
523 }
524
525 return this->cpu_data().typed<T>()[this->get_pixel_index(texel)];
526}
527
528template<typename T, bool CouldBeSingleValue>
530{
531 if constexpr (CouldBeSingleValue) {
532 if (is_single_value_) {
533 return this->get_single_value<T>();
534 }
535 }
536 else {
537 BLI_assert(!this->is_single_value());
538 }
539
540 const int2 clamped_texel = math::clamp(texel, int2(0), domain_.size - int2(1));
541 return this->cpu_data().typed<T>()[this->get_pixel_index(clamped_texel)];
542}
543
544template<typename T, bool CouldBeSingleValue>
545BLI_INLINE_METHOD T Result::load_pixel_fallback(const int2 &texel, const T &fallback) const
546{
547 if constexpr (CouldBeSingleValue) {
548 if (is_single_value_) {
549 return this->get_single_value<T>();
550 }
551 }
552 else {
553 BLI_assert(!this->is_single_value());
554 }
555
556 if (texel.x < 0 || texel.y < 0 || texel.x >= domain_.size.x || texel.y >= domain_.size.y) {
557 return fallback;
558 }
559
560 return this->cpu_data().typed<T>()[this->get_pixel_index(texel)];
561}
562
563template<typename T, bool CouldBeSingleValue>
565{
566 return this->load_pixel_fallback<T, CouldBeSingleValue>(texel, T(0));
567}
568
570{
571 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
572 if (is_single_value_) {
573 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
574 }
575 else {
576 this->get_cpp_type().copy_assign(this->cpu_data()[this->get_pixel_index(texel)], pixel_value);
577 }
578 return pixel_value;
579}
580
581template<typename T>
582BLI_INLINE_METHOD void Result::store_pixel(const int2 &texel, const T &pixel_value)
583{
584 this->cpu_data().typed<T>()[this->get_pixel_index(texel)] = pixel_value;
585}
586
588 const float4 &pixel_value)
589{
590 this->get_cpp_type().copy_assign(pixel_value, this->cpu_data()[this->get_pixel_index(texel)]);
591}
592
594{
595 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
596 if (is_single_value_) {
597 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
598 return pixel_value;
599 }
600
601 const int2 size = domain_.size;
602 const float2 texel_coordinates = coordinates * float2(size);
603
604 const float *buffer = static_cast<const float *>(this->cpu_data().data());
606 pixel_value,
607 size.x,
608 size.y,
609 this->channels_count(),
610 texel_coordinates.x,
611 texel_coordinates.y);
612 return pixel_value;
613}
614
616 bool wrap_x,
617 bool wrap_y) const
618{
619 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
620 if (is_single_value_) {
621 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
622 return pixel_value;
623 }
624
625 const int2 size = domain_.size;
626 const float2 texel_coordinates = coordinates * float2(size);
627
628 const float *buffer = static_cast<const float *>(this->cpu_data().data());
630 buffer,
631 pixel_value,
632 size.x,
633 size.y,
634 this->channels_count(),
635 texel_coordinates.x,
636 texel_coordinates.y,
639 return pixel_value;
640}
641
643 bool wrap_x,
644 bool wrap_y) const
645{
646 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
647 if (is_single_value_) {
648 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
649 return pixel_value;
650 }
651
652 const int2 size = domain_.size;
653 const float2 texel_coordinates = coordinates * float2(size) - 0.5f;
654
655 const float *buffer = static_cast<const float *>(this->cpu_data().data());
657 buffer,
658 pixel_value,
659 size.x,
660 size.y,
661 this->channels_count(),
662 texel_coordinates.x,
663 texel_coordinates.y,
666 return pixel_value;
667}
668
670 bool wrap_x,
671 bool wrap_y) const
672{
673 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
674 if (is_single_value_) {
675 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
676 return pixel_value;
677 }
678
679 const int2 size = domain_.size;
680 const float2 texel_coordinates = coordinates * float2(size) - 0.5f;
681
682 const float *buffer = static_cast<const float *>(this->cpu_data().data());
684 buffer,
685 pixel_value,
686 size.x,
687 size.y,
688 this->channels_count(),
689 texel_coordinates.x,
690 texel_coordinates.y,
693 return pixel_value;
694}
695
697{
698 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
699 if (is_single_value_) {
700 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
701 return pixel_value;
702 }
703
704 const int2 size = domain_.size;
705 const float2 texel_coordinates = (coordinates * float2(size)) - 0.5f;
706
707 const float *buffer = static_cast<const float *>(this->cpu_data().data());
709 pixel_value,
710 size.x,
711 size.y,
712 this->channels_count(),
713 texel_coordinates.x,
714 texel_coordinates.y);
715 return pixel_value;
716}
717
719{
720 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
721 if (is_single_value_) {
722 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
723 return pixel_value;
724 }
725
726 const int2 size = domain_.size;
727 const float2 texel_coordinates = coordinates * float2(size);
728
729 const float *buffer = static_cast<const float *>(this->cpu_data().data());
731 pixel_value,
732 size.x,
733 size.y,
734 this->channels_count(),
735 texel_coordinates.x,
736 texel_coordinates.y);
737 return pixel_value;
738}
739
741{
742 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
743 if (is_single_value_) {
744 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
745 return pixel_value;
746 }
747
748 const int2 size = domain_.size;
749 const float2 texel_coordinates = (coordinates * float2(size)) - 0.5f;
750
751 const float *buffer = static_cast<const float *>(this->cpu_data().data());
753 pixel_value,
754 size.x,
755 size.y,
756 this->channels_count(),
757 texel_coordinates.x,
758 texel_coordinates.y);
759 return pixel_value;
760}
761
763{
764 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
765 if (is_single_value_) {
766 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
767 return pixel_value;
768 }
769
770 const int2 size = domain_.size;
771 const float2 texel_coordinates = (coordinates * float2(size)) - 0.5f;
772
773 const float *buffer = static_cast<const float *>(this->cpu_data().data());
775 pixel_value,
776 size.x,
777 size.y,
778 this->channels_count(),
779 texel_coordinates.x,
780 texel_coordinates.y);
781 return pixel_value;
782}
783
788static void sample_ewa_extended_read_callback(void *userdata, int x, int y, float result[4])
789{
790 const Result *input = static_cast<const Result *>(userdata);
791 const float4 sampled_result = input->load_pixel_extended<float4>(int2(x, y));
792 copy_v4_v4(result, sampled_result);
793}
794
796 const float2 &x_gradient,
797 const float2 &y_gradient) const
798{
800
801 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
802 if (is_single_value_) {
803 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
804 return pixel_value;
805 }
806
807 const int2 size = domain_.size;
809 size.y,
810 false,
811 true,
812 coordinates,
813 x_gradient,
814 y_gradient,
816 const_cast<Result *>(this),
817 pixel_value);
818 return pixel_value;
819}
820
825static void sample_ewa_zero_read_callback(void *userdata, int x, int y, float result[4])
826{
827 const Result *input = static_cast<const Result *>(userdata);
828 const float4 sampled_result = input->load_pixel_zero<float4>(int2(x, y));
829 copy_v4_v4(result, sampled_result);
830}
831
833 const float2 &x_gradient,
834 const float2 &y_gradient) const
835{
837
838 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
839 if (is_single_value_) {
840 this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value);
841 return pixel_value;
842 }
843
844 const int2 size = domain_.size;
846 size.y,
847 false,
848 true,
849 coordinates,
850 x_gradient,
851 y_gradient,
853 const_cast<Result *>(this),
854 pixel_value);
855 return pixel_value;
856}
857
858BLI_INLINE_METHOD int64_t Result::get_pixel_index(const int2 &texel) const
859{
860 BLI_assert(!is_single_value_);
861 BLI_assert(this->is_allocated());
862 BLI_assert(texel.x >= 0 && texel.y >= 0 && texel.x < domain_.size.x && texel.y < domain_.size.y);
863 return int64_t(texel.y) * domain_.size.x + texel.x;
864}
865
866} // namespace blender::compositor
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE_METHOD
void BLI_ewa_filter(int width, int height, bool intpol, bool use_alpha, const float uv[2], const float du[2], const float dv[2], ewa_filter_read_pixel_cb read_pixel_cb, void *userdata, float result[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
float[4] Color
eGPUTextureFormat
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
void copy_assign(const void *src, void *dst) const
Span< T > typed() const
const void * data() const
static Domain identity()
Definition domain.cc:25
float4 sample_nearest_extended(const float2 &coordinates) const
void decrement_reference_count(int count=1)
Definition result.cc:514
float4 sample_cubic_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const
void share_data(const Result &source)
Definition result.cc:401
RealizationOptions & get_realization_options()
Definition result.cc:494
eGPUTextureFormat get_gpu_texture_format() const
Definition result.cc:304
float4 sample_nearest_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const
const CPPType & get_cpp_type() const
Definition result.cc:299
T get_single_value_default(const T &default_value) const
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:309
void store_pixel(const int2 &texel, const T &pixel_value)
int reference_count() const
Definition result.cc:642
static ResultPrecision precision(eGPUTextureFormat format)
Definition result.cc:166
float4 sample_nearest_zero(const float2 &coordinates) const
void unbind_as_texture() const
Definition result.cc:389
static ResultType type(eGPUTextureFormat format)
Definition result.cc:194
void bind_as_texture(GPUShader *shader, const char *texture_name) const
Definition result.cc:365
static const char * type_name(const ResultType type)
Definition result.cc:269
float4 sample_ewa_extended(const float2 &coordinates, const float2 &x_gradient, const float2 &y_gradient) const
bool is_allocated() const
Definition result.cc:630
float4 sample_cubic_extended(const float2 &coordinates) const
void set_transformation(const float3x3 &transformation)
Definition result.cc:484
T load_pixel_zero(const int2 &texel) const
float4 sample_bilinear_zero(const float2 &coordinates) const
GPointer single_value() const
Definition result.cc:647
void set_single_value(const T &value)
ResultPrecision precision() const
Definition result.cc:606
float4 sample_bilinear_wrap(const float2 &coordinates, bool wrap_x, bool wrap_y) const
ResultType type() const
Definition result.cc:601
void store_pixel_generic_type(const int2 &texel, const float4 &pixel_value)
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:42
T load_pixel_extended(const int2 &texel) const
static ResultType float_type(const int channels_count)
Definition result.cc:225
void set_precision(ResultPrecision precision)
Definition result.cc:618
void transform(const float3x3 &transformation)
Definition result.cc:489
void wrap_external(GPUTexture *texture)
Definition result.cc:448
GPUTexture * gpu_texture() const
void increment_reference_count(int count=1)
Definition result.cc:509
const Domain & domain() const
static const CPPType & cpp_type(const ResultType type)
Definition result.cc:244
T load_pixel(const int2 &texel) const
int64_t channels_count() const
void bind_as_image(GPUShader *shader, const char *image_name, bool read=false) const
Definition result.cc:376
void unbind_as_image() const
Definition result.cc:395
T load_pixel_fallback(const int2 &texel, const T &fallback) const
Result(Context &context)
Definition result.cc:30
float4 sample_ewa_zero(const float2 &coordinates, const float2 &x_gradient, const float2 &y_gradient) const
DerivedResources & derived_resources()
Definition result.cc:593
float4 sample_bilinear_extended(const float2 &coordinates) const
float4 load_pixel_generic_type(const int2 &texel) const
void set_reference_count(int count)
Definition result.cc:504
bool is_single_value() const
Definition result.cc:625
void steal_data(Result &source)
Definition result.cc:418
const T & get_single_value() const
void set_type(ResultType type)
Definition result.cc:611
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define input
#define this
int count
format
#define T
static void sample_ewa_extended_read_callback(void *userdata, int x, int y, float result[4])
static void sample_ewa_zero_read_callback(void *userdata, int x, int y, float result[4])
T clamp(const T &a, const T &min, const T &max)
void interpolate_nearest_fl(const float *buffer, float *output, int width, int height, int components, float u, float v)
void interpolate_nearest_border_fl(const float *buffer, float *output, int width, int height, int components, float u, float v)
float4 interpolate_bilinear_border_fl(const float *buffer, int width, int height, float u, float v)
float4 interpolate_cubic_bspline_fl(const float *buffer, int width, int height, float u, float v)
void interpolate_nearest_wrapmode_fl(const float *buffer, float *output, int width, int height, int components, float u, float v, InterpWrapMode wrap_u, InterpWrapMode wrap_v)
float4 interpolate_bilinear_fl(const float *buffer, int width, int height, float u, float v)
void interpolate_bilinear_wrapmode_fl(const float *buffer, float *output, int width, int height, int components, float u, float v, InterpWrapMode wrap_u, InterpWrapMode wrap_v)
void interpolate_cubic_bspline_wrapmode_fl(const float *buffer, float *output, int width, int height, int components, float u, float v, InterpWrapMode wrap_u, InterpWrapMode wrap_v)
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
MatBase< float, 3, 3 > float3x3
read