[Libreoffice-commits] core.git: vcl/inc vcl/qa vcl/skia vcl/source

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Mon Oct 5 09:30:37 UTC 2020


 vcl/inc/salbmp.hxx           |    5 +++
 vcl/inc/skia/salbmp.hxx      |    1 
 vcl/qa/cppunit/skia/skia.cxx |   60 +++++++++++++++++++++++++++++++++++++++++++
 vcl/skia/salbmp.cxx          |   46 ++++++++++++++++++++++++++++++++
 vcl/source/gdi/alpha.cxx     |    9 ++++++
 5 files changed, 121 insertions(+)

New commits:
commit be44d7723c03184a132834d187c8ab0087e1b241
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Oct 2 15:31:51 2020 +0200
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Mon Oct 5 11:30:01 2020 +0200

    make it possible to accelerate AlphaMask::BlendWith()
    
    If SkiaSalBitmap has the data already on the GPU, then without this
    the pixel data for both bitmaps would get read from the GPU (which is
    somewhat expensive), the operation would be done on the CPU, and
    afterwards quite likely the result would be sent to the GPU again.
    
    Change-Id: Ic6b7bf08b30e7083f6099eb66a45a82ebb54f326
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103888
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/vcl/inc/salbmp.hxx b/vcl/inc/salbmp.hxx
index ab16b317d7eb..1f5ea18cb048 100644
--- a/vcl/inc/salbmp.hxx
+++ b/vcl/inc/salbmp.hxx
@@ -90,6 +90,11 @@ public:
     {
         return false;
     }
+    // Optimized case for AlphaMask::BlendWith().
+    virtual bool            AlphaBlendWith( const SalBitmap& /*rSalBmp*/ )
+    {
+        return false;
+    }
 
     void GetChecksum(BitmapChecksum& rChecksum) const
     {
diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx
index 6f74ac04b6f9..0cd48c8c46c2 100644
--- a/vcl/inc/skia/salbmp.hxx
+++ b/vcl/inc/skia/salbmp.hxx
@@ -60,6 +60,7 @@ public:
     virtual bool InterpretAs8Bit() override;
     virtual bool ConvertToGreyscale() override;
     virtual bool Erase(const Color& color) override;
+    virtual bool AlphaBlendWith(const SalBitmap& rSalBmp) override;
 
     const BitmapPalette& Palette() const { return mPalette; }
 
diff --git a/vcl/qa/cppunit/skia/skia.cxx b/vcl/qa/cppunit/skia/skia.cxx
index 7fa4a9e3f00e..c3f1c215b570 100644
--- a/vcl/qa/cppunit/skia/skia.cxx
+++ b/vcl/qa/cppunit/skia/skia.cxx
@@ -33,11 +33,13 @@ public:
     void testBitmapErase();
     void testDrawShaders();
     void testInterpretAs8Bit();
+    void testAlphaBlendWith();
 
     CPPUNIT_TEST_SUITE(SkiaTest);
     CPPUNIT_TEST(testBitmapErase);
     CPPUNIT_TEST(testDrawShaders);
     CPPUNIT_TEST(testInterpretAs8Bit);
+    CPPUNIT_TEST(testAlphaBlendWith);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -201,6 +203,64 @@ void SkiaTest::testInterpretAs8Bit()
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(34), BitmapReadAccess(bitmap).GetPixelIndex(0, 0));
 }
 
+void SkiaTest::testAlphaBlendWith()
+{
+    if (!SkiaHelper::isVCLSkiaEnabled())
+        return;
+    AlphaMask alpha(Size(10, 10));
+    Bitmap bitmap(Size(10, 10), 24);
+    // Test with erase colors set.
+    alpha.Erase(64);
+    SkiaSalBitmap* skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
+    CPPUNIT_ASSERT(skiaAlpha->unittestHasEraseColor());
+    bitmap.Erase(Color(64, 64, 64));
+    SkiaSalBitmap* skiaBitmap = dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+    CPPUNIT_ASSERT(skiaBitmap->unittestHasEraseColor());
+    alpha.BlendWith(bitmap);
+    skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
+    CPPUNIT_ASSERT(skiaAlpha->unittestHasEraseColor());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), alpha.GetBitCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(112),
+                         AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 0));
+
+    // Test with images set.
+    alpha.Erase(64);
+    AlphaMask::ScopedReadAccess(alpha)->GetColor(0, 0); // Reading a pixel will create pixel data.
+    skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
+    skiaAlpha->GetSkImage();
+    CPPUNIT_ASSERT(!skiaAlpha->unittestHasEraseColor());
+    CPPUNIT_ASSERT(skiaAlpha->unittestHasImage());
+    bitmap.Erase(Color(64, 64, 64));
+    Bitmap::ScopedReadAccess(bitmap)->GetColor(0, 0); // Reading a pixel will create pixel data.
+    skiaBitmap = dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+    skiaBitmap->GetSkImage();
+    CPPUNIT_ASSERT(!skiaBitmap->unittestHasEraseColor());
+    CPPUNIT_ASSERT(skiaBitmap->unittestHasImage());
+    alpha.BlendWith(bitmap);
+    skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
+    CPPUNIT_ASSERT(skiaAlpha->unittestHasImage());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), alpha.GetBitCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(112),
+                         AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 0));
+
+    // Test with erase color for alpha and image for other bitmap.
+    alpha.Erase(64);
+    skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
+    CPPUNIT_ASSERT(skiaAlpha->unittestHasEraseColor());
+    bitmap.Erase(Color(64, 64, 64));
+    Bitmap::ScopedReadAccess(bitmap)->GetColor(0, 0); // Reading a pixel will create pixel data.
+    skiaBitmap = dynamic_cast<SkiaSalBitmap*>(bitmap.ImplGetSalBitmap().get());
+    skiaBitmap->GetSkImage();
+    CPPUNIT_ASSERT(!skiaBitmap->unittestHasEraseColor());
+    CPPUNIT_ASSERT(skiaBitmap->unittestHasImage());
+    alpha.BlendWith(bitmap);
+    skiaAlpha = dynamic_cast<SkiaSalBitmap*>(alpha.ImplGetSalBitmap().get());
+    CPPUNIT_ASSERT(skiaAlpha->unittestHasImage());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(8), alpha.GetBitCount());
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt8>(112),
+                         AlphaMask::ScopedReadAccess(alpha)->GetPixelIndex(0, 0));
+}
+
 } // namespace
 
 CPPUNIT_TEST_SUITE_REGISTRATION(SkiaTest);
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index 7bce30b6b637..24f955891e05 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -469,6 +469,52 @@ void SkiaSalBitmap::EraseInternal(const Color& color)
     mEraseColor = color;
 }
 
