1/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "src/gpu/ccpr/GrCCClipProcessor.h"
9
10#include "src/gpu/ccpr/GrCCClipPath.h"
11#include "src/gpu/effects/GrTextureEffect.h"
12#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
13#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
14
15static GrSurfaceProxyView make_view(const GrCaps& caps, GrSurfaceProxy* proxy,
16 bool isCoverageCount) {
17 GrColorType ct = isCoverageCount ? GrColorType::kAlpha_F16 : GrColorType::kAlpha_8;
18 GrSwizzle swizzle = caps.getReadSwizzle(proxy->backendFormat(), ct);
19 return { sk_ref_sp(proxy), GrCCAtlas::kTextureOrigin, swizzle };
20}
21
22GrCCClipProcessor::GrCCClipProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
23 const GrCaps& caps,
24 const GrCCClipPath* clipPath,
25 IsCoverageCount isCoverageCount,
26 MustCheckBounds mustCheckBounds)
27 : INHERITED(kGrCCClipProcessor_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag)
28 , fClipPath(clipPath)
29 , fIsCoverageCount(IsCoverageCount::kYes == isCoverageCount)
30 , fMustCheckBounds(MustCheckBounds::kYes == mustCheckBounds) {
31 auto view = make_view(caps, clipPath->atlasLazyProxy(), fIsCoverageCount);
32 auto texEffect = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType);
33 this->registerChild(std::move(texEffect), SkSL::SampleUsage::Explicit());
34 this->registerChild(std::move(inputFP));
35}
36
37GrCCClipProcessor::GrCCClipProcessor(const GrCCClipProcessor& that)
38 : INHERITED(kGrCCClipProcessor_ClassID, that.optimizationFlags())
39 , fClipPath(that.fClipPath)
40 , fIsCoverageCount(that.fIsCoverageCount)
41 , fMustCheckBounds(that.fMustCheckBounds) {
42 this->cloneAndRegisterAllChildProcessors(that);
43}
44
45std::unique_ptr<GrFragmentProcessor> GrCCClipProcessor::clone() const {
46 return std::unique_ptr<GrFragmentProcessor>(new GrCCClipProcessor(*this));
47}
48
49void GrCCClipProcessor::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
50 const SkPath& clipPath = fClipPath->deviceSpacePath();
51 uint32_t key = (fIsCoverageCount) ? (uint32_t)GrFillRuleForSkPath(clipPath) : 0;
52 key = (key << 1) | ((clipPath.isInverseFillType()) ? 1 : 0);
53 key = (key << 1) | ((fMustCheckBounds) ? 1 : 0);
54 b->add32(key);
55}
56
57bool GrCCClipProcessor::onIsEqual(const GrFragmentProcessor& fp) const {
58 const GrCCClipProcessor& that = fp.cast<GrCCClipProcessor>();
59 return that.fClipPath->deviceSpacePath().getGenerationID() ==
60 fClipPath->deviceSpacePath().getGenerationID() &&
61 that.fClipPath->deviceSpacePath().getFillType() ==
62 fClipPath->deviceSpacePath().getFillType() &&
63 that.fIsCoverageCount == fIsCoverageCount && that.fMustCheckBounds == fMustCheckBounds;
64}
65
66class GrCCClipProcessor::Impl : public GrGLSLFragmentProcessor {
67public:
68 void emitCode(EmitArgs& args) override {
69 const GrCCClipProcessor& proc = args.fFp.cast<GrCCClipProcessor>();
70 GrGLSLUniformHandler* uniHandler = args.fUniformHandler;
71 GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
72
73 f->codeAppend("half coverage;");
74
75 if (proc.fMustCheckBounds) {
76 const char* pathIBounds;
77 fPathIBoundsUniform = uniHandler->addUniform(&proc, kFragment_GrShaderFlag,
78 kFloat4_GrSLType, "path_ibounds",
79 &pathIBounds);
80 f->codeAppendf("if (all(greaterThan(float4(sk_FragCoord.xy, %s.zw), "
81 "float4(%s.xy, sk_FragCoord.xy)))) {",
82 pathIBounds, pathIBounds);
83 }
84
85 const char* atlasTranslate;
86 fAtlasTranslateUniform = uniHandler->addUniform(&proc, kFragment_GrShaderFlag,
87 kFloat2_GrSLType, "atlas_translate",
88 &atlasTranslate);
89 SkString coord;
90 coord.printf("sk_FragCoord.xy + %s.xy", atlasTranslate);
91 constexpr int kTexEffectFPIndex = 0;
92 SkString sample = this->invokeChild(kTexEffectFPIndex, args, coord.c_str());
93 f->codeAppendf("coverage = %s.a;", sample.c_str());
94
95 if (proc.fIsCoverageCount) {
96 auto fillRule = GrFillRuleForSkPath(proc.fClipPath->deviceSpacePath());
97 if (GrFillRule::kEvenOdd == fillRule) {
98 f->codeAppend("half t = mod(abs(coverage), 2);");
99 f->codeAppend("coverage = 1 - abs(t - 1);");
100 } else {
101 SkASSERT(GrFillRule::kNonzero == fillRule);
102 f->codeAppend("coverage = min(abs(coverage), 1);");
103 }
104 }
105
106 if (proc.fMustCheckBounds) {
107 f->codeAppend("} else {");
108 f->codeAppend( "coverage = 0;");
109 f->codeAppend("}");
110 }
111
112 if (proc.fClipPath->deviceSpacePath().isInverseFillType()) {
113 f->codeAppend("coverage = 1 - coverage;");
114 }
115
116 constexpr int kInputFPIndex = 1;
117 SkString inputColor = this->invokeChild(kInputFPIndex, args);
118
119 f->codeAppendf("%s = %s * coverage;", args.fOutputColor, inputColor.c_str());
120 }
121
122 void onSetData(const GrGLSLProgramDataManager& pdman,
123 const GrFragmentProcessor& fp) override {
124 const GrCCClipProcessor& proc = fp.cast<GrCCClipProcessor>();
125 if (proc.fMustCheckBounds) {
126 const SkRect pathIBounds = SkRect::Make(proc.fClipPath->pathDevIBounds());
127 pdman.set4f(fPathIBoundsUniform, pathIBounds.left(), pathIBounds.top(),
128 pathIBounds.right(), pathIBounds.bottom());
129 }
130 const SkIVector& trans = proc.fClipPath->atlasTranslate();
131 pdman.set2f(fAtlasTranslateUniform, trans.x(), trans.y());
132 }
133
134private:
135 UniformHandle fPathIBoundsUniform;
136 UniformHandle fAtlasTranslateUniform;
137};
138
139GrGLSLFragmentProcessor* GrCCClipProcessor::onCreateGLSLInstance() const {
140 return new Impl();
141}
142