summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2020-10-02 15:31:51 +0200
committerLuboš Luňák <l.lunak@collabora.com>2020-10-05 11:30:01 +0200
commitbe44d7723c03184a132834d187c8ab0087e1b241 (patch)
tree97e83b416fbb9e9d73ee4ea2fd38f49b8552d3ea
parent980cb24e1e94ed928b6db9e6b8b5ba377de2a574 (diff)
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@collabora.com>
-rw-r--r--vcl/inc/salbmp.hxx5
-rw-r--r--vcl/inc/skia/salbmp.hxx1
-rw-r--r--vcl/qa/cppunit/skia/skia.cxx60
-rw-r--r--vcl/skia/salbmp.cxx46
-rw-r--r--vcl/source/gdi/alpha.cxx9
5 files changed, 121 insertions, 0 deletions
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);