blob: 8ac5757cbde7a018a5c45b48c914ffb3acedcb41 [file] [log] [blame]
/*
* 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/ganesh/GrStencilSettings.h"
#include "include/private/base/SkDebug.h"
#include "src/gpu/KeyBuilder.h"
#include <algorithm>
#include <cstddef>
#include <cstring>
constexpr const GrUserStencilSettings gUnused(
GrUserStencilSettings::StaticInit<
0x0000,
GrUserStencilTest::kAlwaysIfInClip,
0xffff,
GrUserStencilOp::kKeep,
GrUserStencilOp::kKeep,
0x0000>()
);
static_assert(kAll_StencilFlags == (gUnused.fCWFlags[0] & gUnused.fCCWFlags[0]));
const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;
void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
int numStencilBits) {
uint16_t cwFlags = user.fCWFlags[hasStencilClip];
if (cwFlags & kSingleSided_StencilFlag) {
SkASSERT(cwFlags == user.fCCWFlags[hasStencilClip]);
fFlags = cwFlags;
if (!this->isDisabled()) {
fCWFace.reset(user.fCWFace, hasStencilClip, numStencilBits);
}
return;
}
uint16_t ccwFlags = user.fCCWFlags[hasStencilClip];
fFlags = cwFlags & ccwFlags;
if (this->isDisabled()) {
return;
}
if (!(cwFlags & kDisabled_StencilFlag)) {
fCWFace.reset(user.fCWFace, hasStencilClip, numStencilBits);
} else {
fCWFace.setDisabled();
}
if (!(ccwFlags & kDisabled_StencilFlag)) {
fCCWFace.reset(user.fCCWFace, hasStencilClip, numStencilBits);
} else {
fCCWFace.setDisabled();
}
}
void GrStencilSettings::reset(const GrStencilSettings& that) {
fFlags = that.fFlags;
if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
return;
}
if (!this->isTwoSided()) {
memcpy(&fCWFace, &that.fCWFace, sizeof(Face));
} else {
memcpy(&fCWFace, &that.fCWFace, 2 * sizeof(Face));
static_assert(sizeof(Face) ==
offsetof(GrStencilSettings, fCCWFace) - offsetof(GrStencilSettings, fCWFace));
}
}
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(&fCWFace, &that.fCWFace, sizeof(Face)); // Both are single sided.
} else if (kSingleSided_StencilFlag & (fFlags | that.fFlags)) {
return false;
} else {
return 0 == memcmp(&fCWFace, &that.fCWFace, 2 * sizeof(Face));
static_assert(sizeof(Face) ==
offsetof(GrStencilSettings, fCCWFace) - offsetof(GrStencilSettings, fCWFace));
}
// memcmp relies on GrStencilSettings::Face being tightly packed.
static_assert(0 == offsetof(Face, fRef));
static_assert(2 == sizeof(Face::fRef));
static_assert(2 == offsetof(Face, fTest));
static_assert(2 == sizeof(Face::fTest));
static_assert(4 == offsetof(Face, fTestMask));
static_assert(2 == sizeof(Face::fTestMask));
static_assert(6 == offsetof(Face, fPassOp));
static_assert(1 == sizeof(Face::fPassOp));
static_assert(7 == offsetof(Face, fFailOp));
static_assert(1 == sizeof(Face::fFailOp));
static_assert(8 == offsetof(Face, fWriteMask));
static_assert(2 == sizeof(Face::fWriteMask));
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
};
static_assert(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
static_assert(1 == (int)GrUserStencilTest::kEqualIfInClip);
static_assert(2 == (int)GrUserStencilTest::kLessIfInClip);
static_assert(3 == (int)GrUserStencilTest::kLEqualIfInClip);
static_assert(4 == (int)GrUserStencilTest::kAlways);
static_assert(5 == (int)GrUserStencilTest::kNever);
static_assert(6 == (int)GrUserStencilTest::kGreater);
static_assert(7 == (int)GrUserStencilTest::kGEqual);
static_assert(8 == (int)GrUserStencilTest::kLess);
static_assert(9 == (int)GrUserStencilTest::kLEqual);
static_assert(10 == (int)GrUserStencilTest::kEqual);
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.
};
static_assert(0 == (int)GrUserStencilOp::kKeep);
static_assert(1 == (int)GrUserStencilOp::kZero);
static_assert(2 == (int)GrUserStencilOp::kReplace);
static_assert(3 == (int)GrUserStencilOp::kInvert);
static_assert(4 == (int)GrUserStencilOp::kIncWrap);
static_assert(5 == (int)GrUserStencilOp::kDecWrap);
static_assert(6 == (int)GrUserStencilOp::kIncMaybeClamp);
static_assert(7 == (int)GrUserStencilOp::kDecMaybeClamp);
static_assert(8 == (int)GrUserStencilOp::kZeroClipBit);
static_assert(9 == (int)GrUserStencilOp::kSetClipBit);
static_assert(10 == (int)GrUserStencilOp::kInvertClipBit);
static_assert(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
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 = std::max(user.fPassOp, user.fFailOp);
SkDEBUGCODE(GrUserStencilOp otherOp = std::min(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));
static_assert(0 == (int)GrStencilTest::kAlways);
static_assert(0 == (int)GrStencilOp::kKeep);
}
static constexpr GrUserStencilSettings gZeroStencilClipBit(
GrUserStencilSettings::StaticInit<
0x0000,
GrUserStencilTest::kAlways,
0xffff,
GrUserStencilOp::kZeroClipBit,
GrUserStencilOp::kZeroClipBit,
0x0000>()
);
static constexpr GrUserStencilSettings gSetStencilClipBit(
GrUserStencilSettings::StaticInit<
0x0000,
GrUserStencilTest::kAlways,
0xffff,
GrUserStencilOp::kSetClipBit,
GrUserStencilOp::kSetClipBit,
0x0000>()
);
const GrUserStencilSettings* GrStencilSettings::SetClipBitSettings(bool setToInside) {
return setToInside ? &gSetStencilClipBit : &gZeroStencilClipBit;
}
void GrStencilSettings::genKey(skgpu::KeyBuilder* b, bool includeRefs) const {
b->addBits(6, fFlags, "stencilFlags");
if (this->isDisabled()) {
return;
}
if (!this->isTwoSided()) {
if (includeRefs) {
b->addBytes(sizeof(Face), &fCWFace, "stencilCWFace");
} else {
Face tempFace = fCWFace;
tempFace.fRef = 0;
b->addBytes(sizeof(Face), &tempFace, "stencilCWFace");
}
} else {
if (includeRefs) {
b->addBytes(sizeof(Face), &fCWFace, "stencilCWFace");
b->addBytes(sizeof(Face), &fCCWFace, "stencilCCWFace");
} else {
Face tempFaces[2];
tempFaces[0] = fCWFace;
tempFaces[0].fRef = 0;
tempFaces[1] = fCCWFace;
tempFaces[1].fRef = 0;
b->addBytes(sizeof(Face), &tempFaces[0], "stencilCWFace");
b->addBytes(sizeof(Face), &tempFaces[1], "stencilCCWFace");
}
}
// We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
static_assert(0 == offsetof(Face, fRef));
static_assert(2 == sizeof(Face::fRef));
static_assert(2 == offsetof(Face, fTest));
static_assert(2 == sizeof(Face::fTest));
static_assert(4 == offsetof(Face, fTestMask));
static_assert(2 == sizeof(Face::fTestMask));
static_assert(6 == offsetof(Face, fPassOp));
static_assert(1 == sizeof(Face::fPassOp));
static_assert(7 == offsetof(Face, fFailOp));
static_assert(1 == sizeof(Face::fFailOp));
static_assert(8 == offsetof(Face, fWriteMask));
static_assert(2 == sizeof(Face::fWriteMask));
static_assert(10 == sizeof(Face));
}