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