| 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/gpu/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&) override {} |
| 62 | }; |
| 63 | |
| 64 | GrGLSLPrimitiveProcessor* StencilResolveProcessor::createGLSLInstance(const GrShaderCaps&) const { |
| 65 | return new Impl(); |
| 66 | } |
| 67 | |
| 68 | } // namespace |
| 69 | |
| 70 | std::unique_ptr<GrDrawOp> GrStencilAtlasOp::Make( |
| 71 | GrRecordingContext* context, sk_sp<const GrCCPerFlushResources> resources, |
| 72 | FillBatchID fillBatchID, StrokeBatchID strokeBatchID, int baseStencilResolveInstance, |
| 73 | int endStencilResolveInstance, const SkISize& drawBounds) { |
| 74 | GrOpMemoryPool* pool = context->priv().opMemoryPool(); |
| 75 | |
| 76 | return pool->allocate<GrStencilAtlasOp>( |
| 77 | std::move(resources), fillBatchID, strokeBatchID, baseStencilResolveInstance, |
| 78 | endStencilResolveInstance, drawBounds); |
| 79 | } |
| 80 | |
| 81 | // Increments clockwise triangles and decrements counterclockwise. We use the same incr/decr |
| 82 | // settings regardless of fill rule; fill rule is accounted for during the resolve step. |
| 83 | static constexpr GrUserStencilSettings kIncrDecrStencil( |
| 84 | GrUserStencilSettings::StaticInitSeparate< |
| 85 | 0x0000, 0x0000, |
| 86 | GrUserStencilTest::kNever, GrUserStencilTest::kNever, |
| 87 | 0xffff, 0xffff, |
| 88 | GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap, |
| 89 | GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap, |
| 90 | 0xffff, 0xffff>() |
| 91 | ); |
| 92 | |
| 93 | // Resolves stencil winding counts to A8 coverage. Leaves stencil values untouched. |
| 94 | // NOTE: For the CCW face we intentionally use "1 == (stencil & 1)" because the contrapositive logic |
| 95 | // (i.e. 0 != ...) causes bugs on Adreno Vulkan. http://skbug.com/9643 |
| 96 | static constexpr GrUserStencilSettings kResolveStencilCoverage( |
| 97 | GrUserStencilSettings::StaticInitSeparate< |
| 98 | 0x0000, 0x0001, |
| 99 | GrUserStencilTest::kNotEqual, GrUserStencilTest::kEqual, |
| 100 | 0xffff, 0x0001, |
| 101 | GrUserStencilOp::kKeep, GrUserStencilOp::kKeep, |
| 102 | GrUserStencilOp::kKeep, GrUserStencilOp::kKeep, |
| 103 | 0xffff, 0xffff>() |
| 104 | ); |
| 105 | |
| 106 | // Same as above, but also resets stencil values to zero. This is better for non-tilers |
| 107 | // where we prefer to not clear the stencil buffer at the beginning of every render pass. |
| 108 | static constexpr GrUserStencilSettings kResolveStencilCoverageAndReset( |
| 109 | GrUserStencilSettings::StaticInitSeparate< |
| 110 | 0x0000, 0x0000, |
| 111 | GrUserStencilTest::kNotEqual, GrUserStencilTest::kNotEqual, |
| 112 | 0xffff, 0x0001, |
| 113 | GrUserStencilOp::kZero, GrUserStencilOp::kZero, |
| 114 | GrUserStencilOp::kKeep, GrUserStencilOp::kZero, |
| 115 | 0xffff, 0xffff>() |
| 116 | ); |
| 117 | |
| 118 | // Same as above, but done in two passes for D3D, which doesn't support mismatched refs or masks on |
| 119 | // dual sided stencil settings. |
| 120 | static constexpr GrUserStencilSettings kResolveWindingCoverageAndReset( |
| 121 | GrUserStencilSettings::StaticInitSeparate< |
| 122 | 0x0000, 0x0000, |
| 123 | GrUserStencilTest::kNotEqual, GrUserStencilTest::kNever, |
| 124 | 0xffff, 0xffff, |
| 125 | GrUserStencilOp::kZero, GrUserStencilOp::kKeep, |
| 126 | GrUserStencilOp::kKeep, GrUserStencilOp::kKeep, |
| 127 | 0xffff, 0xffff>() |
| 128 | ); |
| 129 | static constexpr GrUserStencilSettings kResolveEvenOddCoverageAndReset( |
| 130 | GrUserStencilSettings::StaticInitSeparate< |
| 131 | 0x0000, 0x0000, |
| 132 | GrUserStencilTest::kNever, GrUserStencilTest::kNotEqual, |
| 133 | 0x0001, 0x0001, |
| 134 | GrUserStencilOp::kKeep, GrUserStencilOp::kZero, |
| 135 | GrUserStencilOp::kKeep, GrUserStencilOp::kZero, |
| 136 | 0xffff, 0xffff>() |
| 137 | ); |
| 138 | |
| 139 | |
| 140 | void GrStencilAtlasOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) { |
| 141 | SkIRect drawBoundsRect = SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height()); |
| 142 | |
| 143 | GrPipeline pipeline(GrScissorTest::kEnabled, GrDisableColorXPFactory::MakeXferProcessor(), |
| 144 | flushState->drawOpArgs().writeSwizzle(), |
| 145 | GrPipeline::InputFlags::kHWAntialias, &kIncrDecrStencil); |
| 146 | |
| 147 | GrSampleMaskProcessor sampleMaskProc; |
| 148 | |
| 149 | fResources->filler().drawFills( |
| 150 | flushState, &sampleMaskProc, pipeline, fFillBatchID, drawBoundsRect); |
| 151 | |
| 152 | fResources->stroker().drawStrokes( |
| 153 | flushState, &sampleMaskProc, fStrokeBatchID, drawBoundsRect); |
| 154 | |
| 155 | // We resolve the stencil coverage to alpha by drawing pixel-aligned boxes. Fine raster is |
| 156 | // not necessary, and will even cause artifacts if using mixed samples. |
| 157 | constexpr auto noHWAA = GrPipeline::InputFlags::kNone; |
| 158 | |
| 159 | GrPipeline resolvePipeline(GrScissorTest::kEnabled, SkBlendMode::kSrc, |
| 160 | flushState->drawOpArgs().writeSwizzle(), noHWAA); |
| 161 | StencilResolveProcessor primProc; |
| 162 | |
| 163 | if (!flushState->caps().twoSidedStencilRefsAndMasksMustMatch()) { |
| 164 | if (flushState->caps().discardStencilValuesAfterRenderPass()) { |
| 165 | resolvePipeline.setUserStencil(&kResolveStencilCoverage); |
| 166 | } else { |
| 167 | resolvePipeline.setUserStencil(&kResolveStencilCoverageAndReset); |
| 168 | } |
| 169 | this->drawResolve(flushState, resolvePipeline, primProc, drawBoundsRect); |
| 170 | return; |
| 171 | } |
| 172 | |
| 173 | // If this ever becomes true then we should add new per-fill-type stencil settings that also |
| 174 | // don't reset back to zero. |
| 175 | SkASSERT(!flushState->caps().discardStencilValuesAfterRenderPass()); |
| 176 | |
| 177 | resolvePipeline.setUserStencil(&kResolveWindingCoverageAndReset); |
| 178 | this->drawResolve(flushState, resolvePipeline, primProc, drawBoundsRect); |
| 179 | |
| 180 | resolvePipeline.setUserStencil(&kResolveEvenOddCoverageAndReset); |
| 181 | this->drawResolve(flushState, resolvePipeline, primProc, drawBoundsRect); |
| 182 | } |
| 183 | |
| 184 | void GrStencilAtlasOp::drawResolve(GrOpFlushState* flushState, const GrPipeline& resolvePipeline, |
| 185 | const GrPrimitiveProcessor& primProc, |
| 186 | const SkIRect& drawBounds) const { |
| 187 | GrProgramInfo programInfo(flushState->proxy()->numSamples(), |
| 188 | flushState->proxy()->numStencilSamples(), |
| 189 | flushState->proxy()->backendFormat(), |
| 190 | flushState->writeView()->origin(), &resolvePipeline, &primProc, |
| 191 | GrPrimitiveType::kTriangleStrip); |
| 192 | flushState->bindPipeline(programInfo, SkRect::Make(drawBounds)); |
| 193 | flushState->setScissorRect(drawBounds); |
| 194 | flushState->bindBuffers(nullptr, fResources->stencilResolveBuffer(), nullptr); |
| 195 | flushState->drawInstanced(fEndStencilResolveInstance - fBaseStencilResolveInstance, |
| 196 | fBaseStencilResolveInstance, 4, 0); |
| 197 | } |
| 198 | |