Kaydet (Commit) 33761c69 authored tarafından Ashod Nakashian's avatar Ashod Nakashian Kaydeden (comit) Ashod Nakashian

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.

Unit tests updated since the bitmap memory bytes
are crc-ed, which obviously are different in size
if not in content.

(cherry picked from commit 354ad875)
Reviewed-on: https://gerrit.libreoffice.org/46679Reviewed-by: 's avatarJan Holesovsky <kendy@collabora.com>
Tested-by: 's avatarJan Holesovsky <kendy@collabora.com>
(cherry picked from commit 11adb51f)

Change-Id: I3919f7c56d14d09e67f163f035b4c7683b49087c
Reviewed-on: https://gerrit.libreoffice.org/47009Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarAshod Nakashian <ashnakash@gmail.com>
üst 6723728a
......@@ -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;
......
......@@ -24,6 +24,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>
......@@ -124,25 +125,110 @@ 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;
const 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 (long y = 0; y < nHeight; ++y)
{
sal_uInt8* pS = pSrc->mpBits + y * pSrc->mnScanlineSize;
sal_uInt8* pD = pDst->mpBits + y * pDst->mnScanlineSize;
for (long x = 0; x < nWidth; ++x)
{
#if defined ANDROID
static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcRgba, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra");
static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb");
pD[0] = pS[0];
pD[1] = pS[1];
pD[2] = pS[2];
pD[3] = 0xff; // Alpha
#elif defined OSL_BIGENDIAN
static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcArgb, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra");
static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcRgb, "Expected SVP_24BIT_FORMAT set to N24BitTcRgb");
pD[0] = 0xff; // Alpha
pD[1] = pS[0];
pD[2] = pS[1];
pD[3] = pS[2];
#else
static_assert((SVP_CAIRO_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N32BitTcBgra, "Expected SVP_CAIRO_FORMAT set to N32BitTcBgra");
static_assert((SVP_24BIT_FORMAT & ~ScanlineFormat::TopDown) == ScanlineFormat::N24BitTcBgr, "Expected SVP_24BIT_FORMAT set to N24BitTcBgr");
pD[0] = pS[0];
pD[1] = pS[1];
pD[2] = pS[2];
pD[3] = 0xff; // Alpha
#endif
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());
......@@ -1351,6 +1437,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;
......
......@@ -38,19 +38,23 @@
//which is internal in that case, to swap the rgb components so that
//cairo then matches the OpenGL GL_RGBA format so we can use it there
//where we don't have GL_BGRA support.
// SVP_24BIT_FORMAT is used to store 24-bit images in 3-byte pixels to conserve memory.
#if defined ANDROID
# define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown)
# define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcRgba | ScanlineFormat::TopDown)
# define SVP_CAIRO_BLUE 1
# define SVP_CAIRO_GREEN 2
# define SVP_CAIRO_RED 0
# define SVP_CAIRO_ALPHA 3
#elif defined OSL_BIGENDIAN
# define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcRgb | ScanlineFormat::TopDown)
# define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcArgb | ScanlineFormat::TopDown)
# define SVP_CAIRO_BLUE 3
# define SVP_CAIRO_GREEN 2
# define SVP_CAIRO_RED 1
# define SVP_CAIRO_ALPHA 0
#else
# define SVP_24BIT_FORMAT (ScanlineFormat::N24BitTcBgr | ScanlineFormat::TopDown)
# define SVP_CAIRO_FORMAT (ScanlineFormat::N32BitTcBgra | ScanlineFormat::TopDown)
# define SVP_CAIRO_BLUE 0
# define SVP_CAIRO_GREEN 1
......
......@@ -75,12 +75,12 @@ void BitmapTest::testConvert()
CPPUNIT_ASSERT_EQUAL(sal_uInt16(24), aBitmap.GetBitCount());
{
Bitmap::ScopedReadAccess pReadAccess(aBitmap);
// 24 bit Bitmap on SVP backend can now use 24bit RGB everywhere.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), pReadAccess->GetBitCount());
#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());
CPPUNIT_ASSERT_EQUAL(sal_uLong(32), pReadAccess->GetScanlineSize());
#else
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16>(24), pReadAccess->GetBitCount());
#if defined(_WIN32)
if (!OpenGLHelper::isVCLOpenGLEnabled())
{
......@@ -93,6 +93,7 @@ void BitmapTest::testConvert()
CPPUNIT_ASSERT_EQUAL(sal_uLong(30), pReadAccess->GetScanlineSize());
}
#endif
CPPUNIT_ASSERT(!pReadAccess->HasPalette());
Color aColor = pReadAccess->GetPixel(0, 0);
CPPUNIT_ASSERT_EQUAL(sal_Int32(204), sal_Int32(aColor.GetRed()));
......
......@@ -759,14 +759,14 @@ void SvmTest::checkBitmaps(const GDIMetaFile& rMetaFile)
xmlDocPtr pDoc = dumpMeta(rMetaFile);
#ifdef LINUX
assertXPathAttrs(pDoc, "/metafile/bmp[1]", {{"x", "1"}, {"y", "2"}, {"crc", "7932585a"}});
assertXPathAttrs(pDoc, "/metafile/bmp[1]", {{"x", "1"}, {"y", "2"}, {"crc", "b8dee5da"}});
assertXPathAttrs(pDoc, "/metafile/bmpscale[1]", {
{"x", "1"}, {"y", "2"}, {"width", "3"}, {"height", "4"}, {"crc", "08bfca1f"}
{"x", "1"}, {"y", "2"}, {"width", "3"}, {"height", "4"}, {"crc", "281fc589"}
});
assertXPathAttrs(pDoc, "/metafile/bmpscalepart[1]", {
{"destx", "1"}, {"desty", "2"}, {"destwidth", "3"}, {"destheight", "4"},
{"srcx", "2"}, {"srcy", "1"}, {"srcwidth", "4"}, {"srcheight", "3"},
{"crc", "abd45514"}
{"crc", "5e01ddcc"}
});
#else
assertXPathAttrs(pDoc, "/metafile/bmp[1]", {{"x", "1"}, {"y", "2"}, {"crc", "b8dee5da"}});
......@@ -815,16 +815,16 @@ void SvmTest::checkBitmapExs(const GDIMetaFile& rMetaFile)
#ifdef LINUX
assertXPathAttrs(pDoc, "/metafile/bmpex[1]", {
{"x", "1"}, {"y", "2"}, {"crc", "7932585a"}, {"transparenttype", "bitmap"}
{"x", "1"}, {"y", "2"}, {"crc", "b8dee5da"}, {"transparenttype", "bitmap"}
});
assertXPathAttrs(pDoc, "/metafile/bmpexscale[1]", {
{"x", "1"}, {"y", "2"}, {"width", "3"}, {"height", "4"},
{"crc", "08bfca1f"}, {"transparenttype", "bitmap"}
{"crc", "281fc589"}, {"transparenttype", "bitmap"}
});
assertXPathAttrs(pDoc, "/metafile/bmpexscalepart[1]", {
{"destx", "1"}, {"desty", "2"}, {"destwidth", "3"}, {"destheight", "4"},
{"srcx", "2"}, {"srcy", "1"}, {"srcwidth", "4"}, {"srcheight", "3"},
{"crc", "abd45514"}, {"transparenttype", "bitmap"}
{"crc", "5e01ddcc"}, {"transparenttype", "bitmap"}
});
#else
assertXPathAttrs(pDoc, "/metafile/bmpex[1]", {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment