summaryrefslogtreecommitdiff
path: root/vcl/headless
diff options
context:
space:
mode:
authorArmin Le Grand (Collabora) <armin.le.grand@me.com>2020-02-21 16:58:17 +0100
committerArmin Le Grand <Armin.Le.Grand@me.com>2020-02-21 20:16:59 +0100
commit828504974d70111e4a35b31d579cf42fe660a660 (patch)
tree4c2f7720b3efaecf55b8fa7b9b3eeccb278160e6 /vcl/headless
parent813cde918338bccc4f711230616340cad2c1d4a0 (diff)
tdf#130768 speedup huge pixel graphics Cairo
For more information/documentation please refer to the bugzilla task Fixed a crash in CppunitTest_desktop_lib which led to a missing test of mpGraphics in OutputDevice::DrawTransformedBitmapEx. Other public methods test that and one of the goals of the cange was to use that method more often, so this may have never been detected before Change-Id: I10e57bd05db0c8cf868ff98d63f5af3d116a3015 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/89230 Tested-by: Jenkins Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Diffstat (limited to 'vcl/headless')
-rw-r--r--vcl/headless/svpbmp.cxx7
-rw-r--r--vcl/headless/svpgdi.cxx219
2 files changed, 206 insertions, 20 deletions
diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx
index 6dd5aeb64bfb..4d881f025d0b 100644
--- a/vcl/headless/svpbmp.cxx
+++ b/vcl/headless/svpbmp.cxx
@@ -34,6 +34,13 @@
using namespace basegfx;
+SvpSalBitmap::SvpSalBitmap()
+: SalBitmap(),
+ basegfx::SystemDependentDataHolder(), // MM02
+ mpDIB()
+{
+}
+
SvpSalBitmap::~SvpSalBitmap()
{
Destroy();
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index cd59eee1af16..9a2fe936e782 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -323,6 +323,44 @@ namespace
SourceHelper& operator=(const SourceHelper&) = delete;
};
+ class SystemDependentData_SourceHelper : public basegfx::SystemDependentData
+ {
+ private:
+ std::shared_ptr<SourceHelper> maSourceHelper;
+
+ public:
+ SystemDependentData_SourceHelper(
+ basegfx::SystemDependentDataManager& rSystemDependentDataManager,
+ const std::shared_ptr<SourceHelper>& rSourceHelper)
+ : basegfx::SystemDependentData(rSystemDependentDataManager),
+ maSourceHelper(rSourceHelper)
+ {
+ }
+
+ const std::shared_ptr<SourceHelper>& getSourceHelper() const { return maSourceHelper; };
+ virtual sal_Int64 estimateUsageInBytes() const override;
+ };
+
+ // MM02 class to allow buffering of SourceHelper
+ sal_Int64 SystemDependentData_SourceHelper::estimateUsageInBytes() const
+ {
+ sal_Int64 nRetval(0);
+ cairo_surface_t* source(maSourceHelper ? maSourceHelper->getSurface() : nullptr);
+
+ if(source)
+ {
+ const long nStride(cairo_image_surface_get_stride(source));
+ const long nHeight(cairo_image_surface_get_height(source));
+
+ if(0 != nStride && 0 != nHeight)
+ {
+ nRetval = nStride * nHeight;
+ }
+ }
+
+ return nRetval;
+ }
+
class MaskHelper
{
public:
@@ -388,6 +426,123 @@ namespace
MaskHelper(const MaskHelper&) = delete;
MaskHelper& operator=(const MaskHelper&) = delete;
};
+
+ class SystemDependentData_MaskHelper : public basegfx::SystemDependentData
+ {
+ private:
+ std::shared_ptr<MaskHelper> maMaskHelper;
+
+ public:
+ SystemDependentData_MaskHelper(
+ basegfx::SystemDependentDataManager& rSystemDependentDataManager,
+ const std::shared_ptr<MaskHelper>& rMaskHelper)
+ : basegfx::SystemDependentData(rSystemDependentDataManager),
+ maMaskHelper(rMaskHelper)
+ {
+ }
+
+ const std::shared_ptr<MaskHelper>& getMaskHelper() const { return maMaskHelper; };
+ virtual sal_Int64 estimateUsageInBytes() const override;
+ };
+
+ // MM02 class to allow buffering of MaskHelper
+ sal_Int64 SystemDependentData_MaskHelper::estimateUsageInBytes() const
+ {
+ sal_Int64 nRetval(0);
+ cairo_surface_t* mask(maMaskHelper ? maMaskHelper->getMask() : nullptr);
+
+ if(mask)
+ {
+ const long nStride(cairo_image_surface_get_stride(mask));
+ const long nHeight(cairo_image_surface_get_height(mask));
+
+ if(0 != nStride && 0 != nHeight)
+ {
+ nRetval = nStride * nHeight;
+ }
+ }
+
+ return nRetval;
+ }
+
+ // MM02 decide to use buffers or not
+ static const char* pDisableMM02Goodies(getenv("SAL_DISABLE_MM02_GOODIES"));
+ static bool bUseBuffer(nullptr == pDisableMM02Goodies);
+ static long nMinimalSquareSizeToBuffer(64*64);
+
+ void tryToUseSourceBuffer(
+ const SalBitmap& rSourceBitmap,
+ std::shared_ptr<SourceHelper>& rSurface)
+ {
+ // MM02 try to access buffered SourceHelper
+ std::shared_ptr<SystemDependentData_SourceHelper> pSystemDependentData_SourceHelper;
+ const bool bBufferSource(bUseBuffer
+ && rSourceBitmap.GetSize().Width() * rSourceBitmap.GetSize().Height() > nMinimalSquareSizeToBuffer);
+
+ if(bBufferSource)
+ {
+ const SvpSalBitmap& rSrcBmp(static_cast<const SvpSalBitmap&>(rSourceBitmap));
+ pSystemDependentData_SourceHelper = rSrcBmp.getSystemDependentData<SystemDependentData_SourceHelper>();
+
+ if(pSystemDependentData_SourceHelper)
+ {
+ // reuse buffered data
+ rSurface = pSystemDependentData_SourceHelper->getSourceHelper();
+ }
+ }
+
+ if(!rSurface)
+ {
+ // create data on-demand
+ rSurface = std::make_shared<SourceHelper>(rSourceBitmap);
+
+ if(bBufferSource)
+ {
+ // add to buffering mechanism to potentially reuse next time
+ const SvpSalBitmap& rSrcBmp(static_cast<const SvpSalBitmap&>(rSourceBitmap));
+ rSrcBmp.addOrReplaceSystemDependentData<SystemDependentData_SourceHelper>(
+ ImplGetSystemDependentDataManager(),
+ rSurface);
+ }
+ }
+ }
+
+ void tryToUseMaskBuffer(
+ const SalBitmap& rMaskBitmap,
+ std::shared_ptr<MaskHelper>& rMask)
+ {
+ // MM02 try to access buffered MaskHelper
+ std::shared_ptr<SystemDependentData_MaskHelper> pSystemDependentData_MaskHelper;
+ const bool bBufferMask(bUseBuffer
+ && rMaskBitmap.GetSize().Width() * rMaskBitmap.GetSize().Height() > nMinimalSquareSizeToBuffer);
+
+ if(bBufferMask)
+ {
+ const SvpSalBitmap& rSrcBmp(static_cast<const SvpSalBitmap&>(rMaskBitmap));
+ pSystemDependentData_MaskHelper = rSrcBmp.getSystemDependentData<SystemDependentData_MaskHelper>();
+
+ if(pSystemDependentData_MaskHelper)
+ {
+ // reuse buffered data
+ rMask = pSystemDependentData_MaskHelper->getMaskHelper();
+ }
+ }
+
+ if(!rMask)
+ {
+ // create data on-demand
+ rMask = std::make_shared<MaskHelper>(rMaskBitmap);
+
+ if(bBufferMask)
+ {
+ // add to buffering mechanism to potentially reuse next time
+ const SvpSalBitmap& rSrcBmp(static_cast<const SvpSalBitmap&>(rMaskBitmap));
+ rSrcBmp.addOrReplaceSystemDependentData<SystemDependentData_MaskHelper>(
+ ImplGetSystemDependentDataManager(),
+ rMask);
+ }
+ }
+ }
}
bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, const SalBitmap& rSourceBitmap, const SalBitmap& rAlphaBitmap )
@@ -398,16 +553,22 @@ bool SvpSalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, const SalBitmap& rS
return false;
}
- SourceHelper aSurface(rSourceBitmap);
- cairo_surface_t* source = aSurface.getSurface();
+ // MM02 try to access buffered SourceHelper
+ std::shared_ptr<SourceHelper> aSurface;
+ tryToUseSourceBuffer(rSourceBitmap, aSurface);
+ cairo_surface_t* source = aSurface->getSurface();
+
if (!source)
{
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case");
return false;
}
- MaskHelper aMask(rAlphaBitmap);
- cairo_surface_t *mask = aMask.getMask();
+ // MM02 try to access buffered MaskHelper
+ std::shared_ptr<MaskHelper> aMask;
+ tryToUseMaskBuffer(rAlphaBitmap, aMask);
+ cairo_surface_t *mask = aMask->getMask();
+
if (!mask)
{
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case");
@@ -468,29 +629,34 @@ bool SvpSalGraphics::drawTransformedBitmap(
return false;
}
- SourceHelper aSurface(rSourceBitmap);
- cairo_surface_t* source = aSurface.getSurface();
- if (!source)
+ // MM02 try to access buffered SourceHelper
+ std::shared_ptr<SourceHelper> aSurface;
+ tryToUseSourceBuffer(rSourceBitmap, aSurface);
+ cairo_surface_t* source(aSurface->getSurface());
+
+ if(!source)
{
SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case");
return false;
}
- std::unique_ptr<MaskHelper> xMask;
- cairo_surface_t *mask = nullptr;
- if (pAlphaBitmap)
+ // MM02 try to access buffered MaskHelper
+ std::shared_ptr<MaskHelper> aMask;
+
+ if(nullptr != pAlphaBitmap)
{
- xMask.reset(new MaskHelper(*pAlphaBitmap));
- mask = xMask->getMask();
- if (!mask)
- {
- SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case");
- return false;
- }
+ tryToUseMaskBuffer(*pAlphaBitmap, aMask);
}
- const Size aSize = rSourceBitmap.GetSize();
+ // access cairo_surface_t from MaskHelper
+ cairo_surface_t* mask(aMask ? aMask->getMask() : nullptr);
+ if(nullptr != pAlphaBitmap && nullptr == mask)
+ {
+ SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawTransformedBitmap case");
+ return false;
+ }
+ const Size aSize = rSourceBitmap.GetSize();
cairo_t* cr = getCairoContext(false);
clipRegion(cr);
@@ -1761,8 +1927,17 @@ void SvpSalGraphics::copyBits( const SalTwoRect& rTR,
void SvpSalGraphics::drawBitmap(const SalTwoRect& rTR, const SalBitmap& rSourceBitmap)
{
- SourceHelper aSurface(rSourceBitmap);
- cairo_surface_t* source = aSurface.getSurface();
+ // MM02 try to access buffered SourceHelper
+ std::shared_ptr<SourceHelper> aSurface;
+ tryToUseSourceBuffer(rSourceBitmap, aSurface);
+ cairo_surface_t* source = aSurface->getSurface();
+
+ if (!source)
+ {
+ SAL_WARN("vcl.gdi", "unsupported SvpSalGraphics::drawAlphaBitmap case");
+ return;
+ }
+
copyWithOperator(rTR, source, CAIRO_OPERATOR_OVER);
}
@@ -1786,6 +1961,10 @@ void SvpSalGraphics::drawMask( const SalTwoRect& rTR,
{
/** creates an image from the given rectangle, replacing all black pixels
* with nMaskColor and make all other full transparent */
+ // MM02 here decided *against* using buffered SourceHelper
+ // because the data gets somehow 'unmuliplied'. This may also be
+ // done just once, but I am not sure if this is safe to do.
+ // So for now dispense re-using data here.
SourceHelper aSurface(rSalBitmap, true); // The mask is argb32
if (!aSurface.getSurface())
{