summaryrefslogtreecommitdiff
path: root/SharedGraphics/PNGLoader.cpp
diff options
context:
space:
mode:
authorAndreas Kling <awesomekling@gmail.com>2019-03-21 16:40:40 +0100
committerAndreas Kling <awesomekling@gmail.com>2019-03-21 16:45:04 +0100
commitcd1afde48c72e356f87117673e956e85d2a902fb (patch)
treec3ce1ce41f66b3e63c09e1b2326bc9bbc0b4de38 /SharedGraphics/PNGLoader.cpp
parentcfc521d57e31e8ea9ab4a135862462439083580d (diff)
downloadserenity-cd1afde48c72e356f87117673e956e85d2a902fb.zip
PNGLoader: Templatize the unfiltering functions to reduce branchiness.
This also allows us to dodge processing alpha values in non-alpha PNGs without a branch.
Diffstat (limited to 'SharedGraphics/PNGLoader.cpp')
-rw-r--r--SharedGraphics/PNGLoader.cpp140
1 files changed, 103 insertions, 37 deletions
diff --git a/SharedGraphics/PNGLoader.cpp b/SharedGraphics/PNGLoader.cpp
index 252161115a..204c695996 100644
--- a/SharedGraphics/PNGLoader.cpp
+++ b/SharedGraphics/PNGLoader.cpp
@@ -137,7 +137,7 @@ RetainPtr<GraphicsBitmap> load_png(const String& path)
return bitmap;
}
-static byte paeth_predictor(int a, int b, int c)
+[[gnu::always_inline]] static inline byte paeth_predictor(int a, int b, int c)
{
int p = a + b - c;
int pa = abs(p - a);
@@ -161,6 +161,81 @@ union [[gnu::packed]] Pixel {
};
static_assert(sizeof(Pixel) == 4);
+template<bool has_alpha, byte filter_type>
+[[gnu::always_inline]] static inline void unfilter_impl(const GraphicsBitmap& bitmap, int y)
+{
+ if constexpr (filter_type == 1) {
+ auto* pixels = (Pixel*)bitmap.scanline(y);
+ for (int i = 0; i < bitmap.width(); ++i) {
+ auto& x = pixels[i];
+ swap(x.r, x.b);
+ Pixel a;
+ if (i != 0) a.rgba = bitmap.scanline(y)[i - 1];
+ x.r += a.r;
+ x.g += a.g;
+ x.b += a.b;
+ if constexpr (has_alpha)
+ x.a += a.a;
+ }
+ return;
+ }
+ if constexpr (filter_type == 2) {
+ auto* pixels = (Pixel*)bitmap.scanline(y);
+ for (int i = 0; i < bitmap.width(); ++i) {
+ auto& x = pixels[i];
+ swap(x.r, x.b);
+ Pixel b;
+ if (y != 0) b.rgba = bitmap.scanline(y - 1)[i];
+ x.r += b.r;
+ x.g += b.g;
+ x.b += b.b;
+ if constexpr (has_alpha)
+ x.a += b.a;
+ }
+ return;
+ }
+
+ if constexpr (filter_type == 3) {
+ auto* pixels = (Pixel*)bitmap.scanline(y);
+ for (int i = 0; i < bitmap.width(); ++i) {
+ auto& x = pixels[i];
+ swap(x.r, x.b);
+ Pixel a;
+ Pixel b;
+ if (i != 0) a.rgba = bitmap.scanline(y)[i - 1];
+ if (y != 0) b.rgba = bitmap.scanline(y - 1)[i];
+ x.r = x.r + ((a.r + b.r) / 2);
+ x.g = x.g + ((a.g + b.g) / 2);
+ x.b = x.b + ((a.b + b.b) / 2);
+ if constexpr (has_alpha)
+ x.a = x.a + ((a.a + b.a) / 2);
+ }
+ return;
+ }
+
+ if constexpr (filter_type == 4) {
+ auto* pixels = (Pixel*)bitmap.scanline(y);
+ for (int i = 0; i < bitmap.width(); ++i) {
+ auto& x = pixels[i];
+ swap(x.r, x.b);
+ Pixel a;
+ Pixel b;
+ Pixel c;
+ if (i != 0) a.rgba = bitmap.scanline(y)[i - 1];
+ if (y != 0) b.rgba = bitmap.scanline(y - 1)[i];
+ if (y != 0 && i != 0) c.rgba = bitmap.scanline(y - 1)[i - 1];
+ x.r += paeth_predictor(a.r, b.r, c.r);
+ x.g += paeth_predictor(a.g, b.g, c.g);
+ x.b += paeth_predictor(a.b, b.b, c.b);
+ if constexpr (has_alpha)
+ x.a += paeth_predictor(a.a, b.a, c.a);
+ }
+ }
+}
+
+
+
+
[[gnu::noinline]] static void unfilter(PNGLoadingContext& context)
{
{
@@ -196,42 +271,33 @@ static_assert(sizeof(Pixel) == 4);
auto filter = context.scanlines[y].filter;
if (filter == 0)
continue;
- for (int i = 0; i < context.width; ++i) {
- auto& x = (Pixel&)context.bitmap->scanline(y)[i];
- swap(x.r, x.b);
- Pixel a;
- Pixel b;
-
- if (i != 0) a.rgba = context.bitmap->scanline(y)[i - 1];
- if (y != 0) b.rgba = context.bitmap->scanline(y - 1)[i];
-
- if (filter == 1) {
- x.r += a.r;
- x.g += a.g;
- x.b += a.b;
- if (context.has_alpha())
- x.a += a.a;
- } else if (filter == 2) {
- x.r += b.r;
- x.g += b.g;
- x.b += b.b;
- if (context.has_alpha())
- x.a += b.a;
- } if (filter == 3) {
- x.r = x.r + ((a.r + b.r) / 2);
- x.g = x.g + ((a.g + b.g) / 2);
- x.b = x.b + ((a.b + b.b) / 2);
- if (context.has_alpha())
- x.a = x.a + ((a.a + b.a) / 2);
- } if (filter == 4) {
- Pixel c;
- if (y != 0 && i != 0) c.rgba = context.bitmap->scanline(y - 1)[i - 1];
- x.r += paeth_predictor(a.r, b.r, c.r);
- x.g += paeth_predictor(a.g, b.g, c.g);
- x.b += paeth_predictor(a.b, b.b, c.b);
- if (context.has_alpha())
- x.a += paeth_predictor(a.a, b.a, c.a);
- }
+ if (filter == 1) {
+ if (context.has_alpha())
+ unfilter_impl<true, 1>(*context.bitmap, y);
+ else
+ unfilter_impl<false, 1>(*context.bitmap, y);
+ continue;
+ }
+ if (filter == 2) {
+ if (context.has_alpha())
+ unfilter_impl<true, 2>(*context.bitmap, y);
+ else
+ unfilter_impl<false, 2>(*context.bitmap, y);
+ continue;
+ }
+ if (filter == 3) {
+ if (context.has_alpha())
+ unfilter_impl<true, 3>(*context.bitmap, y);
+ else
+ unfilter_impl<false, 3>(*context.bitmap, y);
+ continue;
+ }
+ if (filter == 4) {
+ if (context.has_alpha())
+ unfilter_impl<true, 4>(*context.bitmap, y);
+ else
+ unfilter_impl<false, 4>(*context.bitmap, y);
+ continue;
}
}
}