Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
Classes | Public Types | Public Member Functions | List of all members
skgpu::ganesh::ClipStack Class Referencefinal

#include <ClipStack.h>

Inheritance diagram for skgpu::ganesh::ClipStack:
GrClip

Classes

class  Draw
 
struct  Element
 
class  ElementIter
 

Public Types

enum class  ClipState : uint8_t {
  kEmpty , kWideOpen , kDeviceRect , kDeviceRRect ,
  kComplex
}
 
- Public Types inherited from GrClip
enum class  Effect { kClipped , kUnclipped , kClippedOut }
 
enum class  BoundsType { kExterior , kInterior }
 

Public Member Functions

 ClipStack (const SkIRect &deviceBounds, const SkMatrix *ctm, bool forceAA)
 
 ~ClipStack () override
 
 ClipStack (const ClipStack &)=delete
 
ClipStackoperator= (const ClipStack &)=delete
 
ClipState clipState () const
 
ElementIter begin () const
 
ElementIter end () const
 
void save ()
 
void restore ()
 
void clipRect (const SkMatrix &ctm, const SkRect &rect, GrAA aa, SkClipOp op)
 
void clipRRect (const SkMatrix &ctm, const SkRRect &rrect, GrAA aa, SkClipOp op)
 
void clipPath (const SkMatrix &ctm, const SkPath &path, GrAA aa, SkClipOp op)
 
void clipShader (sk_sp< SkShader > shader)
 
void replaceClip (const SkIRect &rect)
 
GrClip::Effect apply (GrRecordingContext *, skgpu::ganesh::SurfaceDrawContext *, GrDrawOp *, GrAAType, GrAppliedClip *, SkRect *bounds) const override
 
GrClip::PreClipResult preApply (const SkRect &drawBounds, GrAA aa) const override
 
SkIRect getConservativeBounds () const override
 
- Public Member Functions inherited from GrClip
virtual ~GrClip ()
 

Additional Inherited Members

- Static Public Member Functions inherited from GrClip
static bool IsInsideClip (const SkIRect &innerClipBounds, const SkRect &drawBounds, GrAA aa)
 
static bool IsOutsideClip (const SkIRect &outerClipBounds, const SkRect &drawBounds, GrAA aa)
 
static SkIRect GetPixelIBounds (const SkRect &bounds, GrAA aa, BoundsType mode=BoundsType::kExterior)
 
static bool IsPixelAligned (const SkRect &rect)
 
- Static Public Attributes inherited from GrClip
static constexpr SkScalar kBoundsTolerance = 1e-3f
 
static constexpr SkScalar kHalfPixelRoundingTolerance = 5e-2f
 

Detailed Description

Definition at line 33 of file ClipStack.h.

Member Enumeration Documentation

◆ ClipState

enum class skgpu::ganesh::ClipStack::ClipState : uint8_t
strong
Enumerator
kEmpty 
kWideOpen 
kDeviceRect 
kDeviceRRect 
kComplex 

Definition at line 35 of file ClipStack.h.

Constructor & Destructor Documentation

◆ ClipStack() [1/2]

skgpu::ganesh::ClipStack::ClipStack ( const SkIRect deviceBounds,
const SkMatrix ctm,
bool  forceAA 
)

Definition at line 1147 of file ClipStack.cpp.

1148 : fElements(kElementStackIncrement)
1149 , fSaves(kSaveStackIncrement)
1150 , fMasks(kMaskStackIncrement)
1151 , fProxyProvider(nullptr)
1152 , fDeviceBounds(deviceBounds)
1153 , fCTM(ctm)
1154 , fForceAA(forceAA) {
1155 // Start with a save record that is wide open
1156 fSaves.emplace_back(deviceBounds);
1157}
T & emplace_back(Args &&... args)
static constexpr int kElementStackIncrement
static constexpr int kSaveStackIncrement
static constexpr int kMaskStackIncrement

◆ ~ClipStack()

skgpu::ganesh::ClipStack::~ClipStack ( )
override

Definition at line 1159 of file ClipStack.cpp.

1159 {
1160 // Invalidate all mask keys that remain. Since we're tearing the clip stack down, we don't need
1161 // to go through SaveRecord.
1162 SkASSERT(fProxyProvider || fMasks.empty());
1163 if (fProxyProvider) {
1164 for (Mask& m : fMasks.ritems()) {
1165 m.invalidate(fProxyProvider);
1166 }
1167 }
1168}
#define SkASSERT(cond)
Definition SkAssert.h:116
bool empty() const

