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 if (is_external_) {
534 return;
535 }
536
537 if (!this->is_allocated()) {
538 return;
539 }
540
541 /* Data is still shared with some other result, so decrement data reference count and reset data
542 * members without actually freeing the data itself. */
543 BLI_assert(*data_reference_count_ >= 1);
544 if (*data_reference_count_ != 1) {
545 (*data_reference_count_)--;
546
547 switch (storage_type_) {
549 gpu_texture_ = nullptr;
550 break;
553 break;
554 }
555
556 data_reference_count_ = nullptr;
557 derived_resources_ = nullptr;
558
559 return;
560 }
561
562 switch (storage_type_) {
564 if (is_from_pool_) {
566 }
567 else {
569 }
570 gpu_texture_ = nullptr;
571 break;
573 MEM_freeN(this->cpu_data().data());
575 break;
576 }
577
578 delete data_reference_count_;
579 data_reference_count_ = nullptr;
580
581 delete derived_resources_;
582 derived_resources_ = nullptr;
583}
584
586{
587 return reference_count_ != 0;
588}
589
591{
592 if (!derived_resources_) {
593 derived_resources_ = new DerivedResources();
594 }
595 return *derived_resources_;
596}
597
599{
600 return type_;
601}
602
604{
605 return precision_;
606}
607
609{
610 /* Changing the type can only be done if it wasn't allocated yet. */
611 BLI_assert(!this->is_allocated());
612 type_ = type;
613}
614
616{
617 /* Changing the precision can only be done if it wasn't allocated yet. */
618 BLI_assert(!this->is_allocated());
619 precision_ = precision;
620}
621
623{
624 return is_single_value_;
625}
626
628{
629 switch (storage_type_) {
631 return this->gpu_texture();
633 return this->cpu_data().data();
634 }
635
636 return false;
637}
638
640{
641 return reference_count_;
642}
643
645{
646 return std::visit([](const auto &value) { return GPointer(&value); }, single_value_);
647}
648
650{
651 return std::visit([](auto &value) { return GMutablePointer(&value); }, single_value_);
652}
653
655{
657 BLI_assert(this->is_allocated());
658
659 switch (storage_type_) {
661 switch (type_) {
667 break;
668 case ResultType::Float3: {
669 /* Float3 results are stored in 4-component textures due to hardware limitations. So
670 * pad the value with a zero before updating. */
671 const float4 vector_value = float4(this->get_single_value<float3>(), 0.0f);
672 GPU_texture_update(this->gpu_texture(), GPU_DATA_FLOAT, vector_value);
673 break;
674 }
675 case ResultType::Int:
676 case ResultType::Int2:
677 case ResultType::Bool:
679 break;
680 }
681 break;
683 this->get_cpp_type().copy_assign(this->single_value().get(), this->cpu_data().data());
684 break;
685 }
686}
687
688void Result::allocate_data(int2 size, bool from_pool)
689{
690 BLI_assert(!this->is_allocated());
691
692 if (context_->use_gpu()) {
693 storage_type_ = ResultStorageType::GPU;
694 is_from_pool_ = from_pool;
695
698 if (from_pool) {
700 }
701 else {
702 gpu_texture_ = GPU_texture_create_2d(__func__, size.x, size.y, 1, format, usage, nullptr);
703 }
704 }
705 else {
706 storage_type_ = ResultStorageType::CPU;
707
708 const CPPType &cpp_type = this->get_cpp_type();
709 const int64_t item_size = cpp_type.size;
710 const int64_t alignment = cpp_type.alignment;
711 const int64_t array_size = int64_t(size.x) * int64_t(size.y);
712 const int64_t memory_size = array_size * item_size;
713
714 void *data = MEM_mallocN_aligned(memory_size, alignment, AT);
715 cpp_type.default_construct_n(data, array_size);
716
717 cpu_data_ = GMutableSpan(cpp_type, data, array_size);
718 }
719
720 data_reference_count_ = new int(1);
721}
722
723} // 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:639
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:627
void set_transformation(const float3x3 &transformation)
Definition result.cc:484
GPointer single_value() const
Definition result.cc:644
void set_single_value(const T &value)
ResultPrecision precision() const
Definition result.cc:603
ResultType type() const
Definition result.cc:598
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:615
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:590
void set_reference_count(int count)
Definition result.cc:504
bool is_single_value() const
Definition result.cc:622
void steal_data(Result &source)
Definition result.cc:418
const T & get_single_value() const
void set_type(ResultType type)
Definition result.cc:608
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