blob: 88c8fcecdd39fe1b16547ab2689e80a283f09b3e [file] [log] [blame]
Chris Daltonb832ce62020-01-06 19:49:37 -07001/*
2 * Copyright 2019 Google LLC.
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/tessellate/GrTessellatePathOp.h"
9
10#include "src/gpu/GrGpu.h"
11#include "src/gpu/GrOpFlushState.h"
12#include "src/gpu/GrOpsRenderPass.h"
13#include "src/gpu/GrProgramInfo.h"
14#include "src/gpu/tessellate/GrCenterWedgePatchGen.h"
15#include "src/gpu/tessellate/GrCoverShader.h"
16#include "src/gpu/tessellate/GrTessellateWedgeShader.h"
17
18GrTessellatePathOp::FixedFunctionFlags GrTessellatePathOp::fixedFunctionFlags() const {
19 auto flags = FixedFunctionFlags::kUsesStencil;
20 if (GrAAType::kNone != fAAType) {
21 flags |= FixedFunctionFlags::kUsesHWAA;
22 }
23 return flags;
24}
25
26void GrTessellatePathOp::onPrepare(GrOpFlushState* state) {
27 SkSTArray<16, SkPoint, true> contourMidpoints;
28 GrCenterWedgePatchGen patchGen(fPath);
29 int numPatches = patchGen.walkPath(nullptr, &contourMidpoints);
30 if (!numPatches) {
31 return;
32 }
33 if (auto* wedgeData = (std::array<SkPoint, 5>*)state->makeVertexSpace(
34 sizeof(SkPoint), numPatches * 5, &fWedgeBuffer, &fBaseWedgeVertex)) {
35 fNumWedges = patchGen.walkPath(wedgeData, &contourMidpoints);
36 SkASSERT(fNumWedges == numPatches);
37 }
38}
39
40void GrTessellatePathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
41 if (!fWedgeBuffer) {
42 return;
43 }
44
45 GrAppliedClip clip = state->detachAppliedClip();
46 GrPipeline::FixedDynamicState fixedDynamicState;
47 if (clip.scissorState().enabled()) {
48 fixedDynamicState.fScissorRect = clip.scissorState().rect();
49 }
50
51 this->drawStencilPass(state, clip.hardClip(), &fixedDynamicState);
52 if (!(Flags::kStencilOnly & fFlags)) {
53 this->drawCoverPass(state, std::move(clip), &fixedDynamicState);
54 }
55}
56
57void GrTessellatePathOp::drawStencilPass(GrOpFlushState* state, const GrAppliedHardClip& hardClip,
58 const GrPipeline::FixedDynamicState* fixedDynamicState) {
59 // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill.
60 constexpr static GrUserStencilSettings kIncrDecrStencil(
61 GrUserStencilSettings::StaticInitSeparate<
62 0x0000, 0x0000,
63 GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip,
64 0xffff, 0xffff,
65 GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
66 GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
67 0xffff, 0xffff>());
68
69 // Inverts the bottom stencil bit. Used for "even/odd" fill.
70 constexpr static GrUserStencilSettings kInvertStencil(
71 GrUserStencilSettings::StaticInit<
72 0x0000,
73 GrUserStencilTest::kAlwaysIfInClip,
74 0xffff,
75 GrUserStencilOp::kInvert,
76 GrUserStencilOp::kKeep,
77 0x0001>());
78
79 GrPipeline::InitArgs initArgs;
80 if (GrAAType::kNone != fAAType) {
81 initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
82 }
83 if (state->caps().wireframeSupport() && (Flags::kWireframe & fFlags)) {
84 initArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe;
85 }
86 SkASSERT(SkPathFillType::kWinding == fPath.getFillType() ||
87 SkPathFillType::kEvenOdd == fPath.getFillType());
88 initArgs.fUserStencil = (SkPathFillType::kWinding == fPath.getFillType()) ?
89 &kIncrDecrStencil : &kInvertStencil;
90 initArgs.fCaps = &state->caps();
91
92 GrPipeline pipeline(initArgs, GrDisableColorXPFactory::MakeXferProcessor(), hardClip);
93 GrTessellateWedgeShader shader(fViewMatrix);
94 GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
95 state->proxy()->backendFormat(), state->view()->origin(), &pipeline,
96 &shader, fixedDynamicState, nullptr, 0,
97 GrPrimitiveType::kPatches, 5);
98
99 GrMesh mesh(GrPrimitiveType::kPatches, 5);
100 mesh.setNonIndexedNonInstanced(fNumWedges * 5);
101 mesh.setVertexData(fWedgeBuffer, fBaseWedgeVertex);
102
103 state->opsRenderPass()->draw(programInfo, &mesh, 1, this->bounds());
104
105 // http://skbug.com/9739
106 if (state->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) {
107 state->gpu()->insertManualFramebufferBarrier();
108 }
109}
110
111void GrTessellatePathOp::drawCoverPass(GrOpFlushState* state, GrAppliedClip&& clip,
112 const GrPipeline::FixedDynamicState* fixedDynamicState) {
113 // Allows non-zero stencil values to pass and write a color, and resets the stencil value back
114 // to zero; discards immediately on stencil values of zero.
115 // NOTE: It's ok to not check the clip here because the previous stencil pass only wrote to
116 // samples already inside the clip.
117 constexpr static GrUserStencilSettings kTestAndResetStencil(
118 GrUserStencilSettings::StaticInit<
119 0x0000,
120 GrUserStencilTest::kNotEqual,
121 0xffff,
122 GrUserStencilOp::kZero,
123 GrUserStencilOp::kKeep,
124 0xffff>());
125
126 GrPipeline::InitArgs initArgs;
127 if (GrAAType::kNone != fAAType) {
128 initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias;
129 if (1 == state->proxy()->numSamples()) {
130 SkASSERT(GrAAType::kCoverage == fAAType);
131 // We are mixed sampled. Use conservative raster to make the sample coverage mask 100%
132 // at every fragment. This way we will still get a double hit on shared edges, but
133 // whichever side comes first will cover every sample and will clear the stencil. The
134 // other side will then be discarded and not cause a double blend.
135 initArgs.fInputFlags |= GrPipeline::InputFlags::kConservativeRaster;
136 }
137 }
138 initArgs.fUserStencil = &kTestAndResetStencil;
139 initArgs.fCaps = &state->caps();
140 initArgs.fDstProxyView = state->drawOpArgs().dstProxyView();
141 initArgs.fOutputSwizzle = state->drawOpArgs().outputSwizzle();
142
143 GrPipeline pipeline(initArgs, std::move(fProcessors), std::move(clip));
144 GrCoverShader shader(fViewMatrix, fPath.getBounds(), fColor);
145 GrProgramInfo programInfo(state->proxy()->numSamples(), state->proxy()->numStencilSamples(),
146 state->proxy()->backendFormat(), state->view()->origin(), &pipeline,
147 &shader, fixedDynamicState, nullptr, 0,
148 GrPrimitiveType::kTriangleStrip);
149
150 GrMesh mesh(GrPrimitiveType::kTriangleStrip);
151 mesh.setNonIndexedNonInstanced(4);
152
153 state->opsRenderPass()->draw(programInfo, &mesh, 1, this->bounds());
154}