◆ ClipStack() [2/2]

skgpu::ganesh::ClipStack::ClipStack ( const ClipStack )
delete

Member Function Documentation

◆ apply()

GrClip::Effect skgpu::ganesh::ClipStack::apply ( GrRecordingContext ,
skgpu::ganesh::SurfaceDrawContext ,
GrDrawOp ,
GrAAType  ,
GrAppliedClip ,
SkRect bounds 
) const
overridevirtual

This computes a GrAppliedClip from the clip which in turn can be used to build a GrPipeline. To determine the appropriate clipping implementation the GrClip subclass must know whether the draw will enable HW AA or uses the stencil buffer. On input 'bounds' is a conservative bounds of the draw that is to be clipped. If kClipped or kUnclipped is returned, the 'bounds' will have been updated to be contained within the clip bounds (or the device's, for wide-open clips). If kNoDraw is returned, 'bounds' and the applied clip are in an undetermined state and should be ignored (and the draw should be skipped).

Implements GrClip.

Definition at line 1267 of file ClipStack.cpp.

1272 {
1273 // TODO: Once we no longer store SW masks, we don't need to sneak the provider in like this
1274 if (!fProxyProvider) {
1275 fProxyProvider = rContext->priv().proxyProvider();
1276 }
1277 SkASSERT(fProxyProvider == rContext->priv().proxyProvider());
1278 const GrCaps* caps = rContext->priv().caps();
1279
1280 // Convert the bounds to a Draw and apply device bounds clipping, making our query as tight
1281 // as possible.
1282 Draw draw(*bounds, GrAA(fForceAA || aa != GrAAType::kNone));
1283 if (!draw.applyDeviceBounds(fDeviceBounds)) {
1284 return Effect::kClippedOut;
1285 }
1286 SkAssertResult(bounds->intersect(SkRect::Make(fDeviceBounds)));
1287
1288 const SaveRecord& cs = this->currentSaveRecord();
1289 // Early out if we know a priori that the clip is full 0s or full 1s.
1290 if (cs.state() == ClipState::kEmpty) {
1291 return Effect::kClippedOut;
1292 } else if (cs.state() == ClipState::kWideOpen) {
1293 SkASSERT(!cs.shader());
1294 return Effect::kUnclipped;
1295 }
1296
1297 // Convert any clip shader first, since it's not geometrically related to the draw bounds
1298 std::unique_ptr<GrFragmentProcessor> clipFP = nullptr;
1299 if (cs.shader()) {
1300 static const GrColorInfo kCoverageColorInfo{GrColorType::kUnknown, kPremul_SkAlphaType,
1301 nullptr};
1302 GrFPArgs args(
1303 rContext, &kCoverageColorInfo, sdc->surfaceProps(), GrFPArgs::Scope::kDefault);
1304 clipFP = GrFragmentProcessors::Make(cs.shader(), args, *fCTM);
1305 if (clipFP) {
1306 // The initial input is the coverage from the geometry processor, so this ensures it
1307 // is multiplied properly with the alpha of the clip shader.
1308 clipFP = GrFragmentProcessor::MulInputByChildAlpha(std::move(clipFP));
1309 }
1310 }
1311
1312 // A refers to the entire clip stack, B refers to the draw
1313 switch (get_clip_geometry(cs, draw)) {
1314 case ClipGeometry::kEmpty:
1315 return Effect::kClippedOut;
1316
1317 case ClipGeometry::kBOnly:
1318 // Geometrically unclipped, but may need to add the shader as a coverage FP
1319 if (clipFP) {
1320 out->addCoverageFP(std::move(clipFP));
1321 return Effect::kClipped;
1322 } else {
1323 return Effect::kUnclipped;
1324 }
1325
1326 case ClipGeometry::kAOnly:
1327 // Shouldn't happen since draws don't report inner bounds
1328 SkASSERT(false);
1329 [[fallthrough]];
1330
1331 case ClipGeometry::kBoth:
1332 // The draw is combined with the saved clip elements; the below logic tries to skip
1333 // as many elements as possible.
1334 SkASSERT(cs.state() == ClipState::kDeviceRect ||
1335 cs.state() == ClipState::kDeviceRRect ||
1336 cs.state() == ClipState::kComplex);
1337 break;
1338 }
1339
1340 // We can determine a scissor based on the draw and the overall stack bounds.
1341 SkIRect scissorBounds;
1342 if (cs.op() == SkClipOp::kIntersect) {
1343 // Initially we keep this as large as possible; if the clip is applied solely with coverage
1344 // FPs then using a loose scissor increases the chance we can batch the draws.
1345 // We tighten it later if any form of mask or atlas element is needed.
1346 scissorBounds = cs.outerBounds();
1347 } else {
1348 scissorBounds = subtract(draw.outerBounds(), cs.innerBounds(), /* exact */ true);
1349 }
1350
1351 // We mark this true once we have a coverage FP (since complex clipping is occurring), or we
1352 // have an element that wouldn't affect the scissored draw bounds, but does affect the regular
1353 // draw bounds. In that case, the scissor is sufficient for clipping and we can skip the
1354 // element but definitely cannot then drop the scissor.
1355 bool scissorIsNeeded = SkToBool(cs.shader());
1356 SkDEBUGCODE(bool opClippedInternally = false;)
1357
1358 int remainingAnalyticFPs = kMaxAnalyticFPs;
1359
1360 // If window rectangles are supported, we can use them to exclude inner bounds of difference ops
1361 int maxWindowRectangles = sdc->maxWindowRectangles();
1362 GrWindowRectangles windowRects;
1363
1364 // Elements not represented as an analytic FP or skipped will be collected here and later
1365 // applied by using the stencil buffer or a cached SW mask.
1367
1368 bool maskRequiresAA = false;
1369 auto atlasPathRenderer = rContext->priv().drawingManager()->getAtlasPathRenderer();
1370
1371 int i = fElements.count();
1372 for (const RawElement& e : fElements.ritems()) {
1373 --i;
1374 if (i < cs.oldestElementIndex()) {
1375 // All earlier elements have been invalidated by elements already processed
1376 break;
1377 } else if (e.isInvalid()) {
1378 continue;
1379 }
1380
1381 switch (get_clip_geometry(e, draw)) {
1382 case ClipGeometry::kEmpty:
1383 // This can happen for difference op elements that have a larger fInnerBounds than
1384 // can be preserved at the next level.
1385 return Effect::kClippedOut;
1386
1387 case ClipGeometry::kBOnly:
1388 // We don't need to produce a coverage FP or mask for the element
1389 break;
1390
1391 case ClipGeometry::kAOnly:
1392 // Shouldn't happen for draws, fall through to regular element processing
1393 SkASSERT(false);
1394 [[fallthrough]];
1395
1396 case ClipGeometry::kBoth: {
1397 // The element must apply coverage to the draw, enable the scissor to limit overdraw
1398 scissorIsNeeded = true;
1399
1400 // First apply using HW methods (scissor and window rects). When the inner and outer
1401 // bounds match, nothing else needs to be done.
1402 bool fullyApplied = false;
1403
1404 // First check if the op knows how to apply this clip internally.
1405 SkASSERT(!e.shape().inverted());
1406 auto result = op->clipToShape(sdc, e.op(), e.localToDevice(), e.shape(),
1407 GrAA(e.aa() == GrAA::kYes || fForceAA));
1410 return Effect::kClippedOut;
1411 }
1413 // The op clipped its own geometry. Tighten the draw bounds.
1414 bounds->intersect(SkRect::Make(e.outerBounds()));
1415 }
1416 fullyApplied = true;
1417 SkDEBUGCODE(opClippedInternally = true;)
1418 }
1419
1420 if (!fullyApplied) {
1421 if (e.op() == SkClipOp::kIntersect) {
1422 // The second test allows clipped draws that are scissored by multiple
1423 // elements to remain scissor-only.
1424 fullyApplied = e.innerBounds() == e.outerBounds() ||
1425 e.innerBounds().contains(scissorBounds);
1426 } else {
1427 if (!e.innerBounds().isEmpty() &&
1428 windowRects.count() < maxWindowRectangles) {
1429 // TODO: If we have more difference ops than available window rects, we
1430 // should prioritize those with the largest inner bounds.
1431 windowRects.addWindow(e.innerBounds());
1432 fullyApplied = e.innerBounds() == e.outerBounds();
1433 }
1434 }
1435 }
1436
1437 if (!fullyApplied && remainingAnalyticFPs > 0) {
1438 std::tie(fullyApplied, clipFP) = analytic_clip_fp(e.asElement(),
1439 *caps->shaderCaps(),
1440 std::move(clipFP));
1441 if (!fullyApplied && atlasPathRenderer) {
1442 std::tie(fullyApplied, clipFP) = clip_atlas_fp(sdc, op,
1443 atlasPathRenderer,
1444 scissorBounds, e.asElement(),
1445 std::move(clipFP));
1446 }
1447 if (fullyApplied) {
1448 remainingAnalyticFPs--;
1449 }
1450 }
1451
1452 if (!fullyApplied) {
1453 elementsForMask.push_back(&e.asElement());
1454 maskRequiresAA |= (e.aa() == GrAA::kYes);
1455 }
1456
1457 break;
1458 }
1459 }
1460 }
1461
1462 if (!scissorIsNeeded) {
1463 // More detailed analysis of the element shapes determined no clip is needed
1464 SkASSERT(elementsForMask.empty() && !clipFP);
1465 return Effect::kUnclipped;
1466 }
1467
1468 // Fill out the GrAppliedClip with what we know so far, possibly with a tightened scissor
1469 if (cs.op() == SkClipOp::kIntersect && !elementsForMask.empty()) {
1470 SkAssertResult(scissorBounds.intersect(draw.outerBounds()));
1471 }
1472 if (!GrClip::IsInsideClip(scissorBounds, *bounds, draw.aa())) {
1473 out->hardClip().addScissor(scissorBounds, bounds);
1474 }
1475 if (!windowRects.empty()) {
1476 out->hardClip().addWindowRectangles(windowRects, GrWindowRectsState::Mode::kExclusive);
1477 }
1478
1479 // Now rasterize any remaining elements, either to the stencil or a SW mask. All elements are
1480 // flattened into a single mask.
1481 if (!elementsForMask.empty()) {
1482 bool stencilUnavailable =
1483 !sdc->asRenderTargetProxy()->canUseStencil(*rContext->priv().caps());
1484
1485 bool hasSWMask = false;
1486 if ((sdc->numSamples() <= 1 && !sdc->canUseDynamicMSAA() && maskRequiresAA) ||
1487 stencilUnavailable) {
1488 // Must use a texture mask to represent the combined clip elements since the stencil
1489 // cannot be used, or cannot handle smooth clips.
1490 std::tie(hasSWMask, clipFP) = GetSWMaskFP(
1491 rContext, &fMasks, cs, scissorBounds, elementsForMask.begin(),
1492 elementsForMask.size(), std::move(clipFP));
1493 }
1494
1495 if (!hasSWMask) {
1496 if (stencilUnavailable) {
1497 SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. "
1498 "Draw will be ignored.\n");
1499 return Effect::kClippedOut;
1500 } else {
1501 // Rasterize the remaining elements to the stencil buffer
1502 render_stencil_mask(rContext, sdc, cs.genID(), scissorBounds,
1503 elementsForMask.begin(), elementsForMask.size(), out);
1504 }
1505 }
1506 }
1507
1508 if (clipFP) {
1509 // This will include all analytic FPs, all atlas FPs, and a SW mask FP.
1510 out->addCoverageFP(std::move(clipFP));
1511 }
1512
1513 SkASSERT(out->doesClip() || opClippedInternally);
1514 return Effect::kClipped;
1515}
GrAA
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkAssertResult(cond)
Definition SkAssert.h:123
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
static bool subtract(const R &a, const R &b, R *out)
Definition SkRect.cpp:177
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
static void draw(SkCanvas *canvas, SkRect &target, int x, int y)
Definition aaclip.cpp:27
const GrShaderCaps * shaderCaps() const
Definition GrCaps.h:63
static bool IsInsideClip(const SkIRect &innerClipBounds, const SkRect &drawBounds, GrAA aa)
Definition GrClip.h:128
static std::unique_ptr< GrFragmentProcessor > MulInputByChildAlpha(std::unique_ptr< GrFragmentProcessor > child)
SkIRect & addWindow(const SkIRect &window)
int count() const
bool empty() const
Definition SkTArray.h:194
int size() const
Definition SkTArray.h:416
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
std::unique_ptr< GrFragmentProcessor > Make(const SkMaskFilter *maskfilter, const GrFPArgs &args, const SkMatrix &ctm)
Optional< SkRect > bounds
Definition SkRecords.h:189
static constexpr int kMaxAnalyticFPs
bool intersect(const SkIRect &r)
Definition SkRect.h:513
static SkRect Make(const SkISize &size)
Definition SkRect.h:669

