summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2014-04-04 12:41:25 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2014-04-04 12:57:50 +0100
commit6e86e84da1c8049a150eb6b5780526fea57e0f9d (patch)
tree976a4fa70a06fa3fe6b854af6ba08826806d96ad
parent31a4c7bc13c5f4560482b450b9ee4788a58930cd (diff)
sna: Precompute OVER/ADD with solids to convert it into a BLT operation
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r--src/sna/sna_blt.c127
1 files changed, 125 insertions, 2 deletions
diff --git a/src/sna/sna_blt.c b/src/sna/sna_blt.c
index b83e6b20..f68d9510 100644
--- a/src/sna/sna_blt.c
+++ b/src/sna/sna_blt.c
@@ -815,6 +815,26 @@ sna_picture_is_solid(PicturePtr picture, uint32_t *color)
}
static bool
+pixel_is_transparent(uint32_t pixel, uint32_t format)
+{
+ unsigned int abits;
+
+ abits = PICT_FORMAT_A(format);
+ if (!abits)
+ return false;
+
+ if (PICT_FORMAT_TYPE(format) == PICT_TYPE_A ||
+ PICT_FORMAT_TYPE(format) == PICT_TYPE_BGRA) {
+ return (pixel & ((1 << abits) - 1)) == 0;
+ } else if (PICT_FORMAT_TYPE(format) == PICT_TYPE_ARGB ||
+ PICT_FORMAT_TYPE(format) == PICT_TYPE_ABGR) {
+ unsigned int ashift = PICT_FORMAT_BPP(format) - abits;
+ return (pixel >> ashift) == 0;
+ } else
+ return false;
+}
+
+static bool
pixel_is_opaque(uint32_t pixel, uint32_t format)
{
unsigned int abits;
@@ -868,6 +888,16 @@ is_white(PicturePtr picture)
return pixel_is_white(get_pixel(picture), picture->format);
}
+static bool
+is_transparent(PicturePtr picture)
+{
+ if (picture->pSourcePict) {
+ PictSolidFill *fill = (PictSolidFill *) picture->pSourcePict;
+ return fill->color == 0;
+ } else
+ return pixel_is_transparent(get_pixel(picture), picture->format);
+}
+
bool
sna_composite_mask_is_opaque(PicturePtr mask)
{
@@ -2361,6 +2391,71 @@ is_clear(PixmapPtr pixmap)
return priv && priv->clear;
}
+static inline uint32_t
+over(uint32_t src, uint32_t dst)
+{
+ uint32_t a = ~src >> 24;
+
+#define G_SHIFT 8
+#define RB_MASK 0xff00ff
+#define RB_ONE_HALF 0x800080
+#define RB_MASK_PLUS_ONE 0x10000100
+
+#define UN8_rb_MUL_UN8(x, a, t) do { \
+ t = ((x) & RB_MASK) * (a); \
+ t += RB_ONE_HALF; \
+ x = (t + ((t >> G_SHIFT) & RB_MASK)) >> G_SHIFT; \
+ x &= RB_MASK; \
+} while (0)
+
+#define UN8_rb_ADD_UN8_rb(x, y, t) do { \
+ t = ((x) + (y)); \
+ t |= RB_MASK_PLUS_ONE - ((t >> G_SHIFT) & RB_MASK); \
+ x = (t & RB_MASK); \
+} while (0)
+
+#define UN8x4_MUL_UN8_ADD_UN8x4(x, a, y) do { \
+ uint32_t r1__, r2__, r3__, t__; \
+ \
+ r1__ = (x); \
+ r2__ = (y) & RB_MASK; \
+ UN8_rb_MUL_UN8(r1__, (a), t__); \
+ UN8_rb_ADD_UN8_rb(r1__, r2__, t__); \
+ \
+ r2__ = (x) >> G_SHIFT; \
+ r3__ = ((y) >> G_SHIFT) & RB_MASK; \
+ UN8_rb_MUL_UN8(r2__, (a), t__); \
+ UN8_rb_ADD_UN8_rb(r2__, r3__, t__); \
+ \
+ (x) = r1__ | (r2__ << G_SHIFT); \
+} while (0)
+
+ UN8x4_MUL_UN8_ADD_UN8x4(dst, a, src);
+
+ return dst;
+}
+
+static inline uint32_t
+add(uint32_t src, uint32_t dst)
+{
+#define UN8x4_ADD_UN8x4(x, y) do { \
+ uint32_t r1__, r2__, r3__, t__; \
+ \
+ r1__ = (x) & RB_MASK; \
+ r2__ = (y) & RB_MASK; \
+ UN8_rb_ADD_UN8_rb(r1__, r2__, t__); \
+ \
+ r2__ = ((x) >> G_SHIFT) & RB_MASK; \
+ r3__ = ((y) >> G_SHIFT) & RB_MASK; \
+ UN8_rb_ADD_UN8_rb(r2__, r3__, t__); \
+ \
+ x = r1__ | (r2__ << G_SHIFT); \
+} while (0)
+
+ UN8x4_ADD_UN8x4(src, dst);
+ return src;
+}
+
bool
sna_blt_composite(struct sna *sna,
uint32_t op,
@@ -2459,12 +2554,40 @@ clear:
}
if (is_solid(src)) {
+ if ((op == PictOpOver || op == PictOpAdd) && is_transparent(src)) {
+ sna_pixmap(tmp->dst.pixmap)->clear = was_clear;
+ return prepare_blt_nop(sna, tmp);
+ }
if (op == PictOpOver && is_opaque_solid(src))
op = PictOpSrc;
if (op == PictOpAdd && is_white(src))
op = PictOpSrc;
- if (was_clear && (op == PictOpAdd || op == PictOpOver))
- op = PictOpSrc;
+ if (was_clear && (op == PictOpAdd || op == PictOpOver)) {
+ if (sna_pixmap(tmp->dst.pixmap)->clear_color == 0)
+ op = PictOpSrc;
+ if (op == PictOpOver) {
+ color = over(get_solid_color(src, PICT_a8r8g8b8),
+ color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
+ dst->format, PICT_a8r8g8b8));
+ op = PictOpSrc;
+ DBG(("%s: precomputing solid OVER (%08x, %08x) -> %08x\n",
+ get_solid_color(src, PICT_a8r8g8b8),
+ color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
+ dst->format, PICT_a8r8g8b8),
+ color));
+ }
+ if (op == PictOpAdd) {
+ color = add(get_solid_color(src, PICT_a8r8g8b8),
+ color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
+ dst->format, PICT_a8r8g8b8));
+ op = PictOpSrc;
+ DBG(("%s: precomputing solid ADD (%08x, %08x) -> %08x\n",
+ get_solid_color(src, PICT_a8r8g8b8),
+ color_convert(sna_pixmap(tmp->dst.pixmap)->clear_color,
+ dst->format, PICT_a8r8g8b8),
+ color));
+ }
+ }
if (op == PictOpOutReverse && is_opaque_solid(src))
goto clear;