blob: 4f2e35725cdeb4cf6245080c9a1bb21963f79317 [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"
Chris Daltonc3318f02019-07-19 14:20:53 -060013#include "src/gpu/GrRecordingContextPriv.h"
Chris Daltonc3318f02019-07-19 14:20:53 -060014#include "src/gpu/ccpr/GrCCPerFlushResources.h"
Mike Klein52337de2019-07-25 09:00:52 -050015#include "src/gpu/ccpr/GrSampleMaskProcessor.h"
16#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17#include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
Chris Daltonc3318f02019-07-19 14:20:53 -060018
19namespace {
20
21class StencilResolveProcessor : public GrGeometryProcessor {
22public:
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
30private:
31 const char* name() const override { return "GrCCPathProcessor"; }
32 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.
41class StencilResolveProcessor::Impl : public GrGLSLGeometryProcessor {
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
58 void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor&,
59 FPCoordTransformIter&&) override {}
60};
61
62GrGLSLPrimitiveProcessor* StencilResolveProcessor::createGLSLInstance(const GrShaderCaps&) const {
63 return new Impl();
64}
65
66}
67
68std::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.
81static 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.
92static 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
102void 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);
Greg Daniel2d41d0d2019-08-26 11:08:51 -0400132 flushState->opsRenderPass()->draw(
Chris Daltonc3318f02019-07-19 14:20:53 -0600133 StencilResolveProcessor(), resolvePipeline, &scissorRectState, nullptr, &mesh, 1,
134 SkRect::Make(drawBoundsRect));
135}