◆ begin()

ClipStack::ElementIter skgpu::ganesh::ClipStack::begin ( ) const
inline

Definition at line 361 of file ClipStack.h.

361 {
362 if (this->currentSaveRecord().state() == ClipState::kEmpty ||
363 this->currentSaveRecord().state() == ClipState::kWideOpen) {
364 // No visible clip elements when empty or wide open
365 return this->end();
366 }
367 int count = fElements.count() - this->currentSaveRecord().oldestElementIndex();
368 return ElementIter(fElements.ritems().begin(), count);
369}
int count
Item begin() const
ElementIter end() const
Definition ClipStack.h:371
AtkStateType state

◆ clipPath()

void skgpu::ganesh::ClipStack::clipPath ( const SkMatrix ctm,
const SkPath path,
GrAA  aa,
SkClipOp  op 
)
inline

Definition at line 80 of file ClipStack.h.

80 {
81 this->clip({ctm, GrShape(path), aa, op});
82 }

◆ clipRect()

void skgpu::ganesh::ClipStack::clipRect ( const SkMatrix ctm,
const SkRect rect,
GrAA  aa,
SkClipOp  op 
)
inline

Definition at line 74 of file ClipStack.h.

74 {
75 this->clip({ctm, GrShape(rect), aa, op});
76 }

