• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 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/GrStencilAtlasOp.h"
9 
10 #include "include/private/GrRecordingContext.h"
11 #include "src/gpu/GrOpFlushState.h"
12 #include "src/gpu/GrOpsRenderPass.h"
13 #include "src/gpu/GrProgramInfo.h"
14 #include "src/gpu/GrRecordingContextPriv.h"
15 #include "src/gpu/ccpr/GrCCPerFlushResources.h"
16 #include "src/gpu/ccpr/GrSampleMaskProcessor.h"
17 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
18 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
19 
20 namespace {
21 
22 class StencilResolveProcessor : public GrGeometryProcessor {
23 public:
StencilResolveProcessor()24     StencilResolveProcessor() : INHERITED(kStencilResolveProcessor_ClassID) {
25         static constexpr Attribute kIBounds = {
26                 "ibounds", kShort4_GrVertexAttribType, kShort4_GrSLType};
27         this->setInstanceAttributes(&kIBounds, 1);
28         SkASSERT(this->instanceStride() == sizeof(GrStencilAtlasOp::ResolveRectInstance));
29     }
30 
31 private:
name() const32     const char* name() const final { return "StencilResolveProcessor"; }
getGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const33     void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
34     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
35     class Impl;
36 
37     typedef GrGeometryProcessor INHERITED;
38 };
39 
40 // This processor draws pixel-aligned rectangles directly on top of every path in the atlas.
41 // The caller should have set up the instance data such that "Nonzero" paths get clockwise
42 // rectangles (l < r) and "even/odd" paths get counter-clockwise (r < l). Its purpose
43 // is to convert winding counts in the stencil buffer to A8 coverage in the color buffer.
44 class StencilResolveProcessor::Impl : public GrGLSLGeometryProcessor {
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)45     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
46         args.fVaryingHandler->emitAttributes(args.fGP.cast<StencilResolveProcessor>());
47 
48         GrGLSLVertexBuilder* v = args.fVertBuilder;
49         v->codeAppendf("short2 devcoord;");
50         v->codeAppendf("devcoord.x = (0 == (sk_VertexID & 1)) ? ibounds.x : ibounds.z;");
51         v->codeAppendf("devcoord.y = (sk_VertexID < 2) ? ibounds.y : ibounds.w;");
52 
53         v->codeAppendf("float2 atlascoord = float2(devcoord);");
54         gpArgs->fPositionVar.set(kFloat2_GrSLType, "atlascoord");
55 
56         // Just output "1" for coverage. This will be modulated by the MSAA stencil test.
57         GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
58         f->codeAppendf("%s = %s = half4(1);", args.fOutputColor, args.fOutputCoverage);
59     }
60 
setData(const GrGLSLProgramDataManager &,const GrPrimitiveProcessor &,const CoordTransformRange &)61     void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&,
62                  const CoordTransformRange&) override {}
63 };
64 
createGLSLInstance(const GrShaderCaps &) const65 GrGLSLPrimitiveProcessor* StencilResolveProcessor::createGLSLInstance(const GrShaderCaps&) const {
66     return new Impl();
67 }
68 
69 }
70 
Make(GrRecordingContext * context,sk_sp<const GrCCPerFlushResources> resources,FillBatchID fillBatchID,StrokeBatchID strokeBatchID,int baseStencilResolveInstance,int endStencilResolveInstance,const SkISize & drawBounds)71 std::unique_ptr<GrDrawOp> GrStencilAtlasOp::Make(
72         GrRecordingContext* context, sk_sp<const GrCCPerFlushResources> resources,
73         FillBatchID fillBatchID, StrokeBatchID strokeBatchID, int baseStencilResolveInstance,
74         int endStencilResolveInstance, const SkISize& drawBounds) {
75     GrOpMemoryPool* pool = context->priv().opMemoryPool();
76 
77     return pool->allocate<GrStencilAtlasOp>(
78             std::move(resources), fillBatchID, strokeBatchID, baseStencilResolveInstance,
79             endStencilResolveInstance, drawBounds);
80 }
81 
82 // Increments clockwise triangles and decrements counterclockwise. We use the same incr/decr
83 // settings regardless of fill rule; fill rule is accounted for during the resolve step.
84 static constexpr GrUserStencilSettings kIncrDecrStencil(
85     GrUserStencilSettings::StaticInitSeparate<
86         0x0000,                        0x0000,
87         GrUserStencilTest::kNever,     GrUserStencilTest::kNever,
88         0xffff,                        0xffff,
89         GrUserStencilOp::kIncWrap,     GrUserStencilOp::kDecWrap,
90         GrUserStencilOp::kIncWrap,     GrUserStencilOp::kDecWrap,
91         0xffff,                        0xffff>()
92 );
93 
94 // Resolves stencil winding counts to A8 coverage. Leaves stencil values untouched.
95 // NOTE: For the CCW face we intentionally use "1 == (stencil & 1)" because the contrapositive logic
96 // (i.e. 0 != ...) causes bugs on Adreno Vulkan. http://skbug.com/9643
97 static constexpr GrUserStencilSettings kResolveStencilCoverage(
98     GrUserStencilSettings::StaticInitSeparate<
99         0x0000,                           0x0001,
100         GrUserStencilTest::kNotEqual,     GrUserStencilTest::kEqual,
101         0xffff,                           0x0001,
102         GrUserStencilOp::kKeep,           GrUserStencilOp::kKeep,
103         GrUserStencilOp::kKeep,           GrUserStencilOp::kKeep,
104         0xffff,                           0xffff>()
105 );
106 
107 // Same as above, but also resets stencil values to zero. This is better for non-tilers
108 // where we prefer to not clear the stencil buffer at the beginning of every render pass.
109 static constexpr GrUserStencilSettings kResolveStencilCoverageAndReset(
110     GrUserStencilSettings::StaticInitSeparate<
111         0x0000,                           0x0000,
112         GrUserStencilTest::kNotEqual,     GrUserStencilTest::kNotEqual,
113         0xffff,                           0x0001,
114         GrUserStencilOp::kZero,           GrUserStencilOp::kZero,
115         GrUserStencilOp::kKeep,           GrUserStencilOp::kKeep,
116         0xffff,                           0xffff>()
117 );
118 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)119 void GrStencilAtlasOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
120     SkIRect drawBoundsRect = SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height());
121 
122     GrPipeline pipeline(GrScissorTest::kEnabled, GrDisableColorXPFactory::MakeXferProcessor(),
123                         flushState->drawOpArgs().outputSwizzle(),
124                         GrPipeline::InputFlags::kHWAntialias, &kIncrDecrStencil);
125 
126     GrSampleMaskProcessor sampleMaskProc;
127 
128     fResources->filler().drawFills(
129             flushState, &sampleMaskProc, pipeline, fFillBatchID, drawBoundsRect);
130 
131     fResources->stroker().drawStrokes(
132             flushState, &sampleMaskProc, fStrokeBatchID, drawBoundsRect);
133 
134     // We resolve the stencil coverage to alpha by drawing pixel-aligned boxes. Fine raster is
135     // not necessary, and will even cause artifacts if using mixed samples.
136     constexpr auto noHWAA = GrPipeline::InputFlags::kNone;
137 
138     const auto* stencilResolveSettings = (flushState->caps().discardStencilValuesAfterRenderPass())
139             // The next draw will be the final op in the renderTargetContext. So if Ganesh is
140             // planning to discard the stencil values anyway, we don't actually need to reset them
141             // back to zero.
142             ? &kResolveStencilCoverage
143             : &kResolveStencilCoverageAndReset;
144 
145     GrPipeline resolvePipeline(GrScissorTest::kEnabled, SkBlendMode::kSrc,
146                                flushState->drawOpArgs().outputSwizzle(), noHWAA,
147                                stencilResolveSettings);
148     GrPipeline::FixedDynamicState scissorRectState(drawBoundsRect);
149 
150     GrMesh mesh;
151     mesh.setInstanced(fResources->refStencilResolveBuffer(),
152                       fEndStencilResolveInstance - fBaseStencilResolveInstance,
153                       fBaseStencilResolveInstance, 4);
154 
155     StencilResolveProcessor primProc;
156 
157     GrProgramInfo programInfo(flushState->proxy()->numSamples(),
158                               flushState->proxy()->numStencilSamples(),
159                               flushState->proxy()->backendFormat(),
160                               flushState->view()->origin(),
161                               &resolvePipeline,
162                               &primProc,
163                               &scissorRectState,
164                               nullptr, 0, GrPrimitiveType::kTriangleStrip);
165 
166     flushState->opsRenderPass()->bindPipeline(programInfo, SkRect::Make(drawBoundsRect));
167     flushState->opsRenderPass()->drawMeshes(programInfo, &mesh, 1);
168 }
169