| 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 |  |