vcl/headless/svpbmp.cxx | 5 +- vcl/headless/svpgdi.cxx | 98 ++++++++++++++++++++++++++++++++++++++++-- vcl/inc/headless/svpgdi.hxx | 3 + vcl/qa/cppunit/BitmapTest.cxx | 22 ++------- 4 files changed, 105 insertions(+), 23 deletions(-)
New commits: commit 11adb51f2553dc4a838c8668d94909771d70e1ab Author: Ashod Nakashian <ashod.nakash...@collabora.co.uk> Date: Sun Dec 3 23:35:26 2017 -0500 vcl-svp: Store 24-bit images in 3-byte pixels This adds support in headless rendering for more compact 24-bit RGB image storage in 3-byte pixels instead of 4 bytes. There is a conversion necessary to accomodate Cairo, which requires 4-byte pixels, but that is relatively. Early tests show no loss of performance at runtime. Change-Id: I3919f7c56d14d09e67f163f035b4c7683b49087c (cherry picked from commit 354ad875092fd0c3b12f232950375206ec5d66a6) Reviewed-on: https://gerrit.libreoffice.org/46679 Reviewed-by: Jan Holesovsky <ke...@collabora.com> Tested-by: Jan Holesovsky <ke...@collabora.com> diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx index c3ba02f57528..63d0ee047046 100644 --- a/vcl/headless/svpbmp.cxx +++ b/vcl/headless/svpbmp.cxx @@ -96,14 +96,15 @@ BitmapBuffer* ImplCreateDIB( pDIB->maColorMask = ColorMask(aRedMask, aGreenMask, aBlueMask); break; } + case 24: + pDIB->mnFormat = SVP_24BIT_FORMAT; + break; default: nBitCount = 32; SAL_FALLTHROUGH; case 32: - { pDIB->mnFormat = SVP_CAIRO_FORMAT; break; - } } pDIB->mnFormat |= ScanlineFormat::TopDown; diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx index 8f09939df899..cd546ab5fdb1 100644 --- a/vcl/headless/svpgdi.cxx +++ b/vcl/headless/svpgdi.cxx @@ -23,6 +23,7 @@ #include "headless/svpcairotextrender.hxx" #include "saldatabasic.hxx" +#include <o3tl/safeint.hxx> #include <vcl/sysdata.hxx> #include <config_cairo_canvas.h> #include <basegfx/numeric/ftools.hxx> @@ -123,25 +124,113 @@ namespace } } + BitmapBuffer* FastConvert24BitRgbTo32BitCairo(const BitmapBuffer* pSrc) + { + if (pSrc == nullptr) + return nullptr; + + assert(pSrc->mnFormat == SVP_24BIT_FORMAT); + const long nWidth = pSrc->mnWidth; + const long nHeight = pSrc->mnHeight; + BitmapBuffer* pDst = new BitmapBuffer; + pDst->mnFormat = (ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown); + pDst->mnWidth = nWidth; + pDst->mnHeight = nHeight; + pDst->mnBitCount = 32; + pDst->maColorMask = pSrc->maColorMask; + pDst->maPalette = pSrc->maPalette; + + long nScanlineBase; + bool bFail = o3tl::checked_multiply<long>(pDst->mnBitCount, nWidth, nScanlineBase); + if (bFail) + { + SAL_WARN("vcl.gdi", "checked multiply failed"); + pDst->mpBits = nullptr; + delete pDst; + return nullptr; + } + + pDst->mnScanlineSize = AlignedWidth4Bytes(nScanlineBase); + if (pDst->mnScanlineSize < nScanlineBase/8) + { + SAL_WARN("vcl.gdi", "scanline calculation wraparound"); + pDst->mpBits = nullptr; + delete pDst; + return nullptr; + } + + try + { + pDst->mpBits = new sal_uInt8[ pDst->mnScanlineSize * nHeight ]; + } + catch( const std::bad_alloc& ) + { + // memory exception, clean up + pDst->mpBits = nullptr; + delete pDst; + return nullptr; + } + + for (int y = 0; y < nHeight; ++y) + { + sal_uInt8* pS = pSrc->mpBits + y * pSrc->mnScanlineSize; + sal_uInt8* pD = pDst->mpBits + y * pDst->mnScanlineSize; + for (int x = 0; x < nWidth; ++x) + { + if ((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcRgba) + { + pD[0] = pS[0]; + pD[1] = pS[1]; + pD[2] = pS[2]; + pD[3] = 0xff; // Alpha + } + else if ((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcArgb) + { + pD[0] = 0xff; // Alpha + pD[1] = pS[0]; + pD[2] = pS[1]; + pD[3] = pS[2]; + } + else if ((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcBgra) + { + pD[0] = pS[2]; + pD[1] = pS[1]; + pD[2] = pS[0]; + pD[3] = 0xff; // Alpha + } + else + { + assert(!"Unsupported SVP_CAIRO_FORMAT!"); + } + + pS += 3; + pD += 4; + } + } + + return pDst; + } + class SourceHelper { public: explicit SourceHelper(const SalBitmap& rSourceBitmap) { const SvpSalBitmap& rSrcBmp = static_cast<const SvpSalBitmap&>(rSourceBitmap); - if (rSrcBmp.GetBitCount() != 32) { //big stupid copy here - static bool bWarnedOnce; + static bool bWarnedOnce = false; SAL_WARN_IF(!bWarnedOnce, "vcl.gdi", "non default depth bitmap, slow convert, upscale the input"); bWarnedOnce = true; const BitmapBuffer* pSrc = rSrcBmp.GetBuffer(); const SalTwoRect aTwoRect = { 0, 0, pSrc->mnWidth, pSrc->mnHeight, 0, 0, pSrc->mnWidth, pSrc->mnHeight }; - aTmpBmp.Create(StretchAndConvert(*pSrc, aTwoRect, SVP_CAIRO_FORMAT)); - + BitmapBuffer* pTmp = (pSrc->mnFormat == SVP_24BIT_FORMAT + ? FastConvert24BitRgbTo32BitCairo(pSrc) + : StretchAndConvert(*pSrc, aTwoRect, SVP_CAIRO_FORMAT)); + aTmpBmp.Create(pTmp); assert(aTmpBmp.GetBitCount() == 32); source = SvpSalGraphics::createCairoSurface(aTmpBmp.GetBuffer()); @@ -1350,6 +1439,7 @@ namespace if (!pBuffer) return false; + // Cairo doesn't support 24-bit RGB; only ARGB with the alpha ignored. if (pBuffer->mnBitCount != 32 && pBuffer->mnBitCount != 1) return false; diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index 488cb51868e0..f092b0375822 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -58,6 +58,9 @@ # define SVP_CAIRO_ALPHA 3 #endif +// Used to store 24-bit images in 3-byte pixels to conserve memory. +#define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown) + struct BitmapBuffer; class GlyphCache; class FreetypeFont; diff --git a/vcl/qa/cppunit/BitmapTest.cxx b/vcl/qa/cppunit/BitmapTest.cxx index fe76f51e5232..3cdea8fdd928 100644 --- a/vcl/qa/cppunit/BitmapTest.cxx +++ b/vcl/qa/cppunit/BitmapTest.cxx @@ -75,24 +75,12 @@ void BitmapTest::testConvert() CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), aBitmap.GetBitCount()); { Bitmap::ScopedReadAccess pReadAccess(aBitmap); -#if defined LINUX || defined FREEBSD - // 24 bit Bitmap on SVP backend uses 32bit BGRA format - CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(32), pReadAccess->GetBitCount()); - CPPUNIT_ASSERT_EQUAL(sal_uLong(40), pReadAccess->GetScanlineSize()); -#else + // 24 bit Bitmap on SVP backend can now use 24bit RGB instad of 32bit BGRA format. CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), pReadAccess->GetBitCount()); -#if defined(_WIN32) - if (!OpenGLHelper::isVCLOpenGLEnabled()) - { - // GDI Scanlines padded to DWORD multiples, it seems - CPPUNIT_ASSERT_EQUAL(sal_uLong(32), pReadAccess->GetScanlineSize()); - } - else -#endif - { - CPPUNIT_ASSERT_EQUAL(sal_uLong(30), pReadAccess->GetScanlineSize()); - } -#endif + + // Scanlines padded to DWORD multiples, it seems + CPPUNIT_ASSERT_EQUAL(sal_uLong(32), pReadAccess->GetScanlineSize()); + CPPUNIT_ASSERT(!pReadAccess->HasPalette()); Color aColor = pReadAccess->GetPixel(0, 0); CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetRed())); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits