123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506 |
- /*
- * Copyright 2011 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/gpu/GrStencilSettings.h"
- #include "src/gpu/GrProcessor.h"
- constexpr const GrUserStencilSettings gUnused(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kKeep,
- GrUserStencilOp::kKeep,
- 0x0000>()
- );
- GR_STATIC_ASSERT(kAll_StencilFlags == (gUnused.fFrontFlags[0] & gUnused.fBackFlags[0]));
- const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;
- void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
- int numStencilBits) {
- uint16_t frontFlags = user.fFrontFlags[hasStencilClip];
- if (frontFlags & kSingleSided_StencilFlag) {
- SkASSERT(frontFlags == user.fBackFlags[hasStencilClip]);
- fFlags = frontFlags;
- if (!this->isDisabled()) {
- fFront.reset(user.fFront, hasStencilClip, numStencilBits);
- }
- return;
- }
- uint16_t backFlags = user.fBackFlags[hasStencilClip];
- fFlags = frontFlags & backFlags;
- if (this->isDisabled()) {
- return;
- }
- if (!(frontFlags & kDisabled_StencilFlag)) {
- fFront.reset(user.fFront, hasStencilClip, numStencilBits);
- } else {
- fFront.setDisabled();
- }
- if (!(backFlags & kDisabled_StencilFlag)) {
- fBack.reset(user.fBack, hasStencilClip, numStencilBits);
- } else {
- fBack.setDisabled();
- }
- }
- void GrStencilSettings::reset(const GrStencilSettings& that) {
- fFlags = that.fFlags;
- if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
- return;
- }
- if (!this->isTwoSided()) {
- memcpy(&fFront, &that.fFront, sizeof(Face));
- } else {
- memcpy(&fFront, &that.fFront, 2 * sizeof(Face));
- GR_STATIC_ASSERT(sizeof(Face) ==
- offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
- }
- }
- bool GrStencilSettings::operator==(const GrStencilSettings& that) const {
- if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & (fFlags | that.fFlags)) {
- // At least one is invalid and/or disabled.
- if (kInvalid_PrivateFlag & (fFlags | that.fFlags)) {
- return false; // We never allow invalid stencils to be equal.
- }
- // They're only equal if both are disabled.
- return kDisabled_StencilFlag & (fFlags & that.fFlags);
- }
- if (kSingleSided_StencilFlag & (fFlags & that.fFlags)) {
- return 0 == memcmp(&fFront, &that.fFront, sizeof(Face)); // Both are single sided.
- } else if (kSingleSided_StencilFlag & (fFlags | that.fFlags)) {
- return false;
- } else {
- return 0 == memcmp(&fFront, &that.fFront, 2 * sizeof(Face));
- GR_STATIC_ASSERT(sizeof(Face) ==
- offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
- }
- // memcmp relies on GrStencilSettings::Face being tightly packed.
- GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
- GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
- GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
- GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
- GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
- GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
- GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
- GR_STATIC_ASSERT(10 == sizeof(Face));
- }
- static constexpr GrStencilTest gUserStencilTestToRaw[kGrUserStencilTestCount] = {
- // Tests that respect the clip.
- GrStencilTest::kAlways, // kAlwaysIfInClip (This is only for when there is not a stencil clip).
- GrStencilTest::kEqual, // kEqualIfInClip.
- GrStencilTest::kLess, // kLessIfInClip.
- GrStencilTest::kLEqual, // kLEqualIfInClip.
- // Tests that ignore the clip.
- GrStencilTest::kAlways,
- GrStencilTest::kNever,
- GrStencilTest::kGreater,
- GrStencilTest::kGEqual,
- GrStencilTest::kLess,
- GrStencilTest::kLEqual,
- GrStencilTest::kEqual,
- GrStencilTest::kNotEqual
- };
- GR_STATIC_ASSERT(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
- GR_STATIC_ASSERT(1 == (int)GrUserStencilTest::kEqualIfInClip);
- GR_STATIC_ASSERT(2 == (int)GrUserStencilTest::kLessIfInClip);
- GR_STATIC_ASSERT(3 == (int)GrUserStencilTest::kLEqualIfInClip);
- GR_STATIC_ASSERT(4 == (int)GrUserStencilTest::kAlways);
- GR_STATIC_ASSERT(5 == (int)GrUserStencilTest::kNever);
- GR_STATIC_ASSERT(6 == (int)GrUserStencilTest::kGreater);
- GR_STATIC_ASSERT(7 == (int)GrUserStencilTest::kGEqual);
- GR_STATIC_ASSERT(8 == (int)GrUserStencilTest::kLess);
- GR_STATIC_ASSERT(9 == (int)GrUserStencilTest::kLEqual);
- GR_STATIC_ASSERT(10 == (int)GrUserStencilTest::kEqual);
- GR_STATIC_ASSERT(11 == (int)GrUserStencilTest::kNotEqual);
- static constexpr GrStencilOp gUserStencilOpToRaw[kGrUserStencilOpCount] = {
- GrStencilOp::kKeep,
- // Ops that only modify user bits.
- GrStencilOp::kZero,
- GrStencilOp::kReplace,
- GrStencilOp::kInvert,
- GrStencilOp::kIncWrap,
- GrStencilOp::kDecWrap,
- GrStencilOp::kIncClamp, // kIncMaybeClamp.
- GrStencilOp::kDecClamp, // kDecMaybeClamp.
- // Ops that only modify the clip bit.
- GrStencilOp::kZero, // kZeroClipBit.
- GrStencilOp::kReplace, // kSetClipBit.
- GrStencilOp::kInvert, // kInvertClipBit.
- // Ops that modify clip and user bits.
- GrStencilOp::kReplace, // kSetClipAndReplaceUserBits.
- GrStencilOp::kZero // kZeroClipAndUserBits.
- };
- GR_STATIC_ASSERT(0 == (int)GrUserStencilOp::kKeep);
- GR_STATIC_ASSERT(1 == (int)GrUserStencilOp::kZero);
- GR_STATIC_ASSERT(2 == (int)GrUserStencilOp::kReplace);
- GR_STATIC_ASSERT(3 == (int)GrUserStencilOp::kInvert);
- GR_STATIC_ASSERT(4 == (int)GrUserStencilOp::kIncWrap);
- GR_STATIC_ASSERT(5 == (int)GrUserStencilOp::kDecWrap);
- GR_STATIC_ASSERT(6 == (int)GrUserStencilOp::kIncMaybeClamp);
- GR_STATIC_ASSERT(7 == (int)GrUserStencilOp::kDecMaybeClamp);
- GR_STATIC_ASSERT(8 == (int)GrUserStencilOp::kZeroClipBit);
- GR_STATIC_ASSERT(9 == (int)GrUserStencilOp::kSetClipBit);
- GR_STATIC_ASSERT(10 == (int)GrUserStencilOp::kInvertClipBit);
- GR_STATIC_ASSERT(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
- GR_STATIC_ASSERT(12 == (int)GrUserStencilOp::kZeroClipAndUserBits);
- void GrStencilSettings::Face::reset(const GrUserStencilSettings::Face& user, bool hasStencilClip,
- int numStencilBits) {
- SkASSERT(user.fTest < (GrUserStencilTest)kGrUserStencilTestCount);
- SkASSERT(user.fPassOp < (GrUserStencilOp)kGrUserStencilOpCount);
- SkASSERT(user.fFailOp < (GrUserStencilOp)kGrUserStencilOpCount);
- SkASSERT(numStencilBits > 0 && numStencilBits <= 16);
- int clipBit = 1 << (numStencilBits - 1);
- int userMask = clipBit - 1;
- GrUserStencilOp maxOp = SkTMax(user.fPassOp, user.fFailOp);
- SkDEBUGCODE(GrUserStencilOp otherOp = SkTMin(user.fPassOp, user.fFailOp);)
- if (maxOp <= kLastUserOnlyStencilOp) {
- // Ops that only modify user bits.
- fWriteMask = user.fWriteMask & userMask;
- SkASSERT(otherOp <= kLastUserOnlyStencilOp);
- } else if (maxOp <= kLastClipOnlyStencilOp) {
- // Ops that only modify the clip bit.
- fWriteMask = clipBit;
- SkASSERT(GrUserStencilOp::kKeep == otherOp ||
- (otherOp > kLastUserOnlyStencilOp && otherOp <= kLastClipOnlyStencilOp));
- } else {
- // Ops that modify both clip and user bits.
- fWriteMask = clipBit | (user.fWriteMask & userMask);
- SkASSERT(GrUserStencilOp::kKeep == otherOp || otherOp > kLastClipOnlyStencilOp);
- }
- fFailOp = gUserStencilOpToRaw[(int)user.fFailOp];
- fPassOp = gUserStencilOpToRaw[(int)user.fPassOp];
- if (!hasStencilClip || user.fTest > kLastClippedStencilTest) {
- // Ignore the clip.
- fTestMask = user.fTestMask & userMask;
- fTest = gUserStencilTestToRaw[(int)user.fTest];
- } else if (GrUserStencilTest::kAlwaysIfInClip != user.fTest) {
- // Respect the clip.
- fTestMask = clipBit | (user.fTestMask & userMask);
- fTest = gUserStencilTestToRaw[(int)user.fTest];
- } else {
- // Test only for clip.
- fTestMask = clipBit;
- fTest = GrStencilTest::kEqual;
- }
- fRef = (clipBit | user.fRef) & (fTestMask | fWriteMask);
- }
- void GrStencilSettings::Face::setDisabled() {
- memset(this, 0, sizeof(*this));
- GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
- GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
- }
- ////////////////////////////////////////////////////////////////////////////////
- // Stencil Rules for Merging user stencil space into clip
- //
- ///////
- // Replace
- static constexpr GrUserStencilSettings gUserToClipReplace(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
- );
- static constexpr GrUserStencilSettings gInvUserToClipReplace(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
- );
- ///////
- // Intersect
- static constexpr GrUserStencilSettings gUserToClipIsect(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kLessIfInClip, // "0 < userBits" is equivalent to "0 != userBits".
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
- );
- ///////
- // Difference
- static constexpr GrUserStencilSettings gUserToClipDiff(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqualIfInClip,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
- );
- ///////
- // Union
- static constexpr GrUserStencilSettings gUserToClipUnion(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kKeep,
- 0xffff>()
- );
- static constexpr GrUserStencilSettings gInvUserToClipUnionPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kSetClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
- );
- ///////
- // Xor
- static constexpr GrUserStencilSettings gUserToClipXorPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
- );
- static constexpr GrUserStencilSettings gInvUserToClipXorPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
- );
- ///////
- // Reverse Diff
- static constexpr GrUserStencilSettings gUserToClipRDiffPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kZeroClipBit,
- 0x0000>()
- );
- static constexpr GrUserStencilSettings gInvUserToClipRDiffPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kZeroClipBit,
- 0x0000>()
- );
- ///////
- // Second pass to clear user bits (only needed sometimes)
- static constexpr GrUserStencilSettings gZeroUserBits(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kKeep,
- 0xffff>()
- );
- static constexpr const GrUserStencilSettings* gUserToClipTable[2][1 + SkRegion::kLastOp][3] = {
- { /* Normal fill. */
- {&gUserToClipDiff, nullptr, nullptr}, // kDifference_Op.
- {&gUserToClipIsect, nullptr, nullptr}, // kIntersect_Op.
- {&gUserToClipUnion, nullptr, nullptr}, // kUnion_Op.
- {&gUserToClipXorPass0, &gZeroUserBits, nullptr}, // kXOR_Op.
- {&gUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // kReverseDifference_Op.
- {&gUserToClipReplace, nullptr, nullptr} // kReplace_Op.
- }, /* Inverse fill. */ {
- {&gUserToClipIsect, nullptr, nullptr}, // ~diff (aka isect).
- {&gUserToClipDiff, nullptr, nullptr}, // ~isect (aka diff).
- {&gInvUserToClipUnionPass0, &gZeroUserBits, nullptr}, // ~union.
- {&gInvUserToClipXorPass0, &gZeroUserBits, nullptr}, // ~xor.
- {&gInvUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // ~reverse diff.
- {&gInvUserToClipReplace, nullptr, nullptr} // ~replace.
- }
- };
- GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
- GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
- GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
- GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
- GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
- GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
- ///////
- // Direct to Stencil
- // We can render a clip element directly without first writing to the client
- // portion of the clip when the fill is not inverse and the set operation will
- // only modify the in/out status of samples covered by the clip element.
- // this one only works if used right after stencil clip was cleared.
- // Our clip mask creation code doesn't allow midstream replace ops.
- static constexpr GrUserStencilSettings gReplaceClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kSetClipBit,
- GrUserStencilOp::kSetClipBit,
- 0x0000>()
- );
- static constexpr GrUserStencilSettings gUnionClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kKeep,
- GrUserStencilOp::kSetClipBit,
- 0x0000>()
- );
- static constexpr GrUserStencilSettings gXorClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kInvertClipBit,
- 0x0000>()
- );
- static constexpr GrUserStencilSettings gDiffClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kZeroClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
- );
- static constexpr const GrUserStencilSettings* gDirectDrawTable[1 + SkRegion::kLastOp][2] = {
- {&gDiffClip, nullptr}, // kDifference_Op.
- {nullptr, nullptr}, // kIntersect_Op.
- {&gUnionClip, nullptr}, // kUnion_Op.
- {&gXorClip, nullptr}, // kXOR_Op.
- {nullptr, nullptr}, // kReverseDifference_Op.
- {&gReplaceClip, nullptr} // kReplace_Op.
- };
- GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
- GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
- GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
- GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
- GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
- GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
- GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::Op op,
- bool canBeDirect,
- bool invertedFill,
- bool* drawDirectToClip) {
- SkASSERT((unsigned)op <= SkRegion::kLastOp);
- if (canBeDirect && !invertedFill) { // TODO: inverse fill + intersect op can be direct.
- GrUserStencilSettings const* const* directPass = gDirectDrawTable[op];
- if (directPass[0]) {
- *drawDirectToClip = true;
- return directPass;
- }
- }
- *drawDirectToClip = false;
- return gUserToClipTable[invertedFill][op];
- }
- static constexpr GrUserStencilSettings gZeroStencilClipBit(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kZeroClipBit,
- GrUserStencilOp::kZeroClipBit,
- 0x0000>()
- );
- const GrUserStencilSettings* GrStencilSettings::SetClipBitSettings(bool setToInside) {
- return setToInside ? &gReplaceClip : &gZeroStencilClipBit;
- }
- void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
- b->add32(fFlags);
- if (this->isDisabled()) {
- return;
- }
- if (!this->isTwoSided()) {
- constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
- GR_STATIC_ASSERT(0 == sizeof(Face) % sizeof(uint16_t));
- uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
- memcpy(key, &fFront, sizeof(Face));
- key[kCount16] = 0;
- GR_STATIC_ASSERT(1 == kCount16 % 2);
- } else {
- constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
- GR_STATIC_ASSERT(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
- uint32_t* key = b->add32n(kCount32);
- memcpy(key, &fFront, 2 * sizeof(Face));
- GR_STATIC_ASSERT(sizeof(Face) ==
- offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
- }
- // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
- GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
- GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
- GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
- GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
- GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
- GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
- GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
- GR_STATIC_ASSERT(10 == sizeof(Face));
- }
|