From bf341ae88c83155752e3a2080bb40cefbbbaf32b Mon Sep 17 00:00:00 2001 From: Chris Dalton Date: Wed, 27 Mar 2019 00:28:22 +0000 Subject: [PATCH] Revert "Add MSAA and non-aa modes to GrFillRRect Op" This reverts commit 16a8e99a371104563c4f1504c7302bd4ece9e6ca. Reason for revert: Amd/Radeon bugs and quality concerns Original change's description: > Add MSAA and non-aa modes to GrFillRRect Op > > Adds a non-aa mode and an MSAA mode that uses the sample mask. Also > adds a new cap to decide whether we prefer this new sample mask Op for > large round rects, or whether it's faster to just continue drawing > them as paths like before. > > Bug: skia: > Change-Id: Iea7d9a78766f67c196a02cb833c84a0ac3f1bbac > Reviewed-on: https://skia-review.googlesource.com/c/skia/+/202921 > Reviewed-by: Brian Salomon > Commit-Queue: Chris Dalton TBR=bsalomon@google.com,brianosman@google.com,csmartdalton@google.com,ethannicholas@google.com Change-Id: If2c3293bdd8c19307e243d83c44fd328446fded7 No-Presubmit: true No-Tree-Checks: true No-Try: true Bug: skia: Reviewed-on: https://skia-review.googlesource.com/c/skia/+/203961 Reviewed-by: Chris Dalton Commit-Queue: Chris Dalton --- gm/samplelocations.cpp | 2 +- src/gpu/GrCaps.cpp | 4 - src/gpu/GrCaps.h | 5 - src/gpu/GrRenderTargetContext.cpp | 61 ++- src/gpu/gl/GrGLCaps.cpp | 6 - src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp | 63 +-- src/gpu/glsl/GrGLSLFragmentShaderBuilder.h | 35 +- src/gpu/ops/GrFillRRectOp.cpp | 504 +++++-------------- src/gpu/ops/GrFillRRectOp.h | 26 +- src/gpu/vk/GrVkCaps.cpp | 5 - 10 files changed, 171 insertions(+), 540 deletions(-) diff --git a/gm/samplelocations.cpp b/gm/samplelocations.cpp index d1034838a6209..2efe19235d48f 100644 --- a/gm/samplelocations.cpp +++ b/gm/samplelocations.cpp @@ -138,7 +138,7 @@ class SampleLocationsTestProcessor::Impl : public GrGLSLGeometryProcessor { f->sampleOffsets(), coord.fsIn()); f->codeAppendf( "if (all(lessThanEqual(abs(samplecoord), float2(1)))) {"); f->maskOffMultisampleCoverage( - "~(1 << i)", GrGLSLFPFragmentBuilder::ScopeFlags::kInsideLoop); + "~(1 << i)", GrGLSLFragmentShaderBuilder::Scope::kInsideLoopOrBranch); f->codeAppendf( "}"); f->codeAppendf("}"); } diff --git a/src/gpu/GrCaps.cpp b/src/gpu/GrCaps.cpp index 7c4bcd723ce33..4011b379534c1 100644 --- a/src/gpu/GrCaps.cpp +++ b/src/gpu/GrCaps.cpp @@ -74,8 +74,6 @@ GrCaps::GrCaps(const GrContextOptions& options) { fPreferVRAMUseOverFlushes = true; - fPreferTrianglesOverSampleMask = false; - // Default to true, allow older versions of OpenGL to disable explicitly fClampToBorderSupport = true; @@ -212,8 +210,6 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const { writer->appendBool("Blacklist Coverage Counting Path Renderer [workaround]", fBlacklistCoverageCounting); writer->appendBool("Prefer VRAM Use over flushes [workaround]", fPreferVRAMUseOverFlushes); - writer->appendBool("Prefer more triangles over sample mask [MSAA only]", - fPreferTrianglesOverSampleMask); writer->appendBool("Avoid stencil buffers [workaround]", fAvoidStencilBuffers); if (this->advancedBlendEquationSupport()) { diff --git a/src/gpu/GrCaps.h b/src/gpu/GrCaps.h index 74cdb7a087601..b11077ad65a20 100644 --- a/src/gpu/GrCaps.h +++ b/src/gpu/GrCaps.h @@ -73,8 +73,6 @@ class GrCaps : public SkRefCnt { bool preferVRAMUseOverFlushes() const { return fPreferVRAMUseOverFlushes; } - bool preferTrianglesOverSampleMask() const { return fPreferTrianglesOverSampleMask; } - bool blacklistCoverageCounting() const { return fBlacklistCoverageCounting; } bool avoidStencilBuffers() const { return fAvoidStencilBuffers; } @@ -360,9 +358,6 @@ class GrCaps : public SkRefCnt { // ANGLE performance workaround bool fPreferVRAMUseOverFlushes : 1; - // On some platforms it's better to make more triangles than to use the sample mask (MSAA only). - bool fPreferTrianglesOverSampleMask : 1; - // TODO: this may need to be an enum to support different fence types bool fFenceSyncSupport : 1; diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp index ff3c7c63f5710..19c7c425449ea 100644 --- a/src/gpu/GrRenderTargetContext.cpp +++ b/src/gpu/GrRenderTargetContext.cpp @@ -1225,22 +1225,21 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip, AutoCheckFlush acf(this->drawingManager()); GrAAType aaType = this->chooseAAType(aa); + if (GrAAType::kCoverage == aaType) { + std::unique_ptr op; + if (style.isSimpleFill()) { + op = GrFillRRectOp::Make(fContext, viewMatrix, rrect, *this->caps(), std::move(paint)); + } + if (!op) { + assert_alive(paint); + op = GrOvalOpFactory::MakeRRectOp(fContext, std::move(paint), viewMatrix, rrect, stroke, + this->caps()->shaderCaps()); + } - std::unique_ptr op; - if (style.isSimpleFill()) { - assert_alive(paint); - op = GrFillRRectOp::Make( - fContext, aaType, viewMatrix, rrect, *this->caps(), std::move(paint)); - } - if (!op && GrAAType::kCoverage == aaType) { - assert_alive(paint); - op = GrOvalOpFactory::MakeRRectOp( - fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps()); - - } - if (op) { - this->addDrawOp(*clip, std::move(op)); - return; + if (op) { + this->addDrawOp(*clip, std::move(op)); + return; + } } assert_alive(paint); @@ -1631,31 +1630,29 @@ void GrRenderTargetContext::drawOval(const GrClip& clip, AutoCheckFlush acf(this->drawingManager()); GrAAType aaType = this->chooseAAType(aa); - - std::unique_ptr op; - if (style.isSimpleFill()) { + if (GrAAType::kCoverage == aaType) { + std::unique_ptr op; // GrFillRRectOp has special geometry and a fragment-shader branch to conditionally evaluate // the arc equation. This same special geometry and fragment branch also turn out to be a // substantial optimization for drawing ovals (namely, by not evaluating the arc equation // inside the oval's inner diamond). Given these optimizations, it's a clear win to draw // ovals the exact same way we do round rects. // - // However, we still don't draw true circles as round rects in coverage mode, because it can - // cause perf regressions on some platforms as compared to the dedicated circle Op. - if (GrAAType::kCoverage != aaType || oval.height() != oval.width()) { + // However, we still don't draw true circles as round rects, because it can cause perf + // regressions on some platforms as compared to the dedicated circle Op. + if (style.isSimpleFill() && oval.height() != oval.width()) { + op = GrFillRRectOp::Make( + fContext, viewMatrix, SkRRect::MakeOval(oval), *this->caps(), std::move(paint)); + } + if (!op) { assert_alive(paint); - op = GrFillRRectOp::Make(fContext, aaType, viewMatrix, SkRRect::MakeOval(oval), - *this->caps(), std::move(paint)); + op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style, + this->caps()->shaderCaps()); + } + if (op) { + this->addDrawOp(clip, std::move(op)); + return; } - } - if (!op && GrAAType::kCoverage == aaType) { - assert_alive(paint); - op = GrOvalOpFactory::MakeOvalOp(fContext, std::move(paint), viewMatrix, oval, style, - this->caps()->shaderCaps()); - } - if (op) { - this->addDrawOp(clip, std::move(op)); - return; } assert_alive(paint); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index acbac057168df..80121feddd666 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -526,12 +526,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fPreferVRAMUseOverFlushes = !isANGLE; #endif - if (kARM_GrGLVendor == ctxInfo.vendor()) { - // ARM seems to do better with larger quantities of fine triangles, as opposed to using the - // sample mask. (At least in our current round rect op.) - fPreferTrianglesOverSampleMask = true; - } - if (kChromium_GrGLDriver == ctxInfo.driver()) { fMustClearUploadedBufferData = true; } diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp index 5c4b1dc516aa5..891e973f73338 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp @@ -91,8 +91,7 @@ const char* GrGLSLFragmentShaderBuilder::sampleOffsets() { return "_sampleOffsets"; } -void GrGLSLFragmentShaderBuilder::maskOffMultisampleCoverage( - const char* mask, ScopeFlags scopeFlags) { +void GrGLSLFragmentShaderBuilder::maskOffMultisampleCoverage(const char* mask, Scope scope) { const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); if (!shaderCaps.sampleVariablesSupport()) { SkDEBUGFAIL("Attempted to mask sample coverage without support."); @@ -102,58 +101,16 @@ void GrGLSLFragmentShaderBuilder::maskOffMultisampleCoverage( this->addFeature(1 << kSampleVariables_GLSLPrivateFeature, extension); } - if (!fHasModifiedSampleMask) { - fHasModifiedSampleMask = true; - if (ScopeFlags::kTopLevel != scopeFlags) { - this->codePrependf("gl_SampleMask[0] = ~0;"); - } - if (!(ScopeFlags::kInsideLoop & scopeFlags)) { - this->codeAppendf("gl_SampleMask[0] = (%s);", mask); - return; - } + if (!fHasInitializedSampleMask && Scope::kTopLevel == scope) { + this->codeAppendf("gl_SampleMask[0] = (%s);", mask); + fHasInitializedSampleMask = true; + return; } - - this->codeAppendf("gl_SampleMask[0] &= (%s);", mask); -} - -void GrGLSLFragmentShaderBuilder::applyFnToMultisampleMask( - const char* fn, const char* grad, ScopeFlags scopeFlags) { - SkASSERT(CustomFeatures::kSampleLocations & fProgramBuilder->header().processorFeatures()); - SkDEBUGCODE(fUsedProcessorFeaturesThisStage_DebugOnly |= CustomFeatures::kSampleLocations); - SkDEBUGCODE(fUsedProcessorFeaturesAllStages_DebugOnly |= CustomFeatures::kSampleLocations); - - int sampleCnt = fProgramBuilder->effectiveSampleCnt(); - SkASSERT(sampleCnt > 1); - - this->codeAppendf("{"); - - if (!grad) { - SkASSERT(fProgramBuilder->shaderCaps()->shaderDerivativeSupport()); - // In order to use HW derivatives, our neighbors within the same primitive must also be - // executing the same code. A per-pixel branch makes this pre-condition impossible to - // fulfill. - SkASSERT(!(ScopeFlags::kInsidePerPixelBranch & scopeFlags)); - this->codeAppendf("float2 grad = float2(dFdx(fn), dFdy(fn));"); - this->codeAppendf("float fnwidth = fwidth(fn);"); - grad = "grad"; - } else { - this->codeAppendf("float fnwidth = abs(%s.x) + abs(%s.y);", grad, grad); + if (!fHasInitializedSampleMask) { + this->codePrependf("gl_SampleMask[0] = ~0;"); + fHasInitializedSampleMask = true; } - - this->codeAppendf("int mask = 0;"); - this->codeAppendf("if (%s*2 < fnwidth) {", fn); // Are ANY samples inside the implicit fn? - this->codeAppendf( "if (%s*-2 >= fnwidth) {", fn); // Are ALL samples inside the implicit? - this->codeAppendf( "mask = ~0;"); - this->codeAppendf( "} else for (int i = 0; i < %i; ++i) {", sampleCnt); - this->codeAppendf( "float fnsample = dot(%s, _sampleOffsets[i]) + %s;", grad, fn); - this->codeAppendf( "if (fnsample < 0) {"); - this->codeAppendf( "mask |= (1 << i);"); - this->codeAppendf( "}"); - this->codeAppendf( "}"); - this->codeAppendf("}"); - this->maskOffMultisampleCoverage("mask", scopeFlags); - - this->codeAppendf("}"); + this->codeAppendf("gl_SampleMask[0] &= (%s);", mask); } const char* GrGLSLFragmentShaderBuilder::dstColor() { @@ -260,10 +217,10 @@ void GrGLSLFragmentShaderBuilder::onFinalize() { == fUsedProcessorFeaturesAllStages_DebugOnly); if (CustomFeatures::kSampleLocations & fProgramBuilder->header().processorFeatures()) { + this->definitions().append("const float2 _sampleOffsets[] = float2[]("); const GrPipeline& pipeline = fProgramBuilder->pipeline(); const SkTArray& sampleLocations = fProgramBuilder->renderTarget()->renderTargetPriv().getSampleLocations(pipeline); - this->definitions().append("const float2 _sampleOffsets[] = float2[]("); for (int i = 0; i < sampleLocations.count(); ++i) { SkPoint offset = sampleLocations[i] - SkPoint::Make(.5f, .5f); if (kBottomLeft_GrSurfaceOrigin == this->getSurfaceOrigin()) { diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h index 3f1c2c5446492..94ba82c0be3c9 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h @@ -54,15 +54,9 @@ class GrGLSLFPFragmentBuilder : virtual public GrGLSLFragmentBuilder { */ virtual const char* sampleOffsets() = 0; - enum class ScopeFlags { - // Every fragment will always execute this code, and will do it exactly once. - kTopLevel = 0, - // Either all fragments in a given primitive, or none, will execute this code. - kInsidePerPrimitiveBranch = (1 << 0), - // Any given fragment may or may not execute this code. - kInsidePerPixelBranch = (1 << 1), - // This code will be executed more than once. - kInsideLoop = (1 << 2) + enum class Scope : bool { + kTopLevel, + kInsideLoopOrBranch }; /** @@ -74,21 +68,7 @@ class GrGLSLFPFragmentBuilder : virtual public GrGLSLFragmentBuilder { * * Requires MSAA and GLSL support for sample variables. */ - virtual void maskOffMultisampleCoverage(const char* mask, ScopeFlags) = 0; - - /** - * Turns off coverage at each sample where the implicit function fn > 0. - * - * The provided "fn" value represents the implicit function at pixel center. We then approximate - * the implicit at each sample by riding the gradient, "grad", linearly from pixel center to - * each sample location. - * - * If "grad" is null, we approximate the gradient using HW derivatives. - * - * Requires MSAA and GLSL support for sample variables. Also requires HW derivatives if not - * providing a gradient. - */ - virtual void applyFnToMultisampleMask(const char* fn, const char* grad, ScopeFlags) = 0; + virtual void maskOffMultisampleCoverage(const char* mask, Scope) = 0; /** * Fragment procs with child procs should call these functions before/after calling emitCode @@ -102,8 +82,6 @@ class GrGLSLFPFragmentBuilder : virtual public GrGLSLFragmentBuilder { virtual void forceHighPrecision() = 0; }; -GR_MAKE_BITFIELD_CLASS_OPS(GrGLSLFPFragmentBuilder::ScopeFlags); - /* * This class is used by Xfer processors to build their fragment code. */ @@ -141,8 +119,7 @@ class GrGLSLFragmentShaderBuilder : public GrGLSLFPFragmentBuilder, public GrGLS // GrGLSLFPFragmentBuilder interface. const char* sampleOffsets() override; - void maskOffMultisampleCoverage(const char* mask, ScopeFlags) override; - void applyFnToMultisampleMask(const char* fn, const char* grad, ScopeFlags) override; + void maskOffMultisampleCoverage(const char* mask, Scope) override; const SkString& getMangleString() const override { return fMangleString; } void onBeforeChildProcEmitCode() override; void onAfterChildProcEmitCode() override; @@ -210,7 +187,7 @@ class GrGLSLFragmentShaderBuilder : public GrGLSLFPFragmentBuilder, public GrGLS bool fHasCustomColorOutput = false; int fCustomColorOutputIndex = -1; bool fHasSecondaryOutput = false; - bool fHasModifiedSampleMask = false; + bool fHasInitializedSampleMask = false; bool fForceHighPrecision = false; friend class GrGLSLProgramBuilder; diff --git a/src/gpu/ops/GrFillRRectOp.cpp b/src/gpu/ops/GrFillRRectOp.cpp index 12d430074d7f1..ead28f62768ba 100644 --- a/src/gpu/ops/GrFillRRectOp.cpp +++ b/src/gpu/ops/GrFillRRectOp.cpp @@ -21,41 +21,34 @@ // Hardware derivatives are not always accurate enough for highly elliptical corners. This method // checks to make sure the corners will still all look good if we use HW derivatives. -static bool can_use_hw_derivatives_with_coverage( - const GrShaderCaps&, const SkMatrix&, const SkRRect&); +static bool can_use_hw_derivatives(const GrShaderCaps&, const SkMatrix&, const SkRRect&); std::unique_ptr GrFillRRectOp::Make( - GrRecordingContext* ctx, GrAAType aaType, const SkMatrix& viewMatrix, const SkRRect& rrect, + GrRecordingContext* ctx, const SkMatrix& viewMatrix, const SkRRect& rrect, const GrCaps& caps, GrPaint&& paint) { if (!caps.instanceAttribSupport()) { return nullptr; } - Flags flags = Flags::kNone; - if (GrAAType::kCoverage == aaType) { - // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we - // already use HW derivatives. The only trick will be adjusting the AA outset to account for - // perspective. (i.e., outset = 0.5 * z.) - if (viewMatrix.hasPerspective()) { - return nullptr; - } - if (can_use_hw_derivatives_with_coverage(*caps.shaderCaps(), viewMatrix, rrect)) { - // HW derivatives (more specifically, fwidth()) are consistently faster on all platforms - // in coverage mode. We use them as long as the approximation will be accurate enough. - flags |= Flags::kUseHWDerivatives; - } - } else { - if (GrAAType::kMSAA == aaType) { - if (!caps.sampleLocationsSupport() || !caps.shaderCaps()->sampleVariablesSupport()) { - return nullptr; - } - } - if (viewMatrix.hasPerspective()) { - // HW derivatives are consistently slower on all platforms in sample mask mode. We - // therefore only use them when there is perspective, since then we can't interpolate - // the symbolic screen-space gradient. - flags |= Flags::kUseHWDerivatives | Flags::kHasPerspective; - } + // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we already + // use HW derivatives. The only trick will be adjusting the AA outset to account for + // perspective. (i.e., outset = 0.5 * z.) + if (viewMatrix.hasPerspective()) { + return nullptr; + } + + GrOpMemoryPool* pool = ctx->priv().opMemoryPool(); + return pool->allocate(*caps.shaderCaps(), viewMatrix, rrect, std::move(paint)); +} + +GrFillRRectOp::GrFillRRectOp(const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, + const SkRRect& rrect, GrPaint&& paint) + : GrDrawOp(ClassID()) + , fOriginalColor(paint.getColor4f()) + , fLocalRect(rrect.rect()) + , fProcessors(std::move(paint)) { + if (can_use_hw_derivatives(shaderCaps, viewMatrix, rrect)) { + fFlags |= Flags::kUseHWDerivatives; } // Produce a matrix that draws the round rect from normalized [-1, -1, +1, +1] space. @@ -67,61 +60,23 @@ std::unique_ptr GrFillRRectOp::Make( // Map to device space. m.postConcat(viewMatrix); - SkRect devBounds; - if (!(flags & Flags::kHasPerspective)) { - // Since m is an affine matrix that maps the rect [-1, -1, +1, +1] into the shape's - // device-space quad, it's quite simple to find the bounding rectangle: - devBounds = SkRect::MakeXYWH(m.getTranslateX(), m.getTranslateY(), 0, 0); - devBounds.outset(SkScalarAbs(m.getScaleX()) + SkScalarAbs(m.getSkewX()), - SkScalarAbs(m.getSkewY()) + SkScalarAbs(m.getScaleY())); - } else { - viewMatrix.mapRect(&devBounds, rrect.rect()); - } - - if (GrAAType::kMSAA == aaType && caps.preferTrianglesOverSampleMask()) { - // We are on a platform that prefers fine triangles instead of using the sample mask. See if - // the round rect is large enough that it will be faster for us to send it off to the - // default path renderer instead. The 200x200 threshold was arrived at using the - // "shapes_rrect" benchmark on an ARM Galaxy S9. - if (devBounds.height() * devBounds.width() > 200 * 200) { - return nullptr; - } - } - - GrOpMemoryPool* pool = ctx->priv().opMemoryPool(); - return pool->allocate(aaType, rrect, flags, m, std::move(paint), devBounds); -} - -GrFillRRectOp::GrFillRRectOp( - GrAAType aaType, const SkRRect& rrect, Flags flags, - const SkMatrix& totalShapeMatrix, GrPaint&& paint, const SkRect& devBounds) - : GrDrawOp(ClassID()) - , fAAType(aaType) - , fOriginalColor(paint.getColor4f()) - , fLocalRect(rrect.rect()) - , fFlags(flags) - , fProcessors(std::move(paint)) { - SkASSERT((fFlags & Flags::kHasPerspective) == totalShapeMatrix.hasPerspective()); - this->setBounds(devBounds, GrOp::HasAABloat::kYes, GrOp::IsZeroArea::kNo); + // Since m is an affine matrix that maps the rect [-1, -1, +1, +1] into the shape's + // device-space quad, it's quite simple to find the bounding rectangle: + SkASSERT(!m.hasPerspective()); + SkRect bounds = SkRect::MakeXYWH(m.getTranslateX(), m.getTranslateY(), 0, 0); + bounds.outset(SkScalarAbs(m.getScaleX()) + SkScalarAbs(m.getSkewX()), + SkScalarAbs(m.getSkewY()) + SkScalarAbs(m.getScaleY())); + this->setBounds(bounds, GrOp::HasAABloat::kYes, GrOp::IsZeroArea::kNo); // Write the matrix attribs. - const SkMatrix& m = totalShapeMatrix; - if (!(fFlags & Flags::kHasPerspective)) { - // Affine 2D transformation (float2x2 plus float2 translate). - SkASSERT(!m.hasPerspective()); - this->writeInstanceData(m.getScaleX(), m.getSkewX(), m.getSkewY(), m.getScaleY()); - this->writeInstanceData(m.getTranslateX(), m.getTranslateY()); - } else { - // Perspective float3x3 transformation matrix. - SkASSERT(m.hasPerspective()); - m.get9(this->appendInstanceData(9)); - } + this->writeInstanceData(m.getScaleX(), m.getSkewX(), m.getSkewY(), m.getScaleY()); + this->writeInstanceData(m.getTranslateX(), m.getTranslateY()); // Convert the radii to [-1, -1, +1, +1] space and write their attribs. Sk4f radiiX, radiiY; Sk4f::Load2(SkRRectPriv::GetRadiiArray(rrect), &radiiX, &radiiY); - (radiiX * (2/rrect.width())).store(this->appendInstanceData(4)); - (radiiY * (2/rrect.height())).store(this->appendInstanceData(4)); + (radiiX * (2/(r - l))).store(this->appendInstanceData(4)); + (radiiY * (2/(b - t))).store(this->appendInstanceData(4)); // We will write the color and local rect attribs during finalize(). } @@ -177,73 +132,13 @@ void GrFillRRectOp::onPrepare(GrOpFlushState* flushState) { } } -class GrFillRRectOp::Processor : public GrGeometryProcessor { -public: - Processor(GrAAType aaType, Flags flags) - : GrGeometryProcessor(kGrFillRRectOp_Processor_ClassID) - , fAAType(aaType) - , fFlags(flags) { - int numVertexAttribs = (GrAAType::kCoverage == fAAType) ? 3 : 2; - this->setVertexAttributes(kVertexAttribs, numVertexAttribs); - - if (!(flags & Flags::kHasPerspective)) { - // Affine 2D transformation (float2x2 plus float2 translate). - fInstanceAttribs.emplace_back("skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType); - fInstanceAttribs.emplace_back( - "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType); - } else { - // Perspective float3x3 transformation matrix. - fInstanceAttribs.emplace_back("persp_x", kFloat3_GrVertexAttribType, kFloat3_GrSLType); - fInstanceAttribs.emplace_back("persp_y", kFloat3_GrVertexAttribType, kFloat3_GrSLType); - fInstanceAttribs.emplace_back("persp_z", kFloat3_GrVertexAttribType, kFloat3_GrSLType); - } - fInstanceAttribs.emplace_back("radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType); - fInstanceAttribs.emplace_back("radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType); - fColorAttrib = &fInstanceAttribs.push_back( - MakeColorAttribute("color", (flags & Flags::kWideColor))); - if (fFlags & Flags::kHasLocalCoords) { - fInstanceAttribs.emplace_back( - "local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType); - } - this->setInstanceAttributes(fInstanceAttribs.begin(), fInstanceAttribs.count()); - - if (GrAAType::kMSAA == fAAType) { - this->setWillUseCustomFeature(CustomFeatures::kSampleLocations); - } - } - - const char* name() const override { return "GrFillRRectOp::Processor"; } - - void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { - b->add32(((uint32_t)fFlags << 16) | (uint32_t)fAAType); - } - - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; - -private: - static constexpr Attribute kVertexAttribs[] = { - {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, - {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, - // Coverage only. - {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}}; - - const GrAAType fAAType; - const Flags fFlags; - - SkSTArray<6, Attribute> fInstanceAttribs; - const Attribute* fColorAttrib; +namespace { - class CoverageImpl; - class MSAAImpl; -}; - -constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[]; - -// Our coverage geometry consists of an inset octagon with solid coverage, surrounded by linear +// Our round rect geometry consists of an inset octagon with solid coverage, surrounded by linear // coverage ramps on the horizontal and vertical edges, and "arc coverage" pieces on the diagonal // edges. The Vertex struct tells the shader where to place its vertex within a normalized // ([l, t, r, b] = [-1, -1, +1, +1]) space, and how to calculate coverage. See onEmitCode. -struct CoverageVertex { +struct Vertex { std::array fRadiiSelector; std::array fCorner; std::array fRadiusOutset; @@ -257,7 +152,7 @@ struct CoverageVertex { // rectangles. static constexpr float kOctoOffset = 1/(1 + SK_ScalarRoot2Over2); -static constexpr CoverageVertex kCoverageVertexData[] = { +static constexpr Vertex kVertexData[] = { // Left inset edge. {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}, {{+1,0}}, 1, 1}, {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}, {{+1,0}}, 1, 1}, @@ -324,9 +219,9 @@ static constexpr CoverageVertex kCoverageVertexData[] = { {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}, {{-1,+1}}, 0, 0}, {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}, {{-1,+1}}, 0, 0}}; -GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey); +GR_DECLARE_STATIC_UNIQUE_KEY(gVertexBufferKey); -static constexpr uint16_t kCoverageIndexData[] = { +static constexpr uint16_t kIndexData[] = { // Inset octagon (solid coverage). 0, 1, 7, 1, 2, 7, @@ -365,18 +260,64 @@ static constexpr uint16_t kCoverageIndexData[] = { 39, 36, 38, 36, 38, 37}; -GR_DECLARE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey); +GR_DECLARE_STATIC_UNIQUE_KEY(gIndexBufferKey); + +} + +class GrFillRRectOp::Processor : public GrGeometryProcessor { +public: + Processor(Flags flags) + : GrGeometryProcessor(kGrFillRRectOp_Processor_ClassID) + , fFlags(flags) { + this->setVertexAttributes(kVertexAttribs, 3); + fInSkew = { "skew", kFloat4_GrVertexAttribType, kFloat4_GrSLType }; + fInTranslate = { "translate", kFloat2_GrVertexAttribType, kFloat2_GrSLType }; + fInRadiiX = { "radii_x", kFloat4_GrVertexAttribType, kFloat4_GrSLType }; + fInRadiiY = { "radii_y", kFloat4_GrVertexAttribType, kFloat4_GrSLType }; + fInColor = MakeColorAttribute("color", (flags & Flags::kWideColor)); + fInLocalRect = {"local_rect", kFloat4_GrVertexAttribType, kFloat4_GrSLType}; + + this->setInstanceAttributes(&fInSkew, (flags & Flags::kHasLocalCoords) ? 6 : 5); + SkASSERT(this->vertexStride() == sizeof(Vertex)); + } + + const char* name() const override { return "GrFillRRectOp::Processor"; } + + void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { + b->add32(static_cast(fFlags)); + } + + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; -class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor { +private: + static constexpr Attribute kVertexAttribs[] = { + {"radii_selector", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, + {"corner_and_radius_outsets", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, + {"aa_bloat_and_coverage", kFloat4_GrVertexAttribType, kFloat4_GrSLType}}; + + Attribute fInSkew; + Attribute fInTranslate; + Attribute fInRadiiX; + Attribute fInRadiiY; + Attribute fInColor; + Attribute fInLocalRect; // Conditional. + + const Flags fFlags; + + class Impl; +}; + +constexpr GrPrimitiveProcessor::Attribute GrFillRRectOp::Processor::kVertexAttribs[]; + +class GrFillRRectOp::Processor::Impl : public GrGLSLGeometryProcessor { +public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const auto& proc = args.fGP.cast(); bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives); - SkASSERT(proc.vertexStride() == sizeof(CoverageVertex)); - GrGLSLVaryingHandler* varyings = args.fVaryingHandler; varyings->emitAttributes(proc); - varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor, + varyings->addPassThroughAttribute(proc.fInColor, args.fOutputColor, GrGLSLVaryingHandler::Interpolation::kCanBeFlat); // Emit the vertex shader. @@ -447,7 +388,6 @@ class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor { args.fFPCoordTransformHandler); // Transform to device space. - SkASSERT(!(proc.fFlags & Flags::kHasPerspective)); v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);"); v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;"); gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord"); @@ -480,7 +420,7 @@ class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor { f->codeAppendf("float x_plus_1=%s.x, y=%s.y;", arcCoord.fsIn(), arcCoord.fsIn()); f->codeAppendf("half coverage;"); f->codeAppendf("if (0 == x_plus_1) {"); - f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (linear coverage). + f->codeAppendf( "coverage = half(y);"); // We are a non-arc pixel (i.e., linear coverage). f->codeAppendf("} else {"); f->codeAppendf( "float fn = x_plus_1 * (x_plus_1 - 2);"); // fn = (x+1)*(x-1) = x^2-1 f->codeAppendf( "fn = fma(y,y, fn);"); // fn = x^2 + y^2 - 1 @@ -503,195 +443,9 @@ class GrFillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor { } }; -// Our MSAA geometry consists of an inset octagon with full sample mask coverage, circumscribed -// by a larger octagon that modifies the sample mask for the arc at each corresponding corner. -struct MSAAVertex { - std::array fRadiiSelector; - std::array fCorner; - std::array fRadiusOutset; -}; - -static constexpr MSAAVertex kMSAAVertexData[] = { - // Left edge. (Negative radii selector indicates this is not an arc section.) - {{{0,0,0,-1}}, {{-1,+1}}, {{0,-1}}}, - {{{-1,0,0,0}}, {{-1,-1}}, {{0,+1}}}, - - // Top edge. - {{{-1,0,0,0}}, {{-1,-1}}, {{+1,0}}}, - {{{0,-1,0,0}}, {{+1,-1}}, {{-1,0}}}, - - // Right edge. - {{{0,-1,0,0}}, {{+1,-1}}, {{0,+1}}}, - {{{0,0,-1,0}}, {{+1,+1}}, {{0,-1}}}, - - // Bottom edge. - {{{0,0,-1,0}}, {{+1,+1}}, {{-1,0}}}, - {{{0,0,0,-1}}, {{-1,+1}}, {{+1,0}}}, - - // Top-left corner. - {{{1,0,0,0}}, {{-1,-1}}, {{0,+1}}}, - {{{1,0,0,0}}, {{-1,-1}}, {{0,+kOctoOffset}}}, - {{{1,0,0,0}}, {{-1,-1}}, {{+1,0}}}, - {{{1,0,0,0}}, {{-1,-1}}, {{+kOctoOffset,0}}}, - - // Top-right corner. - {{{0,1,0,0}}, {{+1,-1}}, {{-1,0}}}, - {{{0,1,0,0}}, {{+1,-1}}, {{-kOctoOffset,0}}}, - {{{0,1,0,0}}, {{+1,-1}}, {{0,+1}}}, - {{{0,1,0,0}}, {{+1,-1}}, {{0,+kOctoOffset}}}, - - // Bottom-right corner. - {{{0,0,1,0}}, {{+1,+1}}, {{0,-1}}}, - {{{0,0,1,0}}, {{+1,+1}}, {{0,-kOctoOffset}}}, - {{{0,0,1,0}}, {{+1,+1}}, {{-1,0}}}, - {{{0,0,1,0}}, {{+1,+1}}, {{-kOctoOffset,0}}}, - - // Bottom-left corner. - {{{0,0,0,1}}, {{-1,+1}}, {{+1,0}}}, - {{{0,0,0,1}}, {{-1,+1}}, {{+kOctoOffset,0}}}, - {{{0,0,0,1}}, {{-1,+1}}, {{0,-1}}}, - {{{0,0,0,1}}, {{-1,+1}}, {{0,-kOctoOffset}}}}; - -GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey); - -static constexpr uint16_t kMSAAIndexData[] = { - // Inset octagon. (Full sample mask.) - 0, 1, 2, - 0, 2, 3, - 0, 3, 6, - 3, 4, 5, - 3, 5, 6, - 6, 7, 0, - - // Top-left arc. (Sample mask is set to the arc.) - 8, 9, 10, - 9, 11, 10, - - // Top-right arc. - 12, 13, 14, - 13, 15, 14, - - // Bottom-right arc. - 16, 17, 18, - 17, 19, 18, - - // Bottom-left arc. - 20, 21, 22, - 21, 23, 22}; - -GR_DECLARE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey); - -class GrFillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor { - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { - const auto& proc = args.fGP.cast(); - bool useHWDerivatives = (proc.fFlags & Flags::kUseHWDerivatives); - bool hasPerspective = (proc.fFlags & Flags::kHasPerspective); - bool hasLocalCoords = (proc.fFlags & Flags::kHasLocalCoords); - SkASSERT(useHWDerivatives == hasPerspective); - - SkASSERT(proc.vertexStride() == sizeof(MSAAVertex)); - - // Emit the vertex shader. - GrGLSLVertexBuilder* v = args.fVertBuilder; - - GrGLSLVaryingHandler* varyings = args.fVaryingHandler; - varyings->emitAttributes(proc); - varyings->addPassThroughAttribute(*proc.fColorAttrib, args.fOutputColor, - GrGLSLVaryingHandler::Interpolation::kCanBeFlat); - - // Unpack vertex attribs. - v->codeAppendf("float2 corner = corner_and_radius_outsets.xy;"); - v->codeAppendf("float2 radius_outset = corner_and_radius_outsets.zw;"); - - // Identify our radii. - v->codeAppend("float2 radii;"); - v->codeAppend("radii.x = dot(radii_selector, radii_x);"); - v->codeAppend("radii.y = dot(radii_selector, radii_y);"); - v->codeAppendf("bool is_arc_section = (radii.x > 0);"); - v->codeAppendf("radii = abs(radii);"); - - // Find our vertex position, adjusted for radii. Our rect is drawn in normalized - // [-1,-1,+1,+1] space. - v->codeAppend("float2 vertexpos = corner + radius_outset * radii;"); - - // Emit transforms. - GrShaderVar localCoord("", kFloat2_GrSLType); - if (hasLocalCoords) { - v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + " - "local_rect.zw * (1 + vertexpos)) * .5;"); - localCoord.set(kFloat2_GrSLType, "localcoord"); - } - this->emitTransforms(v, varyings, args.fUniformHandler, localCoord, - args.fFPCoordTransformHandler); - - // Transform to device space. - if (!hasPerspective) { - v->codeAppend("float2x2 skewmatrix = float2x2(skew.xy, skew.zw);"); - v->codeAppend("float2 devcoord = vertexpos * skewmatrix + translate;"); - gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord"); - } else { - v->codeAppend("float3x3 persp_matrix = float3x3(persp_x, persp_y, persp_z);"); - v->codeAppend("float3 devcoord = float3(vertexpos, 1) * persp_matrix;"); - gpArgs->fPositionVar.set(kFloat3_GrSLType, "devcoord"); - } - - // Determine normalized arc coordinates for the implicit function. - GrGLSLVarying arcCoord((useHWDerivatives) ? kFloat2_GrSLType : kFloat4_GrSLType); - varyings->addVarying("arccoord", &arcCoord); - v->codeAppendf("if (is_arc_section) {"); - v->codeAppendf( "%s.xy = 1 - abs(radius_outset);", arcCoord.vsOut()); - if (!useHWDerivatives) { - // The gradient is order-1: Interpolate it across arccoord.zw. - // This doesn't work with perspective. - SkASSERT(!hasPerspective); - v->codeAppendf("float2x2 derivatives = inverse(skewmatrix);"); - v->codeAppendf("%s.zw = derivatives * (%s.xy/radii * corner * 2);", - arcCoord.vsOut(), arcCoord.vsOut()); - } - v->codeAppendf("} else {"); - if (useHWDerivatives) { - v->codeAppendf("%s = float2(0);", arcCoord.vsOut()); - } else { - v->codeAppendf("%s = float4(0);", arcCoord.vsOut()); - } - v->codeAppendf("}"); - - // Emit the fragment shader. - GrGLSLFPFragmentBuilder* f = args.fFragBuilder; - - f->codeAppendf("%s = half4(1);", args.fOutputCoverage); - - // If x,y == 0, then we are drawing a triangle that does not track an arc. - f->codeAppendf("if (float2(0) != %s.xy) {", arcCoord.fsIn()); - f->codeAppendf( "float fn = dot(%s.xy, %s.xy) - 1;", arcCoord.fsIn(), arcCoord.fsIn()); - if (GrAAType::kMSAA == proc.fAAType) { - using ScopeFlags = GrGLSLFPFragmentBuilder::ScopeFlags; - if (!useHWDerivatives) { - f->codeAppendf("float2 grad = %s.zw;", arcCoord.fsIn()); - f->applyFnToMultisampleMask("fn", "grad", ScopeFlags::kInsidePerPrimitiveBranch); - } else { - f->applyFnToMultisampleMask("fn", nullptr, ScopeFlags::kInsidePerPrimitiveBranch); - } - } else { - f->codeAppendf("if (fn > 0) {"); - f->codeAppendf( "%s = half4(0);", args.fOutputCoverage); - f->codeAppendf("}"); - } - f->codeAppendf("}"); - } - - void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, - FPCoordTransformIter&& transformIter) override { - this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter); - } -}; - GrGLSLPrimitiveProcessor* GrFillRRectOp::Processor::createGLSLInstance( const GrShaderCaps&) const { - if (GrAAType::kCoverage != fAAType) { - return new MSAAImpl(); - } - return new CoverageImpl(); + return new Impl(); } void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) { @@ -699,50 +453,26 @@ void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBou return; // Setup failed. } - sk_sp indexBuffer, vertexBuffer; - int indexCount; - - if (GrAAType::kCoverage == fAAType) { - GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageIndexBufferKey); + GR_DEFINE_STATIC_UNIQUE_KEY(gIndexBufferKey); - indexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer( - GrGpuBufferType::kIndex, sizeof(kCoverageIndexData), kCoverageIndexData, - gCoverageIndexBufferKey); - - GR_DEFINE_STATIC_UNIQUE_KEY(gCoverageVertexBufferKey); - - vertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer( - GrGpuBufferType::kVertex, sizeof(kCoverageVertexData), kCoverageVertexData, - gCoverageVertexBufferKey); - - indexCount = SK_ARRAY_COUNT(kCoverageIndexData); - } else { - GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAIndexBufferKey); - - indexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer( - GrGpuBufferType::kIndex, sizeof(kMSAAIndexData), kMSAAIndexData, - gMSAAIndexBufferKey); - - GR_DEFINE_STATIC_UNIQUE_KEY(gMSAAVertexBufferKey); - - vertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer( - GrGpuBufferType::kVertex, sizeof(kMSAAVertexData), kMSAAVertexData, - gMSAAVertexBufferKey); - - indexCount = SK_ARRAY_COUNT(kMSAAIndexData); + sk_sp indexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer( + GrGpuBufferType::kIndex, sizeof(kIndexData), kIndexData, gIndexBufferKey); + if (!indexBuffer) { + return; } - if (!indexBuffer || !vertexBuffer) { + GR_DEFINE_STATIC_UNIQUE_KEY(gVertexBufferKey); + + sk_sp vertexBuffer = flushState->resourceProvider()->findOrMakeStaticBuffer( + GrGpuBufferType::kVertex, sizeof(kVertexData), kVertexData, gVertexBufferKey); + if (!vertexBuffer) { return; } - Processor proc(fAAType, fFlags); + Processor proc(fFlags); SkASSERT(proc.instanceStride() == (size_t)fInstanceStride); GrPipeline::InitArgs initArgs; - if (GrAAType::kMSAA == fAAType) { - initArgs.fFlags = GrPipeline::kHWAntialias_Flag; - } initArgs.fCaps = &flushState->caps(); initArgs.fResourceProvider = flushState->resourceProvider(); initArgs.fDstProxy = flushState->drawOpArgs().fDstProxy; @@ -751,16 +481,15 @@ void GrFillRRectOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBou GrPipeline pipeline(initArgs, std::move(fProcessors), std::move(clip)); GrMesh mesh(GrPrimitiveType::kTriangles); - mesh.setIndexedInstanced( - std::move(indexBuffer), indexCount, fInstanceBuffer, fInstanceCount, fBaseInstance, - GrPrimitiveRestart::kNo); + mesh.setIndexedInstanced(std::move(indexBuffer), SK_ARRAY_COUNT(kIndexData), fInstanceBuffer, + fInstanceCount, fBaseInstance, GrPrimitiveRestart::kNo); mesh.setVertexData(std::move(vertexBuffer)); - flushState->rtCommandBuffer()->draw( - proc, pipeline, &fixedDynamicState, nullptr, &mesh, 1, this->bounds()); + flushState->rtCommandBuffer()->draw(proc, pipeline, &fixedDynamicState, nullptr, &mesh, 1, + this->bounds()); } // Will the given corner look good if we use HW derivatives? -static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2f& cornerRadii) { +static bool can_use_hw_derivatives(const Sk2f& devScale, const Sk2f& cornerRadii) { Sk2f devRadii = devScale * cornerRadii; if (devRadii[1] < devRadii[0]) { devRadii = SkNx_shuffle<1,0>(devRadii); @@ -771,14 +500,13 @@ static bool can_use_hw_derivatives_with_coverage(const Sk2f& devScale, const Sk2 return minDevRadius * minDevRadius * 5 > devRadii[1]; } -static bool can_use_hw_derivatives_with_coverage( - const Sk2f& devScale, const SkVector& cornerRadii) { - return can_use_hw_derivatives_with_coverage(devScale, Sk2f::Load(&cornerRadii)); +static bool can_use_hw_derivatives(const Sk2f& devScale, const SkVector& cornerRadii) { + return can_use_hw_derivatives(devScale, Sk2f::Load(&cornerRadii)); } // Will the given round rect look good if we use HW derivatives? -static bool can_use_hw_derivatives_with_coverage( - const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, const SkRRect& rrect) { +static bool can_use_hw_derivatives(const GrShaderCaps& shaderCaps, const SkMatrix& viewMatrix, + const SkRRect& rrect) { if (!shaderCaps.shaderDerivativeSupport()) { return false; } @@ -793,27 +521,27 @@ static bool can_use_hw_derivatives_with_coverage( case SkRRect::kOval_Type: case SkRRect::kSimple_Type: - return can_use_hw_derivatives_with_coverage(devScale, rrect.getSimpleRadii()); + return can_use_hw_derivatives(devScale, rrect.getSimpleRadii()); case SkRRect::kNinePatch_Type: { Sk2f r0 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect)); Sk2f r1 = Sk2f::Load(SkRRectPriv::GetRadiiArray(rrect) + 2); Sk2f minRadii = Sk2f::Min(r0, r1); Sk2f maxRadii = Sk2f::Max(r0, r1); - return can_use_hw_derivatives_with_coverage(devScale, Sk2f(minRadii[0], maxRadii[1])) && - can_use_hw_derivatives_with_coverage(devScale, Sk2f(maxRadii[0], minRadii[1])); + return can_use_hw_derivatives(devScale, Sk2f(minRadii[0], maxRadii[1])) && + can_use_hw_derivatives(devScale, Sk2f(maxRadii[0], minRadii[1])); } case SkRRect::kComplex_Type: { for (int i = 0; i < 4; ++i) { auto corner = static_cast(i); - if (!can_use_hw_derivatives_with_coverage(devScale, rrect.radii(corner))) { + if (!can_use_hw_derivatives(devScale, rrect.radii(corner))) { return false; } } return true; } } - SK_ABORT("Invalid round rect type."); + SK_ABORT("Unreachable code."); return false; // Add this return to keep GCC happy. } diff --git a/src/gpu/ops/GrFillRRectOp.h b/src/gpu/ops/GrFillRRectOp.h index 9bc88a0e690df..3aad81882f504 100644 --- a/src/gpu/ops/GrFillRRectOp.h +++ b/src/gpu/ops/GrFillRRectOp.h @@ -16,16 +16,11 @@ class GrFillRRectOp : public GrDrawOp { public: DEFINE_OP_CLASS_ID - static std::unique_ptr Make( - GrRecordingContext*, GrAAType, const SkMatrix& viewMatrix, const SkRRect&, - const GrCaps&, GrPaint&&); + static std::unique_ptr Make(GrRecordingContext*, const SkMatrix&, + const SkRRect&, const GrCaps&, GrPaint&&); const char* name() const override { return "GrFillRRectOp"; } - FixedFunctionFlags fixedFunctionFlags() const override { - return (GrAAType::kMSAA == fAAType) - ? FixedFunctionFlags::kUsesHWAA - : FixedFunctionFlags::kNone; - } + FixedFunctionFlags fixedFunctionFlags() const override { return FixedFunctionFlags::kNone; } GrProcessorSet::Analysis finalize( const GrCaps&, const GrAppliedClip*, GrFSAAType, GrClampType) override; CombineResult onCombineIfPossible(GrOp*, const GrCaps&) override; @@ -40,24 +35,22 @@ class GrFillRRectOp : public GrDrawOp { enum class Flags { kNone = 0, kUseHWDerivatives = 1 << 0, - kHasPerspective = 1 << 1, - kHasLocalCoords = 1 << 2, - kWideColor = 1 << 3 + kHasLocalCoords = 1 << 1, + kWideColor = 1 << 2 }; GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Flags); class Processor; - GrFillRRectOp(GrAAType, const SkRRect&, Flags, const SkMatrix& totalShapeMatrix, - GrPaint&&, const SkRect& devBounds); + GrFillRRectOp(const GrShaderCaps&, const SkMatrix&, const SkRRect&, GrPaint&&); // These methods are used to append data of various POD types to our internal array of instance // data. The actual layout of the instance buffer can vary from Op to Op. - template inline T* appendInstanceData(int count) { + template inline void* appendInstanceData(int count) { static_assert(std::is_pod::value, ""); static_assert(4 == alignof(T), ""); - return reinterpret_cast(fInstanceData.push_back_n(sizeof(T) * count)); + return fInstanceData.push_back_n(sizeof(T) * count); } template @@ -68,10 +61,9 @@ class GrFillRRectOp : public GrDrawOp { void writeInstanceData() {} // Halt condition. - const GrAAType fAAType; const SkPMColor4f fOriginalColor; const SkRect fLocalRect; - Flags fFlags; + Flags fFlags = Flags::kNone; GrProcessorSet fProcessors; SkSTArray fInstanceData; diff --git a/src/gpu/vk/GrVkCaps.cpp b/src/gpu/vk/GrVkCaps.cpp index 6f9eed7b9e66c..2c71f72baade3 100644 --- a/src/gpu/vk/GrVkCaps.cpp +++ b/src/gpu/vk/GrVkCaps.cpp @@ -386,11 +386,6 @@ void GrVkCaps::init(const GrContextOptions& contextOptions, const GrVkInterface* fAvoidUpdateBuffers = true; } - if (kARM_VkVendor == properties.vendorID) { - // ARM seems to do better with more fine triangles as opposed to using the sample mask. - // (At least in our current round rect op.) - fPreferTrianglesOverSampleMask = true; - } this->initConfigTable(vkInterface, physDev, properties); this->initStencilFormat(vkInterface, physDev);