Blender V4.3
result.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 "MEM_guardedalloc.h"
6
7#include "BLI_assert.h"
9#include "BLI_math_vector.h"
11
12#include "GPU_shader.hh"
13#include "GPU_state.hh"
14#include "GPU_texture.hh"
15
16#include "COM_context.hh"
17#include "COM_domain.hh"
18#include "COM_result.hh"
19
21
22Result::Result(Context &context) : context_(&context) {}
23
25 : context_(&context), type_(type), precision_(precision)
26{
27}
28
30{
31 switch (precision) {
33 switch (type) {
35 return GPU_R16F;
38 return GPU_RGBA16F;
40 return GPU_RG16F;
42 return GPU_RGB16F;
44 return GPU_RG16I;
45 }
46 break;
48 switch (type) {
50 return GPU_R32F;
53 return GPU_RGBA32F;
55 return GPU_RG32F;
57 return GPU_RGB32F;
59 return GPU_RG32I;
60 }
61 break;
62 }
63
65 return GPU_RGBA32F;
66}
67
69{
70 switch (precision) {
72 switch (format) {
73 /* Already half precision, return the input format. */
74 case GPU_R16F:
75 case GPU_RG16F:
76 case GPU_RGB16F:
77 case GPU_RGBA16F:
78 case GPU_RG16I:
79 return format;
80
81 case GPU_R32F:
82 return GPU_R16F;
83 case GPU_RG32F:
84 return GPU_RG16F;
85 case GPU_RGB32F:
86 return GPU_RGB16F;
87 case GPU_RGBA32F:
88 return GPU_RGBA16F;
89 case GPU_RG32I:
90 return GPU_RG16I;
91 default:
92 break;
93 }
94 break;
96 switch (format) {
97 /* Already full precision, return the input format. */
98 case GPU_R32F:
99 case GPU_RG32F:
100 case GPU_RGB32F:
101 case GPU_RGBA32F:
102 case GPU_RG32I:
103 return format;
104
105 case GPU_R16F:
106 return GPU_R32F;
107 case GPU_RG16F:
108 return GPU_RG32F;
109 case GPU_RGB16F:
110 return GPU_RGB32F;
111 case GPU_RGBA16F:
112 return GPU_RGBA32F;
113 case GPU_RG16I:
114 return GPU_RG32I;
115 default:
116 break;
117 }
118 break;
119 }
120
122 return format;
123}
124
126{
127 switch (format) {
128 case GPU_R16F:
129 case GPU_RG16F:
130 case GPU_RGB16F:
131 case GPU_RGBA16F:
132 case GPU_RG16I:
134 case GPU_R32F:
135 case GPU_RG32F:
136 case GPU_RGB32F:
137 case GPU_RGBA32F:
138 case GPU_RG32I:
140 default:
141 break;
142 }
143
146}
147
149{
150 switch (format) {
151 case GPU_R16F:
152 case GPU_R32F:
153 return ResultType::Float;
154 case GPU_RG16F:
155 case GPU_RG32F:
156 return ResultType::Float2;
157 case GPU_RGB16F:
158 case GPU_RGB32F:
159 return ResultType::Float3;
160 case GPU_RGBA16F:
161 case GPU_RGBA32F:
162 return ResultType::Color;
163 case GPU_RG16I:
164 case GPU_RG32I:
165 return ResultType::Int2;
166 default:
167 break;
168 }
169
171 return ResultType::Color;
172}
173
174ResultType Result::float_type(const int channels_count)
175{
176 switch (channels_count) {
177 case 1:
178 return ResultType::Float;
179 case 2:
180 return ResultType::Float2;
181 case 3:
182 return ResultType::Float3;
183 case 4:
184 return ResultType::Color;
185 default:
186 break;
187 }
188
190 return ResultType::Color;
191}
192
193Result::operator GPUTexture *() const
194{
195 BLI_assert(storage_type_ == ResultStorageType::GPU);
196 return gpu_texture_;
197}
198
200{
201 return Result::gpu_texture_format(type_, precision_);
202}
203
204void Result::allocate_texture(Domain domain, bool from_pool)
205{
206 /* The result is not actually needed, so allocate a dummy single value texture instead. See the
207 * method description for more information. */
208 if (!should_compute()) {
211 return;
212 }
213
214 is_single_value_ = false;
215 this->allocate_data(domain.size, from_pool);
216 domain_ = domain;
217}
218
220{
221 /* Single values are stored in 1x1 textures as well as the single value members. Further, they
222 * are always allocated from the pool. */
223 is_single_value_ = true;
224 this->allocate_data(int2(1), true);
225 domain_ = Domain::identity();
226}
227
229{
231 switch (type_) {
233 set_float_value(0.0f);
234 break;
237 break;
239 set_color_value(float4(0.0f));
240 break;
243 break;
246 break;
247 case ResultType::Int2:
249 break;
250 }
251}
252
253void Result::bind_as_texture(GPUShader *shader, const char *texture_name) const
254{
255 BLI_assert(storage_type_ == ResultStorageType::GPU);
256
257 /* Make sure any prior writes to the texture are reflected before reading from it. */
259
260 const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
261 GPU_texture_bind(gpu_texture_, texture_image_unit);
262}
263
264void Result::bind_as_image(GPUShader *shader, const char *image_name, bool read) const
265{
266 BLI_assert(storage_type_ == ResultStorageType::GPU);
267
268 /* Make sure any prior writes to the texture are reflected before reading from it. */
269 if (read) {
271 }
272
273 const int image_unit = GPU_shader_get_sampler_binding(shader, image_name);
275}
276
282
288
290{
291 /* Increment the reference count of the master by the original reference count of the target. */
292 increment_reference_count(target.reference_count());
293
294 /* Make the target an exact copy of this result, but keep the initial reference count, as this is
295 * a property of the original result and is needed for correctly resetting the result before the
296 * next evaluation. */
297 const int initial_reference_count = target.initial_reference_count_;
298 target = *this;
299 target.initial_reference_count_ = initial_reference_count;
300
301 target.master_ = this;
302}
303
305{
306 BLI_assert(type_ == source.type_);
307 BLI_assert(precision_ == source.precision_);
308 BLI_assert(!this->is_allocated() && source.is_allocated());
309 BLI_assert(master_ == nullptr && source.master_ == nullptr);
310
311 /* Overwrite everything except reference counts. */
312 const int reference_count = reference_count_;
313 const int initial_reference_count = initial_reference_count_;
314 *this = source;
315 reference_count_ = reference_count;
316 initial_reference_count_ = initial_reference_count;
317
318 source.reset();
319}
320
321void Result::wrap_external(GPUTexture *texture)
322{
324 BLI_assert(!this->is_allocated());
325 BLI_assert(!master_);
326
328 storage_type_ = ResultStorageType::GPU;
329 is_external_ = true;
330 is_single_value_ = false;
331 domain_ = Domain(int2(GPU_texture_width(texture), GPU_texture_height(texture)));
332}
333
334void Result::wrap_external(float *texture, int2 size)
335{
336 BLI_assert(!this->is_allocated());
337 BLI_assert(!master_);
338
340 storage_type_ = ResultStorageType::FloatCPU;
341 is_external_ = true;
342 domain_ = Domain(size);
343}
344
345void Result::wrap_external(int *texture, int2 size)
346{
347 BLI_assert(!this->is_allocated());
348 BLI_assert(!master_);
349
351 storage_type_ = ResultStorageType::IntegerCPU;
352 is_external_ = true;
353 domain_ = Domain(size);
354}
355
356void Result::set_transformation(const float3x3 &transformation)
357{
358 domain_.transformation = transformation;
359}
360
361void Result::transform(const float3x3 &transformation)
362{
363 domain_.transform(transformation);
364}
365
370
372{
374 BLI_assert(is_single_value_);
375 return float_value_;
376}
377
379{
381 BLI_assert(is_single_value_);
382 return vector_value_;
383}
384
386{
388 BLI_assert(is_single_value_);
389 return color_value_;
390}
391
393{
395 BLI_assert(is_single_value_);
396 return float2_value_;
397}
398
400{
402 BLI_assert(is_single_value_);
403 return float3_value_;
404}
405
407{
409 BLI_assert(is_single_value_);
410 return int2_value_;
411}
412
413float Result::get_float_value_default(float default_value) const
414{
416 if (is_single_value()) {
417 return get_float_value();
418 }
419 return default_value;
420}
421
423{
425 if (is_single_value()) {
426 return get_vector_value();
427 }
428 return default_value;
429}
430
432{
434 if (is_single_value()) {
435 return get_color_value();
436 }
437 return default_value;
438}
439
441{
443 if (is_single_value()) {
444 return get_float2_value();
445 }
446 return default_value;
447}
448
450{
452 if (is_single_value()) {
453 return get_float3_value();
454 }
455 return default_value;
456}
457
458int2 Result::get_int2_value_default(const int2 &default_value) const
459{
461 if (is_single_value()) {
462 return get_int2_value();
463 }
464 return default_value;
465}
466
467void Result::set_float_value(float value)
468{
470 BLI_assert(is_single_value_);
471 BLI_assert(this->is_allocated());
472
473 float_value_ = value;
474 switch (storage_type_) {
477 break;
479 *float_texture_ = value;
480 break;
483 break;
484 }
485}
486
488{
490 BLI_assert(is_single_value_);
491 BLI_assert(this->is_allocated());
492
493 vector_value_ = value;
494 switch (storage_type_) {
497 break;
500 break;
503 break;
504 }
505}
506
508{
510 BLI_assert(is_single_value_);
511 BLI_assert(this->is_allocated());
512
513 color_value_ = value;
514 switch (storage_type_) {
517 break;
520 break;
523 break;
524 }
525}
526
528{
530 BLI_assert(is_single_value_);
531 BLI_assert(this->is_allocated());
532
533 float2_value_ = value;
534 switch (storage_type_) {
537 break;
540 break;
543 break;
544 }
545}
546
548{
550 BLI_assert(is_single_value_);
551 BLI_assert(this->is_allocated());
552
553 float3_value_ = value;
554 switch (storage_type_) {
557 break;
560 break;
563 break;
564 }
565}
566
567void Result::set_int2_value(const int2 &value)
568{
570 BLI_assert(is_single_value_);
571 BLI_assert(this->is_allocated());
572
573 int2_value_ = value;
574 switch (storage_type_) {
577 break;
580 break;
583 break;
584 }
585}
586
588{
589 initial_reference_count_ = count;
590}
591
593{
594 const int initial_reference_count = initial_reference_count_;
595 *this = Result(*context_, type_, precision_);
596 initial_reference_count_ = initial_reference_count;
597 reference_count_ = initial_reference_count;
598}
599
601{
602 /* If there is a master result, increment its reference count instead. */
603 if (master_) {
605 return;
606 }
607
608 reference_count_ += count;
609}
610
612{
613 /* If there is a master result, release it instead. */
614 if (master_) {
615 master_->release();
616 return;
617 }
618
619 /* Decrement the reference count, and if it reaches zero, release the texture back into the
620 * texture pool. */
621 reference_count_--;
622 if (reference_count_ != 0) {
623 return;
624 }
625
626 if (is_external_) {
627 return;
628 }
629
630 if (!this->is_allocated()) {
631 return;
632 }
633
634 switch (storage_type_) {
636 if (is_from_pool_) {
637 context_->texture_pool().release(gpu_texture_);
638 }
639 else {
641 }
642 gpu_texture_ = nullptr;
643 break;
646 float_texture_ = nullptr;
647 break;
650 integer_texture_ = nullptr;
651 break;
652 }
653}
654
656{
657 return initial_reference_count_ != 0;
658}
659
661{
662 return type_;
663}
664
666{
667 return precision_;
668}
669
671{
672 /* Changing the type can only be done if it wasn't allocated yet. */
673 BLI_assert(!this->is_allocated());
674 type_ = type;
675}
676
678{
679 /* Changing the precision can only be done if it wasn't allocated yet. */
680 BLI_assert(!this->is_allocated());
681 precision_ = precision;
682}
683
685{
686 return is_single_value_;
687}
688
690{
691 switch (storage_type_) {
693 return gpu_texture_ != nullptr;
695 return float_texture_ != nullptr;
697 return integer_texture_ != nullptr;
698 }
699
700 return false;
701}
702
704{
705 /* If there is a master result, return its reference count instead. */
706 if (master_) {
707 return master_->reference_count();
708 }
709 return reference_count_;
710}
711
712const Domain &Result::domain() const
713{
714 return domain_;
715}
716
718{
719 BLI_assert(storage_type_ == ResultStorageType::FloatCPU);
720 return float_texture_;
721}
722
723float4 Result::load_pixel(const int2 &texel) const
724{
725 float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f);
726 if (is_single_value_) {
727 this->copy_pixel(pixel_value, float_texture_);
728 }
729 else {
730 this->copy_pixel(pixel_value, this->get_float_pixel(texel));
731 }
732 return pixel_value;
733}
734
735void Result::store_pixel(const int2 &texel, const float4 &pixel_value)
736{
737 this->copy_pixel(this->get_float_pixel(texel), pixel_value);
738}
739
740void Result::allocate_data(int2 size, bool from_pool)
741{
742 if (context_->use_gpu()) {
743 is_from_pool_ = from_pool;
744 if (from_pool) {
745 gpu_texture_ = context_->texture_pool().acquire(size, this->get_gpu_texture_format());
746 }
747 else {
749 size.x,
750 size.y,
751 1,
752 this->get_gpu_texture_format(),
754 nullptr);
755 }
756 }
757 else {
758 switch (type_) {
764 float_texture_ = static_cast<float *>(MEM_malloc_arrayN(
765 int64_t(size.x) * int64_t(size.y), this->channels_count() * sizeof(float), __func__));
766 storage_type_ = ResultStorageType::FloatCPU;
767 break;
768 case ResultType::Int2:
769 integer_texture_ = static_cast<int *>(MEM_malloc_arrayN(
770 int64_t(size.x) * int64_t(size.y), this->channels_count() * sizeof(int), __func__));
771 storage_type_ = ResultStorageType::IntegerCPU;
772 break;
773 }
774 }
775}
776
777int64_t Result::channels_count() const
778{
779 switch (type_) {
781 return 1;
783 case ResultType::Int2:
784 return 2;
786 return 3;
789 return 4;
790 }
791 return 4;
792}
793
794float *Result::get_float_pixel(const int2 &texel) const
795{
796 return float_texture_ + (texel.y * domain_.size.x + texel.x) * this->channels_count();
797}
798
799void Result::copy_pixel(float *target, const float *source) const
800{
801 switch (type_) {
803 *target = *source;
804 break;
806 case ResultType::Int2:
807 copy_v2_v2(target, source);
808 break;
810 copy_v3_v3(target, source);
811 break;
814 copy_v4_v4(target, source);
815 break;
816 }
817}
818
819} // namespace blender::realtime_compositor
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:374
@ GPU_BARRIER_TEXTURE_FETCH
Definition GPU_state.hh:37
@ GPU_BARRIER_SHADER_IMAGE_ACCESS
Definition GPU_state.hh:35
int GPU_texture_height(const GPUTexture *texture)
void GPU_texture_bind(GPUTexture *texture, int unit)
GPUTexture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, eGPUTextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(GPUTexture *texture)
int GPU_texture_width(const GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_DATA_INT
@ GPU_DATA_FLOAT
@ GPU_TEXTURE_USAGE_GENERAL
void GPU_texture_image_unbind(GPUTexture *texture)
void GPU_texture_image_bind(GPUTexture *texture, int unit)
eGPUTextureFormat
@ GPU_RG16I
@ GPU_RG32I
@ GPU_RGB32F
@ GPU_RG32F
@ GPU_RGB16F
void GPU_texture_update(GPUTexture *texture, eGPUDataFormat data_format, const void *data)
eGPUTextureFormat GPU_texture_format(const GPUTexture *texture)
Read Guarded memory(de)allocation.
struct GPUShader GPUShader
virtual bool use_gpu() const =0
void transform(const float3x3 &input_transformation)
Definition domain.cc:19
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
GPUTexture * acquire(int2 size, eGPUTextureFormat format)
additional_info("compositor_sum_float_shared") .push_constant(Type additional_info("compositor_sum_float_shared") .push_constant(Type GPU_RGBA32F
local_group_size(16, 16) .push_constant(Type texture
int count
format
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
VecBase< float, 3 > float3
__int64 int64_t
Definition stdint.h:89
int x
Definition types_int2.h:15
int y
Definition types_int2.h:15