summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2020-03-03 19:16:04 +0100
committerBent Bisballe Nyeng <deva@aasimon.org>2020-03-07 19:23:12 +0100
commitdf71bccf9c4731af9bcca79eee8d95651646bd82 (patch)
tree1c9485bed0fdd64410282156537553b8fde3bb86
parent560574d2e565510edd39dd9daf1d957a85f2220c (diff)
Further optimize pixel blending. And re-introduce lineBlending in Painter::drawImage.
-rw-r--r--plugingui/nativewindow_x11.cc1
-rw-r--r--plugingui/painter.cc14
-rw-r--r--plugingui/pixelbuffer.cc78
-rw-r--r--plugingui/texture.cc2
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