◆ clipRRect()

void skgpu::ganesh::ClipStack::clipRRect ( const SkMatrix ctm,
const SkRRect rrect,
GrAA  aa,
SkClipOp  op 
)
inline

Definition at line 77 of file ClipStack.h.

77 {
78 this->clip({ctm, GrShape(rrect), aa, op});
79 }

◆ clipShader()

void skgpu::ganesh::ClipStack::clipShader ( sk_sp< SkShader shader)

Definition at line 1531 of file ClipStack.cpp.

1531 {
1532 // Shaders can't bring additional coverage
1533 if (this->currentSaveRecord().state() == ClipState::kEmpty) {
1534 return;
1535 }
1536
1537 bool wasDeferred;
1538 this->writableSaveRecord(&wasDeferred).addShader(std::move(shader));
1539 // Masks and geometry elements are not invalidated by updating the clip shader
1540}

◆ clipState()

ClipState skgpu::ganesh::ClipStack::clipState ( ) const
inline

Definition at line 62 of file ClipStack.h.

62{ return this->currentSaveRecord().state(); }

◆ end()

ClipStack::ElementIter skgpu::ganesh::ClipStack::end ( ) const
inline

Definition at line 371 of file ClipStack.h.

371 {
372 return ElementIter(fElements.ritems().end(), 0);
373}

