From df71bccf9c4731af9bcca79eee8d95651646bd82 Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Tue, 3 Mar 2020 19:16:04 +0100 Subject: Further optimize pixel blending. And re-introduce lineBlending in Painter::drawImage. --- plugingui/nativewindow_x11.cc | 1 - plugingui/painter.cc | 14 +++++--- plugingui/pixelbuffer.cc | 78 ++++++++++++++++++++++++++----------------- plugingui/texture.cc | 2 +- 4 files changed, 58 insertions(+), 37 deletions(-) diff --git a/plugingui/nativewindow_x11.cc b/plugingui/nativewindow_x11.cc index de215c2..33dde7b 100644 --- a/plugingui/nativewindow_x11.cc +++ b/plugingui/nativewindow_x11.cc @@ -680,7 +680,6 @@ void NativeWindowX11::updateImageFromBuffer(std::size_t x1, std::size_t y1, if(depth >= 24) // RGB 888 format { std::uint32_t* shm_addr = (std::uint32_t*)shm_info.shmaddr; - for(std::size_t y = y1; y < y2; ++y) { for(std::size_t x = x1; x < x2; ++x) diff --git a/plugingui/painter.cc b/plugingui/painter.cc index 761fe9b..7f8acba 100644 --- a/plugingui/painter.cc +++ b/plugingui/painter.cc @@ -65,7 +65,11 @@ static void plot(PixelBufferAlpha& pixbuf, const Colour& colour, } // plot the pixel at (x, y) with brightness c (where 0 ≤ c ≤ 1) - Colour col(colour.red(), colour.green(), colour.blue(), (std::uint8_t)(colour.alpha() * c)); + Colour col(colour); + if(c != 1) + { + col.data()[3] *= c; + } pixbuf.addPixel(x, y, col); } @@ -369,7 +373,7 @@ void Painter::drawImage(int x0, int y0, const Drawable& image) if(image.hasAlpha()) { - if(true || !image.line(0)) + if(!image.line(0)) { for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) { @@ -398,7 +402,8 @@ void Painter::drawImage(int x0, int y0, const Drawable& image) std::size_t x = -1 * std::min(0, x0); for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) { - pixbuf.blendLine(x + x0, y + y0, image.line(y), image.width()); + pixbuf.blendLine(x + x0, y + y0, image.line(y), + std::min((int)image.width(), fw - (int)x)); } } } @@ -407,7 +412,8 @@ void Painter::drawImage(int x0, int y0, const Drawable& image) std::size_t x = -1 * std::min(0, x0); for(std::size_t y = -1 * std::min(0, y0); y < (std::size_t)fh; ++y) { - pixbuf.writeLine(x + x0, y + y0, image.line(y), image.width()); + pixbuf.writeLine(x + x0, y + y0, image.line(y), + std::min((int)image.width(), fw - (int)x)); } } } diff --git a/plugingui/pixelbuffer.cc b/plugingui/pixelbuffer.cc index fd02703..918298b 100644 --- a/plugingui/pixelbuffer.cc +++ b/plugingui/pixelbuffer.cc @@ -269,7 +269,9 @@ void PixelBufferAlpha::writeLine(std::size_t x, std::size_t y, std::memcpy(offset, line, len * 4); } + // SIMD: https://github.com/WojciechMula/toys/blob/master/blend_32bpp/blend_32bpp.c +// Alpha blending: http://en.wikipedia.org/wiki/Alpha_compositing void PixelBufferAlpha::blendLine(std::size_t x, std::size_t y, const std::uint8_t* line, std::size_t len) @@ -279,56 +281,70 @@ void PixelBufferAlpha::blendLine(std::size_t x, std::size_t y, return; // out of bounds } + int a, b; std::uint8_t* target = &buf[PX(0)]; - for(std::size_t x = 0; x < len; ++x) + while(len) { - unsigned int a = line[3]; - unsigned int b = 255 - a; + if(line[3] == 0xff) + { + const std::uint8_t* end = line; + while(end[3] == 0xff && end < line + len * 4) + { + end += 4; + } + auto chunk_len = end - line; + memcpy(target, line, chunk_len); + line += chunk_len; + target += chunk_len; + len -= chunk_len / 4; + continue; + } + else if(line[3] == 0) + { + // Do nothing + } + else + { + a = line[3]; + b = target[3] * (255 - a) / 255; + + target[0] = (line[0] * a + target[0] * b) / (a + b); + target[1] = (line[1] * a + target[1] * b) / (a + b); + target[2] = (line[2] * a + target[2] * b) / (a + b); + target[3] = (int)target[3] + line[3] * (255 - target[3]) / 255; + } - target[0] = (std::uint8_t)((line[0] * a + target[0] * b) / 255); - target[1] = (std::uint8_t)((line[1] * a + target[1] * b) / 255); - target[2] = (std::uint8_t)((line[2] * a + target[2] * b) / 255); - target[3] = a * b / 255; line += 4; target += 4; + --len; } } - -// http://en.wikipedia.org/wiki/Alpha_compositing -static inline void getAlpha(std::uint8_t _a, std::uint8_t _b, - float &a, float &b) -{ - a = _a / 255.0; - b = _b / 255.0; - b *= (1 - a); -} - void PixelBufferAlpha::addPixel(std::size_t x, std::size_t y, const Colour& c) { - if(c.alpha() == 0) + const std::uint8_t* colour = c.data(); + + if(colour[3] == 0) { return; } - std::uint8_t* pixel = &buf[PX(0)]; + int a, b; + std::uint8_t* target = &buf[PX(0)]; - if(c.alpha() < 255) + if(colour[3] == 0xff) { - float a, b; - getAlpha(c.alpha(), buf[PX(3)], a, b); - - *pixel = (std::uint8_t)((c.red() * a + *pixel * b) / (a + b)); - ++pixel; - *pixel = (std::uint8_t)((c.green() * a + *pixel * b) / (a + b)); - ++pixel; - *pixel = (std::uint8_t)((c.blue() * a + *pixel * b) / (a + b)); - ++pixel; - *pixel = (a + b) * 255; + memcpy(target, colour, 4); } else { - memcpy(pixel, c.data(), 4); + a = colour[3]; + b = target[3] * (255 - a) / 255; + + target[0] = (colour[0] * a + target[0] * b) / (a + b); + target[1] = (colour[1] * a + target[1] * b) / (a + b); + target[2] = (colour[2] * a + target[2] * b) / (a + b); + target[3] = (int)target[3] + colour[3] * (255 - target[3]) / 255; } } diff --git a/plugingui/texture.cc b/plugingui/texture.cc index 39d417d..a5908cb 100644 --- a/plugingui/texture.cc +++ b/plugingui/texture.cc @@ -61,7 +61,7 @@ const Colour& Texture::getPixel(size_t x, size_t y) const const std::uint8_t* Texture::line(std::size_t y) const { - return image.line(y + _y); + return image.line(y + _y) + _x * 4; } bool Texture::hasAlpha() const -- cgit v1.2.3