diff options
author | Brian Salomon <bsalomon@google.com> | 2017-03-06 11:29:48 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-03-06 17:10:10 +0000 |
commit | 42c456fd20bd45dd02f6d5eb0af7acf04341b1ee (patch) | |
tree | 8ef8bc1815f2725a7d40822c78d12b1ae6f10db6 /src | |
parent | 0bb6f38e511365670b9917ad76ece6f0bee9e282 (diff) |
Remove PLS path renderer
Change-Id: Ib727b0749a5a7da95832970e79804417e8b6a247
Reviewed-on: https://skia-review.googlesource.com/9300
Reviewed-by: Ethan Nicholas <ethannicholas@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Diffstat (limited to 'src')
31 files changed, 41 insertions, 1534 deletions
diff --git a/src/gpu/GrDrawOpTest.cpp b/src/gpu/GrDrawOpTest.cpp index 5d0aa56ee9..fcf70e0d7b 100644 --- a/src/gpu/GrDrawOpTest.cpp +++ b/src/gpu/GrDrawOpTest.cpp @@ -32,7 +32,6 @@ DRAW_OP_TEST_EXTERN(DIEllipseOp); DRAW_OP_TEST_EXTERN(EllipseOp); DRAW_OP_TEST_EXTERN(GrDrawAtlasOp); DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp); -DRAW_OP_TEST_EXTERN(PLSPathOp); DRAW_OP_TEST_EXTERN(RRectOp); DRAW_OP_TEST_EXTERN(TesselatingPathOp); DRAW_OP_TEST_EXTERN(TextBlobOp); @@ -56,8 +55,6 @@ std::unique_ptr<GrDrawOp> GrRandomDrawOp(SkRandom* random, GrContext* context) { DRAW_OP_TEST_ENTRY(EllipseOp), DRAW_OP_TEST_ENTRY(GrDrawAtlasOp), DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp), - // This currently hits an assert when the GrDisableColorXPFactory is randomly selected. - // DRAW_OP_TEST_ENTRY(PLSPathOp), DRAW_OP_TEST_ENTRY(RRectOp), DRAW_OP_TEST_ENTRY(TesselatingPathOp), DRAW_OP_TEST_ENTRY(TextBlobOp), diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h index 3abe8f8194..5b69ead462 100644 --- a/src/gpu/GrGpu.h +++ b/src/gpu/GrGpu.h @@ -376,7 +376,7 @@ public: const GrGpuCommandBuffer::LoadAndStoreInfo& stencilInfo) = 0; // Called by GrOpList when flushing. - // Provides a hook for post-flush actions (e.g. PLS reset and Vulkan command buffer submits). + // Provides a hook for post-flush actions (e.g. Vulkan command buffer submits). virtual void finishOpList() {} virtual GrFence SK_WARN_UNUSED_RESULT insertFence() = 0; diff --git a/src/gpu/GrPLSGeometryProcessor.h b/src/gpu/GrPLSGeometryProcessor.h deleted file mode 100644 index 0640af63f0..0000000000 --- a/src/gpu/GrPLSGeometryProcessor.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrPLSGeometryProcessor_DEFINED -#define GrPLSGeometryProcessor_DEFINED - -#include "GrGeometryProcessor.h" - -/** - * A minor extension to GrGeometryProcessor that adds bounds tracking for pixel local storage - * purposes. - */ -class GrPLSGeometryProcessor : public GrGeometryProcessor { -public: - GrPixelLocalStorageState getPixelLocalStorageState() const override { - return GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState; - } - - const SkRect& getBounds() const { - return fBounds; - } - - void setBounds(SkRect& bounds) { - fBounds = bounds; - } - -private: - SkRect fBounds; -}; - -#endif diff --git a/src/gpu/GrPathRendererChain.cpp b/src/gpu/GrPathRendererChain.cpp index b371c3ef75..6c8177f8e0 100644 --- a/src/gpu/GrPathRendererChain.cpp +++ b/src/gpu/GrPathRendererChain.cpp @@ -21,7 +21,6 @@ #include "ops/GrDashLinePathRenderer.h" #include "ops/GrDefaultPathRenderer.h" #include "ops/GrMSAAPathRenderer.h" -#include "ops/GrPLSPathRenderer.h" #include "ops/GrStencilAndCoverPathRenderer.h" #include "ops/GrTessellatingPathRenderer.h" @@ -54,11 +53,6 @@ GrPathRendererChain::GrPathRendererChain(GrContext* context, const Options& opti if (options.fGpuPathRenderers & GpuPathRenderers::kAALinearizing) { fChain.push_back(sk_make_sp<GrAALinearizingConvexPathRenderer>()); } - if (options.fGpuPathRenderers & GpuPathRenderers::kPLS) { - if (caps.shaderCaps()->plsPathRenderingSupport()) { - fChain.push_back(sk_make_sp<GrPLSPathRenderer>()); - } - } if (options.fGpuPathRenderers & GpuPathRenderers::kDistanceField) { fChain.push_back(sk_make_sp<GrAADistanceFieldPathRenderer>()); } diff --git a/src/gpu/GrPrimitiveProcessor.h b/src/gpu/GrPrimitiveProcessor.h index b9fe7b2c8b..f5b8fe9cf0 100644 --- a/src/gpu/GrPrimitiveProcessor.h +++ b/src/gpu/GrPrimitiveProcessor.h @@ -35,16 +35,6 @@ class GrGLSLPrimitiveProcessor; struct GrInitInvariantOutput; -// Describes the state of pixel local storage with respect to the current draw. -enum GrPixelLocalStorageState { - // The draw is actively updating PLS. - kDraw_GrPixelLocalStorageState, - // The draw is a "finish" operation which is reading from PLS and writing color. - kFinish_GrPixelLocalStorageState, - // The draw does not use PLS. - kDisabled_GrPixelLocalStorageState -}; - /* * This class allows the GrPipeline to communicate information about the pipeline to a GrOp which * inform its decisions for GrPrimitiveProcessor setup. These are not properly part of the pipeline @@ -167,10 +157,6 @@ public: virtual bool isPathRendering() const { return false; } - virtual GrPixelLocalStorageState getPixelLocalStorageState() const { - return kDisabled_GrPixelLocalStorageState; - } - /** * If non-null, overrides the dest color returned by GrGLSLFragmentShaderBuilder::dstColor(). */ diff --git a/src/gpu/GrProcessorSet.cpp b/src/gpu/GrProcessorSet.cpp index c61fe8bc79..e5beca0382 100644 --- a/src/gpu/GrProcessorSet.cpp +++ b/src/gpu/GrProcessorSet.cpp @@ -38,11 +38,9 @@ GrProcessorSet::GrProcessorSet(GrPaint&& paint) { void GrProcessorSet::FragmentProcessorAnalysis::internalReset(const GrPipelineInput& colorInput, const GrPipelineInput coverageInput, const GrProcessorSet& processors, - bool usesPLSDstRead, const GrFragmentProcessor* clipFP, const GrCaps& caps) { GrProcOptInfo colorInfo(colorInput); - fUsesPLSDstRead = usesPLSDstRead; fCompatibleWithCoverageAsAlpha = !coverageInput.isLCDCoverage(); const GrFragmentProcessor* const* fps = processors.fFragmentProcessors.get(); @@ -91,15 +89,14 @@ void GrProcessorSet::FragmentProcessorAnalysis::internalReset(const GrPipelineIn void GrProcessorSet::FragmentProcessorAnalysis::reset(const GrPipelineInput& colorInput, const GrPipelineInput coverageInput, const GrProcessorSet& processors, - bool usesPLSDstRead, const GrAppliedClip& appliedClip, const GrCaps& caps) { - this->internalReset(colorInput, coverageInput, processors, usesPLSDstRead, + this->internalReset(colorInput, coverageInput, processors, appliedClip.clipCoverageFragmentProcessor(), caps); } GrProcessorSet::FragmentProcessorAnalysis::FragmentProcessorAnalysis( const GrPipelineInput& colorInput, const GrPipelineInput coverageInput, const GrCaps& caps) : FragmentProcessorAnalysis() { - this->internalReset(colorInput, coverageInput, GrProcessorSet(GrPaint()), false, nullptr, caps); + this->internalReset(colorInput, coverageInput, GrProcessorSet(GrPaint()), nullptr, caps); } diff --git a/src/gpu/GrProcessorSet.h b/src/gpu/GrProcessorSet.h index 722bc048bd..de8bd6944b 100644 --- a/src/gpu/GrProcessorSet.h +++ b/src/gpu/GrProcessorSet.h @@ -56,12 +56,12 @@ public: class FragmentProcessorAnalysis { public: FragmentProcessorAnalysis() = default; - // This version is used by a unit test that assumes no clip, no processors, and no PLS. + // This version is used by a unit test that assumes no clip and no fragment processors. FragmentProcessorAnalysis(const GrPipelineInput& colorInput, const GrPipelineInput coverageInput, const GrCaps&); void reset(const GrPipelineInput& colorInput, const GrPipelineInput coverageInput, - const GrProcessorSet&, bool usesPLSDstRead, const GrAppliedClip&, const GrCaps&); + const GrProcessorSet&, const GrAppliedClip&, const GrCaps&); int initialColorProcessorsToEliminate(GrColor* newInputColor) const { if (fInitialColorProcessorsToEliminate > 0) { @@ -70,7 +70,6 @@ public: return fInitialColorProcessorsToEliminate; } - bool usesPLSDstRead() const { return fUsesPLSDstRead; } bool usesLocalCoords() const { return fUsesLocalCoords; } bool isCompatibleWithCoverageAsAlpha() const { return fCompatibleWithCoverageAsAlpha; } bool isOutputColorOpaque() const { @@ -89,13 +88,11 @@ public: private: void internalReset(const GrPipelineInput& colorInput, const GrPipelineInput coverageInput, - const GrProcessorSet&, bool usesPLSDstRead, - const GrFragmentProcessor* clipFP, const GrCaps&); + const GrProcessorSet&, const GrFragmentProcessor* clipFP, const GrCaps&); enum class ColorType { kUnknown, kOpaqueConstant, kConstant, kOpaque }; enum class CoverageType { kNone, kSingleChannel, kLCD }; - bool fUsesPLSDstRead = false; bool fCompatibleWithCoverageAsAlpha = true; bool fUsesLocalCoords = false; CoverageType fCoverageType = CoverageType::kNone; diff --git a/src/gpu/GrRenderTargetOpList.cpp b/src/gpu/GrRenderTargetOpList.cpp index 6edab11beb..6a7f7573e0 100644 --- a/src/gpu/GrRenderTargetOpList.cpp +++ b/src/gpu/GrRenderTargetOpList.cpp @@ -298,18 +298,6 @@ void GrRenderTargetOpList::addDrawOp(const GrPipelineBuilder& pipelineBuilder, } args.fCaps = this->caps(); args.fAnalysis = &analysis; - if (analysis.usesPLSDstRead()) { - int width = renderTargetContext->width(); - int height = renderTargetContext->height(); - SkIRect ibounds; - ibounds.fLeft = SkTPin(SkScalarFloorToInt(op->bounds().fLeft), 0, width); - ibounds.fTop = SkTPin(SkScalarFloorToInt(op->bounds().fTop), 0, height); - ibounds.fRight = SkTPin(SkScalarCeilToInt(op->bounds().fRight), 0, width); - ibounds.fBottom = SkTPin(SkScalarCeilToInt(op->bounds().fBottom), 0, height); - if (!appliedClip.addScissor(ibounds)) { - return; - } - } if (!renderTargetContext->accessRenderTarget()) { return; diff --git a/src/gpu/GrShaderCaps.cpp b/src/gpu/GrShaderCaps.cpp index 69af070bc7..e3e6b07361 100644 --- a/src/gpu/GrShaderCaps.cpp +++ b/src/gpu/GrShaderCaps.cpp @@ -47,7 +47,6 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { fTexelBufferSupport = false; fImageLoadStoreSupport = false; fShaderPrecisionVaries = false; - fPLSPathRenderingSupport = false; fDropsTileOnZeroDivide = false; fFBFetchSupport = false; fFBFetchNeedsCustomOutput = false; @@ -67,8 +66,6 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { fExternalTextureSupport = false; fTexelFetchSupport = false; - fPixelLocalStorageSize = 0; - fVersionDeclString = nullptr; fShaderDerivativeExtensionString = nullptr; fFragCoordConventionsExtensionString = nullptr; diff --git a/src/gpu/GrXferProcessor.cpp b/src/gpu/GrXferProcessor.cpp index a926812818..3b8a2bfb87 100644 --- a/src/gpu/GrXferProcessor.cpp +++ b/src/gpu/GrXferProcessor.cpp @@ -188,7 +188,7 @@ bool GrXPFactory::WillNeedDstTexture(const GrXPFactory* factory, const GrCaps& c const GrProcessorSet::FragmentProcessorAnalysis& analysis) { bool result; if (factory) { - result = !analysis.usesPLSDstRead() && !caps.shaderCaps()->dstReadInShaderSupport() && + result = !caps.shaderCaps()->dstReadInShaderSupport() && factory->willReadDstInShader(caps, analysis); } else { result = GrPorterDuffXPFactory::WillSrcOverNeedDstTexture(caps, analysis); @@ -197,14 +197,6 @@ bool GrXPFactory::WillNeedDstTexture(const GrXPFactory* factory, const GrCaps& c return result; } -bool GrXPFactory::willReadDstInShader(const GrCaps& caps, - const FragmentProcessorAnalysis& analysis) const { - if (analysis.usesPLSDstRead()) { - return true; - } - return this->onWillReadDstInShader(caps, analysis); -} - GrXferProcessor* GrXPFactory::createXferProcessor(const FragmentProcessorAnalysis& analysis, bool hasMixedSamples, const DstTexture* dstTexture, diff --git a/src/gpu/GrXferProcessor.h b/src/gpu/GrXferProcessor.h index c00bcbeff2..d6d6fa33e3 100644 --- a/src/gpu/GrXferProcessor.h +++ b/src/gpu/GrXferProcessor.h @@ -325,14 +325,11 @@ private: bool hasMixedSamples, const DstTexture*) const = 0; - bool willReadDstInShader(const GrCaps& caps, const FragmentProcessorAnalysis& analysis) const; - /** * Returns true if the XP generated by this factory will explicitly read dst in the fragment - * shader. This will not be called for draws that read from PLS since the dst color is always - * available in such draws. + * shader. */ - virtual bool onWillReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const = 0; + virtual bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const = 0; }; #if defined(__GNUC__) || defined(__clang) #pragma GCC diagnostic pop diff --git a/src/gpu/effects/GrCoverageSetOpXP.cpp b/src/gpu/effects/GrCoverageSetOpXP.cpp index d86467e668..52ebaad309 100644 --- a/src/gpu/effects/GrCoverageSetOpXP.cpp +++ b/src/gpu/effects/GrCoverageSetOpXP.cpp @@ -142,94 +142,6 @@ void CoverageSetOpXP::onGetBlendInfo(GrXferProcessor::BlendInfo* blendInfo) cons /////////////////////////////////////////////////////////////////////////////// -class ShaderCSOXferProcessor : public GrXferProcessor { -public: - ShaderCSOXferProcessor(const DstTexture* dstTexture, - bool hasMixedSamples, - SkRegion::Op regionOp, - bool invertCoverage) - : INHERITED(dstTexture, true, hasMixedSamples) - , fRegionOp(regionOp) - , fInvertCoverage(invertCoverage) { - this->initClassID<ShaderCSOXferProcessor>(); - } - - const char* name() const override { return "Coverage Set Op Shader"; } - - GrGLSLXferProcessor* createGLSLInstance() const override; - - SkRegion::Op regionOp() const { return fRegionOp; } - bool invertCoverage() const { return fInvertCoverage; } - -private: - GrXferProcessor::OptFlags onGetOptimizations(const FragmentProcessorAnalysis&) const override { - // We never look at the color input - return GrXferProcessor::kIgnoreColor_OptFlag; - } - - void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override; - - bool onIsEqual(const GrXferProcessor& xpBase) const override { - const ShaderCSOXferProcessor& xp = xpBase.cast<ShaderCSOXferProcessor>(); - return (fRegionOp == xp.fRegionOp && - fInvertCoverage == xp.fInvertCoverage); - } - - SkRegion::Op fRegionOp; - bool fInvertCoverage; - - typedef GrXferProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -class GLShaderCSOXferProcessor : public GrGLSLXferProcessor { -public: - static void GenKey(const GrProcessor& processor, GrProcessorKeyBuilder* b) { - const ShaderCSOXferProcessor& xp = processor.cast<ShaderCSOXferProcessor>(); - b->add32(xp.regionOp()); - uint32_t key = xp.invertCoverage() ? 0x0 : 0x1; - b->add32(key); - } - -private: - void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder, - GrGLSLUniformHandler* uniformHandler, - const char* srcColor, - const char* srcCoverage, - const char* dstColor, - const char* outColor, - const char* outColorSecondary, - const GrXferProcessor& proc) override { - const ShaderCSOXferProcessor& xp = proc.cast<ShaderCSOXferProcessor>(); - - if (xp.invertCoverage()) { - fragBuilder->codeAppendf("%s = 1.0 - %s;", outColor, srcCoverage); - } else { - fragBuilder->codeAppendf("%s = %s;", outColor, srcCoverage); - } - - GrGLSLBlend::AppendRegionOp(fragBuilder, outColor, dstColor, outColor, xp.regionOp()); - } - - void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override {} - - typedef GrGLSLXferProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -void ShaderCSOXferProcessor::onGetGLSLProcessorKey(const GrShaderCaps&, - GrProcessorKeyBuilder* b) const { - GLShaderCSOXferProcessor::GenKey(*this, b); -} - -GrGLSLXferProcessor* ShaderCSOXferProcessor::createGLSLInstance() const { - return new GLShaderCSOXferProcessor; -} - -/////////////////////////////////////////////////////////////////////////////// -// constexpr GrCoverageSetOpXPFactory::GrCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) : fRegionOp(regionOp), fInvertCoverage(invertCoverage) {} @@ -328,9 +240,6 @@ GrXferProcessor* GrCoverageSetOpXPFactory::onCreateXferProcessor( return nullptr; } - if (analysis.usesPLSDstRead()) { - return new ShaderCSOXferProcessor(dst, hasMixedSamples, fRegionOp, fInvertCoverage); - } return CoverageSetOpXP::Create(fRegionOp, fInvertCoverage); } diff --git a/src/gpu/effects/GrCoverageSetOpXP.h b/src/gpu/effects/GrCoverageSetOpXP.h index ed6b9aa9f0..02db11b811 100644 --- a/src/gpu/effects/GrCoverageSetOpXP.h +++ b/src/gpu/effects/GrCoverageSetOpXP.h @@ -41,7 +41,7 @@ private: bool hasMixedSamples, const DstTexture*) const override; - bool onWillReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override { + bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override { return false; } diff --git a/src/gpu/effects/GrCustomXfermode.cpp b/src/gpu/effects/GrCustomXfermode.cpp index ccbab73f86..8895d7c02b 100644 --- a/src/gpu/effects/GrCustomXfermode.cpp +++ b/src/gpu/effects/GrCustomXfermode.cpp @@ -52,16 +52,11 @@ static constexpr GrBlendEquation hw_blend_equation(SkBlendMode mode) { #undef EQ_OFFSET } -static bool can_use_hw_blend_equation(GrBlendEquation equation, - bool usePLSRead, - bool isLCDCoverage, +static bool can_use_hw_blend_equation(GrBlendEquation equation, bool isLCDCoverage, const GrCaps& caps) { if (!caps.advancedBlendEquationSupport()) { return false; } - if (usePLSRead) { - return false; - } if (isLCDCoverage) { return false; // LCD coverage must be applied after the blend equation. } @@ -334,7 +329,7 @@ private: bool willReadsDst(const FragmentProcessorAnalysis&) const override { return true; } - bool onWillReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override; + bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override; GR_DECLARE_XP_FACTORY_TEST; @@ -352,20 +347,16 @@ GrXferProcessor* CustomXPFactory::onCreateXferProcessor(const GrCaps& caps, bool hasMixedSamples, const DstTexture* dstTexture) const { SkASSERT(GrCustomXfermode::IsSupportedMode(fMode)); - if (can_use_hw_blend_equation(fHWBlendEquation, analysis.usesPLSDstRead(), - analysis.hasLCDCoverage(), caps)) { + if (can_use_hw_blend_equation(fHWBlendEquation, analysis.hasLCDCoverage(), caps)) { SkASSERT(!dstTexture || !dstTexture->texture()); return new CustomXP(fMode, fHWBlendEquation); } return new CustomXP(dstTexture, hasMixedSamples, fMode); } -bool CustomXPFactory::onWillReadDstInShader(const GrCaps& caps, - const FragmentProcessorAnalysis& analysis) const { - // This should not be called if we're using PLS dst read. - static constexpr bool kUsesPLSRead = false; - return !can_use_hw_blend_equation(fHWBlendEquation, kUsesPLSRead, analysis.hasLCDCoverage(), - caps); +bool CustomXPFactory::willReadDstInShader(const GrCaps& caps, + const FragmentProcessorAnalysis& analysis) const { + return !can_use_hw_blend_equation(fHWBlendEquation, analysis.hasLCDCoverage(), caps); } GR_DEFINE_XP_FACTORY_TEST(CustomXPFactory); diff --git a/src/gpu/effects/GrDisableColorXP.cpp b/src/gpu/effects/GrDisableColorXP.cpp index 6bdf1885e9..f95cd9b81a 100644 --- a/src/gpu/effects/GrDisableColorXP.cpp +++ b/src/gpu/effects/GrDisableColorXP.cpp @@ -90,7 +90,6 @@ GrXferProcessor* GrDisableColorXPFactory::onCreateXferProcessor( const FragmentProcessorAnalysis& analysis, bool hasMixedSamples, const DstTexture* dst) const { - SkASSERT(!analysis.usesPLSDstRead()); return DisableColorXP::Create(); } diff --git a/src/gpu/effects/GrDisableColorXP.h b/src/gpu/effects/GrDisableColorXP.h index b4cd00a599..6a9f2add17 100644 --- a/src/gpu/effects/GrDisableColorXP.h +++ b/src/gpu/effects/GrDisableColorXP.h @@ -28,7 +28,7 @@ private: constexpr GrDisableColorXPFactory() {} - bool onWillReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override { + bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override { return false; } diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.cpp b/src/gpu/effects/GrPorterDuffXferProcessor.cpp index 7378874da9..c7e61cace3 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.cpp +++ b/src/gpu/effects/GrPorterDuffXferProcessor.cpp @@ -735,9 +735,6 @@ GrXferProcessor* GrPorterDuffXPFactory::onCreateXferProcessor( const FragmentProcessorAnalysis& analysis, bool hasMixedSamples, const DstTexture* dstTexture) const { - if (analysis.usesPLSDstRead()) { - return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, fBlendMode); - } BlendFormula blendFormula; if (analysis.hasLCDCoverage()) { if (SkBlendMode::kSrcOver == fBlendMode && analysis.hasKnownOutputColor() && @@ -768,8 +765,8 @@ bool GrPorterDuffXPFactory::willReadsDst(const FragmentProcessorAnalysis& analys return (colorFormula.usesDstColor() || analysis.hasCoverage()); } -bool GrPorterDuffXPFactory::onWillReadDstInShader(const GrCaps& caps, - const FragmentProcessorAnalysis& analysis) const { +bool GrPorterDuffXPFactory::willReadDstInShader(const GrCaps& caps, + const FragmentProcessorAnalysis& analysis) const { if (caps.shaderCaps()->dualSourceBlendingSupport()) { return false; } @@ -830,9 +827,6 @@ GrXferProcessor* GrPorterDuffXPFactory::CreateSrcOverXferProcessor( const FragmentProcessorAnalysis& analysis, bool hasMixedSamples, const GrXferProcessor::DstTexture* dstTexture) { - if (analysis.usesPLSDstRead()) { - return new ShaderPDXferProcessor(dstTexture, hasMixedSamples, SkBlendMode::kSrcOver); - } // We want to not make an xfer processor if possible. Thus for the simple case where we are not // doing lcd blending we will just use our global SimpleSrcOverXP. This slightly differs from diff --git a/src/gpu/effects/GrPorterDuffXferProcessor.h b/src/gpu/effects/GrPorterDuffXferProcessor.h index 6d7dc90fcf..b82c1068ff 100644 --- a/src/gpu/effects/GrPorterDuffXferProcessor.h +++ b/src/gpu/effects/GrPorterDuffXferProcessor.h @@ -52,7 +52,7 @@ private: bool hasMixedSamples, const DstTexture*) const override; - bool onWillReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override; + bool willReadDstInShader(const GrCaps&, const FragmentProcessorAnalysis&) const override; GR_DECLARE_XP_FACTORY_TEST; static void TestGetXPOutputTypes(const GrXferProcessor*, int* outPrimary, int* outSecondary); diff --git a/src/gpu/gl/GrGLCaps.cpp b/src/gpu/gl/GrGLCaps.cpp index 0bcb7e817b..d2e18995a3 100644 --- a/src/gpu/gl/GrGLCaps.cpp +++ b/src/gpu/gl/GrGLCaps.cpp @@ -290,17 +290,6 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; // We use this value for GLSL ES 3.0. } - if (ctxInfo.hasExtension("GL_EXT_shader_pixel_local_storage")) { - #define GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT 0x8F63 - GR_GL_GetIntegerv(gli, GL_MAX_SHADER_PIXEL_LOCAL_STORAGE_FAST_SIZE_EXT, - &shaderCaps->fPixelLocalStorageSize); - shaderCaps->fPLSPathRenderingSupport = shaderCaps->fFBFetchSupport; - } - else { - shaderCaps->fPixelLocalStorageSize = 0; - shaderCaps->fPLSPathRenderingSupport = false; - } - // Protect ourselves against tracking huge amounts of texture state. static const uint8_t kMaxSaneSamplers = 32; GrGLint maxSamplers; diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp index cfbef9fd7a..bda1c16b59 100644 --- a/src/gpu/gl/GrGLGpu.cpp +++ b/src/gpu/gl/GrGLGpu.cpp @@ -16,7 +16,6 @@ #include "GrGLTextureRenderTarget.h" #include "GrGpuResourcePriv.h" #include "GrMesh.h" -#include "GrPLSGeometryProcessor.h" #include "GrPipeline.h" #include "GrRenderTargetPriv.h" #include "GrShaderCaps.h" @@ -32,7 +31,6 @@ #include "SkTemplates.h" #include "SkTypes.h" #include "builders/GrGLShaderStringBuilder.h" -#include "glsl/GrGLSLPLSPathRendering.h" #include "instanced/GLInstancedRendering.h" #define GL_CALL(X) GR_GL_CALL(this->glInterface(), X) @@ -206,8 +204,6 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) , fTempDstFBOID(0) , fStencilClearFBOID(0) , fHWMaxUsedBufferTextureUnit(-1) - , fHWPLSEnabled(false) - , fPLSHasBeenUsed(false) , fHWMinSampleShading(0.0) { for (size_t i = 0; i < SK_ARRAY_COUNT(fCopyPrograms); ++i) { fCopyPrograms[i].fProgram = 0; @@ -216,7 +212,6 @@ GrGLGpu::GrGLGpu(GrGLContext* ctx, GrContext* context) fMipmapPrograms[i].fProgram = 0; } fWireRectProgram.fProgram = 0; - fPLSSetupProgram.fProgram = 0; SkASSERT(ctx); fCaps.reset(SkRef(ctx->caps())); @@ -274,7 +269,6 @@ GrGLGpu::~GrGLGpu() { fCopyProgramArrayBuffer.reset(); fMipmapProgramArrayBuffer.reset(); fWireRectArrayBuffer.reset(); - fPLSSetupProgram.fArrayBuffer.reset(); if (0 != fHWProgramID) { // detach the current program so there is no confusion on OpenGL's part @@ -308,129 +302,9 @@ GrGLGpu::~GrGLGpu() { GL_CALL(DeleteProgram(fWireRectProgram.fProgram)); } - if (0 != fPLSSetupProgram.fProgram) { - GL_CALL(DeleteProgram(fPLSSetupProgram.fProgram)); - } - delete fProgramCache; } -bool GrGLGpu::createPLSSetupProgram() { - if (!fPLSSetupProgram.fArrayBuffer) { - static const GrGLfloat vdata[] = { - 0, 0, - 0, 1, - 1, 0, - 1, 1 - }; - fPLSSetupProgram.fArrayBuffer.reset(GrGLBuffer::Create(this, sizeof(vdata), - kVertex_GrBufferType, - kStatic_GrAccessPattern, vdata)); - if (!fPLSSetupProgram.fArrayBuffer) { - return false; - } - } - - SkASSERT(!fPLSSetupProgram.fProgram); - GL_CALL_RET(fPLSSetupProgram.fProgram, CreateProgram()); - if (!fPLSSetupProgram.fProgram) { - return false; - } - - const GrShaderCaps* shaderCaps = this->caps()->shaderCaps(); - const char* version = shaderCaps->versionDeclString(); - - GrShaderVar aVertex("a_vertex", kVec2f_GrSLType, GrShaderVar::kIn_TypeModifier); - GrShaderVar uTexCoordXform("u_texCoordXform", kVec4f_GrSLType, - GrShaderVar::kUniform_TypeModifier); - GrShaderVar uPosXform("u_posXform", kVec4f_GrSLType, GrShaderVar::kUniform_TypeModifier); - GrShaderVar uTexture("u_texture", kTexture2DSampler_GrSLType, - GrShaderVar::kUniform_TypeModifier); - GrShaderVar vTexCoord("v_texCoord", kVec2f_GrSLType, GrShaderVar::kOut_TypeModifier); - - SkString vshaderTxt(version); - if (shaderCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) { - vshaderTxt.appendf("#extension %s : require\n", extension); - } - vTexCoord.addModifier("noperspective"); - } - aVertex.appendDecl(shaderCaps, &vshaderTxt); - vshaderTxt.append(";"); - uTexCoordXform.appendDecl(shaderCaps, &vshaderTxt); - vshaderTxt.append(";"); - uPosXform.appendDecl(shaderCaps, &vshaderTxt); - vshaderTxt.append(";"); - vTexCoord.appendDecl(shaderCaps, &vshaderTxt); - vshaderTxt.append(";"); - - vshaderTxt.append( - "// PLS Setup Program VS\n" - "void main() {" - " gl_Position.xy = a_vertex * u_posXform.xy + u_posXform.zw;" - " gl_Position.zw = vec2(0, 1);" - "}" - ); - - SkString fshaderTxt(version); - if (shaderCaps->noperspectiveInterpolationSupport()) { - if (const char* extension = shaderCaps->noperspectiveInterpolationExtensionString()) { - fshaderTxt.appendf("#extension %s : require\n", extension); - } - } - fshaderTxt.append("#extension "); - fshaderTxt.append(shaderCaps->fbFetchExtensionString()); - fshaderTxt.append(" : require\n"); - fshaderTxt.append("#extension GL_EXT_shader_pixel_local_storage : require\n"); - GrGLSLAppendDefaultFloatPrecisionDeclaration(kDefault_GrSLPrecision, *shaderCaps, &fshaderTxt); - vTexCoord.setTypeModifier(GrShaderVar::kIn_TypeModifier); - vTexCoord.appendDecl(shaderCaps, &fshaderTxt); - fshaderTxt.append(";"); - uTexture.appendDecl(shaderCaps, &fshaderTxt); - fshaderTxt.append(";"); - - fshaderTxt.appendf( - "// PLS Setup Program FS\n" - GR_GL_PLS_PATH_DATA_DECL - "void main() {\n" - " " GR_GL_PLS_DSTCOLOR_NAME " = gl_LastFragColorARM;\n" - " pls.windings = ivec4(0, 0, 0, 0);\n" - "}" - ); - - const char* str; - GrGLint length; - - str = vshaderTxt.c_str(); - length = SkToInt(vshaderTxt.size()); - SkSL::Program::Settings settings; - settings.fCaps = shaderCaps; - SkSL::Program::Inputs inputs; - GrGLuint vshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram, - GR_GL_VERTEX_SHADER, &str, &length, 1, &fStats, - settings, &inputs); - SkASSERT(inputs.isEmpty()); - - str = fshaderTxt.c_str(); - length = SkToInt(fshaderTxt.size()); - GrGLuint fshader = GrGLCompileAndAttachShader(*fGLContext, fPLSSetupProgram.fProgram, - GR_GL_FRAGMENT_SHADER, &str, &length, 1, &fStats, - settings, &inputs); - SkASSERT(inputs.isEmpty()); - - GL_CALL(LinkProgram(fPLSSetupProgram.fProgram)); - - GL_CALL_RET(fPLSSetupProgram.fPosXformUniform, GetUniformLocation(fPLSSetupProgram.fProgram, - "u_posXform")); - - GL_CALL(BindAttribLocation(fPLSSetupProgram.fProgram, 0, "a_vertex")); - - GL_CALL(DeleteShader(vshader)); - GL_CALL(DeleteShader(fshader)); - - return true; -} - void GrGLGpu::disconnect(DisconnectType type) { INHERITED::disconnect(type); if (DisconnectType::kCleanup == type) { @@ -459,9 +333,6 @@ void GrGLGpu::disconnect(DisconnectType type) { if (fWireRectProgram.fProgram) { GL_CALL(DeleteProgram(fWireRectProgram.fProgram)); } - if (fPLSSetupProgram.fProgram) { - GL_CALL(DeleteProgram(fPLSSetupProgram.fProgram)); - } } else { if (fProgramCache) { fProgramCache->abandon(); @@ -485,8 +356,6 @@ void GrGLGpu::disconnect(DisconnectType type) { } fWireRectProgram.fProgram = 0; fWireRectArrayBuffer.reset(); - fPLSSetupProgram.fProgram = 0; - fPLSSetupProgram.fArrayBuffer.reset(); if (this->glCaps().shaderCaps()->pathRenderingSupport()) { this->glPathRendering()->disconnect(type); } @@ -2672,25 +2541,6 @@ GrGpuCommandBuffer* GrGLGpu::createCommandBuffer( return new GrGLGpuCommandBuffer(this); } -void GrGLGpu::finishOpList() { - if (fPLSHasBeenUsed) { - /* There is an ARM driver bug where if we use PLS, and then draw a frame which does not - * use PLS, it leaves garbage all over the place. As a workaround, we use PLS in a - * trivial way every frame. And since we use it every frame, there's never a point at which - * it becomes safe to stop using this workaround once we start. - */ - this->disableScissor(); - this->disableWindowRectangles(); - // using PLS in the presence of MSAA results in GL_INVALID_OPERATION - this->flushHWAAState(nullptr, false, false); - SkASSERT(!fHWPLSEnabled); - SkASSERT(fMSAAEnabled != kYes_TriState); - GL_CALL(Enable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - this->stampPLSSetupRect(SkRect::MakeXYWH(-100.0f, -100.0f, 0.01f, 0.01f)); - GL_CALL(Disable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - } -} - void GrGLGpu::flushRenderTarget(GrGLRenderTarget* target, const SkIRect* bounds, bool disableSRGB) { SkASSERT(target); @@ -2786,16 +2636,6 @@ void GrGLGpu::draw(const GrPipeline& pipeline, if (!this->flushGLState(pipeline, primProc, hasPoints)) { return; } - GrPixelLocalStorageState plsState = primProc.getPixelLocalStorageState(); - if (!fHWPLSEnabled && plsState != - GrPixelLocalStorageState::kDisabled_GrPixelLocalStorageState) { - GL_CALL(Enable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - this->setupPixelLocalStorage(pipeline, primProc); - fHWPLSEnabled = true; - } - if (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) { - this->disableStencil(); - } for (int i = 0; i < meshCount; ++i) { if (GrXferBarrierType barrierType = pipeline.xferBarrierType(*this->caps())) { @@ -2840,16 +2680,6 @@ void GrGLGpu::draw(const GrPipeline& pipeline, } while ((nonInstMesh = iter.next())); } - if (fHWPLSEnabled && plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState) { - // PLS draws always involve multiple draws, finishing up with a non-PLS - // draw that writes to the color buffer. That draw ends up here; we wait - // until after it is complete to actually disable PLS. - GL_CALL(Disable(GR_GL_SHADER_PIXEL_LOCAL_STORAGE)); - fHWPLSEnabled = false; - this->disableScissor(); - this->disableWindowRectangles(); - } - #if SWAP_PER_DRAW glFlush(); #if defined(SK_BUILD_FOR_MAC) @@ -2864,65 +2694,6 @@ void GrGLGpu::draw(const GrPipeline& pipeline, #endif } -void GrGLGpu::stampPLSSetupRect(const SkRect& bounds) { - SkASSERT(this->caps()->shaderCaps()->plsPathRenderingSupport()); - - if (!fPLSSetupProgram.fProgram) { - if (!this->createPLSSetupProgram()) { - SkDebugf("Failed to create PLS setup program.\n"); - return; - } - } - - GL_CALL(UseProgram(fPLSSetupProgram.fProgram)); - this->fHWVertexArrayState.setVertexArrayID(this, 0); - - GrGLAttribArrayState* attribs = this->fHWVertexArrayState.bindInternalVertexArray(this); - attribs->set(this, 0, fPLSSetupProgram.fArrayBuffer.get(), kVec2f_GrVertexAttribType, - 2 * sizeof(GrGLfloat), 0); - attribs->disableUnusedArrays(this, 0x1); - - GL_CALL(Uniform4f(fPLSSetupProgram.fPosXformUniform, bounds.width(), bounds.height(), - bounds.left(), bounds.top())); - - GrXferProcessor::BlendInfo blendInfo; - blendInfo.reset(); - this->flushBlend(blendInfo, GrSwizzle()); - this->flushColorWrite(true); - this->flushDrawFace(GrDrawFace::kBoth); - if (!fHWStencilSettings.isDisabled()) { - GL_CALL(Disable(GR_GL_STENCIL_TEST)); - } - GL_CALL(DrawArrays(GR_GL_TRIANGLE_STRIP, 0, 4)); - GL_CALL(UseProgram(fHWProgramID)); - if (!fHWStencilSettings.isDisabled()) { - GL_CALL(Enable(GR_GL_STENCIL_TEST)); - } -} - -void GrGLGpu::setupPixelLocalStorage(const GrPipeline& pipeline, - const GrPrimitiveProcessor& primProc) { - fPLSHasBeenUsed = true; - const SkRect& bounds = - static_cast<const GrPLSGeometryProcessor&>(primProc).getBounds(); - // setup pixel local storage -- this means capturing and storing the current framebuffer color - // and initializing the winding counts to zero - GrRenderTarget* rt = pipeline.getRenderTarget(); - SkScalar width = SkIntToScalar(rt->width()); - SkScalar height = SkIntToScalar(rt->height()); - // dst rect edges in NDC (-1 to 1) - // having some issues with rounding, just expand the bounds by 1 and trust the scissor to keep - // it contained properly - GrGLfloat dx0 = 2.0f * (bounds.left() - 1) / width - 1.0f; - GrGLfloat dx1 = 2.0f * (bounds.right() + 1) / width - 1.0f; - GrGLfloat dy0 = -2.0f * (bounds.top() - 1) / height + 1.0f; - GrGLfloat dy1 = -2.0f * (bounds.bottom() + 1) / height + 1.0f; - SkRect deviceBounds = SkRect::MakeXYWH(dx0, dy0, dx1 - dx0, dy1 - dy0); - - GL_CALL(Enable(GR_GL_FETCH_PER_SAMPLE_ARM)); - this->stampPLSSetupRect(deviceBounds); -} - void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target) { GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(target); if (rt->needsResolve()) { diff --git a/src/gpu/gl/GrGLGpu.h b/src/gpu/gl/GrGLGpu.h index 57068fb916..564ed7629a 100644 --- a/src/gpu/gl/GrGLGpu.h +++ b/src/gpu/gl/GrGLGpu.h @@ -144,8 +144,6 @@ public: void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override; - void finishOpList() override; - GrFence SK_WARN_UNUSED_RESULT insertFence() override; bool waitFence(GrFence, uint64_t timeout) override; void deleteFence(GrFence) const override; @@ -273,10 +271,6 @@ private: const SkIPoint& dstPoint); bool generateMipmap(GrGLTexture* texture, bool gammaCorrect); - void stampPLSSetupRect(const SkRect& bounds); - - void setupPixelLocalStorage(const GrPipeline&, const GrPrimitiveProcessor&); - static bool BlendCoeffReferencesConstant(GrBlendCoeff coeff); class ProgramCache : public ::SkNoncopyable { @@ -404,7 +398,6 @@ private: bool createCopyProgram(GrTexture* srcTexture); bool createMipmapProgram(int progIdx); bool createWireRectProgram(); - bool createPLSSetupProgram(); // GL program-related state ProgramCache* fProgramCache; @@ -647,15 +640,6 @@ private: return (wide ? 0x2 : 0x0) | (tall ? 0x1 : 0x0); } - struct { - GrGLuint fProgram; - GrGLint fPosXformUniform; - sk_sp<GrGLBuffer> fArrayBuffer; - } fPLSSetupProgram; - - bool fHWPLSEnabled; - bool fPLSHasBeenUsed; - float fHWMinSampleShading; typedef GrGpu INHERITED; diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp index f09b66869f..d9e73f04e4 100644 --- a/src/gpu/gl/GrGLProgram.cpp +++ b/src/gpu/gl/GrGLProgram.cpp @@ -77,12 +77,9 @@ void GrGLProgram::setData(const GrPrimitiveProcessor& primProc, const GrPipeline this->setFragmentData(primProc, pipeline, &nextSamplerIdx); - if (primProc.getPixelLocalStorageState() != - GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) { - const GrXferProcessor& xp = pipeline.getXferProcessor(); - fXferProcessor->setData(fProgramDataManager, xp); - this->bindTextures(xp, pipeline.getAllowSRGBInputs(), &nextSamplerIdx); - } + const GrXferProcessor& xp = pipeline.getXferProcessor(); + fXferProcessor->setData(fProgramDataManager, xp); + this->bindTextures(xp, pipeline.getAllowSRGBInputs(), &nextSamplerIdx); } void GrGLProgram::generateMipmaps(const GrPrimitiveProcessor& primProc, @@ -93,12 +90,6 @@ void GrGLProgram::generateMipmaps(const GrPrimitiveProcessor& primProc, while (const GrFragmentProcessor* fp = iter.next()) { this->generateMipmaps(*fp, pipeline.getAllowSRGBInputs()); } - - if (primProc.getPixelLocalStorageState() != - GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) { - const GrXferProcessor& xp = pipeline.getXferProcessor(); - this->generateMipmaps(xp, pipeline.getAllowSRGBInputs()); - } } void GrGLProgram::setFragmentData(const GrPrimitiveProcessor& primProc, diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp index f583420f29..a1f5173436 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp @@ -96,13 +96,6 @@ GrGLSLFragmentShaderBuilder::GrGLSLFragmentShaderBuilder(GrGLSLProgramBuilder* p bool GrGLSLFragmentShaderBuilder::enableFeature(GLSLFeature feature) { const GrShaderCaps& shaderCaps = *fProgramBuilder->shaderCaps(); switch (feature) { - case kPixelLocalStorage_GLSLFeature: - if (shaderCaps.pixelLocalStorageSize() <= 0) { - return false; - } - this->addFeature(1 << kPixelLocalStorage_GLSLFeature, - "GL_EXT_shader_pixel_local_storage"); - return true; case kMultisampleInterpolation_GLSLFeature: if (!shaderCaps.multisampleInterpolationSupport()) { return false; diff --git a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h index ab806ea914..764f3bd812 100644 --- a/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h +++ b/src/gpu/glsl/GrGLSLFragmentShaderBuilder.h @@ -29,7 +29,6 @@ public: * if code is added that uses one of these features without calling enableFeature() */ enum GLSLFeature { - kPixelLocalStorage_GLSLFeature = kLastGLSLPrivateFeature + 1, kMultisampleInterpolation_GLSLFeature }; diff --git a/src/gpu/glsl/GrGLSLPLSPathRendering.h b/src/gpu/glsl/GrGLSLPLSPathRendering.h deleted file mode 100644 index 60889e98d2..0000000000 --- a/src/gpu/glsl/GrGLSLPLSPathRendering.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#define GR_GL_PLS_DSTCOLOR_NAME "pls.dstColor" -#define GR_GL_PLS_PATH_DATA_DECL "__pixel_localEXT PLSData {\n"\ - " layout(rgba8i) ivec4 windings;\n"\ - " layout(rgba8) vec4 dstColor;\n"\ - "} pls;\n" diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp index 385026a52d..1fcf0405f7 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp +++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp @@ -62,12 +62,8 @@ bool GrGLSLProgramBuilder::emitAndInstallProcs(GrGLSLExpr4* inputColor, this->emitAndInstallPrimProc(primProc, inputColor, inputCoverage); this->emitAndInstallFragProcs(inputColor, inputCoverage); - if (primProc.getPixelLocalStorageState() != - GrPixelLocalStorageState::kDraw_GrPixelLocalStorageState) { - this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, - *inputCoverage, primProc.getPixelLocalStorageState()); - this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); - } + this->emitAndInstallXferProc(this->pipeline().getXferProcessor(), *inputColor, *inputCoverage); + this->emitFSOutputSwizzle(this->pipeline().getXferProcessor().hasSecondaryOutput()); return this->checkSamplerCounts() && this->checkImageStorageCounts(); } @@ -217,8 +213,7 @@ void GrGLSLProgramBuilder::emitAndInstallFragProc(const GrFragmentProcessor& fp, void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - GrPixelLocalStorageState plsState) { + const GrGLSLExpr4& coverageIn) { // Program builders have a bit of state we need to clear with each effect AutoStageAdvance adv(this); @@ -243,7 +238,6 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, SkSTArray<2, ImageStorageHandle> imageStorageArray(xp.numImageStorages()); this->emitSamplersAndImageStorages(xp, &texSamplers, &bufferSamplers, &imageStorageArray); - bool usePLSDstRead = (plsState == GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState); GrGLSLXferProcessor::EmitArgs args(&fFS, this->uniformHandler(), this->shaderCaps(), @@ -253,8 +247,7 @@ void GrGLSLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp, fFS.getSecondaryColorOutputName(), texSamplers.begin(), bufferSamplers.begin(), - imageStorageArray.begin(), - usePLSDstRead); + imageStorageArray.begin()); fXferProcessor->emitCode(args); // We have to check that effects and the code they emit are consistent, ie if an effect diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.h b/src/gpu/glsl/GrGLSLProgramBuilder.h index 321d81cad2..748664625f 100644 --- a/src/gpu/glsl/GrGLSLProgramBuilder.h +++ b/src/gpu/glsl/GrGLSLProgramBuilder.h @@ -154,8 +154,7 @@ private: GrGLSLExpr4* output); void emitAndInstallXferProc(const GrXferProcessor&, const GrGLSLExpr4& colorIn, - const GrGLSLExpr4& coverageIn, - GrPixelLocalStorageState plsState); + const GrGLSLExpr4& coverageIn); void emitSamplersAndImageStorages(const GrProcessor& processor, SkTArray<SamplerHandle>* outTexSamplerHandles, SkTArray<SamplerHandle>* outBufferSamplerHandles, diff --git a/src/gpu/glsl/GrGLSLXferProcessor.h b/src/gpu/glsl/GrGLSLXferProcessor.h index 90c1bce5b2..b4bde37e30 100644 --- a/src/gpu/glsl/GrGLSLXferProcessor.h +++ b/src/gpu/glsl/GrGLSLXferProcessor.h @@ -35,20 +35,18 @@ public: const char* outputSecondary, const SamplerHandle* texSamplers, const SamplerHandle* bufferSamplers, - const ImageStorageHandle* imageStorages, - const bool usePLSDstRead) - : fXPFragBuilder(fragBuilder) - , fUniformHandler(uniformHandler) - , fShaderCaps(caps) - , fXP(xp) - , fInputColor(inputColor) - , fInputCoverage(inputCoverage) - , fOutputPrimary(outputPrimary) - , fOutputSecondary(outputSecondary) - , fTexSamplers(texSamplers) - , fBufferSamplers(bufferSamplers) - , fImageStorages(imageStorages) - , fUsePLSDstRead(usePLSDstRead) {} + const ImageStorageHandle* imageStorages) + : fXPFragBuilder(fragBuilder) + , fUniformHandler(uniformHandler) + , fShaderCaps(caps) + , fXP(xp) + , fInputColor(inputColor) + , fInputCoverage(inputCoverage) + , fOutputPrimary(outputPrimary) + , fOutputSecondary(outputSecondary) + , fTexSamplers(texSamplers) + , fBufferSamplers(bufferSamplers) + , fImageStorages(imageStorages) {} GrGLSLXPFragmentBuilder* fXPFragBuilder; GrGLSLUniformHandler* fUniformHandler; @@ -61,7 +59,6 @@ public: const SamplerHandle* fTexSamplers; const SamplerHandle* fBufferSamplers; const ImageStorageHandle* fImageStorages; - bool fUsePLSDstRead; }; /** * This is similar to emitCode() in the base class, except it takes a full shader builder. diff --git a/src/gpu/ops/GrDrawOp.h b/src/gpu/ops/GrDrawOp.h index 1512642bb4..18c218fc9a 100644 --- a/src/gpu/ops/GrDrawOp.h +++ b/src/gpu/ops/GrDrawOp.h @@ -70,8 +70,7 @@ public: const GrCaps& caps) const { FragmentProcessorAnalysisInputs input; this->getFragmentProcessorAnalysisInputs(&input); - analysis->reset(*input.colorInput(), *input.coverageInput(), processors, - input.usesPLSDstRead(), appliedClip, caps); + analysis->reset(*input.colorInput(), *input.coverageInput(), processors, appliedClip, caps); } protected: @@ -121,14 +120,9 @@ protected: GrPipelineInput* colorInput() { return &fColorInput; } GrPipelineInput* coverageInput() { return &fCoverageInput; } - void setUsesPLSDstRead() { fUsesPLSDstRead = true; } - - bool usesPLSDstRead() const { return fUsesPLSDstRead; } - private: GrPipelineInput fColorInput; GrPipelineInput fCoverageInput; - bool fUsesPLSDstRead = false; }; private: diff --git a/src/gpu/ops/GrPLSPathRenderer.cpp b/src/gpu/ops/GrPLSPathRenderer.cpp deleted file mode 100644 index ac2f4fcf2b..0000000000 --- a/src/gpu/ops/GrPLSPathRenderer.cpp +++ /dev/null @@ -1,946 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "GrPLSPathRenderer.h" - -#include "GrCaps.h" -#include "GrContext.h" -#include "GrDefaultGeoProcFactory.h" -#include "GrDrawOpTest.h" -#include "GrOpFlushState.h" -#include "GrPLSGeometryProcessor.h" -#include "GrPathUtils.h" -#include "GrPipelineBuilder.h" -#include "GrProcessor.h" -#include "GrStyle.h" -#include "GrTessellator.h" -#include "SkChunkAlloc.h" -#include "SkGeometry.h" -#include "SkPathPriv.h" -#include "SkString.h" -#include "SkTSort.h" -#include "SkTraceEvent.h" -#include "gl/builders/GrGLProgramBuilder.h" -#include "glsl/GrGLSLGeometryProcessor.h" -#include "glsl/GrGLSLPLSPathRendering.h" -#include "ops/GrMeshDrawOp.h" - -GrPLSPathRenderer::GrPLSPathRenderer() { -} - -struct PLSVertex { - SkPoint fPos; - // for triangles, these are the three triangle vertices - // for quads, vert1 is the texture UV coords, and vert2 and vert3 are the line segment - // comprising the flat edge of the quad - SkPoint fVert1; - SkPoint fVert2; - SkPoint fVert3; - int fWinding; -}; -typedef SkTArray<PLSVertex, true> PLSVertices; - -typedef SkTArray<SkPoint, true> FinishVertices; - -static const float kCubicTolerance = 0.5f; -static const float kConicTolerance = 0.5f; - -static const float kBloatSize = 1.0f; - -static const float kBloatLimit = 640000.0f; - -#define kQuadNumVertices 5 -static void add_quad(SkPoint pts[3], PLSVertices& vertices) { - SkPoint normal = SkPoint::Make(pts[0].fY - pts[2].fY, - pts[2].fX - pts[0].fX); - normal.setLength(kBloatSize); - SkScalar cross = (pts[1] - pts[0]).cross(pts[2] - pts[0]); - if (cross < 0) { - normal = -normal; - } - PLSVertex quad[kQuadNumVertices]; - quad[0].fPos = pts[0] + normal; - quad[1].fPos = pts[0] - normal; - quad[2].fPos = pts[1] - normal; - quad[3].fPos = pts[2] - normal; - quad[4].fPos = pts[2] + normal; - for (int i = 0; i < kQuadNumVertices; i++) { - quad[i].fWinding = cross < 0 ? 1 : -1; - if (cross > 0.0) { - quad[i].fVert2 = pts[0]; - quad[i].fVert3 = pts[2]; - } - else { - quad[i].fVert2 = pts[2]; - quad[i].fVert3 = pts[0]; - } - } - GrPathUtils::QuadUVMatrix DevToUV(pts); - DevToUV.apply<kQuadNumVertices, sizeof(PLSVertex), sizeof(SkPoint)>(quad); - for (int i = 2; i < kQuadNumVertices; i++) { - vertices.push_back(quad[0]); - vertices.push_back(quad[i - 1]); - vertices.push_back(quad[i]); - } -} - -/* Used by bloat_tri; outsets a single point. */ -static bool outset(SkPoint* p1, SkPoint line1, SkPoint line2) { - // rotate the two line vectors 90 degrees to form the normals, and compute - // the dot product of the normals - SkScalar dotProd = line1.fY * line2.fY + line1.fX * line2.fX; - SkScalar lengthSq = 1.0f / ((1.0f - dotProd) / 2.0f); - if (lengthSq > kBloatLimit) { - return false; - } - SkPoint bisector = line1 + line2; - bisector.setLength(SkScalarSqrt(lengthSq) * kBloatSize); - *p1 += bisector; - return true; -} - -/* Bloats a triangle so as to create a border kBloatSize pixels wide all around it. */ -static bool bloat_tri(SkPoint pts[3]) { - SkPoint line1 = pts[0] - pts[1]; - line1.normalize(); - SkPoint line2 = pts[0] - pts[2]; - line2.normalize(); - SkPoint line3 = pts[1] - pts[2]; - line3.normalize(); - - SkPoint result[3]; - result[0] = pts[0]; - if (!outset(&result[0], line1, line2)) { - return false; - } - result[1] = pts[1]; - if (!outset(&result[1], -line1, line3)) { - return false; - } - result[2] = pts[2]; - if (!outset(&result[2], -line3, -line2)) { - return false; - } - pts[0] = result[0]; - pts[1] = result[1]; - pts[2] = result[2]; - return true; -} - -static bool get_geometry(const SkPath& path, const SkMatrix& m, PLSVertices& triVertices, - PLSVertices& quadVertices, GrResourceProvider* resourceProvider, - SkRect bounds) { - SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; - SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, m, bounds); - int contourCnt; - int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); - if (maxPts <= 0) { - return 0; - } - SkPath linesOnlyPath; - linesOnlyPath.setFillType(path.getFillType()); - SkSTArray<15, SkPoint, true> quadPoints; - SkPath::Iter iter(path, true); - bool done = false; - while (!done) { - SkPoint pts[4]; - SkPath::Verb verb = iter.next(pts); - switch (verb) { - case SkPath::kMove_Verb: - SkASSERT(quadPoints.count() % 3 == 0); - for (int i = 0; i < quadPoints.count(); i += 3) { - add_quad(&quadPoints[i], quadVertices); - } - quadPoints.reset(); - m.mapPoints(&pts[0], 1); - linesOnlyPath.moveTo(pts[0]); - break; - case SkPath::kLine_Verb: - m.mapPoints(&pts[1], 1); - linesOnlyPath.lineTo(pts[1]); - break; - case SkPath::kQuad_Verb: - m.mapPoints(pts, 3); - linesOnlyPath.lineTo(pts[2]); - quadPoints.push_back(pts[0]); - quadPoints.push_back(pts[1]); - quadPoints.push_back(pts[2]); - break; - case SkPath::kCubic_Verb: { - m.mapPoints(pts, 4); - SkSTArray<15, SkPoint, true> quads; - GrPathUtils::convertCubicToQuads(pts, kCubicTolerance, &quads); - int count = quads.count(); - for (int q = 0; q < count; q += 3) { - linesOnlyPath.lineTo(quads[q + 2]); - quadPoints.push_back(quads[q]); - quadPoints.push_back(quads[q + 1]); - quadPoints.push_back(quads[q + 2]); - } - break; - } - case SkPath::kConic_Verb: { - m.mapPoints(pts, 3); - SkScalar weight = iter.conicWeight(); - SkAutoConicToQuads converter; - const SkPoint* quads = converter.computeQuads(pts, weight, kConicTolerance); - int count = converter.countQuads(); - for (int i = 0; i < count; ++i) { - linesOnlyPath.lineTo(quads[2 * i + 2]); - quadPoints.push_back(quads[2 * i]); - quadPoints.push_back(quads[2 * i + 1]); - quadPoints.push_back(quads[2 * i + 2]); - } - break; - } - case SkPath::kClose_Verb: - linesOnlyPath.close(); - break; - case SkPath::kDone_Verb: - done = true; - break; - default: SkASSERT(false); - } - } - SkASSERT(quadPoints.count() % 3 == 0); - for (int i = 0; i < quadPoints.count(); i += 3) { - add_quad(&quadPoints[i], quadVertices); - } - - static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); - GrUniqueKey key; - GrUniqueKey::Builder builder(&key, kDomain, 2); - builder[0] = path.getGenerationID(); - builder[1] = path.getFillType(); - builder.finish(); - GrTessellator::WindingVertex* windingVertices; - int triVertexCount = GrTessellator::PathToVertices(linesOnlyPath, 0, bounds, &windingVertices); - if (triVertexCount > 0) { - for (int i = 0; i < triVertexCount; i += 3) { - SkPoint p1 = windingVertices[i].fPos; - SkPoint p2 = windingVertices[i + 1].fPos; - SkPoint p3 = windingVertices[i + 2].fPos; - int winding = windingVertices[i].fWinding; - SkASSERT(windingVertices[i + 1].fWinding == winding); - SkASSERT(windingVertices[i + 2].fWinding == winding); - SkScalar cross = (p2 - p1).cross(p3 - p1); - SkPoint bloated[3] = { p1, p2, p3 }; - if (cross < 0.0f) { - SkTSwap(p1, p3); - } - if (bloat_tri(bloated)) { - triVertices.push_back({ bloated[0], p1, p2, p3, winding }); - triVertices.push_back({ bloated[1], p1, p2, p3, winding }); - triVertices.push_back({ bloated[2], p1, p2, p3, winding }); - } - else { - SkScalar minX = SkTMin(p1.fX, SkTMin(p2.fX, p3.fX)) - 1.0f; - SkScalar minY = SkTMin(p1.fY, SkTMin(p2.fY, p3.fY)) - 1.0f; - SkScalar maxX = SkTMax(p1.fX, SkTMax(p2.fX, p3.fX)) + 1.0f; - SkScalar maxY = SkTMax(p1.fY, SkTMax(p2.fY, p3.fY)) + 1.0f; - triVertices.push_back({ { minX, minY }, p1, p2, p3, winding }); - triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); - triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); - triVertices.push_back({ { maxX, minY }, p1, p2, p3, winding }); - triVertices.push_back({ { maxX, maxY }, p1, p2, p3, winding }); - triVertices.push_back({ { minX, maxY }, p1, p2, p3, winding }); - } - } - delete[] windingVertices; - } - return triVertexCount > 0 || quadVertices.count() > 0; -} - -class PLSAATriangleEffect : public GrPLSGeometryProcessor { -public: - - static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, - bool usesLocalCoords) { - return new PLSAATriangleEffect(localMatrix, usesLocalCoords); - } - - virtual ~PLSAATriangleEffect() {} - - const char* name() const override { return "PLSAATriangle"; } - - const Attribute* inPosition() const { return fInPosition; } - const Attribute* inVertex1() const { return fInVertex1; } - const Attribute* inVertex2() const { return fInVertex2; } - const Attribute* inVertex3() const { return fInVertex3; } - const Attribute* inWindings() const { return fInWindings; } - const SkMatrix& localMatrix() const { return fLocalMatrix; } - bool usesLocalCoords() const { return fUsesLocalCoords; } - - class GLSLProcessor : public GrGLSLGeometryProcessor { - public: - GLSLProcessor(const GrGeometryProcessor&) {} - - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { - const PLSAATriangleEffect& te = args.fGP.cast<PLSAATriangleEffect>(); - GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; - GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - varyingHandler->emitAttributes(te); - - this->setupPosition(vsBuilder, gpArgs, te.inPosition()->fName); - - GrGLSLVertToFrag v1(kVec2f_GrSLType); - varyingHandler->addVarying("Vertex1", &v1, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", - v1.vsOut(), - te.inVertex1()->fName, - te.inVertex1()->fName); - - GrGLSLVertToFrag v2(kVec2f_GrSLType); - varyingHandler->addVarying("Vertex2", &v2, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", - v2.vsOut(), - te.inVertex2()->fName, - te.inVertex2()->fName); - - GrGLSLVertToFrag v3(kVec2f_GrSLType); - varyingHandler->addVarying("Vertex3", &v3, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", - v3.vsOut(), - te.inVertex3()->fName, - te.inVertex3()->fName); - - GrGLSLVertToFrag delta1(kVec2f_GrSLType); - varyingHandler->addVarying("delta1", &delta1, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta1.vsOut(), v1.vsOut(), v2.vsOut(), v2.vsOut(), v1.vsOut()); - - GrGLSLVertToFrag delta2(kVec2f_GrSLType); - varyingHandler->addVarying("delta2", &delta2, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta2.vsOut(), v2.vsOut(), v3.vsOut(), v3.vsOut(), v2.vsOut()); - - GrGLSLVertToFrag delta3(kVec2f_GrSLType); - varyingHandler->addVarying("delta3", &delta3, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta3.vsOut(), v3.vsOut(), v1.vsOut(), v1.vsOut(), v3.vsOut()); - - GrGLSLVertToFrag windings(kInt_GrSLType); - varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", - windings.vsOut(), te.inWindings()->fName); - - // emit transforms - this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, - te.inPosition()->fName, te.localMatrix(), - args.fFPCoordTransformHandler); - - GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder; - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); - fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); - // Compute four subsamples, each shifted a quarter pixel along x and y from - // gl_FragCoord. The oriented box positioning of the subsamples is of course not - // optimal, but it greatly simplifies the math and this simplification is necessary for - // performance reasons. - fsBuilder->codeAppendf("highp vec2 firstSample = sk_FragCoord.xy - vec2(0.25);"); - fsBuilder->codeAppendf("highp vec2 delta1 = %s;", delta1.fsIn()); - fsBuilder->codeAppendf("highp vec2 delta2 = %s;", delta2.fsIn()); - fsBuilder->codeAppendf("highp vec2 delta3 = %s;", delta3.fsIn()); - // Check whether first sample is inside the triangle by computing three dot products. If - // all are < 0, we're inside. The first vector in each case is half of what it is - // "supposed" to be, because we re-use them later as adjustment factors for which half - // is the correct value, so we multiply the dots by two to compensate. - fsBuilder->codeAppendf("highp float d1 = dot(delta1, (firstSample - %s).yx) * 2.0;", - v1.fsIn()); - fsBuilder->codeAppendf("highp float d2 = dot(delta2, (firstSample - %s).yx) * 2.0;", - v2.fsIn()); - fsBuilder->codeAppendf("highp float d3 = dot(delta3, (firstSample - %s).yx) * 2.0;", - v3.fsIn()); - fsBuilder->codeAppend("highp float dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[0] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - // for subsequent samples, we don't recalculate the entire dot product -- just adjust it - // to the value it would have if we did recompute it. - fsBuilder->codeAppend("d1 += delta1.x;"); - fsBuilder->codeAppend("d2 += delta2.x;"); - fsBuilder->codeAppend("d3 += delta3.x;"); - fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[1] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - fsBuilder->codeAppend("d1 += delta1.y;"); - fsBuilder->codeAppend("d2 += delta2.y;"); - fsBuilder->codeAppend("d3 += delta3.y;"); - fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[2] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - fsBuilder->codeAppend("d1 -= delta1.x;"); - fsBuilder->codeAppend("d2 -= delta2.x;"); - fsBuilder->codeAppend("d3 -= delta3.x;"); - fsBuilder->codeAppend("dmax = max(d1, max(d2, d3));"); - fsBuilder->codeAppendf("pls.windings[3] += (dmax <= 0.0) ? %s : 0;", windings.fsIn()); - } - - static inline void GenKey(const GrGeometryProcessor& gp, - const GrShaderCaps&, - GrProcessorKeyBuilder* b) { - const PLSAATriangleEffect& te = gp.cast<PLSAATriangleEffect>(); - uint32_t key = 0; - key |= te.localMatrix().hasPerspective() ? 0x1 : 0x0; - b->add32(key); - } - - void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, - FPCoordTransformIter&& transformIter) override { - this->setTransformDataHelper(gp.cast<PLSAATriangleEffect>().fLocalMatrix, pdman, - &transformIter); - } - - private: - typedef GrGLSLGeometryProcessor INHERITED; - }; - - virtual void getGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const override { - GLSLProcessor::GenKey(*this, caps, b); - } - - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { - return new GLSLProcessor(*this); - } - -private: - PLSAATriangleEffect(const SkMatrix& localMatrix, bool usesLocalCoords) - : fLocalMatrix(localMatrix) - , fUsesLocalCoords(usesLocalCoords) { - this->initClassID<PLSAATriangleEffect>(); - fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInVertex1 = &this->addVertexAttrib("inVertex1", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInVertex2 = &this->addVertexAttrib("inVertex2", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInVertex3 = &this->addVertexAttrib("inVertex3", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInWindings = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType, - kLow_GrSLPrecision); - } - - const Attribute* fInPosition; - const Attribute* fInVertex1; - const Attribute* fInVertex2; - const Attribute* fInVertex3; - const Attribute* fInWindings; - SkMatrix fLocalMatrix; - bool fUsesLocalCoords; - - GR_DECLARE_GEOMETRY_PROCESSOR_TEST; - - typedef GrGeometryProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -/* - * Quadratic specified by 0=u^2-v canonical coords. u and v are the first - * two components of the vertex attribute. Coverage is based on signed - * distance with negative being inside, positive outside. The edge is specified in - * window space (y-down). If either the third or fourth component of the interpolated - * vertex coord is > 0 then the pixel is considered outside the edge. This is used to - * attempt to trim to a portion of the infinite quad. - * Requires shader derivative instruction support. - */ - -class PLSQuadEdgeEffect : public GrPLSGeometryProcessor { -public: - - static GrPLSGeometryProcessor* Create(const SkMatrix& localMatrix, - bool usesLocalCoords) { - return new PLSQuadEdgeEffect(localMatrix, usesLocalCoords); - } - - virtual ~PLSQuadEdgeEffect() {} - - const char* name() const override { return "PLSQuadEdge"; } - - const Attribute* inPosition() const { return fInPosition; } - const Attribute* inUV() const { return fInUV; } - const Attribute* inEndpoint1() const { return fInEndpoint1; } - const Attribute* inEndpoint2() const { return fInEndpoint2; } - const Attribute* inWindings() const { return fInWindings; } - const SkMatrix& localMatrix() const { return fLocalMatrix; } - bool usesLocalCoords() const { return fUsesLocalCoords; } - - class GLSLProcessor : public GrGLSLGeometryProcessor { - public: - GLSLProcessor(const GrGeometryProcessor&) {} - - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { - const PLSQuadEdgeEffect& qe = args.fGP.cast<PLSQuadEdgeEffect>(); - GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; - GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - // emit attributes - varyingHandler->emitAttributes(qe); - - GrGLSLVertToFrag uv(kVec2f_GrSLType); - varyingHandler->addVarying("uv", &uv, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", uv.vsOut(), qe.inUV()->fName); - - GrGLSLVertToFrag ep1(kVec2f_GrSLType); - varyingHandler->addVarying("endpoint1", &ep1, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep1.vsOut(), - qe.inEndpoint1()->fName, qe.inEndpoint1()->fName); - - GrGLSLVertToFrag ep2(kVec2f_GrSLType); - varyingHandler->addVarying("endpoint2", &ep2, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x, %s.y);", ep2.vsOut(), - qe.inEndpoint2()->fName, qe.inEndpoint2()->fName); - - GrGLSLVertToFrag delta(kVec2f_GrSLType); - varyingHandler->addVarying("delta", &delta, kHigh_GrSLPrecision); - vsBuilder->codeAppendf("%s = vec2(%s.x - %s.x, %s.y - %s.y) * 0.5;", - delta.vsOut(), ep1.vsOut(), ep2.vsOut(), ep2.vsOut(), - ep1.vsOut()); - - GrGLSLVertToFrag windings(kInt_GrSLType); - varyingHandler->addFlatVarying("windings", &windings, kLow_GrSLPrecision); - vsBuilder->codeAppendf("%s = %s;", - windings.vsOut(), qe.inWindings()->fName); - - // Setup position - this->setupPosition(vsBuilder, gpArgs, qe.inPosition()->fName); - - // emit transforms - this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, - qe.inPosition()->fName, qe.localMatrix(), - args.fFPCoordTransformHandler); - - GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder; - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); - static const int QUAD_ARGS = 2; - GrShaderVar inQuadArgs[QUAD_ARGS] = { - GrShaderVar("dot", kFloat_GrSLType, 0, kHigh_GrSLPrecision), - GrShaderVar("uv", kVec2f_GrSLType, 0, kHigh_GrSLPrecision) - }; - SkString inQuadName; - - const char* inQuadCode = "if (uv.x * uv.x <= uv.y) {" - "return dot >= 0.0;" - "} else {" - "return false;" - "}"; - fsBuilder->emitFunction(kBool_GrSLType, "in_quad", QUAD_ARGS, inQuadArgs, inQuadCode, - &inQuadName); - fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); - // keep the derivative instructions outside the conditional - fsBuilder->codeAppendf("highp vec2 uvdX = dFdx(%s);", uv.fsIn()); - fsBuilder->codeAppendf("highp vec2 uvdY = dFdy(%s);", uv.fsIn()); - fsBuilder->codeAppend("highp vec2 uvIncX = uvdX * 0.45 + uvdY * -0.1;"); - fsBuilder->codeAppend("highp vec2 uvIncY = uvdX * 0.1 + uvdY * 0.55;"); - fsBuilder->codeAppendf("highp vec2 uv = %s.xy - uvdX * 0.35 - uvdY * 0.25;", - uv.fsIn()); - fsBuilder->codeAppendf("highp vec2 firstSample = sk_FragCoord.xy - vec2(0.25);"); - fsBuilder->codeAppendf("highp float d = dot(%s, (firstSample - %s).yx) * 2.0;", - delta.fsIn(), ep1.fsIn()); - fsBuilder->codeAppendf("pls.windings[0] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - fsBuilder->codeAppend("uv += uvIncX;"); - fsBuilder->codeAppendf("d += %s.x;", delta.fsIn()); - fsBuilder->codeAppendf("pls.windings[1] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - fsBuilder->codeAppend("uv += uvIncY;"); - fsBuilder->codeAppendf("d += %s.y;", delta.fsIn()); - fsBuilder->codeAppendf("pls.windings[2] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - fsBuilder->codeAppend("uv -= uvIncX;"); - fsBuilder->codeAppendf("d -= %s.x;", delta.fsIn()); - fsBuilder->codeAppendf("pls.windings[3] += %s(d, uv) ? %s : 0;", inQuadName.c_str(), - windings.fsIn()); - } - - static inline void GenKey(const GrGeometryProcessor& gp, - const GrShaderCaps&, - GrProcessorKeyBuilder* b) { - const PLSQuadEdgeEffect& qee = gp.cast<PLSQuadEdgeEffect>(); - uint32_t key = 0; - key |= qee.usesLocalCoords() && qee.localMatrix().hasPerspective() ? 0x1 : 0x0; - b->add32(key); - } - - void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, - FPCoordTransformIter&& transformIter) override { - this->setTransformDataHelper(gp.cast<PLSQuadEdgeEffect>().fLocalMatrix, pdman, - &transformIter); - } - - private: - typedef GrGLSLGeometryProcessor INHERITED; - }; - - virtual void getGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const override { - GLSLProcessor::GenKey(*this, caps, b); - } - - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { - return new GLSLProcessor(*this); - } - -private: - PLSQuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords) - : fLocalMatrix(localMatrix) - , fUsesLocalCoords(usesLocalCoords) { - this->initClassID<PLSQuadEdgeEffect>(); - fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInUV = &this->addVertexAttrib("inUV", kVec2f_GrVertexAttribType, kHigh_GrSLPrecision); - fInEndpoint1 = &this->addVertexAttrib("inEndpoint1", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInEndpoint2 = &this->addVertexAttrib("inEndpoint2", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - fInWindings = &this->addVertexAttrib("inWindings", kInt_GrVertexAttribType, - kLow_GrSLPrecision); - } - - const Attribute* fInPosition; - const Attribute* fInUV; - const Attribute* fInEndpoint1; - const Attribute* fInEndpoint2; - const Attribute* fInWindings; - SkMatrix fLocalMatrix; - bool fUsesLocalCoords; - - GR_DECLARE_GEOMETRY_PROCESSOR_TEST; - - typedef GrGeometryProcessor INHERITED; -}; - -class PLSFinishEffect : public GrGeometryProcessor { -public: - - static GrGeometryProcessor* Create(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix, - bool usesLocalCoords) { - return new PLSFinishEffect(color, useEvenOdd, localMatrix, usesLocalCoords); - } - - virtual ~PLSFinishEffect() {} - - const char* name() const override { return "PLSFinish"; } - - const Attribute* inPosition() const { return fInPosition; } - GrColor color() const { return fColor; } - const SkMatrix& localMatrix() const { return fLocalMatrix; } - bool usesLocalCoords() const { return fUsesLocalCoords; } - - GrPixelLocalStorageState getPixelLocalStorageState() const override { - return GrPixelLocalStorageState::kFinish_GrPixelLocalStorageState; - } - - const char* getDestColorOverride() const override { - return GR_GL_PLS_DSTCOLOR_NAME; - } - - class GLSLProcessor : public GrGLSLGeometryProcessor { - public: - GLSLProcessor(const GrGeometryProcessor&) {} - - void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { - const PLSFinishEffect& fe = args.fGP.cast<PLSFinishEffect>(); - GrGLSLVertexBuilder* vsBuilder = args.fVertBuilder; - GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - - fUseEvenOdd = uniformHandler->addUniform(kFragment_GrShaderFlag, - kFloat_GrSLType, kLow_GrSLPrecision, - "useEvenOdd"); - const char* useEvenOdd = uniformHandler->getUniformCStr(fUseEvenOdd); - - varyingHandler->emitAttributes(fe); - this->setupPosition(vsBuilder, gpArgs, fe.inPosition()->fName); - this->emitTransforms(vsBuilder, varyingHandler, uniformHandler, gpArgs->fPositionVar, - fe.inPosition()->fName, fe.localMatrix(), - args.fFPCoordTransformHandler); - - GrGLSLPPFragmentBuilder* fsBuilder = args.fFragBuilder; - SkAssertResult(fsBuilder->enableFeature( - GrGLSLFragmentShaderBuilder::kPixelLocalStorage_GLSLFeature)); - fsBuilder->declAppendf(GR_GL_PLS_PATH_DATA_DECL); - fsBuilder->codeAppend("float coverage;"); - fsBuilder->codeAppendf("if (%s != 0.0) {", useEvenOdd); - fsBuilder->codeAppend("coverage = float(abs(pls.windings[0]) % 2) * 0.25;"); - fsBuilder->codeAppend("coverage += float(abs(pls.windings[1]) % 2) * 0.25;"); - fsBuilder->codeAppend("coverage += float(abs(pls.windings[2]) % 2) * 0.25;"); - fsBuilder->codeAppend("coverage += float(abs(pls.windings[3]) % 2) * 0.25;"); - fsBuilder->codeAppend("} else {"); - fsBuilder->codeAppend("coverage = pls.windings[0] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("coverage += pls.windings[1] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("coverage += pls.windings[2] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("coverage += pls.windings[3] != 0 ? 0.25 : 0.0;"); - fsBuilder->codeAppend("}"); - this->setupUniformColor(fsBuilder, uniformHandler, args.fOutputColor, - &fColorUniform); - fsBuilder->codeAppendf("%s = vec4(coverage);", args.fOutputCoverage); - fsBuilder->codeAppendf("%s = vec4(1.0, 0.0, 1.0, 1.0);", args.fOutputColor); - } - - static inline void GenKey(const GrGeometryProcessor& gp, - const GrShaderCaps&, - GrProcessorKeyBuilder* b) { - const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>(); - uint32_t key = 0; - key |= fe.usesLocalCoords() && fe.localMatrix().hasPerspective() ? 0x1 : 0x0; - b->add32(key); - } - - void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, - FPCoordTransformIter&& transformIter) override { - const PLSFinishEffect& fe = gp.cast<PLSFinishEffect>(); - pdman.set1f(fUseEvenOdd, fe.fUseEvenOdd); - if (fe.color() != fColor) { - GrGLfloat c[4]; - GrColorToRGBAFloat(fe.color(), c); - pdman.set4fv(fColorUniform, 1, c); - fColor = fe.color(); - } - this->setTransformDataHelper(fe.fLocalMatrix, pdman, &transformIter); - } - - private: - GrColor fColor; - UniformHandle fColorUniform; - UniformHandle fUseEvenOdd; - - typedef GrGLSLGeometryProcessor INHERITED; - }; - - virtual void getGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const override { - GLSLProcessor::GenKey(*this, caps, b); - } - - virtual GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override { - return new GLSLProcessor(*this); - } - -private: - PLSFinishEffect(GrColor color, bool useEvenOdd, const SkMatrix& localMatrix, - bool usesLocalCoords) - : fColor(color) - , fUseEvenOdd(useEvenOdd) - , fLocalMatrix(localMatrix) - , fUsesLocalCoords(usesLocalCoords) { - this->initClassID<PLSFinishEffect>(); - fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttribType, - kHigh_GrSLPrecision); - } - - const Attribute* fInPosition; - GrColor fColor; - bool fUseEvenOdd; - SkMatrix fLocalMatrix; - bool fUsesLocalCoords; - - typedef GrGeometryProcessor INHERITED; -}; - -/////////////////////////////////////////////////////////////////////////////// - -bool GrPLSPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const { - // We have support for even-odd rendering, but are having some troublesome - // seams. Disable in the presence of even-odd for now. - SkPath path; - args.fShape->asPath(&path); - return args.fShaderCaps->shaderDerivativeSupport() && GrAAType::kCoverage == args.fAAType && - args.fShape->style().isSimpleFill() && !path.isInverseFillType() && - path.getFillType() == SkPath::FillType::kWinding_FillType; -} - -class PLSPathOp final : public GrMeshDrawOp { -public: - DEFINE_OP_CLASS_ID - static std::unique_ptr<GrDrawOp> Make(GrColor color, const SkPath& path, - const SkMatrix& viewMatrix) { - return std::unique_ptr<GrDrawOp>(new PLSPathOp(color, path, viewMatrix)); - } - - const char* name() const override { return "PLSPathOp"; } - - SkString dumpInfo() const override { - SkString string; - string.printf("Color 0x%08x, UsesLocalCoords: %d\n", fColor, fUsesLocalCoords); - string.append(DumpPipelineInfo(*this->pipeline())); - string.append(INHERITED::dumpInfo()); - return string; - } - -private: - PLSPathOp(GrColor color, const SkPath& path, const SkMatrix& viewMatrix) - : INHERITED(ClassID()), fColor(color), fPath(path), fViewMatrix(viewMatrix) { - // compute bounds - this->setTransformedBounds(path.getBounds(), fViewMatrix, HasAABloat::kYes, - IsZeroArea::kNo); - } - - void getFragmentProcessorAnalysisInputs(FragmentProcessorAnalysisInputs* input) const override { - input->colorInput()->setToConstant(fColor); - input->coverageInput()->setToUnknown(); - input->setUsesPLSDstRead(); - } - - void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override { - optimizations.getOverrideColorIfSet(&fColor); - - fUsesLocalCoords = optimizations.readsLocalCoords(); - } - - void onPrepareDraws(Target* target) const override { - - SkMatrix invert; - if (fUsesLocalCoords && !fViewMatrix.invert(&invert)) { - SkDebugf("Could not invert viewmatrix\n"); - return; - } - - // Setup GrGeometryProcessors - sk_sp<GrPLSGeometryProcessor> triangleProcessor( - PLSAATriangleEffect::Create(invert, fUsesLocalCoords)); - sk_sp<GrPLSGeometryProcessor> quadProcessor( - PLSQuadEdgeEffect::Create(invert, fUsesLocalCoords)); - - GrResourceProvider* rp = target->resourceProvider(); - SkRect bounds; - this->bounds().roundOut(&bounds); - triangleProcessor->setBounds(bounds); - quadProcessor->setBounds(bounds); - - // We use the fact that SkPath::transform path does subdivision based on - // perspective. Otherwise, we apply the view matrix when copying to the - // segment representation. - const SkMatrix* viewMatrix = &fViewMatrix; - - // We avoid initializing the path unless we have to - const SkPath* pathPtr = &fPath; - SkTLazy<SkPath> tmpPath; - if (viewMatrix->hasPerspective()) { - SkPath* tmpPathPtr = tmpPath.init(*pathPtr); - tmpPathPtr->setIsVolatile(true); - tmpPathPtr->transform(*viewMatrix); - viewMatrix = &SkMatrix::I(); - pathPtr = tmpPathPtr; - } - - GrMesh mesh; - - PLSVertices triVertices; - PLSVertices quadVertices; - if (!get_geometry(*pathPtr, *viewMatrix, triVertices, quadVertices, rp, bounds)) { - return; - } - - if (triVertices.count()) { - const GrBuffer* triVertexBuffer; - int firstTriVertex; - size_t triStride = triangleProcessor->getVertexStride(); - PLSVertex* triVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace( - triStride, triVertices.count(), &triVertexBuffer, &firstTriVertex)); - if (!triVerts) { - SkDebugf("Could not allocate vertices\n"); - return; - } - for (int i = 0; i < triVertices.count(); ++i) { - triVerts[i] = triVertices[i]; - } - mesh.init(kTriangles_GrPrimitiveType, triVertexBuffer, firstTriVertex, - triVertices.count()); - target->draw(triangleProcessor.get(), mesh); - } - - if (quadVertices.count()) { - const GrBuffer* quadVertexBuffer; - int firstQuadVertex; - size_t quadStride = quadProcessor->getVertexStride(); - PLSVertex* quadVerts = reinterpret_cast<PLSVertex*>(target->makeVertexSpace( - quadStride, quadVertices.count(), &quadVertexBuffer, &firstQuadVertex)); - if (!quadVerts) { - SkDebugf("Could not allocate vertices\n"); - return; - } - for (int i = 0; i < quadVertices.count(); ++i) { - quadVerts[i] = quadVertices[i]; - } - mesh.init(kTriangles_GrPrimitiveType, quadVertexBuffer, firstQuadVertex, - quadVertices.count()); - target->draw(quadProcessor.get(), mesh); - } - - sk_sp<GrGeometryProcessor> finishProcessor( - PLSFinishEffect::Create(fColor, - pathPtr->getFillType() == - SkPath::FillType::kEvenOdd_FillType, - invert, - fUsesLocalCoords)); - const GrBuffer* rectVertexBuffer; - size_t finishStride = finishProcessor->getVertexStride(); - int firstRectVertex; - static const int kRectVertexCount = 6; - SkPoint* rectVerts = reinterpret_cast<SkPoint*>(target->makeVertexSpace( - finishStride, kRectVertexCount, &rectVertexBuffer, &firstRectVertex)); - if (!rectVerts) { - SkDebugf("Could not allocate vertices\n"); - return; - } - rectVerts[0] = { bounds.fLeft, bounds.fTop }; - rectVerts[1] = { bounds.fLeft, bounds.fBottom }; - rectVerts[2] = { bounds.fRight, bounds.fBottom }; - rectVerts[3] = { bounds.fLeft, bounds.fTop }; - rectVerts[4] = { bounds.fRight, bounds.fTop }; - rectVerts[5] = { bounds.fRight, bounds.fBottom }; - - mesh.init(kTriangles_GrPrimitiveType, rectVertexBuffer, firstRectVertex, - kRectVertexCount); - target->draw(finishProcessor.get(), mesh); - } - - bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { - return false; - } - - bool fUsesLocalCoords; - - GrColor fColor; - SkPath fPath; - SkMatrix fViewMatrix; - typedef GrMeshDrawOp INHERITED; -}; - -SkDEBUGCODE(bool inPLSDraw = false;) -bool GrPLSPathRenderer::onDrawPath(const DrawPathArgs& args) { - SkASSERT(!args.fShape->isEmpty()); - SkASSERT(!inPLSDraw); - SkDEBUGCODE(inPLSDraw = true;) - SkPath path; - args.fShape->asPath(&path); - - std::unique_ptr<GrDrawOp> op = PLSPathOp::Make(args.fPaint.getColor(), path, *args.fViewMatrix); - GrPipelineBuilder pipelineBuilder(std::move(args.fPaint), args.fAAType); - pipelineBuilder.setUserStencil(args.fUserStencilSettings); - - args.fRenderTargetContext->addDrawOp(pipelineBuilder, *args.fClip, std::move(op)); - SkDEBUGCODE(inPLSDraw = false;) - return true; - -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#if GR_TEST_UTILS - -DRAW_OP_TEST_DEFINE(PLSPathOp) { - GrColor color = GrRandomColor(random); - SkMatrix vm = GrTest::TestMatrixInvertible(random); - SkPath path = GrTest::TestPathConvex(random); - - return PLSPathOp::Make(color, path, vm); -} - -#endif diff --git a/src/gpu/ops/GrPLSPathRenderer.h b/src/gpu/ops/GrPLSPathRenderer.h deleted file mode 100644 index 39f21ba68c..0000000000 --- a/src/gpu/ops/GrPLSPathRenderer.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrPLSPathRenderer_DEFINED -#define GrPLSPathRenderer_DEFINED - -#include "GrPathRenderer.h" - -/* - * Renders arbitrary antialiased paths using pixel local storage as a scratch buffer. The overall - * technique is very similar to the approach presented in "Resolution independent rendering of - * deformable vector objects using graphics hardware" by Kokojima et al. - - * We first render the straight-line portions of the path (essentially pretending as if all segments - * were kLine_Verb) as a triangle fan, using a fragment shader which updates the winding counts - * appropriately. We then render the curved portions of the path using a Loop-Blinn shader which - * calculates which portion of the triangle is covered by the quad (conics and cubics are split down - * to quads). Where we diverge from Kokojima is that, instead of rendering into the stencil buffer - * and using built-in MSAA to handle straight-line antialiasing, we use the pixel local storage area - * and calculate the MSAA ourselves in the fragment shader. Essentially, we manually evaluate the - * coverage of each pixel four times, storing four winding counts into the pixel local storage area, - * and compute the final coverage based on those winding counts. - * - * Our approach is complicated by the need to perform antialiasing on straight edges as well, - * without relying on hardware MSAA. We instead bloat the triangles to ensure complete coverage, - * pass the original (un-bloated) vertices in to the fragment shader, and then have the fragment - * shader use these vertices to evaluate whether a given sample is located within the triangle or - * not. This gives us MSAA4 edges on triangles which line up nicely with no seams. We similarly face - * problems on the back (flat) edges of quads, where we have to ensure that the back edge is - * antialiased in the same way. Similar to the triangle case, we pass in the two (unbloated) - * vertices defining the back edge of the quad and the fragment shader uses these vertex coordinates - * to discard samples falling on the other side of the quad's back edge. - */ -class GrPLSPathRenderer : public GrPathRenderer { -public: - GrPLSPathRenderer(); - - bool onCanDrawPath(const CanDrawPathArgs& args) const override; - -protected: - bool onDrawPath(const DrawPathArgs& args) override; -}; - -#endif |