diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2020-09-22 12:48:10 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2020-09-23 08:45:47 +0200 |
commit | 19365e6e2b3311bacb2ae2abb70be5cfaf843776 (patch) | |
tree | 70168c5852cdda44d8d685644516e4066d31d92c | |
parent | assert that SkiaSalBitmap mImage is not deleted if it's the only data (diff) | |
download | core-19365e6e2b3311bacb2ae2abb70be5cfaf843776.tar.gz core-19365e6e2b3311bacb2ae2abb70be5cfaf843776.zip |
if allocating Vulkan surface fails, fall back to Skia raster surface
Occassionally there may be very large surfaces, such as
in tdf#135952. Try to fall back to raster, which is more likely to
succeed, given that it uses system RAM instead of video RAM.
Change-Id: I81994b174e5e52066eacc5f8778e9469b042f9c8
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103170
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r-- | vcl/inc/skia/gdiimpl.hxx | 4 | ||||
-rw-r--r-- | vcl/inc/skia/win/gdiimpl.hxx | 2 | ||||
-rw-r--r-- | vcl/inc/skia/x11/gdiimpl.hxx | 2 | ||||
-rw-r--r-- | vcl/skia/SkiaHelper.cxx | 25 | ||||
-rw-r--r-- | vcl/skia/gdiimpl.cxx | 35 | ||||
-rw-r--r-- | vcl/skia/win/gdiimpl.cxx | 6 | ||||
-rw-r--r-- | vcl/skia/x11/gdiimpl.cxx | 13 |
7 files changed, 46 insertions, 41 deletions
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx index 9405bc39ade2..2d8086639a08 100644 --- a/vcl/inc/skia/gdiimpl.hxx +++ b/vcl/inc/skia/gdiimpl.hxx @@ -235,8 +235,8 @@ protected: void destroySurface(); // Reimplemented for X11. virtual bool avoidRecreateByResize() const { return false; } - void createWindowSurface(); - virtual void createWindowContext() = 0; + void createWindowSurface(bool forceRaster = false); + virtual void createWindowContext(bool forceRaster = false) = 0; void createOffscreenSurface(); void privateDrawAlphaRect(long nX, long nY, long nWidth, long nHeight, double nTransparency, diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx index cdb6977e5bd2..564fcd7e9614 100644 --- a/vcl/inc/skia/win/gdiimpl.hxx +++ b/vcl/inc/skia/win/gdiimpl.hxx @@ -71,7 +71,7 @@ public: static void prepareSkia(); protected: - virtual void createWindowContext() override; + virtual void createWindowContext(bool forceRaster = false) override; virtual void performFlush() override; sk_sp<SkTypeface> createDirectWriteTypeface(const LOGFONTW& logFont); SkFont::Edging getFontEdging(); diff --git a/vcl/inc/skia/x11/gdiimpl.hxx b/vcl/inc/skia/x11/gdiimpl.hxx index 0f86f0907dcd..d131d54bfe8e 100644 --- a/vcl/inc/skia/x11/gdiimpl.hxx +++ b/vcl/inc/skia/x11/gdiimpl.hxx @@ -34,7 +34,7 @@ public: static void prepareSkia(); private: - virtual void createWindowContext() override; + virtual void createWindowContext(bool forceRaster = false) override; virtual void performFlush() override; virtual bool avoidRecreateByResize() const override; static std::unique_ptr<sk_app::WindowContext> diff --git a/vcl/skia/SkiaHelper.cxx b/vcl/skia/SkiaHelper.cxx index 72944a946c71..e029a9137429 100644 --- a/vcl/skia/SkiaHelper.cxx +++ b/vcl/skia/SkiaHelper.cxx @@ -395,11 +395,15 @@ sk_sp<SkSurface> createSkSurface(int width, int height, SkColorType type) surface = SkSurface::MakeRenderTarget( grDirectContext, SkBudgeted::kNo, SkImageInfo::Make(width, height, type, kPremul_SkAlphaType)); - assert(surface); + if (surface) + { #ifdef DBG_UTIL - prefillSurface(surface); + prefillSurface(surface); #endif - return surface; + return surface; + } + SAL_WARN("vcl.skia", + "cannot create Vulkan GPU offscreen surface, falling back to Raster"); } break; } @@ -428,11 +432,16 @@ sk_sp<SkImage> createSkImage(const SkBitmap& bitmap) sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grDirectContext, SkBudgeted::kNo, bitmap.info().makeAlphaType(kPremul_SkAlphaType)); - assert(surface); - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha - surface->getCanvas()->drawBitmap(bitmap, 0, 0, &paint); - return surface->makeImageSnapshot(); + if (surface) + { + SkPaint paint; + paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha + surface->getCanvas()->drawBitmap(bitmap, 0, 0, &paint); + return surface->makeImageSnapshot(); + } + // Try to fall back in non-debug builds. + SAL_WARN("vcl.skia", + "cannot create Vulkan GPU offscreen surface, falling back to Raster"); } break; } diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 8f73db8411fa..1821f48a7cce 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -289,13 +289,13 @@ void SkiaSalGraphicsImpl::createSurface() mFlush->SetPriority(TaskPriority::POST_PAINT); } -void SkiaSalGraphicsImpl::createWindowSurface() +void SkiaSalGraphicsImpl::createWindowSurface(bool forceRaster) { SkiaZone zone; assert(!isOffscreen()); assert(!mSurface); assert(!mWindowContext); - createWindowContext(); + createWindowContext(forceRaster); if (mWindowContext) mSurface = mWindowContext->getBackbufferSurface(); if (!mSurface) @@ -303,16 +303,15 @@ void SkiaSalGraphicsImpl::createWindowSurface() switch (SkiaHelper::renderMethodToUse()) { case SkiaHelper::RenderVulkan: - SAL_WARN("vcl.skia", "cannot create Vulkan GPU window surface, disabling Vulkan"); - // fall back to raster - SkiaHelper::disableRenderMethod(SkiaHelper::RenderVulkan); + SAL_WARN("vcl.skia", + "cannot create Vulkan GPU window surface, falling back to Raster"); destroySurface(); // destroys also WindowContext - return createWindowSurface(); // try again + return createWindowSurface(true); // try again case SkiaHelper::RenderRaster: abort(); // this should not really happen } } - assert((mSurface->getCanvas()->getGrContext() != nullptr) == mIsGPU); + mIsGPU = mSurface->getCanvas()->getGrContext() != nullptr; #ifdef DBG_UTIL SkiaHelper::prefillSurface(mSurface); #endif @@ -335,13 +334,12 @@ void SkiaSalGraphicsImpl::createOffscreenSurface() if (SkiaHelper::getSharedGrDirectContext()) { mSurface = SkiaHelper::createSkSurface(width, height); - assert(mSurface); - assert(mSurface->getCanvas()->getGrContext()); // is GPU-backed - mIsGPU = true; - return; + if (mSurface) + { + mIsGPU = mSurface->getCanvas()->getGrContext() != nullptr; + return; + } } - SAL_WARN("vcl.skia", "cannot create Vulkan offscreen GPU surface, disabling Vulkan"); - SkiaHelper::disableRenderMethod(SkiaHelper::RenderVulkan); break; } default: @@ -1098,7 +1096,8 @@ bool SkiaSalGraphicsImpl::drawPolyPolygonBezier(sal_uInt32, const sal_uInt32*, } static void copyArea(SkCanvas* canvas, sk_sp<SkSurface> surface, long nDestX, long nDestY, - long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, bool srcIsRaster) + long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, bool srcIsRaster, + bool destIsRaster) { // Using SkSurface::draw() should be more efficient than SkSurface::makeImageSnapshot(), // because it may detect copying to itself and avoid some needless copies. @@ -1106,7 +1105,8 @@ static void copyArea(SkCanvas* canvas, sk_sp<SkSurface> surface, long nDestX, lo // (https://groups.google.com/forum/#!topic/skia-discuss/6yiuw24jv0I) and also // raster surfaces do not avoid a copy of the source // (https://groups.google.com/forum/#!topic/skia-discuss/S3FMpCi82k0). - if (canvas == surface->getCanvas() || srcIsRaster) + // Finally, there's not much point if one of them is raster and the other is not (chrome/m86 even crashes). + if (canvas == surface->getCanvas() || srcIsRaster || (srcIsRaster != destIsRaster)) { SkPaint paint; paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha @@ -1135,7 +1135,7 @@ void SkiaSalGraphicsImpl::copyArea(long nDestX, long nDestY, long nSrcX, long nS << SkIRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)); assert(!mXorMode); ::copyArea(getDrawCanvas(), mSurface, nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, - !isGPU()); + !isGPU(), !isGPU()); addXorRegion(SkRect::MakeXYWH(nDestX, nDestY, nSrcWidth, nSrcHeight)); postDraw(); } @@ -1171,7 +1171,8 @@ void SkiaSalGraphicsImpl::copyBits(const SalTwoRect& rPosAry, SalGraphics* pSrcG SAL_INFO("vcl.skia.trace", "copybits(" << this << "): " << srcDebug() << " copy area: " << rPosAry); ::copyArea(getDrawCanvas(), src->mSurface, rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, - rPosAry.mnSrcY, rPosAry.mnDestWidth, rPosAry.mnDestHeight, !src->isGPU()); + rPosAry.mnSrcY, rPosAry.mnDestWidth, rPosAry.mnDestHeight, !src->isGPU(), + !isGPU()); } else { diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx index ea7cb3362386..5c5582b8ffe6 100644 --- a/vcl/skia/win/gdiimpl.cxx +++ b/vcl/skia/win/gdiimpl.cxx @@ -35,21 +35,19 @@ WinSkiaSalGraphicsImpl::WinSkiaSalGraphicsImpl(WinSalGraphics& rGraphics, { } -void WinSkiaSalGraphicsImpl::createWindowContext() +void WinSkiaSalGraphicsImpl::createWindowContext(bool forceRaster) { SkiaZone zone; sk_app::DisplayParams displayParams; - switch (SkiaHelper::renderMethodToUse()) + switch (forceRaster ? SkiaHelper::RenderRaster : SkiaHelper::renderMethodToUse()) { case SkiaHelper::RenderRaster: mWindowContext = sk_app::window_context_factory::MakeRasterForWin(mWinParent.gethWnd(), displayParams); - mIsGPU = false; break; case SkiaHelper::RenderVulkan: mWindowContext = sk_app::window_context_factory::MakeVulkanForWin(mWinParent.gethWnd(), displayParams); - mIsGPU = true; break; } } diff --git a/vcl/skia/x11/gdiimpl.cxx b/vcl/skia/x11/gdiimpl.cxx index 0f430c4f8100..7a55415ee55a 100644 --- a/vcl/skia/x11/gdiimpl.cxx +++ b/vcl/skia/x11/gdiimpl.cxx @@ -40,16 +40,13 @@ void X11SkiaSalGraphicsImpl::Init() SkiaSalGraphicsImpl::Init(); } -void X11SkiaSalGraphicsImpl::createWindowContext() +void X11SkiaSalGraphicsImpl::createWindowContext(bool forceRaster) { assert(mX11Parent.GetDrawable() != None); - mWindowContext = createWindowContext(mX11Parent.GetXDisplay(), mX11Parent.GetDrawable(), - &mX11Parent.GetVisual(), GetWidth(), GetHeight(), - SkiaHelper::renderMethodToUse(), false); - if (mWindowContext && SkiaHelper::renderMethodToUse() == SkiaHelper::RenderVulkan) - mIsGPU = true; - else - mIsGPU = false; + mWindowContext = createWindowContext( + mX11Parent.GetXDisplay(), mX11Parent.GetDrawable(), &mX11Parent.GetVisual(), GetWidth(), + GetHeight(), forceRaster ? SkiaHelper::RenderRaster : SkiaHelper::renderMethodToUse(), + false); } std::unique_ptr<sk_app::WindowContext> |