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>
This commit is contained in:
parent
bbabe9c8dd
commit
cf9be3417b
4 changed files with 62 additions and 21 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -76,29 +76,38 @@ void SvpSalVirtualDevice::CreateSurface(tools::Long nNewDX, tools::Long nNewDY,
|
|||
cairo_surface_destroy(m_pSurface);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (pBuffer)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue