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