◆ getConservativeBounds()

SkIRect skgpu::ganesh::ClipStack::getConservativeBounds ( ) const
overridevirtual

Compute a conservative pixel bounds restricted to the given render target dimensions. The returned bounds represent the limits of pixels that can be drawn; anything outside of the bounds will be entirely clipped out.

Implements GrClip.

Definition at line 1195 of file ClipStack.cpp.

1195 {
1196 const SaveRecord& current = this->currentSaveRecord();
1197 if (current.state() == ClipState::kEmpty) {
1198 return SkIRect::MakeEmpty();
1199 } else if (current.state() == ClipState::kWideOpen) {
1200 return fDeviceBounds;
1201 } else {
1202 if (current.op() == SkClipOp::kDifference) {
1203 // The outer/inner bounds represent what's cut out, so full bounds remains the device
1204 // bounds, minus any fully clipped content that spans the device edge.
1205 return subtract(fDeviceBounds, current.innerBounds(), /* exact */ true);
1206 } else {
1207 SkASSERT(fDeviceBounds.contains(current.outerBounds()));
1208 return current.outerBounds();
1209 }
1210 }
1211}
static constexpr SkIRect MakeEmpty()
Definition SkRect.h:45
bool contains(int32_t x, int32_t y) const
Definition SkRect.h:463

◆ operator=()

ClipStack & skgpu::ganesh::ClipStack::operator= ( const ClipStack )
delete

◆ preApply()

GrClip::PreClipResult skgpu::ganesh::ClipStack::preApply ( const SkRect drawBounds,
GrAA  aa 
) const
overridevirtual

Perform preliminary, conservative analysis on the draw bounds as if it were provided to apply(). The results of this are returned the PreClipResults struct, where 'result.fEffect' corresponds to what 'apply' would return. If this value is kUnclipped or kNoDraw, then it can be assumed that apply() would also always result in the same Effect.

If kClipped is returned, apply() may further refine the effect to kUnclipped or kNoDraw, with one exception. When 'result.fIsRRect' is true, preApply() reports the single round rect and anti-aliased state that would act as an intersection on the draw geometry. If no further action is taken to modify the draw, apply() will represent this round rect in the applied clip.

