[Libreoffice-commits] core.git: solenv/clang-format vcl/inc vcl/opengl vcl/skia
LuboÅ¡ LuÅák (via logerrit)
logerrit at kemper.freedesktop.org
Mon Jan 6 10:12:39 UTC 2020
solenv/clang-format/blacklist | 1
vcl/inc/scanlinewriter.hxx | 90 ++++++++++++++++++++++++++
vcl/inc/skia/salbmp.hxx | 27 ++++++-
vcl/opengl/salbmp.cxx | 59 -----------------
vcl/skia/salbmp.cxx | 145 ++++++++++++++++++++++++++++++++++--------
5 files changed, 233 insertions(+), 89 deletions(-)
New commits:
commit aab9dafdae868b9e55c143cdc08598895f19f63d
Author: Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Dec 13 17:07:44 2019 +0100
Commit: Luboš Luňák <l.lunak at collabora.com>
CommitDate: Mon Jan 6 11:12:04 2020 +0100
convert SkImage -> SkBitmap only on demand
This should possibly save some unneeded conversions.
Change-Id: Ice8a186f13a0e61bee260cf910f8a4d0538ef974
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/85542
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
diff --git a/solenv/clang-format/blacklist b/solenv/clang-format/blacklist
index 84500af7c2ef..eae0f3714d25 100644
--- a/solenv/clang-format/blacklist
+++ b/solenv/clang-format/blacklist
@@ -17320,6 +17320,7 @@ vcl/inc/saltimer.hxx
vcl/inc/salusereventlist.hxx
vcl/inc/salvd.hxx
vcl/inc/salwtype.hxx
+vcl/inc/scanlinewriter.hxx
vcl/inc/schedulerimpl.hxx
vcl/inc/scrptrun.h
vcl/inc/scrwnd.hxx
diff --git a/vcl/inc/scanlinewriter.hxx b/vcl/inc/scanlinewriter.hxx
new file mode 100644
index 000000000000..a5b892b02b6b
--- /dev/null
+++ b/vcl/inc/scanlinewriter.hxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_INC_SCANLINEWRITER_HXX
+#define INCLUDED_VCL_INC_SCANLINEWRITER_HXX
+
+#include <vcl/bitmap.hxx>
+#include <vcl/BitmapPalette.hxx>
+
+namespace vcl
+{
+
+// Write color information for 1, 4 and 8 bit palette bitmap scanlines.
+class ScanlineWriter
+{
+ BitmapPalette& maPalette;
+ sal_uInt8 const mnColorsPerByte; // number of colors that are stored in one byte
+ sal_uInt8 const mnColorBitSize; // number of bits a color takes
+ sal_uInt8 const mnColorBitMask; // bit mask used to isolate the color
+ sal_uInt8* mpCurrentScanline;
+ long mnX;
+
+public:
+
+ ScanlineWriter(BitmapPalette& aPalette, sal_Int8 nColorsPerByte)
+ : maPalette(aPalette)
+ , mnColorsPerByte(nColorsPerByte)
+ , mnColorBitSize(8 / mnColorsPerByte) // bit size is number of bit in a byte divided by number of colors per byte (8 / 2 = 4 for 4-bit)
+ , mnColorBitMask((1 << mnColorBitSize) - 1) // calculate the bit mask from the bit size
+ , mpCurrentScanline(nullptr)
+ , mnX(0)
+ {}
+
+ static std::unique_ptr<ScanlineWriter> Create(sal_uInt16 nBits, BitmapPalette& aPalette)
+ {
+ switch(nBits)
+ {
+ case 1:
+ return std::make_unique<ScanlineWriter>(aPalette, 8);
+ case 4:
+ return std::make_unique<ScanlineWriter>(aPalette, 2);
+ case 8:
+ return std::make_unique<ScanlineWriter>(aPalette, 1);
+ default:
+ abort();
+ }
+ }
+
+ void writeRGB(sal_uInt8 nR, sal_uInt8 nG, sal_uInt8 nB)
+ {
+ // calculate to which index we will write
+ long nScanlineIndex = mnX / mnColorsPerByte;
+
+ // calculate the number of shifts to get the color information to the right place
+ long nShift = (8 - mnColorBitSize) - ((mnX % mnColorsPerByte) * mnColorBitSize);
+
+ sal_uInt16 nColorIndex = maPalette.GetBestIndex(BitmapColor(nR, nG, nB));
+ mpCurrentScanline[nScanlineIndex] &= ~(mnColorBitMask << nShift); // clear
+ mpCurrentScanline[nScanlineIndex] |= (nColorIndex & mnColorBitMask) << nShift; // set
+ mnX++;
+ }
+
+ void nextLine(sal_uInt8* pScanline)
+ {
+ mnX = 0;
+ mpCurrentScanline = pScanline;
+ }
+};
+
+} // namespace vcl
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx
index df3664f26f1c..a0fa2d900c78 100644
--- a/vcl/inc/skia/salbmp.hxx
+++ b/vcl/inc/skia/salbmp.hxx
@@ -68,7 +68,14 @@ public:
#endif
private:
- void ResetCachedBitmap();
+ // Reset the cached images allocated in GetSkImage()/GetAlphaSkImage().
+ void ResetSkImages();
+ // Call to ensure mBitmap or mBuffer have data (will convert from mImage
+ // if necessary).
+ void EnsureBitmapData();
+ void EnsureBitmapData() const { return const_cast<SkiaSalBitmap*>(this)->EnsureBitmapData(); }
+ // Allocate mBitmap or mBuffer (with uninitialized contents).
+ bool CreateBitmapData();
SkBitmap GetAsSkBitmap() const;
#ifdef DBG_UTIL
void verify() const;
@@ -90,17 +97,25 @@ private:
: "");
}
- // Bitmap pixels, if format is supported by Skia. If not, mBuffer is used.
- SkBitmap mBitmap;
BitmapPalette mPalette;
- int mBitCount; // bpp
+ int mBitCount = 0; // bpp
Size mSize;
+ // The contents of the bitmap may be stored in several different ways:
+ // As SkBitmap, if format is supported by Skia.
+ // As mBuffer buffer, if format is not supported by Skia.
+ // As SkImage, as cached GPU-backed data, but sometimes also a result of some operation.
+ // There is no "master" storage that the others would be derived from. The usual
+ // mode of operation is that mBitmap or mBuffer hold the data, mImage is created
+ // on demand as GPU-backed cached data by calling GetSkImage(), and the cached mImage
+ // is reset by ResetCachedImage(). But sometimes only mImage will be set and in that case
+ // mBitmap/mBuffer must be filled from it on demand if necessary by EnsureBitmapData().
+ SkBitmap mBitmap;
+ sk_sp<SkImage> mImage; // possibly GPU-backed
std::unique_ptr<sal_uInt8[]> mBuffer;
int mScanlineSize; // size of one row in mBuffer
- sk_sp<SkImage> mImage; // cached contents, possibly GPU-backed
sk_sp<SkImage> mAlphaImage; // cached contents as alpha image, possibly GPU-backed
#ifdef DBG_UTIL
- int mWriteAccessCount; // number of write AcquireAccess() that have not been released
+ int mWriteAccessCount = 0; // number of write AcquireAccess() that have not been released
#endif
};
diff --git a/vcl/opengl/salbmp.cxx b/vcl/opengl/salbmp.cxx
index 3a033c4afef0..3b500b0945dc 100644
--- a/vcl/opengl/salbmp.cxx
+++ b/vcl/opengl/salbmp.cxx
@@ -32,6 +32,7 @@
#include <salgdi.hxx>
#include <vcleventlisteners.hxx>
#include <vcl/lazydelete.hxx>
+#include <scanlinewriter.hxx>
#include <o3tl/make_shared.hxx>
@@ -333,47 +334,6 @@ void lclInstantiateTexture(OpenGLTexture& rTexture, const int nWidth, const int
rTexture = OpenGLTexture (nWidth, nHeight, nFormat, nType, pData);
}
-// Write color information for 1 and 4 bit palette bitmap scanlines.
-class ScanlineWriter
-{
- BitmapPalette& maPalette;
- sal_uInt8 const mnColorsPerByte; // number of colors that are stored in one byte
- sal_uInt8 const mnColorBitSize; // number of bits a color takes
- sal_uInt8 const mnColorBitMask; // bit mask used to isolate the color
- sal_uInt8* mpCurrentScanline;
- long mnX;
-
-public:
- ScanlineWriter(BitmapPalette& aPalette, sal_Int8 nColorsPerByte)
- : maPalette(aPalette)
- , mnColorsPerByte(nColorsPerByte)
- , mnColorBitSize(8 / mnColorsPerByte) // bit size is number of bit in a byte divided by number of colors per byte (8 / 2 = 4 for 4-bit)
- , mnColorBitMask((1 << mnColorBitSize) - 1) // calculate the bit mask from the bit size
- , mpCurrentScanline(nullptr)
- , mnX(0)
- {}
-
- void writeRGB(sal_uInt8 nR, sal_uInt8 nG, sal_uInt8 nB)
- {
- // calculate to which index we will write
- long nScanlineIndex = mnX / mnColorsPerByte;
-
- // calculate the number of shifts to get the color information to the right place
- long nShift = (8 - mnColorBitSize) - ((mnX % mnColorsPerByte) * mnColorBitSize);
-
- sal_uInt16 nColorIndex = maPalette.GetBestIndex(BitmapColor(nR, nG, nB));
- mpCurrentScanline[nScanlineIndex] &= ~(mnColorBitMask << nShift); // clear
- mpCurrentScanline[nScanlineIndex] |= (nColorIndex & mnColorBitMask) << nShift; // set
- mnX++;
- }
-
- void nextLine(sal_uInt8* pScanline)
- {
- mnX = 0;
- mpCurrentScanline = pScanline;
- }
-};
-
} // end anonymous namespace
Size OpenGLSalBitmap::GetSize() const
@@ -475,22 +435,7 @@ bool OpenGLSalBitmap::ReadTexture()
maTexture.Read(nFormat, nType, pBuffer);
sal_uInt32 nSourceBytesPerRow = lclBytesPerRow(24, mnWidth);
- std::unique_ptr<ScanlineWriter> pWriter;
- switch(mnBits)
- {
- case 1:
- pWriter.reset(new ScanlineWriter(maPalette, 8));
- break;
- case 4:
- pWriter.reset(new ScanlineWriter(maPalette, 2));
- break;
- case 8:
- pWriter.reset(new ScanlineWriter(maPalette, 1));
- break;
- default:
- abort();
- }
-
+ std::unique_ptr<vcl::ScanlineWriter> pWriter = vcl::ScanlineWriter::Create(mnBits, maPalette);
for (int y = 0; y < mnHeight; ++y)
{
sal_uInt8* pSource = &pBuffer[y * nSourceBytesPerRow];
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index b2edfb509c44..9bc2d0ecf217 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -23,6 +23,7 @@
#include <tools/helpers.hxx>
#include <salgdi.hxx>
+#include <scanlinewriter.hxx>
#include <SkCanvas.h>
#include <SkImage.h>
@@ -48,25 +49,47 @@ static bool isValidBitCount(sal_uInt16 nBitCount)
SkiaSalBitmap::SkiaSalBitmap(const sk_sp<SkImage>& image)
{
- if (Create(Size(image->width(), image->height()), 32, BitmapPalette()))
- {
- SkCanvas canvas(mBitmap);
- // TODO makeNonTextureImage() ?
- SkPaint paint;
- paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha
- canvas.drawImage(image, 0, 0, &paint);
- // Also set up the cached image, often it will be immediately read again.
- // TODO Maybe do the image -> bitmap conversion on demand?
- mImage = image;
- }
+ ResetSkImages();
+ mBitmap.reset();
+ mBuffer.reset();
+ mImage = image;
+ mPalette = BitmapPalette();
+ mBitCount = 32;
+ mSize = Size(image->width(), image->height());
+#ifdef DBG_UTIL
+ mWriteAccessCount = 0;
+#endif
+ SAL_INFO("vcl.skia", "bitmapfromimage(" << this << ")");
}
bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal)
{
+ ResetSkImages();
mBitmap.reset();
mBuffer.reset();
if (!isValidBitCount(nBitCount))
return false;
+ mPalette = rPal;
+ mBitCount = nBitCount;
+ mSize = rSize;
+#ifdef DBG_UTIL
+ mWriteAccessCount = 0;
+#endif
+ if (!CreateBitmapData())
+ {
+ mBitCount = 0;
+ mSize = Size();
+ mPalette = BitmapPalette();
+ return false;
+ }
+ SAL_INFO("vcl.skia", "create(" << this << ")");
+ return true;
+}
+
+bool SkiaSalBitmap::CreateBitmapData()
+{
+ assert(mBitmap.isNull());
+ assert(!mBuffer);
// Skia only supports 8bit gray, 16bit and 32bit formats (e.g. 24bpp is actually stored as 32bpp).
// But some of our code accessing the bitmap assumes that when it asked for 24bpp, the format
// really will be 24bpp (e.g. the png loader), so we cannot use SkBitmap to store the data.
@@ -75,7 +98,7 @@ bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const Bitmap
// So basically use Skia only for 32bpp bitmaps.
// TODO what is the performance impact of handling 24bpp ourselves instead of in Skia?
SkColorType colorType = kUnknown_SkColorType;
- switch (nBitCount)
+ switch (mBitCount)
{
case 32:
colorType = kN32_SkColorType;
@@ -94,7 +117,7 @@ bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const Bitmap
// functions that merely read RGB without A, so the premultiplied values would
// not be converted back to unpremultiplied values.
if (!mBitmap.tryAllocPixels(
- SkImageInfo::Make(rSize.Width(), rSize.Height(), colorType, kUnpremul_SkAlphaType)))
+ SkImageInfo::Make(mSize.Width(), mSize.Height(), colorType, kUnpremul_SkAlphaType)))
{
return false;
}
@@ -110,16 +133,16 @@ bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const Bitmap
{
// Image formats not supported by Skia are stored in a buffer and converted as necessary.
int bitScanlineWidth;
- if (o3tl::checked_multiply<int>(rSize.Width(), nBitCount, bitScanlineWidth))
+ if (o3tl::checked_multiply<int>(mSize.Width(), mBitCount, bitScanlineWidth))
{
SAL_WARN("vcl.skia", "checked multiply failed");
return false;
}
mScanlineSize = AlignedWidth4Bytes(bitScanlineWidth);
sal_uInt8* buffer = nullptr;
- if (mScanlineSize != 0 && rSize.Height() != 0)
+ if (mScanlineSize != 0 && mSize.Height() != 0)
{
- size_t allocate = mScanlineSize * rSize.Height();
+ size_t allocate = mScanlineSize * mSize.Height();
#ifdef DBG_UTIL
allocate += sizeof(CANARY);
#endif
@@ -133,13 +156,6 @@ bool SkiaSalBitmap::Create(const Size& rSize, sal_uInt16 nBitCount, const Bitmap
}
mBuffer.reset(buffer);
}
- mPalette = rPal;
- mBitCount = nBitCount;
- mSize = rSize;
-#ifdef DBG_UTIL
- mWriteAccessCount = 0;
-#endif
- SAL_INFO("vcl.skia", "create(" << this << ")");
return true;
}
@@ -159,6 +175,8 @@ bool SkiaSalBitmap::Create(const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount)
if (nNewBitCount == src.GetBitCount())
{
mBitmap = src.mBitmap; // TODO unshare?
+ mImage = src.mImage; // TODO unshare?
+ mAlphaImage = src.mAlphaImage; // TODO unshare?
mPalette = src.mPalette;
mBitCount = src.mBitCount;
mSize = src.mSize;
@@ -199,6 +217,7 @@ void SkiaSalBitmap::Destroy()
#ifdef DBG_UTIL
assert(mWriteAccessCount == 0);
#endif
+ ResetSkImages();
mBitmap.reset();
mBuffer.reset();
}
@@ -212,6 +231,7 @@ BitmapBuffer* SkiaSalBitmap::AcquireBuffer(BitmapAccessMode nMode)
#ifndef DBG_UTIL
(void)nMode; // TODO
#endif
+ EnsureBitmapData();
if (mBitmap.drawsNothing() && !mBuffer)
return nullptr;
#ifdef DBG_UTIL
@@ -282,7 +302,7 @@ void SkiaSalBitmap::ReleaseBuffer(BitmapBuffer* pBuffer, BitmapAccessMode nMode)
--mWriteAccessCount;
#endif
mPalette = pBuffer->maPalette;
- ResetCachedBitmap();
+ ResetSkImages();
}
// Are there any more ground movements underneath us ?
assert(pBuffer->mnWidth == mSize.Width());
@@ -337,6 +357,7 @@ SkBitmap SkiaSalBitmap::GetAsSkBitmap() const
#ifdef DBG_UTIL
assert(mWriteAccessCount == 0);
#endif
+ EnsureBitmapData();
if (!mBitmap.drawsNothing())
return mBitmap;
SkBitmap bitmap;
@@ -409,6 +430,8 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() const
#endif
if (mAlphaImage)
return mAlphaImage;
+ // TODO can we convert directly mImage -> mAlphaImage?
+ EnsureBitmapData();
SkBitmap alphaBitmap;
if (mBuffer && mBitCount <= 8)
{
@@ -470,8 +493,73 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() const
return mAlphaImage;
}
-// Reset the cached images allocated in GetSkImage().
-void SkiaSalBitmap::ResetCachedBitmap()
+void SkiaSalBitmap::EnsureBitmapData()
+{
+ if (!mBitmap.drawsNothing() || mBuffer)
+ return;
+ if (!mImage)
+ return;
+ if (!CreateBitmapData())
+ abort();
+ if (!mBitmap.isNull())
+ {
+ SkCanvas canvas(mBitmap);
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha
+ canvas.drawImage(mImage, 0, 0, &paint);
+ SAL_INFO("vcl.skia", "ensurebitmapdata1(" << this << ")");
+ }
+ else
+ {
+ SkBitmap tmpBitmap;
+ if (!tmpBitmap.tryAllocPixels(SkImageInfo::Make(mSize.Width(), mSize.Height(),
+ kN32_SkColorType, kUnpremul_SkAlphaType)))
+ abort();
+ SkCanvas canvas(tmpBitmap);
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha
+ canvas.drawImage(mImage, 0, 0, &paint);
+ assert(mBuffer != nullptr);
+ if (mBitCount == 24) // non-paletted
+ {
+ for (long y = 0; y < mSize.Height(); ++y)
+ {
+ const uint8_t* src = static_cast<uint8_t*>(tmpBitmap.getAddr(0, y));
+ sal_uInt8* dest = mBuffer.get() + mScanlineSize * y;
+ for (long x = 0; x < mSize.Width(); ++x)
+ {
+ *dest++ = *src++;
+ *dest++ = *src++;
+ *dest++ = *src++;
+ ++src; // skip alpha
+ }
+ }
+ }
+ else
+ {
+ std::unique_ptr<vcl::ScanlineWriter> pWriter
+ = vcl::ScanlineWriter::Create(mBitCount, mPalette);
+ for (long y = 0; y < mSize.Height(); ++y)
+ {
+ const uint8_t* src = static_cast<uint8_t*>(tmpBitmap.getAddr(0, y));
+ sal_uInt8* dest = mBuffer.get() + mScanlineSize * y;
+ pWriter->nextLine(dest);
+ for (long x = 0; x < mSize.Width(); ++x)
+ {
+ sal_uInt8 r = *src++;
+ sal_uInt8 g = *src++;
+ sal_uInt8 b = *src++;
+ ++src; // skip alpha
+ pWriter->writeRGB(r, g, b);
+ }
+ }
+ }
+ verify();
+ SAL_INFO("vcl.skia", "ensurebitmapdata2(" << this << ")");
+ }
+}
+
+void SkiaSalBitmap::ResetSkImages()
{
mAlphaImage.reset();
mImage.reset();
@@ -482,12 +570,17 @@ void SkiaSalBitmap::dump(const char* file) const
{
sk_sp<SkImage> saveImage = mImage;
sk_sp<SkImage> saveAlphaImage = mAlphaImage;
+ SkBitmap saveBitmap = mBitmap;
+ bool resetBuffer = !mBuffer;
int saveWriteAccessCount = mWriteAccessCount;
SkiaSalBitmap* thisPtr = const_cast<SkiaSalBitmap*>(this);
// avoid possible assert
thisPtr->mWriteAccessCount = 0;
SkiaHelper::dump(GetSkImage(), file);
// restore old state, so that debugging doesn't affect it
+ thisPtr->mBitmap = saveBitmap;
+ if (resetBuffer)
+ thisPtr->mBuffer.reset();
thisPtr->mImage = saveImage;
thisPtr->mAlphaImage = saveAlphaImage;
thisPtr->mWriteAccessCount = saveWriteAccessCount;
More information about the Libreoffice-commits
mailing list