[Bf-blender-cvs] [a37147347d3] temp-gpu-image-engine: Revert "Revert recent changes to ImBuf transform"
Jeroen Bakker
noreply at git.blender.org
Mon Dec 13 12:47:44 CET 2021
Commit: a37147347d39166931e3f8fad9c1472def98de07
Author: Jeroen Bakker
Date: Mon Dec 13 07:45:05 2021 +0100
Branches: temp-gpu-image-engine
https://developer.blender.org/rBa37147347d39166931e3f8fad9c1472def98de07
Revert "Revert recent changes to ImBuf transform"
This reverts commit 5a3d5f751f238e568da2bd2b3e3b08dc9e79e3a1.
===================================================================
M source/blender/imbuf/intern/transform.cc
===================================================================
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index 0cb363c3bce..a0b39cd5b7c 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -85,23 +85,206 @@ struct TransformUserData {
}
};
-template<eIMBTransformMode Mode, InterpolationColorFunction ColorInterpolation, int ChannelLen = 4>
-class ScanlineProcessor {
- private:
- void pixel_from_buffer(const struct ImBuf *ibuf, unsigned char **outI, float **outF, int y) const
+/**
+ * \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])
{
- const size_t offset = ((size_t)ibuf->x) * y * ChannelLen;
+ 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,
- if (ibuf->rect) {
- *outI = (unsigned char *)ibuf->rect + offset;
+ /**
+ * \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<ImBufStorageType, float>) {
+ pointer = image_buffer->rect_float + offset;
+ }
+ else if constexpr (std::is_same_v<ImBufStorageType, unsigned char>) {
+ pointer = image_buffer->rect + offset;
}
+ else {
+ pointer = nullptr;
+ }
+ }
- if (ibuf->rect_float) {
- *outF = ibuf->rect_float + offset;
+ float *get_float_pointer()
+ {
+ if constexpr (std::is_same_v<ImBufStorageType, float>) {
+ return pointer;
+ }
+ else {
+ return nullptr;
+ }
+ }
+ unsigned char *get_uchar_pointer()
+ {
+ if constexpr (std::is_same_v<ImBufStorageType, unsigned char>) {
+ 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;
+ }
+
+ float modify_v(const TransformUserData &UNUSED(user_data), float v) override
+ {
+ return v;
+ }
+};
+
+/**
+ * \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;
+ }
+ 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;
+ }
+ 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)
{
@@ -110,27 +293,18 @@ class ScanlineProcessor {
float uv[2];
madd_v2_v2v2fl(uv, user_data->start_uv, user_data->add_y, scanline);
- unsigned char *outI = nullptr;
- float *outF = nullptr;
- pixel_from_buffer(user_data->dst, &outI, &outF, scanline);
-
+ output.init_pixel_pointer(user_data->dst, 0, scanline);
for (int xi = 0; xi < width; xi++) {
- 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]);
+ 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]));
}
+
add_v2_v2(uv, user_data->add_x);
- if (outI) {
- outI += ChannelLen;
- }
- if (outF) {
- outF += ChannelLen;
- }
+ output.increase_pixel_pointer();
}
}
};
@@ -142,20 +316,26 @@ template<typename Processor> void transform_scanline_function(void *custom_data,
processor.process(user_data, scanline);
}
-template<InterpolationColorFunction DefaultFunction, InterpolationColorFunction WrapRepeatFunction>
+template<InterpolationColorFunction InterpolationFunction>
ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
{
switch (mode) {
case IMB_TRANSFORM_MODE_REGULAR:
- return transform_scanline_function<
- ScanlineProcessor<IMB_TRANSFORM_MODE_REGULAR, DefaultFunction>>;
+ return transform_scanline_function<ScanlineProcessor<NoDiscard,
+ InterpolationFunction,
+ TexelPointer<float, 4>,
+ PassThroughUV>>;
case IMB_TRANSFORM_MODE_CROP_SRC:
- return transform_scanline_function<
- ScanlineProcessor<IMB_TRANSFORM_MODE_CROP_SRC, DefaultFunction>>;
+ return transform_scanline_function<ScanlineProcessor<CropSource,
+ InterpolationFunction,
+ TexelPointer<float, 4>,
+ PassThroughUV>>;
case IMB_TRANSFORM_MODE_WRAP_REPEAT:
- return transform_scanline_function<
- ScanlineProcessor<IMB_TRANSFORM_MODE_WRAP_REPEAT, WrapRepeatFunction>>;
+ return transform_scanline_function<ScanlineProcessor<NoDiscard,
+ InterpolationFunction,
+ TexelPointer<float, 4>,
+ WrapRepeatUV>>;
}
BLI_assert_unreachable();
@@ -171,15 +351,13 @@ 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<interpolation_function, nearest_interpolation_color_wrap>(mode);
+ scanline_func = get_scanline_function<interpolation_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<interpolation_function, nearest_interpolation_color_wrap>(mode);
+ scanline_func = get_scanline_function<interpolation_function>(mode);
}
if (scanline_func != nullptr) {
More information about the Bf-blender-cvs
mailing list