summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2019-10-02 17:15:07 +0200
committerLuboš Luňák <l.lunak@collabora.com>2019-10-02 17:15:07 +0200
commitf12a617da1963728260ab2b082c825450435bb87 (patch)
treee4363c9d51cd69e637d78443545f54a964d8492c /vcl
parentfb2d7a6026f746cc37b34e272426664a3b939fa3 (diff)
make the X11/Skia backend finally capable of drawing on screen
Change-Id: I5c847c1036c671137ee27053691189093b1dafae
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/skia/gdiimpl.hxx15
-rw-r--r--vcl/inc/skia/x11/gdiimpl.hxx11
-rw-r--r--vcl/skia/gdiimpl.cxx52
-rw-r--r--vcl/skia/x11/gdiimpl.cxx64
4 files changed, 133 insertions, 9 deletions
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index aad4ea3e8454..c72c5979464d 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -27,6 +27,8 @@
#include <SkSurface.h>
+class SkiaFlushIdle;
+
class VCL_DLLPUBLIC SkiaSalGraphicsImpl : public SalGraphicsImpl
{
public:
@@ -37,8 +39,6 @@ public:
virtual void DeInit() override;
- virtual void freeResources() override;
-
const vcl::Region& getClipRegion() const;
virtual bool setClipRegion(const vcl::Region&) override;
@@ -183,6 +183,12 @@ public:
virtual bool drawGradient(const tools::PolyPolygon& rPolygon,
const Gradient& rGradient) override;
+ // To be called after any drawing.
+ void scheduleFlush();
+
+ // Internal, called by SkiaFlushIdle.
+ virtual void performFlush() = 0;
+
#ifdef DBG_UTIL
void dump(const char* file) const;
void dump(const SkBitmap& bitmap, const char* file) const;
@@ -191,7 +197,9 @@ public:
protected:
void setProvider(SalGeometryProvider* provider) { mProvider = provider; }
-private:
+ bool isOffscreen() const { return mProvider == nullptr || mProvider->IsOffScreen(); }
+
+protected:
// get the width of the device
int GetWidth() const { return mProvider ? mProvider->GetWidth() : 1; }
// get the height of the device
@@ -215,6 +223,7 @@ private:
vcl::Region mClipRegion;
Color mLineColor;
Color mFillColor;
+ std::unique_ptr<SkiaFlushIdle> mFlush;
};
#endif
diff --git a/vcl/inc/skia/x11/gdiimpl.hxx b/vcl/inc/skia/x11/gdiimpl.hxx
index 670c1117d32d..fcc0ecb116d8 100644
--- a/vcl/inc/skia/x11/gdiimpl.hxx
+++ b/vcl/inc/skia/x11/gdiimpl.hxx
@@ -19,14 +19,14 @@
class VCL_PLUGIN_PUBLIC X11SkiaSalGraphicsImpl : public SkiaSalGraphicsImpl, public X11GraphicsImpl
{
private:
- X11SalGraphics& mrX11Parent;
+ X11SalGraphics& mParent;
public:
X11SkiaSalGraphicsImpl(X11SalGraphics& rParent);
virtual ~X11SkiaSalGraphicsImpl() override;
-public:
virtual void Init() override;
+ virtual void freeResources() override;
// implementation of X11GraphicsImpl
void FillPixmapFromScreen(X11Pixmap* pPixmap, int nX, int nY) override;
@@ -34,6 +34,13 @@ public:
bool RenderAndCacheNativeControl(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY,
ControlCacheKey& aControlCacheKey) override;
bool TryRenderCachedNativeControl(ControlCacheKey& rControlCacheKey, int nX, int nY) override;
+
+protected:
+ virtual void performFlush() override;
+
+private:
+ GC getGC();
+ GC mCopyGc;
};
#endif // INCLUDED_VCL_INC_SKIA_X11_GDIIMPL_HXX
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index da8a917f50b5..4a42ea503985 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -21,6 +21,8 @@
#include <salgdi.hxx>
#include <skia/salbmp.hxx>
+#include <vcl/idle.hxx>
+#include <vcl/svapp.hxx>
#include <SkCanvas.h>
#include <SkPath.h>
@@ -30,11 +32,34 @@
#include <fstream>
#endif
+// Class that triggers flushing the backing buffer when idle.
+class SkiaFlushIdle : public Idle
+{
+ SkiaSalGraphicsImpl* graphics;
+
+public:
+ explicit SkiaFlushIdle(SkiaSalGraphicsImpl* graphics)
+ : Idle("skia idle swap")
+ , graphics(graphics)
+ {
+ // We don't want to be swapping before we've painted.
+ SetPriority(TaskPriority::POST_PAINT);
+ }
+
+ virtual void Invoke() override
+ {
+ graphics->performFlush();
+ Stop();
+ SetPriority(TaskPriority::HIGHEST);
+ }
+};
+
SkiaSalGraphicsImpl::SkiaSalGraphicsImpl(SalGraphics& rParent, SalGeometryProvider* pProvider)
: mParent(rParent)
, mProvider(pProvider)
, mLineColor(SALCOLOR_NONE)
, mFillColor(SALCOLOR_NONE)
+ , mFlush(new SkiaFlushIdle(this))
{
}
@@ -46,12 +71,13 @@ void SkiaSalGraphicsImpl::Init()
mSurface = SkSurface::MakeRasterN32Premul(GetWidth(), GetHeight());
mSurface->getCanvas()->save(); // see SetClipRegion()
mClipRegion = vcl::Region(tools::Rectangle(0, 0, GetWidth(), GetHeight()));
+
+ // We don't want to be swapping before we've painted.
+ mFlush->SetPriority(TaskPriority::POST_PAINT);
}
void SkiaSalGraphicsImpl::DeInit() { mSurface.reset(); }
-void SkiaSalGraphicsImpl::freeResources() {}
-
static SkIRect toSkIRect(const tools::Rectangle& rectangle)
{
return SkIRect::MakeXYWH(rectangle.Left(), rectangle.Top(), rectangle.GetWidth(),
@@ -129,6 +155,7 @@ void SkiaSalGraphicsImpl::drawPixel(long nX, long nY)
return;
SkCanvas* canvas = mSurface->getCanvas();
canvas->drawPoint(nX, nY, SkPaint());
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::drawPixel(long nX, long nY, Color nColor)
@@ -141,6 +168,7 @@ void SkiaSalGraphicsImpl::drawPixel(long nX, long nY, Color nColor)
// Apparently drawPixel() is actually expected to set the pixel and not draw it.
paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha
canvas->drawPoint(nX, nY, paint);
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::drawLine(long nX1, long nY1, long nX2, long nY2)
@@ -151,6 +179,7 @@ void SkiaSalGraphicsImpl::drawLine(long nX1, long nY1, long nX2, long nY2)
SkPaint paint;
paint.setColor(toSkColor(mLineColor));
canvas->drawLine(nX1, nY1, nX2, nY2, paint);
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::drawRect(long nX, long nY, long nWidth, long nHeight)
@@ -169,6 +198,7 @@ void SkiaSalGraphicsImpl::drawRect(long nX, long nY, long nWidth, long nHeight)
paint.setStyle(SkPaint::kStroke_Style);
canvas->drawIRect(SkIRect::MakeXYWH(nX, nY, nWidth - 1, nHeight - 1), paint);
}
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAry)
@@ -183,6 +213,7 @@ void SkiaSalGraphicsImpl::drawPolyLine(sal_uInt32 nPoints, const SalPoint* pPtAr
paint.setColor(toSkColor(mLineColor));
mSurface->getCanvas()->drawPoints(SkCanvas::kLines_PointMode, nPoints, pointVector.data(),
paint);
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry)
@@ -208,6 +239,7 @@ void SkiaSalGraphicsImpl::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry
paint.setStyle(SkPaint::kStroke_Style);
mSurface->getCanvas()->drawPath(path, paint);
}
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints,
@@ -242,6 +274,7 @@ void SkiaSalGraphicsImpl::drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pP
paint.setStyle(SkPaint::kStroke_Style);
mSurface->getCanvas()->drawPath(path, paint);
}
+ scheduleFlush();
}
bool SkiaSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
@@ -306,6 +339,7 @@ void SkiaSalGraphicsImpl::copyArea(long nDestX, long nDestY, long nSrcX, long nS
= mSurface->makeImageSnapshot(SkIRect::MakeXYWH(nSrcX, nSrcY, nSrcWidth, nSrcHeight));
// TODO makeNonTextureImage() ?
mSurface->getCanvas()->drawImage(image, nDestX, nDestY);
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics)
@@ -326,6 +360,7 @@ void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcG
rPosAry.mnDestWidth,
rPosAry.mnDestHeight),
nullptr);
+ scheduleFlush();
}
bool SkiaSalGraphicsImpl::blendBitmap(const SalTwoRect&, const SalBitmap& rBitmap)
@@ -356,6 +391,7 @@ void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap&
SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth,
rPosAry.mnDestHeight),
nullptr);
+ scheduleFlush();
}
void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap,
@@ -385,6 +421,7 @@ void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& rPosAry, const SalBitmap& r
SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth,
rPosAry.mnDestHeight),
nullptr);
+ scheduleFlush();
}
std::shared_ptr<SalBitmap> SkiaSalGraphicsImpl::getBitmap(long nX, long nY, long nWidth,
@@ -459,6 +496,7 @@ bool SkiaSalGraphicsImpl::drawAlphaBitmap(const SalTwoRect& rPosAry, const SalBi
SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth,
rPosAry.mnDestHeight),
nullptr);
+ scheduleFlush();
return true;
}
@@ -495,6 +533,16 @@ bool SkiaSalGraphicsImpl::drawGradient(const tools::PolyPolygon& rPolygon,
return false;
}
+void SkiaSalGraphicsImpl::scheduleFlush()
+{
+ if (isOffscreen())
+ return;
+ if (!Application::IsInExecute())
+ performFlush(); // otherwise nothing would trigger idle rendering
+ else if (!mFlush->IsActive())
+ mFlush->Start();
+}
+
#ifdef DBG_UTIL
void SkiaSalGraphicsImpl::dump(const char* file) const
{
diff --git a/vcl/skia/x11/gdiimpl.cxx b/vcl/skia/x11/gdiimpl.cxx
index 22608754f5d9..3891de5b059e 100644
--- a/vcl/skia/x11/gdiimpl.cxx
+++ b/vcl/skia/x11/gdiimpl.cxx
@@ -5,13 +5,23 @@
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Some of this code is based on Skia source code, covered by the following
+ * license notice (see readlicense_oo for the full license):
+ *
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
*/
#include <skia/x11/gdiimpl.hxx>
X11SkiaSalGraphicsImpl::X11SkiaSalGraphicsImpl(X11SalGraphics& rParent)
: SkiaSalGraphicsImpl(rParent, rParent.GetGeometryProvider())
- , mrX11Parent(rParent)
+ , mParent(rParent)
+ , mCopyGc(None)
{
}
@@ -20,10 +30,60 @@ X11SkiaSalGraphicsImpl::~X11SkiaSalGraphicsImpl() {}
void X11SkiaSalGraphicsImpl::Init()
{
// The m_pFrame and m_pVDev pointers are updated late in X11
- setProvider(mrX11Parent.GetGeometryProvider());
+ setProvider(mParent.GetGeometryProvider());
SkiaSalGraphicsImpl::Init();
}
+GC X11SkiaSalGraphicsImpl::getGC()
+{
+ if (mCopyGc == None)
+ {
+ XGCValues values;
+ values.graphics_exposures = False;
+ values.subwindow_mode = ClipByChildren;
+ mCopyGc = XCreateGC(mParent.GetXDisplay(), mParent.GetDrawable(),
+ GCGraphicsExposures | GCSubwindowMode, &values);
+ }
+ return mCopyGc;
+}
+
+void X11SkiaSalGraphicsImpl::freeResources()
+{
+ if (mCopyGc != None)
+ {
+ XFreeGC(mParent.GetXDisplay(), mCopyGc);
+ mCopyGc = None;
+ }
+}
+
+void X11SkiaSalGraphicsImpl::performFlush()
+{
+ Display* dpy = mParent.GetXDisplay();
+ Drawable drawable = mParent.GetDrawable();
+ GC gc = getGC();
+ SkPixmap pm;
+ if (!mSurface->peekPixels(&pm))
+ abort();
+ int bitsPerPixel = pm.info().bytesPerPixel() * 8;
+ XImage image;
+ memset(&image, 0, sizeof(image));
+ image.width = pm.width();
+ image.height = pm.height();
+ image.format = ZPixmap;
+ image.data = (char*)pm.addr();
+ image.byte_order = LSBFirst;
+ image.bitmap_unit = bitsPerPixel;
+ image.bitmap_bit_order = LSBFirst;
+ image.bitmap_pad = bitsPerPixel;
+ image.depth = 24;
+ image.bytes_per_line = pm.rowBytes() - pm.width() * pm.info().bytesPerPixel();
+ image.bits_per_pixel = bitsPerPixel;
+ if (!XInitImage(&image))
+ abort();
+ // TODO XPutImage() is somewhat inefficient, XShmPutImage() should be preferred.
+ XPutImage(dpy, drawable, gc, &image, 0, 0, 0, 0, pm.width(), pm.height());
+}
+
void X11SkiaSalGraphicsImpl::FillPixmapFromScreen(X11Pixmap* pPixmap, int nX, int nY)
{
(void)pPixmap;