+bool SkiaSalBitmap::AlphaBlendWith(const SalBitmap& rSalBmp)
+{
+    const SkiaSalBitmap* otherBitmap = dynamic_cast<const SkiaSalBitmap*>(&rSalBmp);
+    if (!otherBitmap)
+        return false;
+    if (mSize != otherBitmap->mSize)
+        return false;
+    // We're called from AlphaMask, which should ensure 8bit.
+    assert(GetBitCount() == 8 && mPalette.IsGreyPalette8Bit());
+    // If neither bitmap have Skia images, then AlphaMask::BlendWith() will be faster,
+    // as it will operate on mBuffer pixel buffers, while for Skia we'd need to convert it.
+    // If one has and one doesn't, do it using Skia, under the assumption that after this
+    // the resulting Skia image will be needed for drawing.
+    if (!(mImage || mEraseColorSet) && !(otherBitmap->mImage || otherBitmap->mEraseColorSet))
+        return false;
+    // This is for AlphaMask, which actually stores the alpha as the pixel values.
+    // I.e. take value of the color channel (one of them, if >8bit, they should be the same).
+    if (mEraseColorSet && otherBitmap->mEraseColorSet)
+    {
+        const sal_uInt16 nGrey1 = mEraseColor.GetRed();
+        const sal_uInt16 nGrey2 = otherBitmap->mEraseColor.GetRed();
+        const sal_uInt8 nGrey = static_cast<sal_uInt8>(nGrey1 + nGrey2 - nGrey1 * nGrey2 / 255);
+        mEraseColor = Color(nGrey, nGrey, nGrey);
+        SAL_INFO("vcl.skia.trace",
+                 "alphablendwith(" << this << ") : with erase color " << otherBitmap);
+        return true;
+    }
+    std::unique_ptr<SkiaSalBitmap> otherBitmapAllocated;
+    if (otherBitmap->GetBitCount() != 8 || !otherBitmap->mPalette.IsGreyPalette8Bit())
+    { // Convert/interpret as 8bit if needed.
+        otherBitmapAllocated = std::make_unique<SkiaSalBitmap>();
+        if (!otherBitmapAllocated->Create(*otherBitmap) || !otherBitmapAllocated->InterpretAs8Bit())
+            return false;
+        otherBitmap = otherBitmapAllocated.get();
+    }
+    sk_sp<SkSurface> surface = SkiaHelper::createSkSurface(mSize);
+    SkPaint paint;
+    paint.setBlendMode(SkBlendMode::kSrc); // set as is
+    surface->getCanvas()->drawImage(GetSkImage(), 0, 0, &paint);
+    paint.setBlendMode(SkBlendMode::kScreen); // src+dest - src*dest/255 (in 0..1)
+    surface->getCanvas()->drawImage(otherBitmap->GetSkImage(), 0, 0, &paint);
+    ResetToSkImage(SkiaHelper::makeCheckedImageSnapshot(surface));
+    SAL_INFO("vcl.skia.trace", "alphablendwith(" << this << ") : with image " << otherBitmap);
+    return true;
+}
+
 SkBitmap SkiaSalBitmap::GetAsSkBitmap() const
 {
 #ifdef DBG_UTIL
diff --git a/vcl/source/gdi/alpha.cxx b/vcl/source/gdi/alpha.cxx
index 168f4fcf5840..284314e28f98 100644
--- a/vcl/source/gdi/alpha.cxx
+++ b/vcl/source/gdi/alpha.cxx
@@ -21,6 +21,9 @@
 #include <tools/color.hxx>
 #include <vcl/alpha.hxx>
 #include <bitmapwriteaccess.hxx>
+#include <salinst.hxx>
+#include <svdata.hxx>
+#include <salbmp.hxx>
 #include <sal/log.hxx>
 
 AlphaMask::AlphaMask() = default;
@@ -140,6 +143,12 @@ void AlphaMask::Replace( sal_uInt8 cSearchTransparency, sal_uInt8 cReplaceTransp
 
 void AlphaMask::BlendWith(const Bitmap& rOther)
 {
+    std::shared_ptr<SalBitmap> xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
+    if (xImpBmp->Create(*ImplGetSalBitmap()) && xImpBmp->AlphaBlendWith(*rOther.ImplGetSalBitmap()))
+    {
+        ImplSetSalBitmap(xImpBmp);
+        return;
+    }
     AlphaMask aOther(rOther); // to 8 bits
     Bitmap::ScopedReadAccess pOtherAcc(aOther);
     AlphaScopedWriteAccess pAcc(*this);


More information about the Libreoffice-commits mailing list