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: |
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: |
32 | const char* name() const final { return "StencilResolveProcessor" ; } |
33 | 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 { |
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 | |
61 | void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&, |
62 | const CoordTransformRange&) override {} |
63 | }; |
64 | |
65 | GrGLSLPrimitiveProcessor* StencilResolveProcessor::createGLSLInstance(const GrShaderCaps&) const { |
66 | return new Impl(); |
67 | } |
68 | |
69 | } |
70 | |
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 | |
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().writeSwizzle(), |
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().writeSwizzle(), noHWAA, |
147 | stencilResolveSettings); |
148 | |
149 | StencilResolveProcessor primProc; |
150 | |
151 | GrProgramInfo programInfo(flushState->proxy()->numSamples(), |
152 | flushState->proxy()->numStencilSamples(), |
153 | flushState->proxy()->backendFormat(), |
154 | flushState->writeView()->origin(), &resolvePipeline, &primProc, |
155 | GrPrimitiveType::kTriangleStrip); |
156 | |
157 | flushState->bindPipeline(programInfo, SkRect::Make(drawBoundsRect)); |
158 | flushState->setScissorRect(drawBoundsRect); |
159 | flushState->bindBuffers(nullptr, fResources->stencilResolveBuffer(), nullptr); |
160 | flushState->drawInstanced(fEndStencilResolveInstance - fBaseStencilResolveInstance, |
161 | fBaseStencilResolveInstance, 4, 0); |
162 | } |
163 | |