• 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/GrGpuCommandBuffer.h"
12 #include "src/gpu/GrOpFlushState.h"
13 #include "src/gpu/GrRecordingContextPriv.h"
14 #include "src/gpu/ccpr/GrCCPerFlushResources.h"
15 #include "src/gpu/ccpr/GrSampleMaskProcessor.h"
16 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17 #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
18 
19 namespace {
20 
21 class StencilResolveProcessor : public GrGeometryProcessor {
22 public:
StencilResolveProcessor()23     StencilResolveProcessor() : GrGeometryProcessor(kStencilResolveProcessor_ClassID) {
24         static constexpr Attribute kIBounds = {
25                 "ibounds", kShort4_GrVertexAttribType, kShort4_GrSLType};
26         this->setInstanceAttributes(&kIBounds, 1);
27         SkASSERT(this->instanceStride() == sizeof(GrStencilAtlasOp::ResolveRectInstance));
28     }
29 
30 private:
name() const31     const char* name() const override { return "GrCCPathProcessor"; }
getGLSLProcessorKey(const GrShaderCaps &,GrProcessorKeyBuilder *) const32     void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
33     GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override;
34     class Impl;
35 };
36 
37 // This processor draws pixel-aligned rectangles directly on top of every path in the atlas.
38 // The caller should have set up the instance data such that "Nonzero" paths get clockwise
39 // rectangles (l < r) and "even/odd" paths get counter-clockwise (r < l). Its purpose
40 // is to convert winding counts in the stencil buffer to A8 coverage in the color buffer.
41 class StencilResolveProcessor::Impl : public GrGLSLGeometryProcessor {
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)42     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
43         args.fVaryingHandler->emitAttributes(args.fGP.cast<StencilResolveProcessor>());
44 
45         GrGLSLVertexBuilder* v = args.fVertBuilder;
46         v->codeAppendf("short2 devcoord;");
47         v->codeAppendf("devcoord.x = (0 == (sk_VertexID & 1)) ? ibounds.x : ibounds.z;");
48         v->codeAppendf("devcoord.y = (sk_VertexID < 2) ? ibounds.y : ibounds.w;");
49 
50         v->codeAppendf("float2 atlascoord = float2(devcoord);");
51         gpArgs->fPositionVar.set(kFloat2_GrSLType, "atlascoord");
52 
53         // Just output "1" for coverage. This will be modulated by the MSAA stencil test.
54         GrGLSLFPFragmentBuilder* f = args.fFragBuilder;
55         f->codeAppendf("%s = %s = half4(1);", args.fOutputColor, args.fOutputCoverage);
56     }
57 
setData(const GrGLSLProgramDataManager &,const GrPrimitiveProcessor &,FPCoordTransformIter &&)58     void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&,
59                  FPCoordTransformIter&&) override {}
60 };
61 
createGLSLInstance(const GrShaderCaps &) const62 GrGLSLPrimitiveProcessor* StencilResolveProcessor::createGLSLInstance(const GrShaderCaps&) const {
63     return new Impl();
64 }
65 
66 }
67 
Make(GrRecordingContext * context,sk_sp<const GrCCPerFlushResources> resources,FillBatchID fillBatchID,StrokeBatchID strokeBatchID,int baseStencilResolveInstance,int endStencilResolveInstance,const SkISize & drawBounds)68 std::unique_ptr<GrDrawOp> GrStencilAtlasOp::Make(
69         GrRecordingContext* context, sk_sp<const GrCCPerFlushResources> resources,
70         FillBatchID fillBatchID, StrokeBatchID strokeBatchID, int baseStencilResolveInstance,
71         int endStencilResolveInstance, const SkISize& drawBounds) {
72     GrOpMemoryPool* pool = context->priv().opMemoryPool();
73 
74     return pool->allocate<GrStencilAtlasOp>(
75             std::move(resources), fillBatchID, strokeBatchID, baseStencilResolveInstance,
76             endStencilResolveInstance, drawBounds);
77 }
78 
79 // Increments clockwise triangles and decrements counterclockwise. We use the same incr/decr
80 // settings regardless of fill rule; fill rule is accounted for during the resolve step.
81 static constexpr GrUserStencilSettings kIncrDecrStencil(
82     GrUserStencilSettings::StaticInitSeparate<
83         0x0000,                        0x0000,
84         GrUserStencilTest::kNever,     GrUserStencilTest::kNever,
85         0xffff,                        0xffff,
86         GrUserStencilOp::kIncWrap,     GrUserStencilOp::kDecWrap,
87         GrUserStencilOp::kIncWrap,     GrUserStencilOp::kDecWrap,
88         0xffff,                        0xffff>()
89 );
90 
91 // Resolves stencil winding counts to A8 coverage and resets stencil values to zero.
92 static constexpr GrUserStencilSettings kResolveStencilCoverageAndReset(
93     GrUserStencilSettings::StaticInitSeparate<
94         0x0000,                           0x0000,
95         GrUserStencilTest::kNotEqual,     GrUserStencilTest::kNotEqual,
96         0xffff,                           0x1,
97         GrUserStencilOp::kZero,           GrUserStencilOp::kZero,
98         GrUserStencilOp::kKeep,           GrUserStencilOp::kKeep,
99         0xffff,                           0xffff>()
100 );
101 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)102 void GrStencilAtlasOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
103     SkIRect drawBoundsRect = SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height());
104 
105     GrPipeline pipeline(
106             GrScissorTest::kEnabled, GrDisableColorXPFactory::MakeXferProcessor(),
107             flushState->drawOpArgs().fOutputSwizzle, GrPipeline::InputFlags::kHWAntialias,
108             &kIncrDecrStencil);
109 
110     GrSampleMaskProcessor sampleMaskProc;
111 
112     fResources->filler().drawFills(
113             flushState, &sampleMaskProc, pipeline, fFillBatchID, drawBoundsRect);
114 
115     fResources->stroker().drawStrokes(
116             flushState, &sampleMaskProc, fStrokeBatchID, drawBoundsRect);
117 
118     // We resolve the stencil coverage to alpha by drawing pixel-aligned boxes. Fine raster is
119     // not necessary, and will even cause artifacts if using mixed samples.
120     constexpr auto noHWAA = GrPipeline::InputFlags::kNone;
121 
122     GrPipeline resolvePipeline(
123             GrScissorTest::kEnabled, SkBlendMode::kSrc, flushState->drawOpArgs().fOutputSwizzle,
124             noHWAA, &kResolveStencilCoverageAndReset);
125     GrPipeline::FixedDynamicState scissorRectState(drawBoundsRect);
126 
127     GrMesh mesh(GrPrimitiveType::kTriangleStrip);
128     mesh.setInstanced(
129             fResources->refStencilResolveBuffer(),
130             fEndStencilResolveInstance - fBaseStencilResolveInstance, fBaseStencilResolveInstance,
131             4);
132     flushState->rtCommandBuffer()->draw(
133             StencilResolveProcessor(), resolvePipeline, &scissorRectState, nullptr, &mesh, 1,
134             SkRect::Make(drawBoundsRect));
135 }
136