diff --git a/source/blender/compositor/COM_result.hh b/source/blender/compositor/COM_result.hh index b0f923749f8..7bf6aba7c3b 100644 --- a/source/blender/compositor/COM_result.hh +++ b/source/blender/compositor/COM_result.hh @@ -6,8 +6,11 @@ #include #include +#include #include "BLI_assert.h" +#include "BLI_cpp_type.hh" +#include "BLI_generic_span.hh" #include "BLI_math_interp.hh" #include "BLI_math_matrix_types.hh" #include "BLI_math_vector.h" @@ -29,7 +32,7 @@ class DerivedResources; /* Make sure to update the format related static methods in the Result class. */ enum class ResultType : uint8_t { /* The following types are user facing and can be used as inputs and outputs of operations. They - * either represent the base type of the result texture or a single value result. The color type + * either represent the base type of the result's image or a single value result. The color type * represents an RGBA color. And the vector type represents a generic 4-component vector, which * can encode two 2D vectors, one 3D vector with the last component ignored, or other dimensional * data. */ @@ -56,10 +59,8 @@ enum class ResultPrecision : uint8_t { enum class ResultStorageType : uint8_t { /* Stored as a GPUTexture on the GPU. */ GPU, - /* Stored as a contiguous float buffer the CPU. */ - FloatCPU, - /* Stored as a contiguous integer buffer the CPU. */ - IntegerCPU, + /* Stored as a buffer on the CPU and wrapped in a GMutableSpan. */ + CPU, }; /* ------------------------------------------------------------------------------------------------ @@ -73,11 +74,11 @@ enum class ResultStorageType : uint8_t { * pool of the context referenced by the result or it can be allocated directly from the GPU * module, see the allocation method for more information. * - * Results are reference counted and their textures are released once their reference count reaches + * Results are reference counted and their data are released once their reference count reaches * zero. After constructing a result, the set_initial_reference_count method is called to declare * the number of operations that needs this result. Once each operation that needs the result no * longer needs it, the release method is called and the reference count is decremented, until it - * reaches zero, where the result's texture is then released. Since results are eventually + * reaches zero, where the result's data is then released. Since results are eventually * decremented to zero by the end of every evaluation, the reference count is restored before every * evaluation to its initial reference count by calling the reset method, which is why a separate * member initial_reference_count_ is stored to keep track of the initial value. @@ -96,9 +97,9 @@ enum class ResultStorageType : uint8_t { * transformation on its domain whatsoever. Proxy results can be created by calling the * pass_through method, see that method for more details. * - * A result can wrap an external texture that is not allocated nor managed by the result. This is - * set up by a call to the wrap_external method. In that case, when the reference count eventually - * reach zero, the texture will not be freed. + * A result can wrap external data that is not allocated nor managed by the result. This is set up + * by a call to the wrap_external method. In that case, when the reference count eventually reach + * zero, the data will not be freed. * * A result may store resources that are computed and cached in case they are needed by multiple * operations. Those are called Derived Resources and can be accessed using the derived_resources @@ -108,27 +109,27 @@ class Result { /* The context that the result was created within, this should be initialized during * construction. */ Context *context_ = nullptr; - /* The base type of the result's texture or single value. */ + /* The base type of the result's image or single value. */ ResultType type_ = ResultType::Float; - /* The precision of the result's texture, host-side single values are always stored using full - * precision. */ + /* The precision of the result's data. Only relevant for GPU textures. CPU buffers and single + * values are always stored using full precision. */ ResultPrecision precision_ = ResultPrecision::Half; - /* If true, the result is a single value, otherwise, the result is a texture. */ + /* If true, the result is a single value, otherwise, the result is an image. */ bool is_single_value_ = false; /* The type of storage used to hold the data. Used to correctly interpret the data union. */ ResultStorageType storage_type_ = ResultStorageType::GPU; - /* A texture storing the result pixel data, either stored in a GPU texture or a raw contagious - * array on CPU. This will be a 1x1 texture if the result is a single value, the value of which - * will be identical to that of the value member. See class description for more information. */ + /* Stores the result's pixel data, either stored in a GPU texture or a buffer that is wrapped in + * a GMutableSpan on CPU. This will represent a 1x1 image if the result is a single value, the + * value of which will be identical to that of the value member. See class description for more + * information. */ union { GPUTexture *gpu_texture_ = nullptr; - float *float_texture_; - int *integer_texture_; + GMutableSpan cpu_data_; }; /* The number of operations that currently needs this result. At the time when the result is * computed, this member will have a value that matches initial_reference_count_. Once each * operation that needs the result no longer needs it, the release method is called and the - * reference count is decremented, until it reaches zero, where the result's texture is then + * reference count is decremented, until it reaches zero, where the result's data is then * released. If this result have a master result, then this reference count is irrelevant and * shadowed by the reference count of the master result. */ int reference_count_ = 1; @@ -139,30 +140,22 @@ class Result { * should be computed by calling the should_compute method. */ int initial_reference_count_ = 1; /* If the result is a single value, this member stores the value of the result, the value of - * which will be identical to that stored in the texture member. The active union member depends + * which will be identical to that stored in the data_ member. The active variant member depends * on the type of the result. This member is uninitialized and should not be used if the result - * is a texture. */ - union { - float float_value_; - float4 vector_value_; - float4 color_value_ = float4(0.0f); - float2 float2_value_; - float3 float3_value_; - int int_value_; - int2 int2_value_; - }; - /* The domain of the result. This only matters if the result was a texture. See the discussion in - * COM_domain.hh for more information. */ + * is not a single value. */ + std::variant single_value_ = 0.0f; + /* The domain of the result. This only matters if the result was not a single value. See the + * discussion in COM_domain.hh for more information. */ Domain domain_ = Domain::identity(); /* If not nullptr, then this result wraps and shares the value of another master result. In this - * case, calls to texture-related methods like increment_reference_count and release should - * operate on the master result as opposed to this result. This member is typically set upon - * calling the pass_through method, which sets this result to be the master of a target result. - * See that method for more information. */ + * case, calls to methods like increment_reference_count and release should operate on the master + * result as opposed to this result. This member is typically set upon calling the pass_through + * method, which sets this result to be the master of a target result. See that method for more + * information. */ Result *master_ = nullptr; - /* If true, then the result wraps an external texture that is not allocated nor managed by the - * result. This is set up by a call to the wrap_external method. In that case, when the reference - * count eventually reach zero, the texture will not be freed. */ + /* If true, then the result wraps external data that is not allocated nor managed by the result. + * This is set up by a call to the wrap_external method. In that case, when the reference count + * eventually reach zero, the data will not be freed. */ bool is_external_ = false; /* If true, the GPU texture that holds the data was allocated from the texture pool of the * context and should be released back into the pool instead of being freed. For CPU storage, @@ -206,6 +199,8 @@ class Result { /* Implicit conversion to the internal GPU texture. */ operator GPUTexture *() const; + const CPPType &get_cpp_type() const; + /* Returns the appropriate texture format based on the result's type and precision. */ eGPUTextureFormat get_gpu_texture_format() const; @@ -234,12 +229,12 @@ class Result { void allocate_texture(Domain domain, bool from_pool = true); /* Declare the result to be a single value result, allocate a texture of an appropriate type with - * size 1x1 from the texture pool, and set the domain to be an identity domain. See class - * description for more information. */ + * size 1x1 from the texture pool, and set the domain to be an identity domain. The value is zero + * initialized. See class description for more information. */ void allocate_single_value(); - /* Allocate a single value result and set its value to zero. This is called for results whose - * value can't be computed and are considered invalid. */ + /* Allocate a single value result whose value is zero. This is called for results whose value + * can't be computed and are considered invalid. */ void allocate_invalid(); /* Bind the GPU texture of the result to the texture image unit with the given name in the @@ -290,11 +285,8 @@ class Result { * is assumed to have a lifetime that covers the evaluation of the compositor. */ void wrap_external(GPUTexture *texture); - /* Identical to GPU variant of wrap_external but wraps a float buffer instead. */ - void wrap_external(float *texture, int2 size); - - /* Identical to GPU variant of wrap_external but wraps an integer buffer instead. */ - void wrap_external(int *texture, int2 size); + /* Identical to GPU variant of wrap_external but wraps a CPU buffer instead. */ + void wrap_external(void *data, int2 size); /* Identical to GPU variant of wrap_external but wraps whatever the given result has instead. */ void wrap_external(const Result &result); @@ -355,7 +347,7 @@ class Result { /* Sets the precision of the result. */ void set_precision(ResultPrecision precision); - /* Returns true if the result is a single value and false of it is a texture. */ + /* Returns true if the result is a single value and false of it is an image. */ bool is_single_value() const; /* Returns true if the result is allocated. */ @@ -371,15 +363,9 @@ class Result { /* Computes the number of channels of the result based on its type. */ int64_t channels_count() const; - /* Returns a reference to the allocate float data. */ - float *float_texture() const; + GPUTexture *gpu_texture() const; - /* Returns a reference to the allocate integer data. */ - int *integer_texture() const; - - /* Returns a reference to the allocated CPU data. The returned data is untyped, use the - * float_texture() or the integer_texture() methods for typed data. */ - void *data() const; + GMutableSpan cpu_data() const; /* Gets the single value stored in the result. Assumes the result stores a value of the given * template type. */ @@ -392,7 +378,7 @@ class Result { template T get_single_value_default(const T &default_value) const; /* Sets the single value of the result to the given value, which also involves setting the single - * pixel in the texture to that value. See the class description for more information. Assumes + * pixel in the image to that value. See the class description for more information. Assumes * the result stores a value of the given template type. */ template void set_single_value(const T &value); @@ -464,46 +450,13 @@ class Result { /* Return true if the provided template type is an int or an int vector. */ template static constexpr bool is_int_type(); - /* Returns the number of channels in the provided template type, this is 1 for scalar types, and - * the number of elements for vector types. */ - template static constexpr int get_type_channels_count(); - - /* Return true if the provided template type is supported by the class. */ - template static constexpr bool is_supported_type(); - - /* Allocates the texture data for the given size, either on the GPU or CPU based on the result's + /* Allocates the image data for the given size, either on the GPU or CPU based on the result's * context. See the allocate_texture method for information about the from_pool argument. */ void allocate_data(int2 size, bool from_pool); - /* Get the index of the start of pixel at the given texel position in its result buffer. Asserts - * if the template type doesn't match the result's type. */ - template int64_t get_pixel_index(const int2 &texel) const; - /* Same as get_pixel_index but can be used when the type of the result is not known at compile * time. */ int64_t get_pixel_index(const int2 &texel) const; - - /* Get a pointer to the float pixel at the given texel position. Asserts if the template type - * doesn't match the result's type. */ - template - std::conditional_t(), int, float> *get_pixel(const int2 &texel) const; - - /* Get a pointer to the float pixel at the given texel position. */ - float *get_float_pixel(const int2 &texel) const; - - /* Get a pointer to the integer pixel at the given texel position. */ - int *get_integer_pixel(const int2 &texel) const; - - /* Copy the float pixel from the source pointer to the target pointer, assuming the given - * channels count. */ - static void copy_pixel(float *target, const float *source, const int channels_count); - - /* Copy the integer pixel from the source pointer to the target pointer, assuming the given - * channels count. */ - static void copy_pixel(int *target, const int *source, const int channels_count); - - /* Copy the float pixel from the source pointer to the target pointer. */ - void copy_pixel(float *target, const float *source) const; }; /* -------------------------------------------------------------------- */ @@ -533,65 +486,23 @@ inline int64_t Result::channels_count() const return 4; } -inline float *Result::float_texture() const +inline GPUTexture *Result::gpu_texture() const { - BLI_assert(storage_type_ == ResultStorageType::FloatCPU); - return float_texture_; + BLI_assert(storage_type_ == ResultStorageType::GPU); + return gpu_texture_; } -inline int *Result::integer_texture() const +inline GMutableSpan Result::cpu_data() const { - BLI_assert(storage_type_ == ResultStorageType::IntegerCPU); - return integer_texture_; -} - -inline void *Result::data() const -{ - switch (storage_type_) { - case ResultStorageType::FloatCPU: - return this->float_texture(); - case ResultStorageType::IntegerCPU: - return this->integer_texture(); - case ResultStorageType::GPU: - break; - } - - BLI_assert_unreachable(); - return nullptr; + BLI_assert(storage_type_ == ResultStorageType::CPU); + return cpu_data_; } template inline const T &Result::get_single_value() const { BLI_assert(this->is_single_value()); - static_assert(Result::is_supported_type()); - if constexpr (std::is_same_v) { - BLI_assert(type_ == ResultType::Float); - return float_value_; - } - else if constexpr (std::is_same_v) { - BLI_assert(type_ == ResultType::Int); - return int_value_; - } - else if constexpr (std::is_same_v) { - BLI_assert(type_ == ResultType::Float2); - return float2_value_; - } - else if constexpr (std::is_same_v) { - BLI_assert(type_ == ResultType::Float3); - return float3_value_; - } - else if constexpr (std::is_same_v) { - BLI_assert(ELEM(type_, ResultType::Color, ResultType::Vector)); - return color_value_; - } - else if constexpr (std::is_same_v) { - BLI_assert(type_ == ResultType::Int2); - return int2_value_; - } - else { - return T(0); - } + return std::get(single_value_); } template inline T &Result::get_single_value() @@ -611,48 +522,30 @@ template inline void Result::set_single_value(const T &value) { BLI_assert(this->is_allocated()); BLI_assert(this->is_single_value()); - static_assert(Result::is_supported_type()); - this->get_single_value() = value; + single_value_ = value; switch (storage_type_) { case ResultStorageType::GPU: if constexpr (Result::is_int_type()) { if constexpr (std::is_scalar_v) { - GPU_texture_update(gpu_texture_, GPU_DATA_INT, &value); + GPU_texture_update(this->gpu_texture(), GPU_DATA_INT, &value); } else { - GPU_texture_update(gpu_texture_, GPU_DATA_INT, value); + GPU_texture_update(this->gpu_texture(), GPU_DATA_INT, value); } } else { if constexpr (std::is_scalar_v) { - GPU_texture_update(gpu_texture_, GPU_DATA_FLOAT, &value); + GPU_texture_update(this->gpu_texture(), GPU_DATA_FLOAT, &value); } else { - GPU_texture_update(gpu_texture_, GPU_DATA_FLOAT, value); + GPU_texture_update(this->gpu_texture(), GPU_DATA_FLOAT, value); } } break; - case ResultStorageType::FloatCPU: - case ResultStorageType::IntegerCPU: - if constexpr (Result::is_int_type()) { - if constexpr (std::is_scalar_v) { - Result::copy_pixel( - this->integer_texture(), &value, Result::get_type_channels_count()); - } - else { - Result::copy_pixel(this->integer_texture(), value, Result::get_type_channels_count()); - } - } - else { - if constexpr (std::is_scalar_v) { - Result::copy_pixel(this->float_texture(), &value, Result::get_type_channels_count()); - } - else { - Result::copy_pixel(this->float_texture(), value, Result::get_type_channels_count()); - } - } + case ResultStorageType::CPU: + this->cpu_data().typed()[0] = value; break; } } @@ -668,12 +561,7 @@ template inline T Result::load_pixel(const BLI_assert(!this->is_single_value()); } - if constexpr (std::is_scalar_v) { - return *this->get_pixel(texel); - } - else { - return T(this->get_pixel(texel)); - } + return this->cpu_data().typed()[this->get_pixel_index(texel)]; } template @@ -689,12 +577,7 @@ inline T Result::load_pixel_extended(const int2 &texel) const } const int2 clamped_texel = math::clamp(texel, int2(0), domain_.size - int2(1)); - if constexpr (std::is_scalar_v) { - return *this->get_pixel(clamped_texel); - } - else { - return T(this->get_pixel(clamped_texel)); - } + return this->cpu_data().typed()[this->get_pixel_index(clamped_texel)]; } template @@ -713,12 +596,7 @@ inline T Result::load_pixel_fallback(const int2 &texel, const T &fallback) const return fallback; } - if constexpr (std::is_scalar_v) { - return *this->get_pixel(texel); - } - else { - return T(this->get_pixel(texel)); - } + return this->cpu_data().typed()[this->get_pixel_index(texel)]; } template @@ -731,42 +609,37 @@ inline float4 Result::load_pixel_generic_type(const int2 &texel) const { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); } else { - this->copy_pixel(pixel_value, this->get_float_pixel(texel)); + this->get_cpp_type().copy_assign(this->cpu_data()[this->get_pixel_index(texel)], pixel_value); } return pixel_value; } template inline void Result::store_pixel(const int2 &texel, const T &pixel_value) { - if constexpr (std::is_scalar_v) { - *this->get_pixel(texel) = pixel_value; - } - else { - Result::copy_pixel( - this->get_pixel(texel), pixel_value, Result::get_type_channels_count()); - } + this->cpu_data().typed()[this->get_pixel_index(texel)] = pixel_value; } inline void Result::store_pixel_generic_type(const int2 &texel, const float4 &pixel_value) { - this->copy_pixel(this->get_float_pixel(texel), pixel_value); + this->get_cpp_type().copy_assign(pixel_value, this->cpu_data()[this->get_pixel_index(texel)]); } inline float4 Result::sample_nearest_zero(const float2 &coordinates) const { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } const int2 size = domain_.size; const float2 texel_coordinates = coordinates * float2(size); - math::interpolate_nearest_border_fl(this->float_texture(), + const float *buffer = static_cast(this->cpu_data().data()); + math::interpolate_nearest_border_fl(buffer, pixel_value, size.x, size.y, @@ -782,15 +655,16 @@ inline float4 Result::sample_nearest_wrap(const float2 &coordinates, { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } const int2 size = domain_.size; const float2 texel_coordinates = coordinates * float2(size); + const float *buffer = static_cast(this->cpu_data().data()); math::interpolate_nearest_wrapmode_fl( - this->float_texture(), + buffer, pixel_value, size.x, size.y, @@ -808,15 +682,16 @@ inline float4 Result::sample_bilinear_wrap(const float2 &coordinates, { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } const int2 size = domain_.size; const float2 texel_coordinates = coordinates * float2(size) - 0.5f; + const float *buffer = static_cast(this->cpu_data().data()); math::interpolate_bilinear_wrapmode_fl( - this->float_texture(), + buffer, pixel_value, size.x, size.y, @@ -832,15 +707,16 @@ inline float4 Result::sample_cubic_wrap(const float2 &coordinates, bool wrap_x, { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } const int2 size = domain_.size; const float2 texel_coordinates = coordinates * float2(size) - 0.5f; + const float *buffer = static_cast(this->cpu_data().data()); math::interpolate_cubic_bspline_wrapmode_fl( - this->float_texture(), + buffer, pixel_value, size.x, size.y, @@ -856,14 +732,15 @@ inline float4 Result::sample_bilinear_zero(const float2 &coordinates) const { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } const int2 size = domain_.size; const float2 texel_coordinates = (coordinates * float2(size)) - 0.5f; - math::interpolate_bilinear_border_fl(this->float_texture(), + const float *buffer = static_cast(this->cpu_data().data()); + math::interpolate_bilinear_border_fl(buffer, pixel_value, size.x, size.y, @@ -877,14 +754,15 @@ inline float4 Result::sample_nearest_extended(const float2 &coordinates) const { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } const int2 size = domain_.size; const float2 texel_coordinates = coordinates * float2(size); - math::interpolate_nearest_fl(this->float_texture(), + const float *buffer = static_cast(this->cpu_data().data()); + math::interpolate_nearest_fl(buffer, pixel_value, size.x, size.y, @@ -898,14 +776,15 @@ inline float4 Result::sample_bilinear_extended(const float2 &coordinates) const { float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } const int2 size = domain_.size; const float2 texel_coordinates = (coordinates * float2(size)) - 0.5f; - math::interpolate_bilinear_fl(this->float_texture(), + const float *buffer = static_cast(this->cpu_data().data()); + math::interpolate_bilinear_fl(buffer, pixel_value, size.x, size.y, @@ -934,7 +813,7 @@ inline float4 Result::sample_ewa_extended(const float2 &coordinates, float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } @@ -971,7 +850,7 @@ inline float4 Result::sample_ewa_zero(const float2 &coordinates, float4 pixel_value = float4(0.0f, 0.0f, 0.0f, 1.0f); if (is_single_value_) { - this->copy_pixel(pixel_value, float_texture_); + this->get_cpp_type().copy_assign(this->cpu_data().data(), pixel_value); return pixel_value; } @@ -999,123 +878,12 @@ template constexpr bool Result::is_int_type() } } -template constexpr int Result::get_type_channels_count() -{ - if constexpr (std::is_scalar_v) { - return 1; - } - else { - return T::type_length; - } -} - -template constexpr bool Result::is_supported_type() -{ - return is_same_any_v; -} - -template inline int64_t Result::get_pixel_index(const int2 &texel) const -{ - BLI_assert(!is_single_value_); - BLI_assert(this->is_allocated()); - BLI_assert(texel.x >= 0 && texel.y >= 0 && texel.x < domain_.size.x && texel.y < domain_.size.y); - static_assert(Result::is_supported_type()); - - constexpr int channels_count = Result::get_type_channels_count(); - BLI_assert(this->channels_count() == channels_count); - - return (int64_t(texel.y) * domain_.size.x + texel.x) * channels_count; -} - inline int64_t Result::get_pixel_index(const int2 &texel) const { BLI_assert(!is_single_value_); BLI_assert(this->is_allocated()); BLI_assert(texel.x >= 0 && texel.y >= 0 && texel.x < domain_.size.x && texel.y < domain_.size.y); - return (int64_t(texel.y) * domain_.size.x + texel.x) * this->channels_count(); -} - -template -inline std::conditional_t(), int, float> *Result::get_pixel( - const int2 &texel) const -{ - if constexpr (Result::is_int_type()) { - return this->integer_texture() + this->get_pixel_index(texel); - } - else { - return this->float_texture() + this->get_pixel_index(texel); - } -} - -inline float *Result::get_float_pixel(const int2 &texel) const -{ - BLI_assert(storage_type_ == ResultStorageType::FloatCPU); - return float_texture_ + this->get_pixel_index(texel); -} - -inline int *Result::get_integer_pixel(const int2 &texel) const -{ - BLI_assert(storage_type_ == ResultStorageType::IntegerCPU); - return integer_texture_ + this->get_pixel_index(texel); -} - -inline void Result::copy_pixel(float *target, const float *source, const int channels_count) -{ - switch (channels_count) { - case 1: - *target = *source; - break; - case 2: - copy_v2_v2(target, source); - break; - case 3: - copy_v3_v3(target, source); - break; - case 4: - copy_v4_v4(target, source); - break; - default: - BLI_assert_unreachable(); - break; - } -} - -inline void Result::copy_pixel(int *target, const int *source, const int channels_count) -{ - switch (channels_count) { - case 1: - *target = *source; - break; - case 2: - copy_v2_v2_int(target, source); - break; - default: - BLI_assert_unreachable(); - break; - } -} - -inline void Result::copy_pixel(float *target, const float *source) const -{ - switch (type_) { - case ResultType::Float: - *target = *source; - break; - case ResultType::Float2: - copy_v2_v2(target, source); - break; - case ResultType::Float3: - copy_v3_v3(target, source); - break; - case ResultType::Vector: - case ResultType::Color: - copy_v4_v4(target, source); - break; - case ResultType::Int: - case ResultType::Int2: - BLI_assert_unreachable(); - break; - } + return int64_t(texel.y) * domain_.size.x + texel.x; } } // namespace blender::compositor diff --git a/source/blender/compositor/derived_resources/intern/denoised_auxiliary_pass.cc b/source/blender/compositor/derived_resources/intern/denoised_auxiliary_pass.cc index 1b971e63d85..7e5f662dc09 100644 --- a/source/blender/compositor/derived_resources/intern/denoised_auxiliary_pass.cc +++ b/source/blender/compositor/derived_resources/intern/denoised_auxiliary_pass.cc @@ -81,7 +81,7 @@ DenoisedAuxiliaryPass::DenoisedAuxiliaryPass(Context &context, this->denoised_buffer = static_cast(GPU_texture_read(pass, GPU_DATA_FLOAT, 0)); } else { - this->denoised_buffer = static_cast(MEM_dupallocN(pass.float_texture())); + this->denoised_buffer = static_cast(MEM_dupallocN(pass.cpu_data().data())); } const int width = pass.domain().size.x; diff --git a/source/blender/compositor/intern/multi_function_procedure_operation.cc b/source/blender/compositor/intern/multi_function_procedure_operation.cc index a1ae1404370..4e274f68b63 100644 --- a/source/blender/compositor/intern/multi_function_procedure_operation.cc +++ b/source/blender/compositor/intern/multi_function_procedure_operation.cc @@ -170,8 +170,7 @@ void MultiFunctionProcedureOperation::execute() add_single_value_input_parameter(parameter_builder, input); } else { - const GSpan span{get_cpp_type(input.type()), input.data(), size}; - parameter_builder.add_readonly_single_input(span); + parameter_builder.add_readonly_single_input(input.cpu_data()); } } else { @@ -181,8 +180,7 @@ void MultiFunctionProcedureOperation::execute() } else { output.allocate_texture(domain); - const GMutableSpan span{get_cpp_type(output.type()), output.data(), size}; - parameter_builder.add_uninitialized_single_output(span); + parameter_builder.add_uninitialized_single_output(output.cpu_data()); } } } diff --git a/source/blender/compositor/intern/reduce_to_single_value_operation.cc b/source/blender/compositor/intern/reduce_to_single_value_operation.cc index d4181e6a1c7..a38204d78c3 100644 --- a/source/blender/compositor/intern/reduce_to_single_value_operation.cc +++ b/source/blender/compositor/intern/reduce_to_single_value_operation.cc @@ -38,7 +38,7 @@ void ReduceToSingleValueOperation::execute() need_to_free_pixel = true; } else { - pixel = input.float_texture(); + pixel = input.cpu_data().data(); } Result &result = get_result(); diff --git a/source/blender/compositor/intern/result.cc b/source/blender/compositor/intern/result.cc index 510c8739174..aeb2a5637f6 100644 --- a/source/blender/compositor/intern/result.cc +++ b/source/blender/compositor/intern/result.cc @@ -2,11 +2,17 @@ * * SPDX-License-Identifier: GPL-2.0-or-later */ +#include +#include + #include "MEM_guardedalloc.h" #include "BLI_assert.h" +#include "BLI_cpp_type.hh" +#include "BLI_generic_span.hh" #include "BLI_math_matrix_types.hh" #include "BLI_math_vector_types.hh" +#include "BLI_utildefines.h" #include "GPU_shader.hh" #include "GPU_state.hh" @@ -212,8 +218,30 @@ ResultType Result::float_type(const int channels_count) Result::operator GPUTexture *() const { - BLI_assert(storage_type_ == ResultStorageType::GPU); - return gpu_texture_; + return this->gpu_texture(); +} + +const CPPType &Result::get_cpp_type() const +{ + switch (this->type()) { + case ResultType::Float: + return CPPType::get(); + case ResultType::Int: + return CPPType::get(); + case ResultType::Vector: + return CPPType::get(); + case ResultType::Color: + return CPPType::get(); + case ResultType::Float2: + return CPPType::get(); + case ResultType::Float3: + return CPPType::get(); + case ResultType::Int2: + return CPPType::get(); + } + + BLI_assert_unreachable(); + return CPPType::get(); } eGPUTextureFormat Result::get_gpu_texture_format() const @@ -238,39 +266,42 @@ void Result::allocate_texture(Domain domain, bool from_pool) void Result::allocate_single_value() { - /* Single values are stored in 1x1 textures as well as the single value members. Further, they + /* Single values are stored in 1x1 image as well as the single value members. Further, they * are always allocated from the pool. */ is_single_value_ = true; this->allocate_data(int2(1), true); domain_ = Domain::identity(); + + /* It is important that we initialize single values because the variant member that stores single + * values need to have its type initialized. */ + switch (type_) { + case ResultType::Float: + this->set_single_value(0.0f); + break; + case ResultType::Vector: + this->set_single_value(float4(0.0f)); + break; + case ResultType::Color: + this->set_single_value(float4(0.0f)); + break; + case ResultType::Float2: + this->set_single_value(float2(0.0f)); + break; + case ResultType::Float3: + this->set_single_value(float3(0.0f)); + break; + case ResultType::Int: + this->set_single_value(0); + break; + case ResultType::Int2: + this->set_single_value(int2(0)); + break; + } } void Result::allocate_invalid() { - allocate_single_value(); - switch (type_) { - case ResultType::Float: - set_single_value(0.0f); - break; - case ResultType::Vector: - set_single_value(float4(0.0f)); - break; - case ResultType::Color: - set_single_value(float4(0.0f)); - break; - case ResultType::Float2: - set_single_value(float2(0.0f)); - break; - case ResultType::Float3: - set_single_value(float3(0.0f)); - break; - case ResultType::Int: - set_single_value(0); - break; - case ResultType::Int2: - set_single_value(int2(0)); - break; - } + this->allocate_single_value(); } void Result::bind_as_texture(GPUShader *shader, const char *texture_name) const @@ -281,7 +312,7 @@ void Result::bind_as_texture(GPUShader *shader, const char *texture_name) const GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH); const int texture_image_unit = GPU_shader_get_sampler_binding(shader, texture_name); - GPU_texture_bind(gpu_texture_, texture_image_unit); + GPU_texture_bind(this->gpu_texture(), texture_image_unit); } void Result::bind_as_image(GPUShader *shader, const char *image_name, bool read) const @@ -294,19 +325,19 @@ void Result::bind_as_image(GPUShader *shader, const char *image_name, bool read) } const int image_unit = GPU_shader_get_sampler_binding(shader, image_name); - GPU_texture_image_bind(gpu_texture_, image_unit); + GPU_texture_image_bind(this->gpu_texture(), image_unit); } void Result::unbind_as_texture() const { BLI_assert(storage_type_ == ResultStorageType::GPU); - GPU_texture_unbind(gpu_texture_); + GPU_texture_unbind(this->gpu_texture()); } void Result::unbind_as_image() const { BLI_assert(storage_type_ == ResultStorageType::GPU); - GPU_texture_image_unbind(gpu_texture_); + GPU_texture_image_unbind(this->gpu_texture()); } void Result::pass_through(Result &target) @@ -354,24 +385,14 @@ void Result::wrap_external(GPUTexture *texture) domain_ = Domain(int2(GPU_texture_width(texture), GPU_texture_height(texture))); } -void Result::wrap_external(float *texture, int2 size) +void Result::wrap_external(void *data, int2 size) { BLI_assert(!this->is_allocated()); BLI_assert(!master_); - float_texture_ = texture; - storage_type_ = ResultStorageType::FloatCPU; - is_external_ = true; - domain_ = Domain(size); -} - -void Result::wrap_external(int *texture, int2 size) -{ - BLI_assert(!this->is_allocated()); - BLI_assert(!master_); - - integer_texture_ = texture; - storage_type_ = ResultStorageType::IntegerCPU; + const int64_t array_size = int64_t(size.x) * int64_t(size.y); + cpu_data_ = GMutableSpan(this->get_cpp_type(), data, array_size); + storage_type_ = ResultStorageType::CPU; is_external_ = true; domain_ = Domain(size); } @@ -468,20 +489,16 @@ void Result::free() switch (storage_type_) { case ResultStorageType::GPU: if (is_from_pool_) { - context_->texture_pool().release(gpu_texture_); + context_->texture_pool().release(this->gpu_texture()); } else { - GPU_texture_free(gpu_texture_); + GPU_texture_free(this->gpu_texture()); } gpu_texture_ = nullptr; break; - case ResultStorageType::FloatCPU: - MEM_freeN(float_texture_); - float_texture_ = nullptr; - break; - case ResultStorageType::IntegerCPU: - MEM_freeN(integer_texture_); - integer_texture_ = nullptr; + case ResultStorageType::CPU: + MEM_freeN(this->cpu_data().data()); + cpu_data_ = GMutableSpan(); break; } @@ -535,11 +552,9 @@ bool Result::is_allocated() const { switch (storage_type_) { case ResultStorageType::GPU: - return gpu_texture_ != nullptr; - case ResultStorageType::FloatCPU: - return float_texture_ != nullptr; - case ResultStorageType::IntegerCPU: - return integer_texture_ != nullptr; + return this->gpu_texture(); + case ResultStorageType::CPU: + return this->cpu_data().data(); } return false; @@ -557,6 +572,7 @@ int Result::reference_count() const void Result::allocate_data(int2 size, bool from_pool) { if (context_->use_gpu()) { + storage_type_ = ResultStorageType::GPU; is_from_pool_ = from_pool; if (from_pool) { gpu_texture_ = context_->texture_pool().acquire(size, this->get_gpu_texture_format()); @@ -572,23 +588,18 @@ void Result::allocate_data(int2 size, bool from_pool) } } else { - switch (type_) { - case ResultType::Float: - case ResultType::Vector: - case ResultType::Color: - case ResultType::Float2: - case ResultType::Float3: - float_texture_ = static_cast(MEM_malloc_arrayN( - int64_t(size.x) * int64_t(size.y), this->channels_count() * sizeof(float), __func__)); - storage_type_ = ResultStorageType::FloatCPU; - break; - case ResultType::Int: - case ResultType::Int2: - integer_texture_ = static_cast(MEM_malloc_arrayN( - int64_t(size.x) * int64_t(size.y), this->channels_count() * sizeof(int), __func__)); - storage_type_ = ResultStorageType::IntegerCPU; - break; - } + storage_type_ = ResultStorageType::CPU; + + const CPPType &cpp_type = this->get_cpp_type(); + const int64_t item_size = cpp_type.size(); + const int64_t alignment = cpp_type.alignment(); + const int64_t array_size = int64_t(size.x) * int64_t(size.y); + const int64_t memory_size = array_size * item_size; + + void *data = MEM_mallocN_aligned(memory_size, alignment, AT); + cpp_type.default_construct_n(data, array_size); + + cpu_data_ = GMutableSpan(cpp_type, data, array_size); } } diff --git a/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc b/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc index 9d81ef983fc..9797557a166 100644 --- a/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc +++ b/source/blender/nodes/composite/nodes/node_composite_convert_color_space.cc @@ -140,7 +140,7 @@ class ConvertColorSpaceOperation : public NodeOperation { }); IMB_colormanagement_processor_apply(color_processor, - output_image.float_texture(), + static_cast(output_image.cpu_data().data()), domain.size.x, domain.size.y, input_image.channels_count(), diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc index 3ce1675234a..1cf132e54c8 100644 --- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc +++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc @@ -148,8 +148,8 @@ class DenoiseOperation : public NodeOperation { temporary_buffers_to_free.append(input_color); } else { - input_color = input_image.float_texture(); - output_color = output_image.float_texture(); + input_color = static_cast(input_image.cpu_data().data()); + output_color = static_cast(output_image.cpu_data().data()); } oidn::FilterRef filter = device.newFilter("RT"); filter.setImage("color", input_color, oidn::Format::Float3, width, height, 0, pixel_stride); @@ -179,7 +179,7 @@ class DenoiseOperation : public NodeOperation { temporary_buffers_to_free.append(albedo); } else { - albedo = input_albedo.float_texture(); + albedo = static_cast(input_albedo.cpu_data().data()); } } @@ -207,7 +207,7 @@ class DenoiseOperation : public NodeOperation { temporary_buffers_to_free.append(normal); } else { - normal = input_normal.float_texture(); + normal = static_cast(input_normal.cpu_data().data()); } } diff --git a/source/blender/nodes/composite/nodes/node_composite_file_output.cc b/source/blender/nodes/composite/nodes/node_composite_file_output.cc index 6552c4bb655..cb2a1ab11d5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_file_output.cc +++ b/source/blender/nodes/composite/nodes/node_composite_file_output.cc @@ -659,14 +659,7 @@ class FileOutputOperation : public NodeOperation { } else { /* Copy the result into a new buffer. */ - const int64_t buffer_size = int64_t(size.x) * size.y * result.channels_count(); - buffer = static_cast( - MEM_malloc_arrayN(buffer_size, sizeof(float), "File Output Buffer Copy.")); - threading::parallel_for(IndexRange(buffer_size), 1024, [&](const IndexRange sub_range) { - for (const int64_t i : sub_range) { - buffer[i] = result.float_texture()[i]; - } - }); + buffer = static_cast(MEM_dupallocN(result.cpu_data().data())); } } @@ -750,15 +743,7 @@ class FileOutputOperation : public NodeOperation { } else { /* Copy the result into a new buffer. */ - const int2 size = result.domain().size; - const int64_t buffer_size = int64_t(size.x) * size.y * result.channels_count(); - buffer = static_cast( - MEM_malloc_arrayN(buffer_size, sizeof(float), "File Output Buffer Copy.")); - threading::parallel_for(IndexRange(buffer_size), 1024, [&](const IndexRange sub_range) { - for (const int64_t i : sub_range) { - buffer[i] = result.float_texture()[i]; - } - }); + buffer = static_cast(MEM_dupallocN(result.cpu_data().data())); } const int2 size = result.domain().size; diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc index a33798272f5..51816c25662 100644 --- a/source/blender/nodes/composite/nodes/node_composite_glare.cc +++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc @@ -1982,7 +1982,7 @@ class GlareOperation : public NodeOperation { highlights_buffer = static_cast(GPU_texture_read(highlights, GPU_DATA_FLOAT, 0)); } else { - highlights_buffer = highlights.float_texture(); + highlights_buffer = static_cast(highlights.cpu_data().data()); } /* Zero pad the image to the required spatial domain size, storing each channel in planar @@ -2060,8 +2060,9 @@ class GlareOperation : public NodeOperation { /* For GPU, write the output to the exist highlights_buffer then upload to the result after, * while for CPU, write to the result directly. */ - float *output = this->context().use_gpu() ? highlights_buffer : - fog_glow_result.float_texture(); + float *output = this->context().use_gpu() ? + highlights_buffer : + static_cast(fog_glow_result.cpu_data().data()); /* Copy the result to the output. */ threading::parallel_for(IndexRange(image_size.y), 1, [&](const IndexRange sub_y_range) { diff --git a/source/blender/render/intern/compositor.cc b/source/blender/render/intern/compositor.cc index 91f2acd18ef..bca0730f15b 100644 --- a/source/blender/render/intern/compositor.cc +++ b/source/blender/render/intern/compositor.cc @@ -507,7 +507,7 @@ class Context : public compositor::Context { MEM_malloc_arrayN(rr->rectx * rr->recty, 4 * sizeof(float), __func__)); IMB_assign_float_buffer(ibuf, data, IB_TAKE_OWNERSHIP); std::memcpy( - data, output_result_.float_texture(), rr->rectx * rr->recty * 4 * sizeof(float)); + data, output_result_.cpu_data().data(), rr->rectx * rr->recty * 4 * sizeof(float)); } } @@ -580,7 +580,7 @@ class Context : public compositor::Context { } else { std::memcpy(image_buffer->float_buffer.data, - viewer_output_result_.float_texture(), + viewer_output_result_.cpu_data().data(), size.x * size.y * 4 * sizeof(float)); }