summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-11-11 20:51:55 +0100
committerLuboš Luňák <l.lunak@collabora.com>2021-11-12 18:49:39 +0100
commit110fa313628c55fef1d35830358aea7e27c1e3ee (patch)
tree6a7f817e299093d1c3db916897dcd3eaf968f191
parent754697f0dcd63e1f0ce2edd70ab8b42b1b4d4484 (diff)
get rid of Skia's 'rasterhack' for Invert()
It seems that manually writing a shader that does the same as SkBlendMode::kDifference works fine even though the blend mode crashes e.g. on Windows/AMD. So get rid of the memory<->GPU conversions and use the shader as a workaround. Change-Id: I971deeeb98f40e5ffa90f6a8dd7b0b21ec491c1a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125101 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
-rw-r--r--vcl/inc/skia/utils.hxx3
-rw-r--r--vcl/skia/SkiaHelper.cxx35
-rw-r--r--vcl/skia/gdiimpl.cxx35
3 files changed, 40 insertions, 33 deletions
diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx
index 0bcc5989493e..ba479c58f234 100644
--- a/vcl/inc/skia/utils.hxx
+++ b/vcl/inc/skia/utils.hxx
@@ -71,6 +71,9 @@ VCL_DLLPUBLIC sk_sp<SkImage> makeCheckedImageSnapshot(sk_sp<SkSurface> surface,
inline Size imageSize(const sk_sp<SkImage>& image) { return Size(image->width(), image->height()); }
+// Do 'paint->setBlendMode(SkBlendMode::kDifference)' (workaround for buggy drivers).
+void setBlendModeDifference(SkPaint* paint);
+
// Must be called in any VCL backend before any Skia functionality is used.
// If not set, Skia will be disabled.
VCL_DLLPUBLIC void
diff --git a/vcl/skia/SkiaHelper.cxx b/vcl/skia/SkiaHelper.cxx
index 458f415befa4..ed04e5f20ec0 100644
--- a/vcl/skia/SkiaHelper.cxx
+++ b/vcl/skia/SkiaHelper.cxx
@@ -42,6 +42,7 @@ bool isVCLSkiaEnabled() { return false; }
#include <SkSurface.h>
#include <SkGraphics.h>
#include <GrDirectContext.h>
+#include <SkRuntimeEffect.h>
#include <skia_compiler.hxx>
#include <skia_opts.hxx>
#include <tools/sk_app/VulkanWindowContext.h>
@@ -645,11 +646,45 @@ tools::Long maxImageCacheSize()
return officecfg::Office::Common::Cache::Skia::ImageCacheSize::get();
}
+static sk_sp<SkBlender> differenceBlender;
+
+void setBlendModeDifference(SkPaint* paint)
+{
+ // This should normally do 'paint->setBlendMode(SkBlendMode::kDifference);'.
+ // But some drivers have a problem with this, namely currently AMD on Windows
+ // (e.g. 'Vulkan API version: 1.2.170, driver version: 2.0.179, vendor: 0x1002 (AMD),
+ // device: 0x15dd, type: integrated, name: AMD Radeon(TM) Vega 8 Graphics')
+ // simply crashes when kDifference is used.
+ // Intel also had repaint problems with kDifference (tdf#130430), but it seems
+ // those do not(?) exist anymore.
+ // Interestingly, explicitly writing a shader that does exactly the same works fine,
+ // so do that.
+ if (!differenceBlender)
+ {
+ const char* diff = R"(
+ vec4 main( vec4 src, vec4 dst )
+ {
+ return vec4(abs( src.r - dst.r ), abs( src.g - dst.g ), abs( src.b - dst.b ), dst.a );
+ }
+ )";
+ auto effect = SkRuntimeEffect::MakeForBlender(SkString(diff));
+ if (!effect.effect)
+ {
+ SAL_WARN("vcl.skia",
+ "SKRuntimeEffect::MakeForBlender failed: " << effect.errorText.c_str());
+ abort();
+ }
+ differenceBlender = effect.effect->makeBlender(nullptr);
+ }
+ paint->setBlender(differenceBlender);
+}
+
void cleanup()
{
sharedWindowContext.reset();
imageCache.clear();
imageCacheSize = 0;
+ differenceBlender.reset();
}
static SkSurfaceProps commonSurfaceProps;
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 9e2da70323de..fd86928c24c9 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -1412,16 +1412,6 @@ void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFl
preDraw();
SAL_INFO("vcl.skia.trace", "invert(" << this << "): " << rPoly << ":" << int(eFlags));
assert(!mXorMode);
- // Intel Vulkan drivers (up to current 0.401.3889) have a problem
- // with SkBlendMode::kDifference(?) and surfaces wider than 1024 pixels, resulting
- // in drawing errors. Work that around by fetching the relevant part of the surface
- // and drawing using CPU.
- bool rasterHack = (isGPU() && getVendor() == DriverBlocklist::VendorIntel && !mXorMode);
- // BackendTest::testDrawInvertTrackFrameWithRectangle() also has a problem
- // with SkBlendMode::kDifference on AMD, leading to crashes or even
- // driver instability. Also work around by drawing using CPU.
- if (isGPU() && getVendor() == DriverBlocklist::VendorAMD && !mXorMode)
- rasterHack = true;
SkPath aPath;
aPath.incReserve(rPoly.count());
addPolygonToPath(rPoly, aPath);
@@ -1429,6 +1419,7 @@ void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFl
addUpdateRegion(aPath.getBounds());
SkAutoCanvasRestore autoRestore(getDrawCanvas(), true);
SkPaint aPaint;
+ setBlendModeDifference(&aPaint);
// TrackFrame just inverts a dashed path around the polygon
if (eFlags == SalInvert::TrackFrame)
{
@@ -1441,13 +1432,11 @@ void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFl
aPaint.setStyle(SkPaint::kStroke_Style);
aPaint.setPathEffect(SkDashPathEffect::Make(intervals, SK_ARRAY_COUNT(intervals), 0));
aPaint.setColor(SkColorSetARGB(255, 255, 255, 255));
- aPaint.setBlendMode(SkBlendMode::kDifference);
}
else
{
aPaint.setColor(SkColorSetARGB(255, 255, 255, 255));
aPaint.setStyle(SkPaint::kFill_Style);
- aPaint.setBlendMode(SkBlendMode::kDifference);
// N50 inverts in checker pattern
if (eFlags == SalInvert::N50)
@@ -1472,27 +1461,7 @@ void SkiaSalGraphicsImpl::invert(basegfx::B2DPolygon const& rPoly, SalInvert eFl
aBitmap.makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkSamplingOptions()));
}
}
- if (!rasterHack)
- getDrawCanvas()->drawPath(aPath, aPaint);
- else
- {
- SkRect area;
- aPath.getBounds().roundOut(&area);
- SkRect size = SkRect::MakeWH(area.width(), area.height());
- sk_sp<SkSurface> surface
- = SkSurface::MakeRasterN32Premul(area.width(), area.height(), surfaceProps());
- SkPaint copy;
- copy.setBlendMode(SkBlendMode::kSrc);
- flushDrawing();
- surface->getCanvas()->drawImageRect(makeCheckedImageSnapshot(mSurface), area, size,
- SkSamplingOptions(), &copy,
- SkCanvas::kFast_SrcRectConstraint);
- aPath.offset(-area.x(), -area.y());
- surface->getCanvas()->drawPath(aPath, aPaint);
- getDrawCanvas()->drawImageRect(makeCheckedImageSnapshot(surface), size, area,
- SkSamplingOptions(), &copy,
- SkCanvas::kFast_SrcRectConstraint);
- }
+ getDrawCanvas()->drawPath(aPath, aPaint);
postDraw();
}