/src/skia/src/gpu/ganesh/StencilMaskHelper.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2020 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/ganesh/StencilMaskHelper.h" |
9 | | |
10 | | #include "include/core/SkMatrix.h" |
11 | | #include "include/core/SkPath.h" |
12 | | #include "include/core/SkRegion.h" |
13 | | #include "src/gpu/ganesh/GrRecordingContextPriv.h" |
14 | | #include "src/gpu/ganesh/GrStencilSettings.h" |
15 | | #include "src/gpu/ganesh/SurfaceDrawContext.h" |
16 | | #include "src/gpu/ganesh/effects/GrDisableColorXP.h" |
17 | | #include "src/gpu/ganesh/geometry/GrShape.h" |
18 | | #include "src/gpu/ganesh/geometry/GrStyledShape.h" |
19 | | |
20 | | namespace { |
21 | | |
22 | | //////////////////////////////////////////////////////////////////////////////// |
23 | | // Stencil Rules for Merging user stencil space into clip |
24 | | // |
25 | | |
26 | | /////// |
27 | | // Replace |
28 | | static constexpr GrUserStencilSettings gUserToClipReplace( |
29 | | GrUserStencilSettings::StaticInit< |
30 | | 0x0000, |
31 | | GrUserStencilTest::kNotEqual, |
32 | | 0xffff, |
33 | | GrUserStencilOp::kSetClipAndReplaceUserBits, |
34 | | GrUserStencilOp::kZeroClipAndUserBits, |
35 | | 0xffff>() |
36 | | ); |
37 | | |
38 | | static constexpr GrUserStencilSettings gInvUserToClipReplace( |
39 | | GrUserStencilSettings::StaticInit< |
40 | | 0x0000, |
41 | | GrUserStencilTest::kEqual, |
42 | | 0xffff, |
43 | | GrUserStencilOp::kSetClipAndReplaceUserBits, |
44 | | GrUserStencilOp::kZeroClipAndUserBits, |
45 | | 0xffff>() |
46 | | ); |
47 | | |
48 | | /////// |
49 | | // Intersect |
50 | | static constexpr GrUserStencilSettings gUserToClipIsect( |
51 | | GrUserStencilSettings::StaticInit< |
52 | | 0x0000, |
53 | | GrUserStencilTest::kLessIfInClip, // "0 < userBits" is equivalent to "0 != userBits". |
54 | | 0xffff, |
55 | | GrUserStencilOp::kSetClipAndReplaceUserBits, |
56 | | GrUserStencilOp::kZeroClipAndUserBits, |
57 | | 0xffff>() |
58 | | ); |
59 | | |
60 | | /////// |
61 | | // Difference |
62 | | static constexpr GrUserStencilSettings gUserToClipDiff( |
63 | | GrUserStencilSettings::StaticInit< |
64 | | 0x0000, |
65 | | GrUserStencilTest::kEqualIfInClip, |
66 | | 0xffff, |
67 | | GrUserStencilOp::kSetClipAndReplaceUserBits, |
68 | | GrUserStencilOp::kZeroClipAndUserBits, |
69 | | 0xffff>() |
70 | | ); |
71 | | |
72 | | /////// |
73 | | // Union |
74 | | static constexpr GrUserStencilSettings gUserToClipUnion( |
75 | | GrUserStencilSettings::StaticInit< |
76 | | 0x0000, |
77 | | GrUserStencilTest::kNotEqual, |
78 | | 0xffff, |
79 | | GrUserStencilOp::kSetClipAndReplaceUserBits, |
80 | | GrUserStencilOp::kKeep, |
81 | | 0xffff>() |
82 | | ); |
83 | | |
84 | | static constexpr GrUserStencilSettings gInvUserToClipUnionPass0( // Does not zero user bits. |
85 | | GrUserStencilSettings::StaticInit< |
86 | | 0x0000, |
87 | | GrUserStencilTest::kEqual, |
88 | | 0xffff, |
89 | | GrUserStencilOp::kSetClipBit, |
90 | | GrUserStencilOp::kKeep, |
91 | | 0x0000>() |
92 | | ); |
93 | | |
94 | | /////// |
95 | | // Xor |
96 | | static constexpr GrUserStencilSettings gUserToClipXorPass0( // Does not zero user bits. |
97 | | GrUserStencilSettings::StaticInit< |
98 | | 0x0000, |
99 | | GrUserStencilTest::kNotEqual, |
100 | | 0xffff, |
101 | | GrUserStencilOp::kInvertClipBit, |
102 | | GrUserStencilOp::kKeep, |
103 | | 0x0000>() |
104 | | ); |
105 | | |
106 | | static constexpr GrUserStencilSettings gInvUserToClipXorPass0( // Does not zero user bits. |
107 | | GrUserStencilSettings::StaticInit< |
108 | | 0x0000, |
109 | | GrUserStencilTest::kEqual, |
110 | | 0xffff, |
111 | | GrUserStencilOp::kInvertClipBit, |
112 | | GrUserStencilOp::kKeep, |
113 | | 0x0000>() |
114 | | ); |
115 | | |
116 | | /////// |
117 | | // Reverse Diff |
118 | | static constexpr GrUserStencilSettings gUserToClipRDiffPass0( // Does not zero user bits. |
119 | | GrUserStencilSettings::StaticInit< |
120 | | 0x0000, |
121 | | GrUserStencilTest::kNotEqual, |
122 | | 0xffff, |
123 | | GrUserStencilOp::kInvertClipBit, |
124 | | GrUserStencilOp::kZeroClipBit, |
125 | | 0x0000>() |
126 | | ); |
127 | | |
128 | | static constexpr GrUserStencilSettings gInvUserToClipRDiffPass0( // Does not zero user bits. |
129 | | GrUserStencilSettings::StaticInit< |
130 | | 0x0000, |
131 | | GrUserStencilTest::kEqual, |
132 | | 0xffff, |
133 | | GrUserStencilOp::kInvertClipBit, |
134 | | GrUserStencilOp::kZeroClipBit, |
135 | | 0x0000>() |
136 | | ); |
137 | | |
138 | | /////// |
139 | | // Second pass to clear user bits (only needed sometimes) |
140 | | static constexpr GrUserStencilSettings gZeroUserBits( |
141 | | GrUserStencilSettings::StaticInit< |
142 | | 0x0000, |
143 | | GrUserStencilTest::kNotEqual, |
144 | | 0xffff, |
145 | | GrUserStencilOp::kZero, |
146 | | GrUserStencilOp::kKeep, |
147 | | 0xffff>() |
148 | | ); |
149 | | |
150 | | static constexpr const GrUserStencilSettings* gUserToClipTable[2][1 + SkRegion::kLastOp][3] = { |
151 | | { /* Normal fill. */ |
152 | | {&gUserToClipDiff, nullptr, nullptr}, // kDifference_Op. |
153 | | {&gUserToClipIsect, nullptr, nullptr}, // kIntersect_Op. |
154 | | {&gUserToClipUnion, nullptr, nullptr}, // kUnion_Op. |
155 | | {&gUserToClipXorPass0, &gZeroUserBits, nullptr}, // kXOR_Op. |
156 | | {&gUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // kReverseDifference_Op. |
157 | | {&gUserToClipReplace, nullptr, nullptr} // kReplace_Op. |
158 | | |
159 | | }, /* Inverse fill. */ { |
160 | | {&gUserToClipIsect, nullptr, nullptr}, // ~diff (aka isect). |
161 | | {&gUserToClipDiff, nullptr, nullptr}, // ~isect (aka diff). |
162 | | {&gInvUserToClipUnionPass0, &gZeroUserBits, nullptr}, // ~union. |
163 | | {&gInvUserToClipXorPass0, &gZeroUserBits, nullptr}, // ~xor. |
164 | | {&gInvUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // ~reverse diff. |
165 | | {&gInvUserToClipReplace, nullptr, nullptr} // ~replace. |
166 | | } |
167 | | }; |
168 | | |
169 | | /////// |
170 | | // Direct to Stencil |
171 | | |
172 | | // We can render a clip element directly without first writing to the client |
173 | | // portion of the clip when the fill is not inverse and the set operation will |
174 | | // only modify the in/out status of samples covered by the clip element. |
175 | | |
176 | | // this one only works if used right after stencil clip was cleared. |
177 | | // Our clip mask creation code doesn't allow midstream replace ops. |
178 | | static constexpr GrUserStencilSettings gReplaceClip( |
179 | | GrUserStencilSettings::StaticInit< |
180 | | 0x0000, |
181 | | GrUserStencilTest::kAlways, |
182 | | 0xffff, |
183 | | GrUserStencilOp::kSetClipBit, |
184 | | GrUserStencilOp::kSetClipBit, |
185 | | 0x0000>() |
186 | | ); |
187 | | |
188 | | static constexpr GrUserStencilSettings gUnionClip( |
189 | | GrUserStencilSettings::StaticInit< |
190 | | 0x0000, |
191 | | GrUserStencilTest::kAlwaysIfInClip, |
192 | | 0xffff, |
193 | | GrUserStencilOp::kKeep, |
194 | | GrUserStencilOp::kSetClipBit, |
195 | | 0x0000>() |
196 | | ); |
197 | | |
198 | | static constexpr GrUserStencilSettings gXorClip( |
199 | | GrUserStencilSettings::StaticInit< |
200 | | 0x0000, |
201 | | GrUserStencilTest::kAlways, |
202 | | 0xffff, |
203 | | GrUserStencilOp::kInvertClipBit, |
204 | | GrUserStencilOp::kInvertClipBit, |
205 | | 0x0000>() |
206 | | ); |
207 | | |
208 | | static constexpr GrUserStencilSettings gDiffClip( |
209 | | GrUserStencilSettings::StaticInit< |
210 | | 0x0000, |
211 | | GrUserStencilTest::kAlwaysIfInClip, |
212 | | 0xffff, |
213 | | GrUserStencilOp::kZeroClipBit, |
214 | | GrUserStencilOp::kKeep, |
215 | | 0x0000>() |
216 | | ); |
217 | | |
218 | | static constexpr const GrUserStencilSettings* gDirectDrawTable[1 + SkRegion::kLastOp][2] = { |
219 | | {&gDiffClip, nullptr}, // kDifference_Op. |
220 | | {nullptr, nullptr}, // kIntersect_Op. |
221 | | {&gUnionClip, nullptr}, // kUnion_Op. |
222 | | {&gXorClip, nullptr}, // kXOR_Op. |
223 | | {nullptr, nullptr}, // kReverseDifference_Op. |
224 | | {&gReplaceClip, nullptr} // kReplace_Op. |
225 | | }; |
226 | | |
227 | | static_assert(0 == SkRegion::kDifference_Op); |
228 | | static_assert(1 == SkRegion::kIntersect_Op); |
229 | | static_assert(2 == SkRegion::kUnion_Op); |
230 | | static_assert(3 == SkRegion::kXOR_Op); |
231 | | static_assert(4 == SkRegion::kReverseDifference_Op); |
232 | | static_assert(5 == SkRegion::kReplace_Op); |
233 | | |
234 | | // Settings used to when not allowed to draw directly to the clip to fill the user stencil bits |
235 | | // before applying the covering clip stencil passes. |
236 | | static constexpr GrUserStencilSettings gDrawToStencil( |
237 | | GrUserStencilSettings::StaticInit< |
238 | | 0x0000, |
239 | | GrUserStencilTest::kAlways, |
240 | | 0xffff, |
241 | | GrUserStencilOp::kIncMaybeClamp, |
242 | | GrUserStencilOp::kIncMaybeClamp, |
243 | | 0xffff>() |
244 | | ); |
245 | | |
246 | | // Get the stencil settings per-pass to achieve the given fill+region op effect on the |
247 | | // stencil buffer. |
248 | | // |
249 | | // If drawDirectToClip comes back false, the caller must first draw the element into the user |
250 | | // stencil bits, and then cover the clip area with multiple passes using the returned |
251 | | // stencil settings. |
252 | | |
253 | | // If drawDirectToClip is true, the returned array will only have one pass and the |
254 | | // caller should use those stencil settings while drawing the element directly. |
255 | | // |
256 | | // This returns a null-terminated list of const GrUserStencilSettings* |
257 | | GrUserStencilSettings const* const* get_stencil_passes( |
258 | | SkRegion::Op op, |
259 | | skgpu::ganesh::PathRenderer::StencilSupport stencilSupport, |
260 | | bool fillInverted, |
261 | 1.67k | bool* drawDirectToClip) { |
262 | 1.67k | bool canRenderDirectToStencil = |
263 | 1.67k | skgpu::ganesh::PathRenderer::kNoRestriction_StencilSupport == stencilSupport; |
264 | | |
265 | | // TODO: inverse fill + intersect op can be direct. |
266 | | // TODO: this can be greatly simplified when we only need intersect and difference ops and |
267 | | // none of the paths will be inverse-filled (just toggle the op instead). |
268 | 1.67k | SkASSERT((unsigned)op <= SkRegion::kLastOp); |
269 | 1.67k | if (canRenderDirectToStencil && !fillInverted) { |
270 | 1.45k | GrUserStencilSettings const* const* directPass = gDirectDrawTable[op]; |
271 | 1.45k | if (directPass[0]) { |
272 | 1.39k | *drawDirectToClip = true; |
273 | 1.39k | return directPass; |
274 | 1.39k | } |
275 | 1.45k | } |
276 | 280 | *drawDirectToClip = false; |
277 | 280 | return gUserToClipTable[fillInverted][op]; |
278 | 1.67k | } |
279 | | |
280 | | void draw_stencil_rect(skgpu::ganesh::SurfaceDrawContext* sdc, |
281 | | const GrHardClip& clip, |
282 | | const GrUserStencilSettings* ss, |
283 | | const SkMatrix& matrix, |
284 | | const SkRect& rect, |
285 | 579 | GrAA aa) { |
286 | 579 | GrPaint paint; |
287 | 579 | paint.setXPFactory(GrDisableColorXPFactory::Get()); |
288 | 579 | sdc->stencilRect(&clip, ss, std::move(paint), aa, matrix, rect); |
289 | 579 | } |
290 | | |
291 | | void draw_path(GrRecordingContext* rContext, |
292 | | skgpu::ganesh::SurfaceDrawContext* sdc, |
293 | | skgpu::ganesh::PathRenderer* pr, |
294 | | const GrHardClip& clip, |
295 | | const SkIRect& bounds, |
296 | | const GrUserStencilSettings* ss, |
297 | | const SkMatrix& matrix, |
298 | | const GrStyledShape& shape, |
299 | 1.16k | GrAA aa) { |
300 | 1.16k | GrPaint paint; |
301 | 1.16k | paint.setXPFactory(GrDisableColorXPFactory::Get()); |
302 | | |
303 | | // kMSAA is the only type of AA that's possible on a stencil buffer. |
304 | 1.16k | GrAAType pathAAType = aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone; |
305 | | |
306 | 1.16k | skgpu::ganesh::PathRenderer::DrawPathArgs args{rContext, |
307 | 1.16k | std::move(paint), |
308 | 1.16k | ss, |
309 | 1.16k | sdc, |
310 | 1.16k | &clip, |
311 | 1.16k | &bounds, |
312 | 1.16k | &matrix, |
313 | 1.16k | &shape, |
314 | 1.16k | pathAAType, |
315 | 1.16k | false}; |
316 | 1.16k | pr->drawPath(args); |
317 | 1.16k | } |
318 | | |
319 | | void stencil_path(GrRecordingContext* rContext, |
320 | | skgpu::ganesh::SurfaceDrawContext* sdc, |
321 | | skgpu::ganesh::PathRenderer* pr, |
322 | | const GrFixedClip& clip, |
323 | | const SkMatrix& matrix, |
324 | | const GrStyledShape& shape, |
325 | 216 | GrAA aa) { |
326 | 216 | skgpu::ganesh::PathRenderer::StencilPathArgs args; |
327 | 216 | args.fContext = rContext; |
328 | 216 | args.fSurfaceDrawContext = sdc; |
329 | 216 | args.fClip = &clip; |
330 | 216 | args.fClipConservativeBounds = &clip.scissorRect(); |
331 | 216 | args.fViewMatrix = &matrix; |
332 | 216 | args.fShape = &shape; |
333 | 216 | args.fDoStencilMSAA = aa; |
334 | | |
335 | 216 | pr->stencilPath(args); |
336 | 216 | } |
337 | | |
338 | 1.67k | GrAA supported_aa(skgpu::ganesh::SurfaceDrawContext* sdc, GrAA aa) { |
339 | 1.67k | return GrAA(sdc->numSamples() > 1 || sdc->canUseDynamicMSAA()); |
340 | 1.67k | } |
341 | | |
342 | | } // namespace |
343 | | |
344 | | namespace skgpu::ganesh { |
345 | | |
346 | | StencilMaskHelper::StencilMaskHelper(GrRecordingContext* rContext, |
347 | | SurfaceDrawContext* sdc) |
348 | | : fContext(rContext) |
349 | | , fSDC(sdc) |
350 | 2.47k | , fClip(sdc->dimensions()) { |
351 | 2.47k | } |
352 | | |
353 | | bool StencilMaskHelper::init(const SkIRect& bounds, uint32_t genID, |
354 | 2.47k | const GrWindowRectangles& windowRects, int numFPs) { |
355 | 2.47k | if (!fSDC->mustRenderClip(genID, bounds, numFPs)) { |
356 | 900 | return false; |
357 | 900 | } |
358 | | |
359 | 1.57k | fClip.setStencilClip(genID); |
360 | | // Should have caught bounds not intersecting the render target much earlier in clip application |
361 | 1.57k | SkAssertResult(fClip.fixedClip().setScissor(bounds)); |
362 | 1.57k | if (!windowRects.empty()) { |
363 | 0 | fClip.fixedClip().setWindowRectangles( |
364 | 0 | windowRects, GrWindowRectsState::Mode::kExclusive); |
365 | 0 | } |
366 | 1.57k | fNumFPs = numFPs; |
367 | 1.57k | return true; |
368 | 2.47k | } skgpu::ganesh::StencilMaskHelper::init(SkIRect const&, unsigned int, GrWindowRectangles const&, int) Line | Count | Source | 354 | 2.47k | const GrWindowRectangles& windowRects, int numFPs) { | 355 | 2.47k | if (!fSDC->mustRenderClip(genID, bounds, numFPs)) { | 356 | 900 | return false; | 357 | 900 | } | 358 | | | 359 | 1.57k | fClip.setStencilClip(genID); | 360 | | // Should have caught bounds not intersecting the render target much earlier in clip application | 361 | 1.57k | SkAssertResult(fClip.fixedClip().setScissor(bounds)); | 362 | 1.57k | if (!windowRects.empty()) { | 363 | 0 | fClip.fixedClip().setWindowRectangles( | 364 | 0 | windowRects, GrWindowRectsState::Mode::kExclusive); | 365 | 0 | } | 366 | 1.57k | fNumFPs = numFPs; | 367 | 1.57k | return true; | 368 | 2.47k | } |
Unexecuted instantiation: skgpu::ganesh::StencilMaskHelper::init(SkIRect const&, unsigned int, GrWindowRectangles const&, int) |
369 | | |
370 | | void StencilMaskHelper::drawRect(const SkRect& rect, |
371 | | const SkMatrix& matrix, |
372 | | SkRegion::Op op, |
373 | 299 | GrAA aa) { |
374 | 299 | if (rect.isEmpty()) { |
375 | 0 | return; |
376 | 0 | } |
377 | | |
378 | 299 | bool drawDirectToClip; |
379 | 299 | auto passes = get_stencil_passes(op, PathRenderer::kNoRestriction_StencilSupport, |
380 | 299 | false, &drawDirectToClip); |
381 | 299 | aa = supported_aa(fSDC, aa); |
382 | | |
383 | 299 | if (!drawDirectToClip) { |
384 | | // Draw to client stencil bits first |
385 | 38 | draw_stencil_rect(fSDC, fClip.fixedClip(), &gDrawToStencil, matrix, rect, aa); |
386 | 38 | } |
387 | | |
388 | | // Now modify the clip bit (either by rendering directly), or by covering the bounding box |
389 | | // of the clip |
390 | 598 | for (GrUserStencilSettings const* const* pass = passes; *pass; ++pass) { |
391 | 299 | if (drawDirectToClip) { |
392 | 261 | draw_stencil_rect(fSDC, fClip, *pass, matrix, rect, aa); |
393 | 261 | } else { |
394 | 38 | draw_stencil_rect(fSDC, fClip, *pass, SkMatrix::I(), |
395 | 38 | SkRect::Make(fClip.fixedClip().scissorRect()), aa); |
396 | 38 | } |
397 | 299 | } |
398 | 299 | } |
399 | | |
400 | | bool StencilMaskHelper::drawPath(const SkPath& path, |
401 | | const SkMatrix& matrix, |
402 | | SkRegion::Op op, |
403 | 1.37k | GrAA aa) { |
404 | 1.37k | if (path.isEmpty()) { |
405 | 0 | return true; |
406 | 0 | } |
407 | | |
408 | | // drawPath follows a similar approach to drawRect(), where we either draw directly to the clip |
409 | | // bit or first draw to client bits and then apply a cover pass. The complicating factor is that |
410 | | // we rely on path rendering and how the chosen path renderer uses the stencil buffer. |
411 | 1.37k | aa = supported_aa(fSDC, aa); |
412 | | |
413 | 1.37k | GrAAType pathAAType = aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone; |
414 | | |
415 | | // This will be used to determine whether the clip shape can be rendered into the |
416 | | // stencil with arbitrary stencil settings. |
417 | 1.37k | PathRenderer::StencilSupport stencilSupport; |
418 | | |
419 | | // Make path canonical with regards to fill type (inverse handled by stencil settings). |
420 | 1.37k | bool fillInverted = path.isInverseFillType(); |
421 | 1.37k | SkTCopyOnFirstWrite<SkPath> clipPath(path); |
422 | 1.37k | if (fillInverted) { |
423 | 0 | clipPath.writable()->toggleInverseFillType(); |
424 | 0 | } |
425 | | |
426 | 1.37k | GrStyledShape shape(*clipPath, GrStyle::SimpleFill()); |
427 | 1.37k | SkASSERT(!shape.inverseFilled()); |
428 | | |
429 | 1.37k | PathRenderer::CanDrawPathArgs canDrawArgs; |
430 | 1.37k | canDrawArgs.fCaps = fContext->priv().caps(); |
431 | 1.37k | canDrawArgs.fProxy = fSDC->asRenderTargetProxy(); |
432 | 1.37k | canDrawArgs.fClipConservativeBounds = &fClip.fixedClip().scissorRect(); |
433 | 1.37k | canDrawArgs.fViewMatrix = &matrix; |
434 | 1.37k | canDrawArgs.fShape = &shape; |
435 | 1.37k | canDrawArgs.fPaint = nullptr; |
436 | 1.37k | canDrawArgs.fSurfaceProps = &fSDC->surfaceProps(); |
437 | 1.37k | canDrawArgs.fAAType = pathAAType; |
438 | 1.37k | canDrawArgs.fHasUserStencilSettings = false; |
439 | | |
440 | 1.37k | auto pr = fContext->priv().drawingManager()->getPathRenderer( |
441 | 1.37k | canDrawArgs, false, PathRendererChain::DrawType::kStencil, &stencilSupport); |
442 | 1.37k | if (!pr) { |
443 | 0 | return false; |
444 | 0 | } |
445 | | |
446 | 1.37k | bool drawDirectToClip; |
447 | 1.37k | auto passes = get_stencil_passes(op, stencilSupport, fillInverted, &drawDirectToClip); |
448 | | |
449 | | // Write to client bits if necessary |
450 | 1.37k | if (!drawDirectToClip) { |
451 | 242 | if (stencilSupport == PathRenderer::kNoRestriction_StencilSupport) { |
452 | 26 | draw_path(fContext, fSDC, pr, fClip.fixedClip(), fClip.fixedClip().scissorRect(), |
453 | 26 | &gDrawToStencil, matrix, shape, aa); |
454 | 216 | } else { |
455 | 216 | stencil_path(fContext, fSDC, pr, fClip.fixedClip(), matrix, shape, aa); |
456 | 216 | } |
457 | 242 | } |
458 | | |
459 | | // Now modify the clip bit (either by rendering directly), or by covering the bounding box |
460 | | // of the clip |
461 | 2.75k | for (GrUserStencilSettings const* const* pass = passes; *pass; ++pass) { |
462 | 1.37k | if (drawDirectToClip) { |
463 | 1.13k | draw_path(fContext, fSDC, pr, fClip, fClip.fixedClip().scissorRect(), |
464 | 1.13k | *pass, matrix, shape, aa); |
465 | 1.13k | } else { |
466 | 242 | draw_stencil_rect(fSDC, fClip, *pass, SkMatrix::I(), |
467 | 242 | SkRect::Make(fClip.fixedClip().scissorRect()), aa); |
468 | 242 | } |
469 | 1.37k | } |
470 | | |
471 | 1.37k | return true; |
472 | 1.37k | } |
473 | | |
474 | | bool StencilMaskHelper::drawShape(const GrShape& shape, |
475 | | const SkMatrix& matrix, |
476 | | SkRegion::Op op, |
477 | 1.67k | GrAA aa) { |
478 | 1.67k | if (shape.isRect() && !shape.inverted()) { |
479 | 299 | this->drawRect(shape.rect(), matrix, op, aa); |
480 | 299 | return true; |
481 | 1.37k | } else { |
482 | 1.37k | SkPath p; |
483 | 1.37k | shape.asPath(&p); |
484 | 1.37k | return this->drawPath(p, matrix, op, aa); |
485 | 1.37k | } |
486 | 1.67k | } |
487 | | |
488 | 1.57k | void StencilMaskHelper::clear(bool insideStencil) { |
489 | 1.57k | if (fClip.fixedClip().hasWindowRectangles()) { |
490 | | // Use a draw to benefit from window rectangles when resetting the stencil buffer; for |
491 | | // large buffers with MSAA this can be significant. |
492 | 0 | draw_stencil_rect(fSDC, fClip.fixedClip(), |
493 | 0 | GrStencilSettings::SetClipBitSettings(insideStencil), SkMatrix::I(), |
494 | 0 | SkRect::Make(fClip.fixedClip().scissorRect()), GrAA::kNo); |
495 | 1.57k | } else { |
496 | 1.57k | fSDC->clearStencilClip(fClip.fixedClip().scissorRect(), insideStencil); |
497 | 1.57k | } |
498 | 1.57k | } |
499 | | |
500 | 1.57k | void StencilMaskHelper::finish() { |
501 | 1.57k | fSDC->setLastClip(fClip.stencilStackID(), fClip.fixedClip().scissorRect(), fNumFPs); |
502 | 1.57k | } |
503 | | |
504 | | } // namespace skgpu::ganesh |