blob: 6c0f7c00b728aacf95da9457336c1363831dd4fd [file] [log] [blame]
Chris Daltonc3318f02019-07-19 14:20:53 -06001/*
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"
Chris Daltonc3318f02019-07-19 14:20:53 -060011#include "src/gpu/GrOpFlushState.h"
Greg Daniel2d41d0d2019-08-26 11:08:51 -040012#include "src/gpu/GrOpsRenderPass.h"
Robert Phillips901aff02019-10-08 12:32:56 -040013#include "src/gpu/GrProgramInfo.h"
Chris Daltonc3318f02019-07-19 14:20:53 -060014#include "src/gpu/GrRecordingContextPriv.h"
Chris Daltonc3318f02019-07-19 14:20:53 -060015#include "src/gpu/ccpr/GrCCPerFlushResources.h"
Mike Klein52337de2019-07-25 09:00:52 -050016#include "src/gpu/ccpr/GrSampleMaskProcessor.h"
17#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
18#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Chris Daltonc3318f02019-07-19 14:20:53 -060019
20namespace {
21
22class StencilResolveProcessor : public GrGeometryProcessor {
23public:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -050024 StencilResolveProcessor() : INHERITED(kStencilResolveProcessor_ClassID) {
Chris Daltonc3318f02019-07-19 14:20:53 -060025 static constexpr Attribute kIBounds = {
26 "ibounds", kShort4_GrVertexAttribType, kShort4_GrSLType};
27 this->setInstanceAttributes(&kIBounds, 1);
28 SkASSERT(this->instanceStride() == sizeof(GrStencilAtlasOp::ResolveRectInstance));
29 }
30
31private:
Robert Phillips7cd0bfe2019-11-20 16:08:10 -050032 const char* name() const final { return "StencilResolveProcessor"; }
33 void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const final {}
34 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final;
Chris Daltonc3318f02019-07-19 14:20:53 -060035 class Impl;
Robert Phillips7cd0bfe2019-11-20 16:08:10 -050036
37 typedef GrGeometryProcessor INHERITED;
Chris Daltonc3318f02019-07-19 14:20:53 -060038};
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.
44class 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&,
Brian Salomonc241b582019-11-27 08:57:17 -050062 const CoordTransformRange&) override {}
Chris Daltonc3318f02019-07-19 14:20:53 -060063};
64
65GrGLSLPrimitiveProcessor* StencilResolveProcessor::createGLSLInstance(const GrShaderCaps&) const {
66 return new Impl();
67}
68
69}
70
71std::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.
84static 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
Chris Dalton674f77a2019-09-30 20:49:39 -060094// Resolves stencil winding counts to A8 coverage. Leaves stencil values untouched.
Chris Daltond53853d2019-11-25 12:54:55 -070095// 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
Chris Dalton674f77a2019-09-30 20:49:39 -060097static constexpr GrUserStencilSettings kResolveStencilCoverage(
98 GrUserStencilSettings::StaticInitSeparate<
Chris Daltond53853d2019-11-25 12:54:55 -070099 0x0000, 0x0001,
100 GrUserStencilTest::kNotEqual, GrUserStencilTest::kEqual,
101 0xffff, 0x0001,
Chris Dalton674f77a2019-09-30 20:49:39 -0600102 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.
Chris Daltonc3318f02019-07-19 14:20:53 -0600109static constexpr GrUserStencilSettings kResolveStencilCoverageAndReset(
110 GrUserStencilSettings::StaticInitSeparate<
111 0x0000, 0x0000,
112 GrUserStencilTest::kNotEqual, GrUserStencilTest::kNotEqual,
Chris Daltond53853d2019-11-25 12:54:55 -0700113 0xffff, 0x0001,
Chris Daltonc3318f02019-07-19 14:20:53 -0600114 GrUserStencilOp::kZero, GrUserStencilOp::kZero,
115 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
116 0xffff, 0xffff>()
117);
118
119void GrStencilAtlasOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
120 SkIRect drawBoundsRect = SkIRect::MakeWH(fDrawBounds.width(), fDrawBounds.height());
121
Robert Phillips3968fcb2019-12-05 16:40:31 -0500122 GrPipeline pipeline(GrScissorTest::kEnabled, GrDisableColorXPFactory::MakeXferProcessor(),
Brian Salomon982f5462020-03-30 12:52:33 -0400123 flushState->drawOpArgs().writeSwizzle(),
Robert Phillips3968fcb2019-12-05 16:40:31 -0500124 GrPipeline::InputFlags::kHWAntialias, &kIncrDecrStencil);
Chris Daltonc3318f02019-07-19 14:20:53 -0600125
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
Chris Dalton674f77a2019-09-30 20:49:39 -0600138 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,
Brian Salomon982f5462020-03-30 12:52:33 -0400146 flushState->drawOpArgs().writeSwizzle(), noHWAA,
Chris Dalton674f77a2019-09-30 20:49:39 -0600147 stencilResolveSettings);
Robert Phillips901aff02019-10-08 12:32:56 -0400148
149 StencilResolveProcessor primProc;
150
Chris Dalton5e8cdfd2019-11-11 15:23:30 -0700151 GrProgramInfo programInfo(flushState->proxy()->numSamples(),
152 flushState->proxy()->numStencilSamples(),
Robert Phillips933484f2019-11-26 09:38:55 -0500153 flushState->proxy()->backendFormat(),
Brian Salomon8afde5f2020-04-01 16:22:00 -0400154 flushState->writeView()->origin(), &resolvePipeline, &primProc,
Chris Dalton304e14d2020-03-17 14:29:06 -0600155 GrPrimitiveType::kTriangleStrip);
Robert Phillips901aff02019-10-08 12:32:56 -0400156
Chris Daltonaa0e45c2020-03-16 10:05:11 -0600157 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);
Chris Daltonc3318f02019-07-19 14:20:53 -0600162}