Blender V4.5
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 <cstdint>
6#include <variant>
7
8#include "MEM_guardedalloc.h"
9
10#include "BLI_assert.h"
11#include "BLI_cpp_type.hh"
13#include "BLI_generic_span.hh"
16#include "BLI_utildefines.h"
17
18#include "GPU_shader.hh"
19#include "GPU_state.hh"
20#include "GPU_texture.hh"
21#include "GPU_texture_pool.hh"
22
23#include "COM_context.hh"
25#include "COM_domain.hh"
26#include "COM_result.hh"
27
28namespace blender::compositor {
29
30Result::Result(Context &context) : context_(&context) {}
31
33 : context_(&context), type_(type), precision_(precision)
34{
35}
36
38 : context_(&context), type_(Result::type(format)), precision_(Result::precision(format))
39{
40}
41
43{
44 switch (precision) {
46 switch (type) {
48 return GPU_R16F;
51 return GPU_RGBA16F;
53 /* RGB textures are not fully supported by hardware, so we store Float3 results in RGBA
54 * textures. */
55 return GPU_RGBA16F;
57 return GPU_RG16F;
58 case ResultType::Int:
59 return GPU_R16I;
61 return GPU_RG16I;
63 /* No bool texture formats, so we store in an 8-bit integer. Precision doesn't matter. */
64 return GPU_R8I;
65 }
66 break;
68 switch (type) {
70 return GPU_R32F;
73 return GPU_RGBA32F;
75 /* RGB textures are not fully supported by hardware, so we store Float3 results in RGBA
76 * textures. */
77 return GPU_RGBA32F;
79 return GPU_RG32F;
80 case ResultType::Int:
81 return GPU_R32I;
83 return GPU_RG32I;
85 /* No bool texture formats, so we store in an 8-bit integer. Precision doesn't matter. */
86 return GPU_R8I;
87 }
88 break;
89 }
90
92 return GPU_RGBA32F;
93}
94
96{
97 switch (precision) {
99 switch (format) {
100 /* Already half precision, return the input format. */
101 case GPU_R16F:
102 case GPU_RG16F:
103 case GPU_RGB16F:
104 case GPU_RGBA16F:
105 case GPU_R16I:
106 case GPU_RG16I:
107 return format;
108
109 /* Used to store booleans where precision doesn't matter. */
110 case GPU_R8I:
111 return format;
112
113 case GPU_R32F:
114 return GPU_R16F;
115 case GPU_RG32F:
116 return GPU_RG16F;
117 case GPU_RGB32F:
118 return GPU_RGB16F;
119 case GPU_RGBA32F:
120 return GPU_RGBA16F;
121 case GPU_R32I:
122 return GPU_R16I;
123 case GPU_RG32I:
124 return GPU_RG16I;
125 default:
126 break;
127 }
128 break;
130 switch (format) {
131 /* Already full precision, return the input format. */
132 case GPU_R32F:
133 case GPU_RG32F:
134 case GPU_RGB32F:
135 case GPU_RGBA32F:
136 case GPU_R32I:
137 case GPU_RG32I:
138 return format;
139
140 /* Used to store booleans where precision doesn't matter. */
141 case GPU_R8I:
142 return format;
143
144 case GPU_R16F:
145 return GPU_R32F;
146 case GPU_RG16F:
147 return GPU_RG32F;
148 case GPU_RGB16F:
149 return GPU_RGB32F;
150 case GPU_RGBA16F:
151 return GPU_RGBA32F;
152 case GPU_R16I:
153 return GPU_R32I;
154 case GPU_RG16I:
155 return GPU_RG32I;
156 default:
157 break;
158 }
159 break;
160 }
161
163 return format;
164}
165
167{
168 switch (format) {
169 case GPU_R16F:
170 case GPU_RG16F:
171 case GPU_RGB16F:
172 case GPU_RGBA16F:
173 case GPU_R16I:
174 case GPU_RG16I:
176 case GPU_R32F:
177 case GPU_RG32F:
178 case GPU_RGB32F:
179 case GPU_RGBA32F:
180 case GPU_R32I:
181 case GPU_RG32I:
183 /* Used to store booleans where precision doesn't matter. */
184 case GPU_R8I:
186 default:
187 break;
188 }
189
192}
193
195{
196 switch (format) {
197 case GPU_R16F:
198 case GPU_R32F:
199 return ResultType::Float;
200 case GPU_RG16F:
201 case GPU_RG32F:
202 return ResultType::Float2;
203 case GPU_RGB16F:
204 case GPU_RGB32F:
205 return ResultType::Float3;
206 case GPU_RGBA16F:
207 case GPU_RGBA32F:
208 return ResultType::Color;
209 case GPU_R16I:
210 case GPU_R32I:
211 return ResultType::Int;
212 case GPU_RG16I:
213 case GPU_RG32I:
214 return ResultType::Int2;
215 case GPU_R8I:
216 return ResultType::Bool;
217 default:
218 break;
219 }
220
222 return ResultType::Color;
223}
224
226{
227 switch (channels_count) {
228 case 1:
229 return ResultType::Float;
230 case 2:
231 return ResultType::Float2;
232 case 3:
233 return ResultType::Float3;
234 case 4:
235 return ResultType::Color;
236 default:
237 break;
238 }
239
241 return ResultType::Color;
242}
243
245{
246 switch (type) {
248 return CPPType::get<float>();
249 case ResultType::Int:
250 return CPPType::get<int32_t>();
252 return CPPType::get<float4>();
254 return CPPType::get<float4>();
256 return CPPType::get<float2>();
258 return CPPType::get<float3>();
259 case ResultType::Int2:
260 return CPPType::get<int2>();
261 case ResultType::Bool:
262 return CPPType::get<bool>();
263 }
264
266 return CPPType::get<float>();
267}
268
270{
271 switch (type) {
273 return "float";
275 return "float2";
277 return "float3";
279 return "float4";
281 return "color";
282 case ResultType::Int2:
283 return "int2";
284 case ResultType::Int:
285 return "int";
286 case ResultType::Bool:
287 return "bool";
288 }
289
291 return "";
292}
293
294Result::operator GPUTexture *() const
295{
296 return this->gpu_texture();
297}
298
300{
301 return Result::cpp_type(this->type());
302}
303
305{
306 return Result::gpu_texture_format(type_, precision_);
307}
308
310{
311 /* Make sure we are not allocating a result that should not be computed. */
312 BLI_assert(this->should_compute());
313
314 is_single_value_ = false;
315 this->allocate_data(domain.size, from_pool);
316 domain_ = domain;
317}
318
320{
321 /* Make sure we are not allocating a result that should not be computed. */
322 BLI_assert(this->should_compute());
323
324 /* Single values are stored in 1x1 image as well as the single value members. Further, they
325 * are always allocated from the pool. */
326 is_single_value_ = true;
327 this->allocate_data(int2(1), true);
328 domain_ = Domain::identity();
329
330 /* It is important that we initialize single values because the variant member that stores single
331 * values need to have its type initialized. */
332 switch (type_) {
334 this->set_single_value(0.0f);
335 break;
337 this->set_single_value(float4(0.0f));
338 break;
340 this->set_single_value(float4(0.0f));
341 break;
343 this->set_single_value(float2(0.0f));
344 break;
346 this->set_single_value(float3(0.0f));
347 break;
348 case ResultType::Int:
349 this->set_single_value(0);
350 break;
351 case ResultType::Int2:
352 this->set_single_value(int2(0));
353 break;
354 case ResultType::Bool:
355 this->set_single_value(false);
356 break;
357 }
358}
359
364
365void Result::bind_as_texture(GPUShader *shader, const char *texture_name) const
366{
367 BLI_assert(storage_type_ == ResultStorageType::GPU);
368
369 /* Make sure any prior writes to the texture are reflected before reading from it. */
371
372 const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name);
373 GPU_texture_bind(this->gpu_texture(), texture_image_unit);
374}
375
376void Result::bind_as_image(GPUShader *shader, const char *image_name, bool read) const
377{
378 BLI_assert(storage_type_ == ResultStorageType::GPU);
379
380 /* Make sure any prior writes to the texture are reflected before reading from it. */
381 if (read) {
383 }
384
385 const int image_unit = GPU_shader_get_sampler_binding(shader, image_name);
386 GPU_texture_image_bind(this->gpu_texture(), image_unit);
387}
388
390{
391 BLI_assert(storage_type_ == ResultStorageType::GPU);
393}
394
396{
397 BLI_assert(storage_type_ == ResultStorageType::GPU);
399}
400
401void Result::share_data(const Result &source)
402{
403 BLI_assert(type_ == source.type_);
404 BLI_assert(!this->is_allocated() && source.is_allocated());
405
406 /* Overwrite everything except reference count. */
407 const int reference_count = reference_count_;
408 *this = source;
409 reference_count_ = reference_count;
410
411 /* External data is intrinsically shared, and data_reference_count_ is nullptr in this case since
412 * it is not needed. */
413 if (!is_external_) {
414 (*data_reference_count_)++;
415 }
416}
417
419{
420 BLI_assert(type_ == source.type_);
421 BLI_assert(precision_ == source.precision_);
422 BLI_assert(!this->is_allocated() && source.is_allocated());
423
424 /* Overwrite everything except reference counts. */
425 const int reference_count = reference_count_;
426 *this = source;
427 reference_count_ = reference_count;
428
429 source = Result(*context_, type_, precision_);
430}
431
432/* Returns true if the given GPU texture is compatible with the type and precision of the given
433 * result. */
434[[maybe_unused]] static bool is_compatible_texture(const GPUTexture *texture, const Result &result)
435{
436 /* Float3 types are an exception, see the documentation on the get_gpu_texture_format method for
437 * more information. */
438 if (result.type() == ResultType::Float3) {
440 {
441 return true;
442 }
443 }
444
445 return GPU_texture_format(texture) == result.get_gpu_texture_format();
446}
447
449{
451 BLI_assert(!this->is_allocated());
452
454 storage_type_ = ResultStorageType::GPU;
455 is_external_ = true;
456 is_single_value_ = false;
458}
459
461{
462 BLI_assert(!this->is_allocated());
463
464 const int64_t array_size = int64_t(size.x) * int64_t(size.y);
465 cpu_data_ = GMutableSpan(this->get_cpp_type(), data, array_size);
466 storage_type_ = ResultStorageType::CPU;
467 is_external_ = true;
468 domain_ = Domain(size);
469}
470
472{
473 BLI_assert(type_ == result.type());
474 BLI_assert(precision_ == result.precision());
475 BLI_assert(!this->is_allocated());
476
477 /* Steal the data of the given result and mark it as wrapping external data, but create a
478 * temporary copy of the result first, since steal_data will reset it. */
479 Result result_copy = result;
480 this->steal_data(result_copy);
481 is_external_ = true;
482}
483
484void Result::set_transformation(const float3x3 &transformation)
485{
486 domain_.transformation = transformation;
487}
488
489void Result::transform(const float3x3 &transformation)
490{
491 domain_.transform(transformation);
492}
493
495{
496 return domain_.realization_options;
497}
498
500{
501 return domain_.realization_options;
502}
503
505{
506 reference_count_ = count;
507}
508
510{
511 reference_count_ += count;
512}
513
515{
516 reference_count_ -= count;
517}
518
520{
521 /* Decrement the reference count, and if it is not yet zero, return and do not free. */
522 reference_count_--;
523 BLI_assert(reference_count_ >= 0);
524 if (reference_count_ != 0) {
525 return;
526 }
527
528 this->free();
529}
530
532{
533 /* The data in the result are not owned by the result, so we only free the derived resources. */
534 if (is_external_) {
535 delete derived_resources_;
536 derived_resources_ = nullptr;
537 return;
538 }
539
540 if (!this->is_allocated()) {
541 return;
542 }
543
544 /* Data is still shared with some other result, so decrement data reference count and reset data
545 * members without actually freeing the data itself. */
546 BLI_assert(*data_reference_count_ >= 1);
547 if (*data_reference_count_ != 1) {
548 (*data_reference_count_)--;
549
550 switch (storage_type_) {
552 gpu_texture_ = nullptr;
553 break;
556 break;
557 }
558
559 data_reference_count_ = nullptr;
560 derived_resources_ = nullptr;
561
562 return;
563 }
564
565 switch (storage_type_) {
567 if (is_from_pool_) {
569 }
570 else {
572 }
573 gpu_texture_ = nullptr;
574 break;
576 MEM_freeN(this->cpu_data().data());
578 break;
579 }
580
581 delete data_reference_count_;
582 data_reference_count_ = nullptr;
583
584 delete derived_resources_;
585 derived_resources_ = nullptr;
586}
587
589{
590 return reference_count_ != 0;
591}
592
594{
595 if (!derived_resources_) {
596 derived_resources_ = new DerivedResources();
597 }
598 return *derived_resources_;
599}
600
602{
603 return type_;
604}
605
607{
608 return precision_;
609}
610
612{
613 /* Changing the type can only be done if it wasn't allocated yet. */
614 BLI_assert(!this->is_allocated());
615 type_ = type;
616}
617
619{
620 /* Changing the precision can only be done if it wasn't allocated yet. */
621 BLI_assert(!this->is_allocated());
622 precision_ = precision;
623}
624
626{
627 return is_single_value_;
628}
629
631{
632 switch (storage_type_) {
634 return this->gpu_texture();
636 return this->cpu_data().data();
637 }
638
639 return false;
640}
641
643{
644 return reference_count_;
645}
646
648{
649 return std::visit([](const auto &value) { return GPointer(&value); }, single_value_);
650}
651
653{
654 return std::visit([](auto &value) { return GMutablePointer(&value); }, single_value_);
655}
656
658{
660 BLI_assert(this->is_allocated());
661
662 switch (storage_type_) {
664 switch (type_) {
670 break;
671 case ResultType::Float3: {
672 /* Float3 results are stored in 4-component textures due to hardware limitations. So
673 * pad the value with a zero before updating. */
674 const float4 vector_value = float4(this->get_single_value<float3>(), 0.0f);
675 GPU_texture_update(this->gpu_texture(), GPU_DATA_FLOAT, vector_value);
676 break;
677 }
678 case ResultType::Int:
679 case ResultType::Int2:
680 case ResultType::Bool:
682 break;
683 }
684 break;
686 this->get_cpp_type().copy_assign(this->single_value().get(), this->cpu_data().data());
687 break;
688 }
689}
690
691void Result::allocate_data(int2 size, bool from_pool)
692{
693 BLI_assert(!this->is_allocated());
694
695 if (context_->use_gpu()) {
696 storage_type_ = ResultStorageType::GPU;
697 is_from_pool_ = from_pool;
698
701 if (from_pool) {
703 }
704 else {
705 gpu_texture_ = GPU_texture_create_2d(__func__, size.x, size.y, 1, format, usage, nullptr);
706 }
707 }
708 else {
709 storage_type_ = ResultStorageType::CPU;
710
711 const CPPType &cpp_type = this->get_cpp_type();
712 const int64_t item_size = cpp_type.size;
713 const int64_t alignment = cpp_type.alignment;
714 const int64_t array_size = int64_t(size.x) * int64_t(size.y);
715 const int64_t memory_size = array_size * item_size;
716
717 void *data = MEM_mallocN_aligned(memory_size, alignment, AT);
718 cpp_type.default_construct_n(data, array_size);
719
720 cpu_data_ = GMutableSpan(cpp_type, data, array_size);
721 }
722
723 data_reference_count_ = new int(1);
724}
725
726} // namespace blender::compositor
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define AT
int GPU_shader_get_sampler_binding(GPUShader *shader, const char *name)
void GPU_memory_barrier(eGPUBarrier barrier)
Definition gpu_state.cc:385
@ 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
eGPUTextureUsage
@ GPU_TEXTURE_USAGE_GENERAL
void GPU_texture_image_unbind(GPUTexture *texture)
void GPU_texture_image_bind(GPUTexture *texture, int unit)
eGPUTextureFormat
@ GPU_RG16F
@ GPU_R32F
@ GPU_R16I
@ GPU_R32I
@ GPU_R16F
@ GPU_RG16I
@ GPU_RGBA32F
@ GPU_RGBA16F
@ GPU_RG32I
@ GPU_R8I
@ 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.
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static const CPPType & get()
void copy_assign(const void *src, void *dst) const
const void * data() const
virtual bool use_gpu() const =0
static Domain identity()
Definition domain.cc:25
void decrement_reference_count(int count=1)
Definition result.cc:514
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
const CPPType & get_cpp_type() const
Definition result.cc:299
void allocate_texture(Domain domain, bool from_pool=true)
Definition result.cc:309
int reference_count() const
Definition result.cc:642
static ResultPrecision precision(eGPUTextureFormat format)
Definition result.cc:166
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
bool is_allocated() const
Definition result.cc:630
void set_transformation(const float3x3 &transformation)
Definition result.cc:484
GPointer single_value() const
Definition result.cc:647
void set_single_value(const T &value)
ResultPrecision precision() const
Definition result.cc:606
ResultType type() const
Definition result.cc:601
static eGPUTextureFormat gpu_texture_format(ResultType type, ResultPrecision precision)
Definition result.cc:42
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
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
Result(Context &context)
Definition result.cc:30
DerivedResources & derived_resources()
Definition result.cc:593
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
void release_texture(GPUTexture *tmp_tex)
static TexturePool & get()
GPUTexture * acquire_texture(int width, int height, eGPUTextureFormat format, eGPUTextureUsage usage)
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
int count
format
void * MEM_mallocN_aligned(size_t len, size_t alignment, const char *str)
Definition mallocn.cc:138
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static bool is_compatible_texture(const GPUTexture *texture, const Result &result)
Definition result.cc:434
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
VecBase< float, 2 > float2
MatBase< float, 3, 3 > float3x3
VecBase< float, 3 > float3
read