summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2022-01-11 19:08:50 +0100
committerLuboš Luňák <l.lunak@collabora.com>2022-01-24 14:40:02 +0100
commitcf9be3417bc2be5f772c03180b7cbd248b82cad5 (patch)
treeb0910dc2282764e7b7ba85da05eaf85e02744f79
parentbbabe9c8ddb116a8e05bf93b29578c38de63e42d (diff)
avoid Xlib cairo surfaces for small virtual devices (bsc#1183308)
The (private :( ) document contains a large number of small shapes for which VclProcessor2D::RenderTransparencePrimitive2D() gets called, which results in GetBitmapEx() on the VirtualDevice. And Cairo normally needs to do a roundtrip to the XServer to fetch the content, which makes the rendering pretty slow. Forcing image-based surface for small sizes of VirtualDevice actually has better performance for the document, and the lack of possible HW acceleration generally shouldn't matter for a surface this small. Additionally drawinglayer's VirtualDevice reusing tries to reuse even a large one when a small one is needed, so a hack is needed to avoid that in this case, I couldn't find a better way. Change-Id: I0f58659ab88165a6bd915f100fc3b1d4802a0fa9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128309 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r--drawinglayer/source/processor2d/vclhelperbufferdevice.cxx34
-rw-r--r--include/vcl/outdev.hxx3
-rw-r--r--vcl/headless/svpvd.cxx37
-rw-r--r--vcl/source/outdev/outdev.cxx9
4 files changed, 62 insertions, 21 deletions
diff --git a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
index 9129271bcb6b..7f20d094b446 100644
--- a/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
+++ b/drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
@@ -63,6 +63,8 @@ private:
// virtualdevice because that isn't safe to do at least for Gtk2
std::map<VclPtr<VirtualDevice>, VclPtr<OutputDevice>> maDeviceTemplates;
+ static bool isSizeSuitable(const VclPtr<VirtualDevice>& device, const Size& size);
+
public:
VDevBuffer();
virtual ~VDevBuffer() override;
@@ -98,6 +100,28 @@ VDevBuffer::~VDevBuffer()
}
}
+bool VDevBuffer::isSizeSuitable(const VclPtr<VirtualDevice>& device, const Size& rSizePixel)
+{
+ if (device->GetOutputWidthPixel() >= rSizePixel.getWidth()
+ && device->GetOutputHeightPixel() >= rSizePixel.getHeight())
+ {
+#if defined(UNX)
+ // HACK: See the small size handling in SvpSalVirtualDevice::CreateSurface().
+ // Make sure to not reuse a larger device when a small one should be preferred.
+ if (device->GetRenderBackendName() == "svp")
+ {
+ if (rSizePixel.getWidth() <= 32 && rSizePixel.getHeight() <= 32
+ && (device->GetOutputWidthPixel() > 32 || device->GetOutputHeightPixel() > 32))
+ {
+ return false;
+ }
+ }
+#endif
+ return true;
+ }
+ return false;
+}
+
VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSizePixel,
bool bTransparent)
{
@@ -124,9 +148,7 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
if (bOkay)
{
// found is valid
- const bool bCandidateOkay(
- a->buf->GetOutputWidthPixel() >= rSizePixel.getWidth()
- && a->buf->GetOutputHeightPixel() >= rSizePixel.getHeight());
+ const bool bCandidateOkay = isSizeSuitable(a->buf, rSizePixel);
if (bCandidateOkay)
{
@@ -151,16 +173,14 @@ VclPtr<VirtualDevice> VDevBuffer::alloc(OutputDevice& rOutDev, const Size& rSize
{
// found is invalid, use candidate
aFound = a;
- bOkay = aFound->buf->GetOutputWidthPixel() >= rSizePixel.getWidth()
- && aFound->buf->GetOutputHeightPixel() >= rSizePixel.getHeight();
+ bOkay = isSizeSuitable(aFound->buf, rSizePixel);
}
}
else
{
// none yet, use candidate
aFound = a;
- bOkay = aFound->buf->GetOutputWidthPixel() >= rSizePixel.getWidth()
- && aFound->buf->GetOutputHeightPixel() >= rSizePixel.getHeight();
+ bOkay = isSizeSuitable(aFound->buf, rSizePixel);
}
}
}
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 7e1a0fad7dcd..a777f9d73569 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -295,6 +295,9 @@ public:
const AllSettings& GetSettings() const { return *mxSettings; }
SystemGraphicsData GetSystemGfxData() const;
+ OUString GetRenderBackendName() const;
+
+ // Used by the canvas module. Despite the name it does not always return true if Cairo is supported.
bool SupportsCairo() const;
/// Create Surface from given cairo surface
cairo::SurfaceSharedPtr CreateSurface(const cairo::CairoSurfaceSharedPtr& rSurface) const;
diff --git a/vcl/headless/svpvd.cxx b/vcl/headless/svpvd.cxx
index f8e9cb5e6874..4d82a46e50c4 100644
--- a/vcl/headless/svpvd.cxx
+++ b/vcl/headless/svpvd.cxx
@@ -76,29 +76,38 @@ void SvpSalVirtualDevice::CreateSurface(tools::Long nNewDX, tools::Long nNewDY,
cairo_surface_destroy(m_pSurface);
}
- if (pBuffer)
+ double fXScale, fYScale;
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // Force scaling of the painting
+ fXScale = fYScale = comphelper::LibreOfficeKit::getDPIScale();
+ }
+ else
{
- double fXScale, fYScale;
- if (comphelper::LibreOfficeKit::isActive())
- {
- // Force scaling of the painting
- fXScale = fYScale = comphelper::LibreOfficeKit::getDPIScale();
- }
- else
- {
- dl_cairo_surface_get_device_scale(m_pRefSurface, &fXScale, &fYScale);
- nNewDX *= fXScale;
- nNewDY *= fYScale;
- }
+ dl_cairo_surface_get_device_scale(m_pRefSurface, &fXScale, &fYScale);
+ nNewDX *= fXScale;
+ nNewDY *= fYScale;
+ }
+ if (pBuffer)
+ {
m_pSurface = cairo_image_surface_create_for_data(pBuffer, CAIRO_FORMAT_ARGB32,
nNewDX, nNewDY, cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, nNewDX));
-
+ dl_cairo_surface_set_device_scale(m_pSurface, fXScale, fYScale);
+ }
+ else if(nNewDX <= 32 && nNewDY <= 32)
+ {
+ // Force image-based surface if small. Small VirtualDevice instances are often used for small
+ // temporary bitmaps that will eventually have GetBitmap() called on them, which would cause
+ // X Server roundtrip with Xlib-based surface, which may be way more costly than doing the drawing
+ // in software (which should be fairly cheap for small surfaces anyway).
+ m_pSurface = cairo_surface_create_similar_image(m_pRefSurface, CAIRO_FORMAT_ARGB32, nNewDX, nNewDY);
dl_cairo_surface_set_device_scale(m_pSurface, fXScale, fYScale);
}
else
{
m_pSurface = cairo_surface_create_similar(m_pRefSurface, CAIRO_CONTENT_COLOR_ALPHA, nNewDX, nNewDY);
+ // Device scale is inherited in this case.
}
}
diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx
index 708a283f44a8..0d9248d2fd77 100644
--- a/vcl/source/outdev/outdev.cxx
+++ b/vcl/source/outdev/outdev.cxx
@@ -231,6 +231,15 @@ SystemGraphicsData OutputDevice::GetSystemGfxData() const
return mpGraphics->GetGraphicsData();
}
+OUString OutputDevice::GetRenderBackendName() const
+{
+ if (!mpGraphics && !AcquireGraphics())
+ return {};
+ assert(mpGraphics);
+
+ return mpGraphics->getRenderBackendName();
+}
+
#if ENABLE_CAIRO_CANVAS
bool OutputDevice::SupportsCairo() const