Roll external/skia 1a049bb04380..25bcd6a6215e (4 commits)
https://skia.googlesource.com/skia.git/+log/1a049bb04380..25bcd6a6215e
If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://skia-autoroll.corp.goog/r/android-master-autoroll
Please CC stani@google.com on the revert to ensure that a human
is aware of the problem.
To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug
Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+/master/autoroll/README.md
Test: Presubmit checks will test this change.
Change-Id: I68b81c463381c7dc956f6ded9fa865196d08830f
Exempt-From-Owner-Approval: The autoroll bot does not require owner approval.
diff --git a/Android.bp b/Android.bp
index ce0c43f..59bd2c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -788,7 +788,7 @@
"src/gpu/ops/GrStrokeRectOp.cpp",
"src/gpu/ops/GrTessellatingPathRenderer.cpp",
"src/gpu/ops/GrTextureOp.cpp",
- "src/gpu/tessellate/GrCoverShader.cpp",
+ "src/gpu/tessellate/GrFillPathShader.cpp",
"src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp",
"src/gpu/tessellate/GrPathParser.cpp",
"src/gpu/tessellate/GrStencilPathShader.cpp",
diff --git a/DEPS b/DEPS
index f03484b..b4b1603 100644
--- a/DEPS
+++ b/DEPS
@@ -7,7 +7,7 @@
deps = {
"buildtools" : "https://chromium.googlesource.com/chromium/buildtools.git@505de88083136eefd056e5ee4ca0f01fe9b33de8",
"common" : "https://skia.googlesource.com/common.git@9737551d7a52c3db3262db5856e6bcd62c462b92",
- "third_party/externals/angle2" : "https://chromium.googlesource.com/angle/angle.git@2bc9cc12f0b091bc5d144d770adaa200d3f417c9",
+ "third_party/externals/angle2" : "https://chromium.googlesource.com/angle/angle.git@ee07cb317579dfda40dabb5d6d9c209e0e9e0643",
"third_party/externals/dawn" : "https://dawn.googlesource.com/dawn.git@604072bc2ed01018eb03bcbbf9d94042f679af63",
"third_party/externals/dng_sdk" : "https://android.googlesource.com/platform/external/dng_sdk.git@c8d0c9b1d16bfda56f15165d39e0ffa360a11123",
"third_party/externals/egl-registry" : "https://skia.googlesource.com/external/github.com/KhronosGroup/EGL-Registry@a0bca08de07c7d7651047bedc0b653cfaaa4f2ae",
@@ -31,13 +31,13 @@
"third_party/externals/spirv-cross" : "https://chromium.googlesource.com/external/github.com/KhronosGroup/SPIRV-Cross@53ab2144b90abede33be5161aec5dfc94ddc3caf",
"third_party/externals/spirv-headers" : "https://skia.googlesource.com/external/github.com/KhronosGroup/SPIRV-Headers.git@29c11140baaf9f7fdaa39a583672c556bf1795a1",
"third_party/externals/spirv-tools" : "https://skia.googlesource.com/external/github.com/KhronosGroup/SPIRV-Tools.git@0c4feb643b89d1792b02f7cbef315e9d95633bd7",
- "third_party/externals/swiftshader" : "https://swiftshader.googlesource.com/SwiftShader@6c3dc3581eaf4345c0507d5ac7bb013d55351547",
+ "third_party/externals/swiftshader" : "https://swiftshader.googlesource.com/SwiftShader@430def835f9f85d52f4a96db9b715cd9a7403c9c",
#"third_party/externals/v8" : "https://chromium.googlesource.com/v8/v8.git@5f1ae66d5634e43563b2d25ea652dfb94c31a3b4",
"third_party/externals/wuffs" : "https://skia.googlesource.com/external/github.com/google/wuffs.git@4080840928c0b05a80cda0d14ac2e2615f679f1a",
"third_party/externals/zlib" : "https://chromium.googlesource.com/chromium/src/third_party/zlib@47af7c547f8551bd25424e56354a2ae1e9062859",
"../src": {
- "url": "https://chromium.googlesource.com/chromium/src.git@243744c215b780cfd060040b037908636e62a8dc",
+ "url": "https://chromium.googlesource.com/chromium/src.git@fbfe7df1b1d42c3b640852e4afa9ba732e12a20d",
"condition": "checkout_chromium",
},
}
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 0dcd690..c36c167 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -418,12 +418,13 @@
"$_src/gpu/gradients/generated/GrTiledGradientEffect.cpp",
"$_src/gpu/gradients/generated/GrTiledGradientEffect.h",
- "$_src/gpu/tessellate/GrCoverShader.cpp",
- "$_src/gpu/tessellate/GrCoverShader.h",
+ "$_src/gpu/tessellate/GrFillPathShader.cpp",
+ "$_src/gpu/tessellate/GrFillPathShader.h",
"$_src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp",
"$_src/gpu/tessellate/GrGpuTessellationPathRenderer.h",
"$_src/gpu/tessellate/GrPathParser.cpp",
"$_src/gpu/tessellate/GrPathParser.h",
+ "$_src/gpu/tessellate/GrPathShader.h",
"$_src/gpu/tessellate/GrStencilPathShader.cpp",
"$_src/gpu/tessellate/GrStencilPathShader.h",
"$_src/gpu/tessellate/GrTessellatePathOp.cpp",
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index db7b656..4985a6e 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -27,11 +27,7 @@
}
fWindowRectsState = hardClip.windowRectsState();
- if (!args.fUserStencil->isDisabled(fFlags & Flags::kHasStencilClip)) {
- fFlags |= Flags::kStencilEnabled;
- }
-
- fUserStencilSettings = args.fUserStencil;
+ this->setUserStencil(args.fUserStencil);
fXferProcessor = std::move(xferProcessor);
@@ -76,16 +72,13 @@
const GrSwizzle& outputSwizzle, InputFlags inputFlags,
const GrUserStencilSettings* userStencil)
: fWindowRectsState()
- , fUserStencilSettings(userStencil)
, fFlags((Flags)inputFlags)
, fXferProcessor(std::move(xp))
, fOutputSwizzle(outputSwizzle) {
if (GrScissorTest::kEnabled == scissorTest) {
fFlags |= Flags::kScissorEnabled;
}
- if (!userStencil->isDisabled(false)) {
- fFlags |= Flags::kStencilEnabled;
- }
+ this->setUserStencil(userStencil);
}
void GrPipeline::genKey(GrProcessorKeyBuilder* b, const GrCaps& caps) const {
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index c057051..a444c74 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -187,6 +187,12 @@
/// @}
const GrUserStencilSettings* getUserStencil() const { return fUserStencilSettings; }
+ void setUserStencil(const GrUserStencilSettings* stencil) {
+ fUserStencilSettings = stencil;
+ if (!fUserStencilSettings->isDisabled(fFlags & Flags::kHasStencilClip)) {
+ fFlags |= Flags::kStencilEnabled;
+ }
+ }
bool isScissorEnabled() const {
return SkToBool(fFlags & Flags::kScissorEnabled);
diff --git a/src/gpu/GrProcessor.h b/src/gpu/GrProcessor.h
index f3ae030..384b8e1 100644
--- a/src/gpu/GrProcessor.h
+++ b/src/gpu/GrProcessor.h
@@ -100,7 +100,6 @@
kGrConicEffect_ClassID,
kGrConstColorProcessor_ClassID,
kGrConvexPolyEffect_ClassID,
- kGrCoverShader_ClassID,
kGrDeviceSpaceTextureDecalFragmentProcessor_ClassID,
kGrDiffuseLightingEffect_ClassID,
kGrDisplacementMapEffect_ClassID,
@@ -160,6 +159,9 @@
kSwizzleFragmentProcessor_ClassID,
kTessellationTestTriShader_ClassID,
kTessellationTestRectShader_ClassID,
+ kTessellate_GrFillBoundingBoxShader_ClassID,
+ kTessellate_GrFillCubicHullShader_ClassID,
+ kTessellate_GrFillTriangleShader_ClassID,
kTessellate_GrStencilCubicShader_ClassID,
kTessellate_GrStencilTriangleShader_ClassID,
kTessellate_GrStencilWedgeShader_ClassID,
diff --git a/src/gpu/tessellate/GrCoverShader.cpp b/src/gpu/tessellate/GrCoverShader.cpp
deleted file mode 100644
index 936fea7..0000000
--- a/src/gpu/tessellate/GrCoverShader.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2019 Google LLC.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "src/gpu/tessellate/GrCoverShader.h"
-
-#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
-#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
-#include "src/gpu/glsl/GrGLSLVarying.h"
-#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
-
-class GrCoverShader::Impl : public GrGLSLGeometryProcessor {
- void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final {
- const char* viewMatrix;
- fViewMatrixUniform = args.fUniformHandler->addUniform(
- kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
-
- const char* pathBounds;
- fPathBoundsUniform = args.fUniformHandler->addUniform(
- kVertex_GrShaderFlag, kFloat4_GrSLType, "path_bounds", &pathBounds);
-
- const char* color;
- fColorUniform = args.fUniformHandler->addUniform(
- kFragment_GrShaderFlag, kHalf4_GrSLType, "color", &color);
-
- args.fVaryingHandler->emitAttributes(args.fGP.cast<GrCoverShader>());
-
- args.fVertBuilder->codeAppendf(R"(
- // Use sk_VertexID and uniforms (instead of vertex data) to find vertex positions.
- float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
- float2 localcoord = mix(%s.xy, %s.zw, T);
- float2 vertexpos = (%s * float3(localcoord, 1)).xy;
-
- // Outset to avoid possible T-junctions with extreme edges of the path.
- float2x2 M2 = float2x2(%s);
- float2 devoutset = .25 * sign(M2 * (T - .5));
- vertexpos += devoutset;
- localcoord += inverse(M2) * devoutset;)",
- pathBounds, pathBounds, viewMatrix, viewMatrix);
-
- this->emitTransforms(args.fVertBuilder, args.fVaryingHandler, args.fUniformHandler,
- GrShaderVar("localcoord", kFloat2_GrSLType),
- args.fFPCoordTransformHandler);
-
- gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
-
- args.fFragBuilder->codeAppendf(R"(
- %s = %s;
- %s = half4(1);)",
- args.fOutputColor, color, args.fOutputCoverage);
- }
-
- void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
- const CoordTransformRange& transformRange) override {
- const GrCoverShader& shader = primProc.cast<GrCoverShader>();
- const SkRect& b = shader.fPathBounds;
- const SkPMColor4f& color = shader.fColor;
- pdman.setSkMatrix(fViewMatrixUniform, shader.fViewMatrix);
- pdman.set4f(fPathBoundsUniform, b.left(), b.top(), b.right(), b.bottom());
- pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
- this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
- }
-
- GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
- GrGLSLUniformHandler::UniformHandle fPathBoundsUniform;
- GrGLSLUniformHandler::UniformHandle fColorUniform;
-};
-
-GrGLSLPrimitiveProcessor* GrCoverShader::createGLSLInstance(const GrShaderCaps&) const {
- return new Impl;
-}
diff --git a/src/gpu/tessellate/GrCoverShader.h b/src/gpu/tessellate/GrCoverShader.h
deleted file mode 100644
index c39cf9e..0000000
--- a/src/gpu/tessellate/GrCoverShader.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2019 Google LLC.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef GrCoverShader_DEFINED
-#define GrCoverShader_DEFINED
-
-#include "src/gpu/GrGeometryProcessor.h"
-
-// Draws a path's bounding box, with a subpixel outset to avoid possible T-junctions with extreme
-// edges of the path. This class is used for the "cover" pass of stencil-then-cover path rendering.
-// NOTE: The emitted geometry may not be axis-aligned, depending on the view matrix.
-class GrCoverShader : public GrGeometryProcessor {
-public:
- GrCoverShader(const SkMatrix& viewMatrix, const SkRect& pathBounds, const SkPMColor4f& color)
- : GrGeometryProcessor(kGrCoverShader_ClassID)
- , fViewMatrix(viewMatrix)
- , fPathBounds(pathBounds)
- , fColor(color) {}
-
- const char* name() const override { return "GrCoverShader"; }
- void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {}
- GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
-
-private:
- const SkMatrix fViewMatrix;
- const SkRect fPathBounds;
- const SkPMColor4f fColor;
-
- class Impl;
-};
-
-#endif
diff --git a/src/gpu/tessellate/GrFillPathShader.cpp b/src/gpu/tessellate/GrFillPathShader.cpp
new file mode 100644
index 0000000..1e12cf2
--- /dev/null
+++ b/src/gpu/tessellate/GrFillPathShader.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2020 Google LLC.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/gpu/tessellate/GrFillPathShader.h"
+
+#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
+#include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
+#include "src/gpu/glsl/GrGLSLVarying.h"
+#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
+
+class GrFillPathShader::Impl : public GrGLSLGeometryProcessor {
+public:
+ void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
+ auto& shader = args.fGP.cast<GrFillPathShader>();
+
+ const char* viewMatrix;
+ fViewMatrixUniform = args.fUniformHandler->addUniform(
+ kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
+
+ args.fVaryingHandler->emitAttributes(shader);
+
+ args.fVertBuilder->codeAppend("float2 localcoord, vertexpos;");
+ shader.emitVertexCode(this, args.fVertBuilder, viewMatrix, args.fUniformHandler);
+
+ this->emitTransforms(args.fVertBuilder, args.fVaryingHandler, args.fUniformHandler,
+ GrShaderVar("localcoord", kFloat2_GrSLType),
+ args.fFPCoordTransformHandler);
+
+ gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos");
+
+ const char* color;
+ fColorUniform = args.fUniformHandler->addUniform(
+ kFragment_GrShaderFlag, kHalf4_GrSLType, "color", &color);
+
+ args.fFragBuilder->codeAppendf("%s = %s;", args.fOutputColor, color);
+ args.fFragBuilder->codeAppendf("%s = half4(1);", args.fOutputCoverage);
+ }
+
+ void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
+ const CoordTransformRange& transformRange) override {
+ const GrFillPathShader& shader = primProc.cast<GrFillPathShader>();
+ pdman.setSkMatrix(fViewMatrixUniform, shader.viewMatrix());
+
+ const SkPMColor4f& color = shader.fColor;
+ pdman.set4f(fColorUniform, color.fR, color.fG, color.fB, color.fA);
+
+ if (fPathBoundsUniform.isValid()) {
+ const SkRect& b = primProc.cast<GrFillBoundingBoxShader>().pathBounds();
+ pdman.set4f(fPathBoundsUniform, b.left(), b.top(), b.right(), b.bottom());
+ }
+
+ this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange);
+ }
+
+ GrGLSLUniformHandler::UniformHandle fViewMatrixUniform;
+ GrGLSLUniformHandler::UniformHandle fColorUniform;
+ GrGLSLUniformHandler::UniformHandle fPathBoundsUniform;
+};
+
+GrGLSLPrimitiveProcessor* GrFillPathShader::createGLSLInstance(const GrShaderCaps&) const {
+ return new Impl;
+}
+
+void GrFillTriangleShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const char* viewMatrix,
+ GrGLSLUniformHandler* uniformHandler) const {
+ v->codeAppendf(R"(
+ localcoord = input_point;
+ vertexpos = (%s * float3(localcoord, 1)).xy;)", viewMatrix);
+}
+
+void GrFillCubicHullShader::emitVertexCode(Impl*, GrGLSLVertexBuilder* v, const char* viewMatrix,
+ GrGLSLUniformHandler* uniformHandler) const {
+ v->codeAppend(R"(
+ float4x2 P = float4x2(input_points_0_1, input_points_2_3);
+
+ // Translate the points to v0..3 where v0=0.
+ float2 v1 = P[1] - P[0], v2 = P[2] - P[0], v3 = P[3] - P[0];
+
+ // Reorder the points so v2 bisects v1 and v3.
+ if (sign(determinant(float2x2(v2,v1))) == sign(determinant(float2x2(v2,v3)))) {
+ float2 tmp = P[2];
+ if (sign(determinant(float2x2(v1,v2))) != sign(determinant(float2x2(v1,v3)))) {
+ P[2] = P[1]; // swap(P2, P1)
+ P[1] = tmp;
+ } else {
+ P[2] = P[3]; // swap(P2, P3)
+ P[3] = tmp;
+ }
+ }
+
+ // Find the "turn direction" of each corner and net turn direction.
+ float4 dir;
+ float netdir = 0.0;
+ for (int i = 0; i < 4; ++i) {
+ float2 prev = P[i] - P[(i + 3) & 3], next = P[(i + 1) & 3] - P[i];
+ dir[i] = sign(determinant(float2x2(prev, next)));
+ netdir += dir[i];
+ }
+
+ // sk_VertexID comes in fan order. Convert to strip order.
+ int vertexidx = sk_VertexID;
+ vertexidx ^= vertexidx >> 1;
+
+ // Remove the non-convex vertex, if any.
+ if (dir[vertexidx] != sign(netdir)) {
+ vertexidx = (vertexidx + 1) & 3;
+ }
+
+ localcoord = P[vertexidx];)");
+
+ v->codeAppendf("vertexpos = (%s * float3(localcoord, 1)).xy;", viewMatrix);
+}
+
+void GrFillBoundingBoxShader::emitVertexCode(Impl* impl, GrGLSLVertexBuilder* v,
+ const char* viewMatrix,
+ GrGLSLUniformHandler* uniformHandler) const {
+ const char* pathBounds;
+ impl->fPathBoundsUniform = uniformHandler->addUniform(
+ kVertex_GrShaderFlag, kFloat4_GrSLType, "path_bounds", &pathBounds);
+
+ v->codeAppendf(R"(
+ // Use sk_VertexID and uniforms (instead of vertex data) to find vertex positions.
+ float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1);
+ localcoord = mix(%s.xy, %s.zw, T);
+ vertexpos = (%s * float3(localcoord, 1)).xy;
+
+ // Outset to avoid possible T-junctions with extreme edges of the path.
+ float2x2 M2 = float2x2(%s);
+ float2 devoutset = .25 * sign(M2 * (T - .5));
+ localcoord += inverse(M2) * devoutset;
+ vertexpos += devoutset;)", pathBounds, pathBounds, viewMatrix, viewMatrix);
+}
diff --git a/src/gpu/tessellate/GrFillPathShader.h b/src/gpu/tessellate/GrFillPathShader.h
new file mode 100644
index 0000000..1373a14
--- /dev/null
+++ b/src/gpu/tessellate/GrFillPathShader.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2020 Google LLC.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrFillPathShader_DEFINED
+#define GrFillPathShader_DEFINED
+
+#include "src/gpu/tessellate/GrPathShader.h"
+
+class GrGLSLUniformHandler;
+class GrGLSLVertexBuilder;
+
+// This is the base class for shaders that fill a path's pixels in the final render target.
+class GrFillPathShader : public GrPathShader {
+public:
+ GrFillPathShader(ClassID classID, const SkMatrix& viewMatrix, SkPMColor4f color,
+ GrPrimitiveType primitiveType)
+ : GrPathShader(classID, viewMatrix, primitiveType, 0)
+ , fColor(color) {
+ }
+
+ void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
+ GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
+
+protected:
+ class Impl;
+
+ virtual void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
+ GrGLSLUniformHandler*) const = 0;
+
+private:
+ const SkPMColor4f fColor;
+};
+
+// Fills a simple array of triangles.
+class GrFillTriangleShader : public GrFillPathShader {
+public:
+ GrFillTriangleShader(const SkMatrix& viewMatrix, SkPMColor4f color)
+ : GrFillPathShader(kTessellate_GrFillTriangleShader_ClassID, viewMatrix, color,
+ GrPrimitiveType::kTriangles) {
+ static constexpr Attribute kPtAttrib = {
+ "input_point", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
+ this->setVertexAttributes(&kPtAttrib, 1);
+ }
+
+private:
+ const char* name() const override { return "GrFillTriangleShader"; }
+ void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
+ GrGLSLUniformHandler*) const override;
+};
+
+// Fills an array of convex hulls surrounding 4-point cubic instances.
+class GrFillCubicHullShader : public GrFillPathShader {
+public:
+ GrFillCubicHullShader(const SkMatrix& viewMatrix, SkPMColor4f color)
+ : GrFillPathShader(kTessellate_GrFillCubicHullShader_ClassID, viewMatrix, color,
+ GrPrimitiveType::kTriangleStrip) {
+ static constexpr Attribute kPtsAttribs[] = {
+ {"input_points_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType},
+ {"input_points_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}};
+ this->setInstanceAttributes(kPtsAttribs, SK_ARRAY_COUNT(kPtsAttribs));
+ }
+
+private:
+ const char* name() const override { return "GrFillCubicHullShader"; }
+ void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
+ GrGLSLUniformHandler*) const override;
+};
+
+// Fills a path's bounding box, with subpixel outset to avoid possible T-junctions with extreme
+// edges of the path.
+// NOTE: The emitted geometry may not be axis-aligned, depending on the view matrix.
+class GrFillBoundingBoxShader : public GrFillPathShader {
+public:
+ GrFillBoundingBoxShader(const SkMatrix& viewMatrix, SkPMColor4f color, const SkRect& pathBounds)
+ : GrFillPathShader(kTessellate_GrFillBoundingBoxShader_ClassID, viewMatrix, color,
+ GrPrimitiveType::kTriangleStrip)
+ , fPathBounds(pathBounds) {
+ }
+
+ const SkRect& pathBounds() const { return fPathBounds; }
+
+private:
+ const char* name() const override { return "GrFillBoundingBoxShader"; }
+ void emitVertexCode(Impl*, GrGLSLVertexBuilder*, const char* viewMatrix,
+ GrGLSLUniformHandler*) const override;
+
+ const SkRect fPathBounds;
+};
+
+#endif
diff --git a/src/gpu/tessellate/GrPathShader.h b/src/gpu/tessellate/GrPathShader.h
new file mode 100644
index 0000000..1443c77
--- /dev/null
+++ b/src/gpu/tessellate/GrPathShader.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2020 Google LLC.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrPathShader_DEFINED
+#define GrPathShader_DEFINED
+
+#include "src/gpu/GrGeometryProcessor.h"
+#include "src/gpu/GrOpFlushState.h"
+#include "src/gpu/GrOpsRenderPass.h"
+#include "src/gpu/GrProgramInfo.h"
+
+ // This is a common base class for shaders in the GPU tessellator.
+class GrPathShader : public GrGeometryProcessor {
+public:
+ GrPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType,
+ int tessellationPatchVertexCount)
+ : GrGeometryProcessor(classID)
+ , fViewMatrix(viewMatrix)
+ , fPrimitiveType(primitiveType)
+ , fTessellationPatchVertexCount(tessellationPatchVertexCount) {
+ if (fTessellationPatchVertexCount) {
+ this->setWillUseTessellationShaders();
+ }
+ }
+
+ const SkMatrix& viewMatrix() const { return fViewMatrix; }
+ GrPrimitiveType primitiveType() const { return fPrimitiveType; }
+ int tessellationPatchVertexCount() const { return fTessellationPatchVertexCount; }
+
+ void issueDraw(GrOpFlushState* state, const GrPipeline* pipeline,
+ const GrPipeline::FixedDynamicState* fixedDynamicState,
+ sk_sp<const GrBuffer> vertexBuffer, int vertexCount, int baseVertex,
+ const SkRect& bounds) {
+ GrMesh mesh(fPrimitiveType, fTessellationPatchVertexCount);
+ mesh.setNonIndexedNonInstanced(vertexCount);
+ mesh.setVertexData(std::move(vertexBuffer), baseVertex);
+ this->issueDraw(state, pipeline, fixedDynamicState, mesh, bounds);
+ }
+
+ void issueDraw(GrOpFlushState* state, const GrPipeline* pipeline,
+ const GrPipeline::FixedDynamicState* fixedDynamicState, const GrMesh& mesh,
+ const SkRect& bounds) {
+ SkASSERT(mesh.primitiveType() == fPrimitiveType);
+ SkASSERT(mesh.tessellationPatchVertexCount() == fTessellationPatchVertexCount);
+ GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
+ state->proxy()->backendFormat(), state->view()->origin(),
+ pipeline, this, fixedDynamicState, nullptr, 0,
+ fPrimitiveType, fTessellationPatchVertexCount);
+ state->opsRenderPass()->draw(programInfo, &mesh, 1, bounds);
+ }
+
+private:
+ const SkMatrix fViewMatrix;
+ const GrPrimitiveType fPrimitiveType;
+ const int fTessellationPatchVertexCount;
+
+ class Impl;
+};
+
+#endif
diff --git a/src/gpu/tessellate/GrStencilPathShader.cpp b/src/gpu/tessellate/GrStencilPathShader.cpp
index cf17222..cc31dea 100644
--- a/src/gpu/tessellate/GrStencilPathShader.cpp
+++ b/src/gpu/tessellate/GrStencilPathShader.cpp
@@ -40,7 +40,7 @@
args.fVaryingHandler->emitAttributes(shader);
GrShaderVar vertexPos = (*shader.vertexAttributes().begin()).asShaderVar();
- if (!shader.fViewMatrix.isIdentity()) {
+ if (!shader.viewMatrix().isIdentity()) {
const char* viewMatrix;
fViewMatrixUniform = args.fUniformHandler->addUniform(
kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix);
@@ -63,8 +63,8 @@
void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc,
const CoordTransformRange& transformRange) override {
const auto& shader = primProc.cast<GrStencilPathShader>();
- if (!shader.fViewMatrix.isIdentity()) {
- pdman.setSkMatrix(fViewMatrixUniform, shader.fViewMatrix);
+ if (!shader.viewMatrix().isIdentity()) {
+ pdman.setSkMatrix(fViewMatrixUniform, shader.viewMatrix());
}
}
diff --git a/src/gpu/tessellate/GrStencilPathShader.h b/src/gpu/tessellate/GrStencilPathShader.h
index f3ea703..0aa0b59 100644
--- a/src/gpu/tessellate/GrStencilPathShader.h
+++ b/src/gpu/tessellate/GrStencilPathShader.h
@@ -8,36 +8,25 @@
#ifndef GrStencilPathShader_DEFINED
#define GrStencilPathShader_DEFINED
-#include "src/gpu/GrGeometryProcessor.h"
+#include "src/gpu/tessellate/GrPathShader.h"
// This is the base class for shaders that stencil path elements, namely, triangles, standalone
// cubics, and wedges.
-class GrStencilPathShader : public GrGeometryProcessor {
+class GrStencilPathShader : public GrPathShader {
public:
GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType,
int tessellationPatchVertexCount = 0)
- : GrGeometryProcessor(classID)
- , fViewMatrix(viewMatrix)
- , fPrimitiveType(primitiveType)
- , fTessellationPatchVertexCount(tessellationPatchVertexCount) {
+ : GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) {
constexpr static Attribute kPointAttrib = {
"point", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
this->setVertexAttributes(&kPointAttrib, 1);
- if (fTessellationPatchVertexCount) {
- this->setWillUseTessellationShaders();
- }
}
- GrPrimitiveType primitiveType() const { return fPrimitiveType; }
- int tessellationPatchVertexCount() const { return fTessellationPatchVertexCount; }
- void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
- b->add32(fViewMatrix.isIdentity());
- }
- GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
private:
- const SkMatrix fViewMatrix;
- const GrPrimitiveType fPrimitiveType;
- const int fTessellationPatchVertexCount;
+ void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final {
+ b->add32(this->viewMatrix().isIdentity());
+ }
+ GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
class Impl;
};
diff --git a/src/gpu/tessellate/GrTessellatePathOp.cpp b/src/gpu/tessellate/GrTessellatePathOp.cpp
index a4ce3f1..53e8382 100644
--- a/src/gpu/tessellate/GrTessellatePathOp.cpp
+++ b/src/gpu/tessellate/GrTessellatePathOp.cpp
@@ -10,9 +10,8 @@
#include "src/gpu/GrEagerVertexAllocator.h"
#include "src/gpu/GrGpu.h"
#include "src/gpu/GrOpFlushState.h"
-#include "src/gpu/GrOpsRenderPass.h"
-#include "src/gpu/GrProgramInfo.h"
-#include "src/gpu/tessellate/GrCoverShader.h"
+#include "src/gpu/GrTessellator.h"
+#include "src/gpu/tessellate/GrFillPathShader.h"
#include "src/gpu/tessellate/GrPathParser.h"
#include "src/gpu/tessellate/GrStencilPathShader.h"
@@ -29,24 +28,66 @@
GrEagerDynamicVertexAllocator cubicInstanceAllocator(state, &fCubicInstanceBuffer,
&fBaseCubicInstance);
- // First see if we should split up inner polygon triangles and curves, and triangulate the inner
+ // First check if the path is large and/or simple enough that we can actually tessellate the
+ // inner polygon(s) on the CPU. This is our fastest approach. It allows us to stencil only the
+ // curves, and then draw the internal polygons directly to the final render target, thus filling
+ // in the majority of pixels in a single render pass.
+ SkScalar scales[2];
+ SkAssertResult(fViewMatrix.getMinMaxScales(scales)); // Will fail if perspective.
+ const SkRect& bounds = fPath.getBounds();
+ int numVerbs = fPath.countVerbs();
+ if (numVerbs <= 0) {
+ return;
+ }
+ float gpuFragmentWork = bounds.height() * scales[0] * bounds.width() * scales[1];
+ float cpuTessellationWork = (float)numVerbs * SkNextLog2(numVerbs); // N log N.
+ if (cpuTessellationWork * 500 + (256 * 256) < gpuFragmentWork) { // Don't try below 256x256.
+ bool pathIsLinear;
+ // PathToTriangles(..kSimpleInnerPolygon..) will fail if the inner polygon is not simple.
+ if ((fPathVertexCount = GrTessellator::PathToTriangles(
+ fPath, 0, SkRect::MakeEmpty(), &pathVertexAllocator,
+ GrTessellator::Mode::kSimpleInnerPolygons, &pathIsLinear))) {
+ if (((Flags::kStencilOnly | Flags::kWireframe) & fFlags) ||
+ GrAAType::kCoverage == fAAType ||
+ (state->appliedClip() && state->appliedClip()->hasStencilClip())) {
+ // If we have certain flags, mixed samples, or a stencil clip then we unfortunately
+ // can't fill the inner polygon directly. Create a stencil shader here to ensure we
+ // still stencil the entire path.
+ fStencilPathShader = state->allocator()->make<GrStencilTriangleShader>(fViewMatrix);
+ }
+ if (!(Flags::kStencilOnly & fFlags)) {
+ fFillPathShader = state->allocator()->make<GrFillTriangleShader>(
+ fViewMatrix, fColor);
+ }
+ if (!pathIsLinear) {
+ fCubicInstanceCount = GrPathParser::EmitCubicInstances(
+ fPath, &cubicInstanceAllocator);
+ SkASSERT(fCubicInstanceCount);
+ }
+ return;
+ }
+ }
+
+ // Next see if we can split up inner polygon triangles and curves, and triangulate the inner
// polygon(s) more efficiently. This causes greater CPU overhead due to the extra shaders and
// draw calls, but the better triangulation can reduce the rasterizer load by a great deal on
// complex paths.
- const SkRect& bounds = fPath.getBounds();
- float scale = fViewMatrix.getMaxScale();
- // Raster-edge work is 1-dimensional, so we sum height and width rather than multiplying them.
- float rasterEdgeWork = (bounds.height() + bounds.width()) * scale * fPath.countVerbs();
+ // NOTE: Raster-edge work is 1-dimensional, so we sum height and width instead of multiplying.
+ float rasterEdgeWork = (bounds.height() + bounds.width()) * scales[1] * fPath.countVerbs();
if (rasterEdgeWork > 1000 * 1000) {
- fPathShader = state->allocator()->make<GrStencilTriangleShader>(fViewMatrix);
- fPathVertexCount = GrPathParser::EmitInnerPolygonTriangles(fPath, &pathVertexAllocator);
+ if ((fPathVertexCount =
+ GrPathParser::EmitInnerPolygonTriangles(fPath, &pathVertexAllocator))) {
+ fStencilPathShader = state->allocator()->make<GrStencilTriangleShader>(fViewMatrix);
+ }
fCubicInstanceCount = GrPathParser::EmitCubicInstances(fPath, &cubicInstanceAllocator);
return;
}
// Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
- fPathShader = state->allocator()->make<GrStencilWedgeShader>(fViewMatrix);
- fPathVertexCount = GrPathParser::EmitCenterWedgePatches(fPath, &pathVertexAllocator);
+
+ if ((fPathVertexCount = GrPathParser::EmitCenterWedgePatches(fPath, &pathVertexAllocator))) {
+ fStencilPathShader = state->allocator()->make<GrStencilWedgeShader>(fViewMatrix);
+ }
}
void GrTessellatePathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
@@ -100,33 +141,19 @@
GrPipeline pipeline(initArgs, GrDisableColorXPFactory::MakeXferProcessor(), hardClip);
- if (fPathVertexBuffer) {
- GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
- state->proxy()->backendFormat(), state->view()->origin(),
- &pipeline, fPathShader, fixedDynamicState, nullptr, 0,
- fPathShader->primitiveType(),
- fPathShader->tessellationPatchVertexCount());
-
- GrMesh mesh(fPathShader->primitiveType(), fPathShader->tessellationPatchVertexCount());
- mesh.setNonIndexedNonInstanced(fPathVertexCount);
- mesh.setVertexData(fPathVertexBuffer, fBasePathVertex);
-
- state->opsRenderPass()->draw(programInfo, &mesh, 1, this->bounds());
+ if (fStencilPathShader) {
+ SkASSERT(fPathVertexBuffer);
+ fStencilPathShader->issueDraw(state, &pipeline, fixedDynamicState, fPathVertexBuffer,
+ fPathVertexCount, fBasePathVertex, this->bounds());
}
if (fCubicInstanceBuffer) {
- // Here we treat the cubic instance buffer as tessellation patches.
- GrStencilCubicShader shader(fViewMatrix);
- GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
- state->proxy()->backendFormat(), state->view()->origin(),
- &pipeline, &shader, fixedDynamicState, nullptr, 0,
- GrPrimitiveType::kPatches, 4);
-
+ // Here we treat the cubic instance buffer as tessellation patches to stencil the curves.
GrMesh mesh(GrPrimitiveType::kPatches, 4);
mesh.setNonIndexedNonInstanced(fCubicInstanceCount * 4);
mesh.setVertexData(fCubicInstanceBuffer, fBaseCubicInstance * 4);
-
- state->opsRenderPass()->draw(programInfo, &mesh, 1, this->bounds());
+ GrStencilCubicShader(fViewMatrix).issueDraw(
+ state, &pipeline, fixedDynamicState, mesh, this->bounds());
}
// http://skbug.com/9739
@@ -162,20 +189,74 @@
initArgs.fInputFlags |= GrPipeline::InputFlags::kConservativeRaster;
}
}
- initArgs.fUserStencil = &kTestAndResetStencil;
initArgs.fCaps = &state->caps();
initArgs.fDstProxyView = state->drawOpArgs().dstProxyView();
initArgs.fOutputSwizzle = state->drawOpArgs().outputSwizzle();
GrPipeline pipeline(initArgs, std::move(fProcessors), std::move(clip));
- GrCoverShader shader(fViewMatrix, fPath.getBounds(), fColor);
- GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
- state->proxy()->backendFormat(), state->view()->origin(), &pipeline,
- &shader, fixedDynamicState, nullptr, 0,
- GrPrimitiveType::kTriangleStrip);
- GrMesh mesh(GrPrimitiveType::kTriangleStrip);
- mesh.setNonIndexedNonInstanced(4);
+ if (fFillPathShader) {
+ SkASSERT(fPathVertexBuffer);
- state->opsRenderPass()->draw(programInfo, &mesh, 1, this->bounds());
+ // These are a twist on the standard red book stencil settings that allow us to draw the
+ // inner polygon directly to the final render target. At this point, the curves are already
+ // stencilled in. So if the stencil value is zero, then it means the path at our sample is
+ // not affected by any curves and we fill the path in directly. If the stencil value is
+ // nonzero, then we don't fill and instead continue the standard red book stencil process.
+ //
+ // NOTE: These settings are currently incompatible with a stencil clip.
+ constexpr static GrUserStencilSettings kFillOrIncrDecrStencil(
+ GrUserStencilSettings::StaticInitSeparate<
+ 0x0000, 0x0000,
+ GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
+ 0xffff, 0xffff,
+ GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
+ GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
+ 0xffff, 0xffff>());
+
+ constexpr static GrUserStencilSettings kFillOrInvertStencil(
+ GrUserStencilSettings::StaticInit<
+ 0x0000,
+ GrUserStencilTest::kEqual,
+ 0xffff,
+ GrUserStencilOp::kKeep,
+ GrUserStencilOp::kZero,
+ 0xffff>());
+
+ if (fStencilPathShader) {
+ // The path was already stencilled. Here we just need to do a cover pass.
+ pipeline.setUserStencil(&kTestAndResetStencil);
+ } else if (!fCubicInstanceBuffer) {
+ // There are no curves, so we can just ignore stencil and fill the path directly.
+ pipeline.setUserStencil(&GrUserStencilSettings::kUnused);
+ } else if (SkPathFillType::kWinding == fPath.getFillType()) {
+ // Fill in the path pixels not touched by curves, incr/decr stencil otherwise.
+ SkASSERT(!pipeline.hasStencilClip());
+ pipeline.setUserStencil(&kFillOrIncrDecrStencil);
+ } else {
+ // Fill in the path pixels not touched by curves, invert stencil otherwise.
+ SkASSERT(!pipeline.hasStencilClip());
+ pipeline.setUserStencil(&kFillOrInvertStencil);
+ }
+ fFillPathShader->issueDraw(state, &pipeline, fixedDynamicState, fPathVertexBuffer,
+ fPathVertexCount, fBasePathVertex, this->bounds());
+
+ if (fCubicInstanceBuffer) {
+ // At this point, every pixel is filled in except the ones touched by curves. Issue a
+ // final cover pass over the curves by drawing their convex hulls. This will fill in any
+ // remaining samples and reset the stencil buffer.
+ GrMesh mesh(GrPrimitiveType::kTriangleStrip);
+ mesh.setInstanced(fCubicInstanceBuffer, fCubicInstanceCount, fBaseCubicInstance, 4);
+ pipeline.setUserStencil(&kTestAndResetStencil);
+ GrFillCubicHullShader(fViewMatrix, fColor).issueDraw(
+ state, &pipeline, fixedDynamicState, mesh, this->bounds());
+ }
+ } else {
+ // There is not a fill shader for the path. Just draw a bounding box.
+ GrMesh mesh(GrPrimitiveType::kTriangleStrip);
+ mesh.setNonIndexedNonInstanced(4);
+ pipeline.setUserStencil(&kTestAndResetStencil);
+ GrFillBoundingBoxShader(fViewMatrix, fColor, fPath.getBounds()).issueDraw(
+ state, &pipeline, fixedDynamicState, mesh, this->bounds());
+ }
}
diff --git a/src/gpu/tessellate/GrTessellatePathOp.h b/src/gpu/tessellate/GrTessellatePathOp.h
index cd0e37b..e080a1d 100644
--- a/src/gpu/tessellate/GrTessellatePathOp.h
+++ b/src/gpu/tessellate/GrTessellatePathOp.h
@@ -11,6 +11,7 @@
#include "src/gpu/ops/GrDrawOp.h"
class GrAppliedHardClip;
+class GrFillPathShader;
class GrStencilPathShader;
// Renders paths using the classic Red Book "stencil, then cover" method. Curves get linearized by
@@ -67,12 +68,25 @@
SkPMColor4f fColor;
GrProcessorSet fProcessors;
- // The "path shader" draws the below path geometry.
- GrStencilPathShader* fPathShader;
+ // These path shaders get created during onPrepare for drawing the below path vertex data.
+ //
+ // If fFillPathShader is null, then we just stencil the full path using fStencilPathShader and
+ // fCubicInstanceBuffer, and then fill it using a simple bounding box.
+ //
+ // If fFillPathShader is not null, then we fill the path using it plus cubic hulls from
+ // fCubicInstanceBuffer instead of a bounding box.
+ //
+ // If fFillPathShader is not null and fStencilPathShader *is* null, then the vertex data
+ // contains non-overlapping path geometry that can be drawn directly to the final render target.
+ // We only need to stencil curves from fCubicInstanceBuffer, and then draw the rest of the path
+ // directly.
+ GrStencilPathShader* fStencilPathShader = nullptr;
+ GrFillPathShader* fFillPathShader = nullptr;
- // The "path vertex buffer" is made up of either inner polygon triangles (see
- // GrPathParser::EmitInnerPolygonTriangles) or cubic wedge patches (see
- // GrPathParser::EmitCenterWedgePatches).
+ // The "path vertex data" is made up of cubic wedges or inner polygon triangles (either red book
+ // style or fully tessellated). The geometry is generated by
+ // GrPathParser::EmitCenterWedgePatches, GrPathParser::EmitInnerPolygonTriangles,
+ // or GrTessellator::PathToTriangles.
sk_sp<const GrBuffer> fPathVertexBuffer;
int fBasePathVertex;
int fPathVertexCount;