vcl/inc/skia/salbmp.hxx |    4 ++
 vcl/skia/salbmp.cxx     |   68 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 69 insertions(+), 3 deletions(-)

New commits:
commit 3c9936a9b77fe18396d048de2f97b9e8eb66a787
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Wed Mar 3 11:29:49 2021 +0100
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Wed Mar 3 19:06:42 2021 +0100

    try to avoid skia alpha blending with fully opaque bitmaps
    
    E.g. the document in tdf#140753 has a PNG which technically has
    an alpha channel, but it's actually completely opaque. Doing this
    avoids having the pixel data for the separate alpha bitmap, and
    it also avoids the pointless (somewhat costly in the raster case)
    alpha blending.
    
    Change-Id: I0916962e5894a111002c667a2f98782765aacb1f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111893
    Tested-by: Luboš Luňák <l.lu...@collabora.com>
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx
index 2a1d309a7fec..0509ed3381b6 100644
--- a/vcl/inc/skia/salbmp.hxx
+++ b/vcl/inc/skia/salbmp.hxx
@@ -123,6 +123,10 @@ private:
     void EraseInternal(const Color& color);
     // Sets pixels to the erase color.
     void PerformErase();
+    // Try to find out if the content is completely black. Used for 
optimizations,
+    // not guaranteed to always return true for such bitmaps.
+    bool IsAllBlack() const;
+    void ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode, bool 
dontChangeToErase);
     SkBitmap GetAsSkBitmap() const;
     bool ConserveMemory() const;
     void verify() const
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index c8d8f1a766b2..68d2f9a76964 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -278,6 +278,12 @@ BitmapBuffer* 
SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode)
 }
 
 void SkiaSalBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode 
nMode)
+{
+    ReleaseBuffer(pBuffer, nMode, false);
+}
+
+void SkiaSalBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode 
nMode,
+                                  bool dontChangeToErase)
 {
     if (nMode == BitmapAccessMode::Write)
     {
@@ -298,6 +304,62 @@ void SkiaSalBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, 
BitmapAccessMode nMode)
     assert(pBuffer->mpBits == mBuffer.get() || nMode == 
BitmapAccessMode::Info);
     verify();
     delete pBuffer;
+    if (nMode == BitmapAccessMode::Write && !dontChangeToErase)
+    {
+        // This saves memory and is also used by IsFullyOpaqueAsAlpha() to 
avoid unnecessary
+        // alpha blending.
+        if (IsAllBlack())
+        {
+            SAL_INFO("vcl.skia.trace", "releasebuffer(" << this << "): erasing 
to black");
+            EraseInternal(COL_BLACK);
+        }
+    }
+}
+
+static bool isAllZero(const sal_uInt8* data, size_t size)
+{ // For performance, check in larger data chunks.
+#ifdef UINT64_MAX
+    const int64_t* d = reinterpret_cast<const int64_t*>(data);
+#else
+    const int32_t* d = reinterpret_cast<const int32_t*>(data);
+#endif
+    constexpr size_t step = sizeof(*d) * 8;
+    for (size_t i = 0; i < size / step; ++i)
+    { // Unrolled loop.
+        if (d[0] != 0)
+            return false;
+        if (d[1] != 0)
+            return false;
+        if (d[2] != 0)
+            return false;
+        if (d[3] != 0)
+            return false;
+        if (d[4] != 0)
+            return false;
+        if (d[5] != 0)
+            return false;
+        if (d[6] != 0)
+            return false;
+        if (d[7] != 0)
+            return false;
+        d += 8;
+    }
+    for (size_t i = size / step * step; i < size; ++i)
+        if (data[i] != 0)
+            return false;
+    return true;
+}
+
+bool SkiaSalBitmap::IsAllBlack() const
+{
+    if (mBitCount % 8 != 0 || (!!mPalette && mPalette[0] != COL_BLACK))
+        return false; // Don't bother.
+    if (mSize.Width() * mBitCount / 8 == mScanlineSize)
+        return isAllZero(mBuffer.get(), mScanlineSize * mSize.Height());
+    for (tools::Long y = 0; y < mSize.Height(); ++y)
+        if (!isAllZero(mBuffer.get() + mScanlineSize * y, mSize.Width() * 
mBitCount / 8))
+            return false;
+    return true;
 }
 
 bool SkiaSalBitmap::GetSystemData(BitmapSystemData&)
@@ -899,8 +961,8 @@ sk_sp<SkShader> SkiaSalBitmap::GetAlphaSkShader(const 
SkSamplingOptions& samplin
 
 bool SkiaSalBitmap::IsFullyOpaqueAsAlpha() const
 {
-    if (!mEraseColorSet)
-        return false; // don't bother figuring it out from the pixels
+    if (!mEraseColorSet) // Set from Erase() or ReleaseBuffer().
+        return false;
     // If the erase color is set so that this bitmap used as alpha would
     // mean a fully opaque alpha mask (= noop), we can skip using it.
     // Note that for alpha bitmaps we use the VCL "transparency" convention,
@@ -943,7 +1005,7 @@ void SkiaSalBitmap::PerformErase()
             memcpy(scanline + y * bitmapBuffer->mnScanlineSize, scanline,
                    bitmapBuffer->mnScanlineSize);
     }
-    ReleaseBuffer(bitmapBuffer, BitmapAccessMode::Write);
+    ReleaseBuffer(bitmapBuffer, BitmapAccessMode::Write, true);
 }
 
 void SkiaSalBitmap::EnsureBitmapData()
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to