Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen Bakker <jeroen@blender.org>2021-12-10 17:19:41 +0300
committerJeroen Bakker <jeroen@blender.org>2021-12-10 17:19:41 +0300
commitf76e04bf4d7cdce8fe563b85bb272e9d5ede2b78 (patch)
tree250ec1511fdf8e7cfd7db16ead47cf99d946e566 /source/blender/imbuf/intern/transform.cc
parent37e799e299d52f57b638463c51cfbeaf8de820a6 (diff)
ImBuf: Use templating for IMB_transform.
Reduce the inner loop of IMB_transform by extracting writing to an output buffer in a template. This reduces a branch in the inner loop and would allow different number of channels in the future.
Diffstat (limited to 'source/blender/imbuf/intern/transform.cc')
-rw-r--r--source/blender/imbuf/intern/transform.cc162
1 files changed, 132 insertions, 30 deletions
diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc
index 6cd5ef23783..7c130c658c4 100644
--- a/source/blender/imbuf/intern/transform.cc
+++ b/source/blender/imbuf/intern/transform.cc
@@ -83,22 +83,136 @@ 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])
+ {
+ 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 = ((size_t)ibuf->x) * y * ChannelLen;
+ const size_t offset = (y * (size_t)image_buffer->x + x) * NumChannels;
- if (ibuf->rect) {
- *outI = (unsigned char *)ibuf->rect + offset;
+ 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;
+ }
+};
+
+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>
+class ScanlineProcessor {
+ Discard discarder;
+ OutputTexelPointer output;
public:
void process(const TransformUserData *user_data, int scanline)
@@ -108,27 +222,15 @@ 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[0], uv[1]);
}
+
add_v2_v2(uv, user_data->add_x);
- if (outI) {
- outI += ChannelLen;
- }
- if (outF) {
- outF += ChannelLen;
- }
+ output.increase_pixel_pointer();
}
}
};
@@ -147,13 +249,13 @@ ScanlineThreadFunc get_scanline_function(const eIMBTransformMode mode)
switch (mode) {
case IMB_TRANSFORM_MODE_REGULAR:
return transform_scanline_function<
- ScanlineProcessor<IMB_TRANSFORM_MODE_REGULAR, DefaultFunction>>;
+ ScanlineProcessor<NoDiscard, DefaultFunction, TexelPointer<float, 4>>>;
case IMB_TRANSFORM_MODE_CROP_SRC:
return transform_scanline_function<
- ScanlineProcessor<IMB_TRANSFORM_MODE_CROP_SRC, DefaultFunction>>;
+ ScanlineProcessor<CropSource, DefaultFunction, TexelPointer<float, 4>>>;
case IMB_TRANSFORM_MODE_WRAP_REPEAT:
return transform_scanline_function<
- ScanlineProcessor<IMB_TRANSFORM_MODE_WRAP_REPEAT, WrapRepeatFunction>>;
+ ScanlineProcessor<NoDiscard, WrapRepeatFunction, TexelPointer<float, 4>>>;
}
BLI_assert_unreachable();