From 5a3d5f751f238e568da2bd2b3e3b08dc9e79e3a1 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 10 Dec 2021 12:52:50 -0600 Subject: Revert recent changes to ImBuf transform This reverts commit 943aed0de35621e328 and f76e04bf4d7cdce8 The latter caused a test failure: `sequencer_render_transform` Reverting since the fix is not obvious (to me), and people are away for the weekend. --- source/blender/imbuf/intern/transform.cc | 254 +++++-------------------------- 1 file changed, 38 insertions(+), 216 deletions(-) diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc index caa43fc4e8d..6cd5ef23783 100644 --- a/source/blender/imbuf/intern/transform.cc +++ b/source/blender/imbuf/intern/transform.cc @@ -83,205 +83,22 @@ struct TransformUserData { } }; -/** - * \brief Base class for source discarding. - * - * The class decides if a specific uv coordinate from the source buffer should be ignored. - * This is used to mix multiple images over a single output buffer. Discarded pixels will - * not change the output buffer. - */ -class BaseDiscard { - public: - virtual ~BaseDiscard() = default; - - /** - * \brief Should the source pixel at the given uv coordinate be discarded. - */ - virtual bool should_discard(const TransformUserData &user_data, const float uv[2]) = 0; -}; - -/** - * \brief Crop uv-coordinates that are outside the user data src_crop rect. - */ -class CropSource : public BaseDiscard { - public: - /** - * \brief Should the source pixel at the given uv coordinate be discarded. - * - * Uses user_data.src_crop to determine if the uv coordinate should be skipped. - */ - virtual bool should_discard(const TransformUserData &user_data, const float uv[2]) - { - return uv[0] < user_data.src_crop.xmin && uv[0] >= user_data.src_crop.xmax && - uv[1] < user_data.src_crop.ymin && uv[1] >= user_data.src_crop.ymax; - } -}; - -/** - * \brief Discard that does not discard anything. - */ -class NoDiscard : public BaseDiscard { - public: - /** - * \brief Should the source pixel at the given uv coordinate be discarded. - * - * Will never discard any pixels. - */ - virtual bool should_discard(const TransformUserData &UNUSED(user_data), - const float UNUSED(uv[2])) - { - return false; - } -}; - -/** - * \brief pointer to a texel to write or read serial. - */ -template< - /** - * \brief Kind of buffer. - * Possible options: float, unsigned char. - */ - typename ImBufStorageType = float, - - /** - * \brief Number of channels of a single pixel. - */ - int NumChannels = 4> -class TexelPointer { - ImBufStorageType *pointer; - - public: - void init_pixel_pointer(const ImBuf *image_buffer, int x, int y) - { - const size_t offset = (y * (size_t)image_buffer->x + x) * NumChannels; - - if constexpr (std::is_same_v) { - pointer = image_buffer->rect_float + offset; - } - else if constexpr (std::is_same_v) { - pointer = image_buffer->rect + offset; - } - else { - pointer = nullptr; - } - } - - float *get_float_pointer() - { - if constexpr (std::is_same_v) { - return pointer; - } - else { - return nullptr; - } - } - unsigned char *get_uchar_pointer() - { - if constexpr (std::is_same_v) { - return pointer; - } - else { - return nullptr; - } - } - - void increase_pixel_pointer() - { - pointer += NumChannels; - } -}; - -/** - * \brief Wrapping mode for the uv coordinates. - * - * Subclasses have the ability to change the UV coordinates before the source buffer will be - * sampled. - */ -class BaseUVWrapping { - public: - /** - * \brief modify the given u coordinate. - */ - virtual float modify_u(const TransformUserData &user_data, float u) = 0; - - /** - * \brief modify the given v coordinate. - */ - virtual float modify_v(const TransformUserData &user_data, float v) = 0; -}; - -/** - * \brief UVWrapping method that does not modify the UV coordinates. - */ -class PassThroughUV : public BaseUVWrapping { - public: - float modify_u(const TransformUserData &UNUSED(user_data), float u) override - { - return u; - } +template +class ScanlineProcessor { + private: + void pixel_from_buffer(const struct ImBuf *ibuf, unsigned char **outI, float **outF, int y) const - float modify_v(const TransformUserData &UNUSED(user_data), float v) override { - return v; - } -}; + const size_t offset = ((size_t)ibuf->x) * y * ChannelLen; -/** - * \brief UVWrapping method that wrap repeats the UV coordinates. - */ -class WrapRepeatUV : public BaseUVWrapping { - public: - float modify_u(const TransformUserData &user_data, float u) override - - { - int x = (int)floor(u); - x = x % user_data.src->x; - if (x < 0) { - x += user_data.src->x; + if (ibuf->rect) { + *outI = (unsigned char *)ibuf->rect + offset; } - return x; - } - float modify_v(const TransformUserData &user_data, float v) override - { - int y = (int)floor(v); - y = y % user_data.src->y; - if (y < 0) { - y += user_data.src->y; + if (ibuf->rect_float) { + *outF = ibuf->rect_float + offset; } - return y; } -}; - -template< - /** - * \brief Discard function to use. - * - * \attention Should be a subclass of BaseDiscard. - */ - typename Discard, - - /** - * \brief Color interpolation function to read from the source buffer. - */ - InterpolationColorFunction ColorInterpolation, - - /** - * \brief Kernel to store to the destination buffer. - * Should be an TexelPointer - */ - typename OutputTexelPointer, - - /** - * \brief Wrapping method to perform - * Should be a subclass of BaseUVWrapper - */ - typename UVWrapping> -class ScanlineProcessor { - Discard discarder; - UVWrapping uv_wrapping; - OutputTexelPointer output; public: void process(const TransformUserData *user_data, int scanline) @@ -291,18 +108,27 @@ class ScanlineProcessor { float uv[2]; madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline); - output.init_pixel_pointer(user_data->dst, 0, scanline); + unsigned char *outI = nullptr; + float *outF = nullptr; + pixel_from_buffer(user_data->dst, &outI, &outF, scanline); + for (int xi = 0; xi < width; xi++) { - if (!discarder.should_discard(*user_data, uv)) { - ColorInterpolation(user_data->src, - output.get_uchar_pointer(), - output.get_float_pointer(), - uv_wrapping.modify_u(*user_data, uv[0]), - uv_wrapping.modify_v(*user_data, uv[1])); + if constexpr (Mode == IMB_TRANSFORM_MODE_CROP_SRC) { + if (uv[0] >= user_data->src_crop.xmin && uv[0] < user_data->src_crop.xmax && + uv[1] >= user_data->src_crop.ymin && uv[1] < user_data->src_crop.ymax) { + ColorInterpolation(user_data->src, outI, outF, uv[0], uv[1]); + } + } + else { + ColorInterpolation(user_data->src, outI, outF, uv[0], uv[1]); } - add_v2_v2(uv, user_data->add_x); - output.increase_pixel_pointer(); + if (outI) { + outI += ChannelLen; + } + if (outF) { + outF += ChannelLen; + } } } }; @@ -314,26 +140,20 @@ template void transform_scanline_function(void *custom_data, processor.process(user_data, scanline); } -template +template ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode) { switch (mode) { case IMB_TRANSFORM_MODE_REGULAR: - return transform_scanline_function, - PassThroughUV>>; + return transform_scanline_function< + ScanlineProcessor>; case IMB_TRANSFORM_MODE_CROP_SRC: - return transform_scanline_function, - PassThroughUV>>; + return transform_scanline_function< + ScanlineProcessor>; case IMB_TRANSFORM_MODE_WRAP_REPEAT: - return transform_scanline_function, - WrapRepeatUV>>; + return transform_scanline_function< + ScanlineProcessor>; } BLI_assert_unreachable(); @@ -349,13 +169,15 @@ static void transform(TransformUserData *user_data, const eIMBTransformMode mode constexpr InterpolationColorFunction interpolation_function = Filter == IMB_FILTER_NEAREST ? nearest_interpolation_color_fl : bilinear_interpolation_color_fl; - scanline_func = get_scanline_function(mode); + scanline_func = + get_scanline_function(mode); } else if (user_data->dst->rect) { constexpr InterpolationColorFunction interpolation_function = Filter == IMB_FILTER_NEAREST ? nearest_interpolation_color_char : bilinear_interpolation_color_char; - scanline_func = get_scanline_function(mode); + scanline_func = + get_scanline_function(mode); } if (scanline_func != nullptr) { -- cgit v1.2.3