When set, 'result.fRRect' will intersect with the render target bounds but may extend beyond it. If the render target bounds are the only clip effect on the draw, this is reported as kUnclipped and not as a degenerate rrect that matches the bounds.

Reimplemented from GrClip.

Definition at line 1213 of file ClipStack.cpp.

1213 {
1214 Draw draw(bounds, fForceAA ? GrAA::kYes : aa);
1215 if (!draw.applyDeviceBounds(fDeviceBounds)) {
1217 }
1218
1219 const SaveRecord& cs = this->currentSaveRecord();
1220 // Early out if we know a priori that the clip is full 0s or full 1s.
1221 if (cs.state() == ClipState::kEmpty) {
1223 } else if (cs.state() == ClipState::kWideOpen) {
1224 SkASSERT(!cs.shader());
1226 }
1227
1228 // Given argument order, 'A' == current clip, 'B' == draw
1229 switch (get_clip_geometry(cs, draw)) {
1230 case ClipGeometry::kEmpty:
1231 // Can ignore the shader since the geometry removed everything already
1233
1234 case ClipGeometry::kBOnly:
1235 // Geometrically, the draw is unclipped, but can't ignore a shader
1237
1238 case ClipGeometry::kAOnly:
1239 // Shouldn't happen since the inner bounds of a draw are unknown
1240 SkASSERT(false);
1241 // But if it did, it technically means the draw covered the clip and should be
1242 // considered kClipped or similar, which is what the next case handles.
1243 [[fallthrough]];
1244
1245 case ClipGeometry::kBoth: {
1246 SkASSERT(fElements.count() > 0);
1247 const RawElement& back = fElements.back();
1248 if (cs.state() == ClipState::kDeviceRect) {
1249 SkASSERT(back.clipType() == ClipState::kDeviceRect);
1250 return {back.shape().rect(), back.aa()};
1251 } else if (cs.state() == ClipState::kDeviceRRect) {
1252 SkASSERT(back.clipType() == ClipState::kDeviceRRect);
1253 return {back.shape().rrect(), back.aa()};
1254 } else {
1255 // The clip stack has complex shapes, multiple elements, or a shader; we could
1256 // iterate per element like we would in apply(), but preApply() is meant to be
1257 // conservative and efficient.
1258 SkASSERT(cs.state() == ClipState::kComplex);
1260 }
1261 }
1262 }
1263
1265}
#define SkUNREACHABLE
Definition SkAssert.h:135

◆ replaceClip()

void skgpu::ganesh::ClipStack::replaceClip ( const SkIRect rect)

Definition at line 1542 of file ClipStack.cpp.

1542 {
1543 bool wasDeferred;
1544 SaveRecord& save = this->writableSaveRecord(&wasDeferred);
1545
1546 if (!wasDeferred) {
1547 save.removeElements(&fElements);
1548 save.invalidateMasks(fProxyProvider, &fMasks);
1549 }
1550
1551 save.reset(fDeviceBounds);
1552 if (rect != fDeviceBounds) {
1554 }
1555}
static const SkMatrix & I()
void clipRect(const SkMatrix &ctm, const SkRect &rect, GrAA aa, SkClipOp op)
Definition ClipStack.h:74

◆ restore()

void skgpu::ganesh::ClipStack::restore ( )

Definition at line 1175 of file ClipStack.cpp.

1175 {
1176 SkASSERT(!fSaves.empty());
1177 SaveRecord& current = fSaves.back();
1178 if (current.popSave()) {
1179 // This was just a deferred save being undone, so the record doesn't need to be removed yet
1180 return;
1181 }
1182
1183 // When we remove a save record, we delete all elements >= its starting index and any masks
1184 // that were rasterized for it.
1185 current.removeElements(&fElements);
1186 SkASSERT(fProxyProvider || fMasks.empty());
1187 if (fProxyProvider) {
1188 current.invalidateMasks(fProxyProvider, &fMasks);
1189 }
1190 fSaves.pop_back();
1191 // Restore any remaining elements that were only invalidated by the now-removed save record.
1192 fSaves.back().restoreElements(&fElements);
1193}

◆ save()

void skgpu::ganesh::ClipStack::save ( )

Definition at line 1170 of file ClipStack.cpp.

1170 {
1171 SkASSERT(!fSaves.empty());
1172 fSaves.back().pushSave();
1173}

The documentation for this class was generated from the following files: