Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Unified Diff: src/gpu/GrUserStencilSettings.h

Issue 1962243002: Separate user and raw stencil settings (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/gpu/GrStencilSettings.cpp ('k') | src/gpu/batches/GrDefaultPathRenderer.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/gpu/GrUserStencilSettings.h
diff --git a/src/gpu/GrUserStencilSettings.h b/src/gpu/GrUserStencilSettings.h
new file mode 100644
index 0000000000000000000000000000000000000000..a07a08300a72d5b8aa8441d6cb97511f87649217
--- /dev/null
+++ b/src/gpu/GrUserStencilSettings.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrUserStencilSettings_DEFINED
+#define GrUserStencilSettings_DEFINED
+
+#include "GrTypes.h"
+
+/**
+ * Gr uses the stencil buffer to implement complex clipping inside the
+ * GrDrawTarget class. The GrDrawTarget makes a subset of the stencil buffer
+ * bits available for other uses by external code (user bits). Client code can
+ * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
+ * provided by clients that fall outside the user range.
+ *
+ * When code outside the GrDrawTarget class uses the stencil buffer the contract
+ * is as follows:
+ *
+ * > Normal stencil funcs allow the client to pass / fail regardless of the
+ * reserved clip bits.
+ * > Additional functions allow a test against the clip along with a limited
+ * set of tests against the user bits.
+ * > Client can assume all user bits are zero initially.
+ * > Client must ensure that after all its passes are finished it has only
+ * written to the color buffer in the region inside the clip. Furthermore, it
+ * must zero all user bits that were modifed (both inside and outside the
+ * clip).
+ */
+
+enum GrStencilFlags {
+ kDisabled_StencilFlag = 0x1,
+ kNoModifyStencil_StencilFlag = 0x2,
+ kNoWrapOps_StencilFlag = 0x4,
+ kSingleSided_StencilFlag = 0x8,
+
+ kLast_StencilFlag = kSingleSided_StencilFlag,
+ kAll_StencilFlags = kLast_StencilFlag | (kLast_StencilFlag - 1)
+};
+
+template<typename TTest, typename TOp> struct GrTStencilFaceSettings {
+ uint16_t fRef; // Reference value for stencil test and ops.
+ TTest fTest; // Stencil test function, where fRef is on the left side.
+ uint16_t fTestMask; // Bitwise "and" to perform on fRef and stencil values before testing.
+ // (e.g. (fRef & fTestMask) < (stencil & fTestMask))
+ TOp fPassOp; // Op to perform when the test passes.
+ TOp fFailOp; // Op to perform when the test fails.
+ uint16_t fWriteMask; // Indicates which bits in the stencil buffer should be updated.
+ // (e.g. stencil = (newValue & fWriteMask) | (stencil & ~fWriteMask))
+};
+
+enum class GrUserStencilTest : uint16_t {
+ // Tests that respect the clip bit. If a stencil clip is not in effect, the "IfInClip" is
+ // ignored and these only act on user bits.
+ kAlwaysIfInClip,
+ kEqualIfInClip,
+ kLessIfInClip,
+ kLEqualIfInClip,
+
+ // Tests that ignore the clip bit. The client is responsible to ensure no color write occurs
+ // outside the clip if it is in use.
+ kAlways,
+ kNever,
+ kGreater,
+ kGEqual,
+ kLess,
+ kLEqual,
+ kEqual,
+ kNotEqual
+};
+constexpr static GrUserStencilTest kLastClippedStencilTest = GrUserStencilTest::kLEqualIfInClip;
+constexpr static int kGrUserStencilTestCount = 1 + (int)GrUserStencilTest::kNotEqual;
+
+enum class GrUserStencilOp : uint8_t {
+ kKeep,
+
+ // Ops that only modify user bits. These must not be paired with ops that modify the clip bit.
+ kZero,
+ kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask).
+ kInvert,
+ kIncWrap,
+ kDecWrap,
+ // These two should only be used if wrap ops are not supported, or if the math is guaranteed
+ // to not overflow. The user bits may or may not clamp, depending on the state of non-user bits.
+ kIncMaybeClamp,
+ kDecMaybeClamp,
+
+ // Ops that only modify the clip bit. These must not be paired with ops that modify user bits.
+ kZeroClipBit,
+ kSetClipBit,
+ kInvertClipBit,
+
+ // Ops that modify both clip and user bits. These can only be paired with kKeep or each other.
+ kSetClipAndReplaceUserBits,
+ kZeroClipAndUserBits
+};
+constexpr static GrUserStencilOp kLastUserOnlyStencilOp = GrUserStencilOp::kDecMaybeClamp;
+constexpr static GrUserStencilOp kLastClipOnlyStencilOp = GrUserStencilOp::kInvertClipBit;
+constexpr static int kGrUserStencilOpCount = 1 + (int)GrUserStencilOp::kZeroClipAndUserBits;
+
+/**
+ * This struct is a compile-time constant representation of user stencil settings. It describes in
+ * abstract terms how a draw will use the stencil buffer. It gets ODR-used at runtime to define a
+ * draw's stencil settings, and is later translated into concrete settings when the pipeline is
+ * finalized.
+ */
+struct GrUserStencilSettings {
+ typedef GrTStencilFaceSettings<GrUserStencilTest, GrUserStencilOp> Face;
+
+ template<GrUserStencilTest, GrUserStencilOp PassOp, GrUserStencilOp FailOp> struct Attrs;
+
+ // Unfortunately, this is the only way to pass template arguments to a constructor.
+ template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
+ GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask> struct Init {};
+
+ template<uint16_t FtRef, uint16_t BkRef,
+ GrUserStencilTest FtTest, GrUserStencilTest BkTest,
+ uint16_t FtTestMask, uint16_t BkTestMask,
+ GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
+ GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
+ uint16_t FtWriteMask, uint16_t BkWriteMask> struct InitSeparate {};
+
+ template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
+ GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask>
+ constexpr static Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask> StaticInit() {
+ return Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>();
+ }
+
+ template<uint16_t FtRef, uint16_t BkRef,
+ GrUserStencilTest FtTest, GrUserStencilTest BkTest,
+ uint16_t FtTestMask, uint16_t BkTestMask,
+ GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
+ GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
+ uint16_t FtWriteMask, uint16_t BkWriteMask>
+ constexpr static InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
+ FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask,
+ BkWriteMask> StaticInitSeparate() {
+ return InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
+ FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>();
+ }
+
+ // We construct with template arguments in order to enforce that the struct be compile-time
+ // constant and to make use of static asserts.
+ template<uint16_t Ref, GrUserStencilTest Test, uint16_t TestMask,
+ GrUserStencilOp PassOp, GrUserStencilOp FailOp, uint16_t WriteMask,
+ typename Attrs = Attrs<Test, PassOp, FailOp> >
+ constexpr explicit GrUserStencilSettings(
+ const Init<Ref, Test, TestMask, PassOp, FailOp, WriteMask>&)
+ : fFrontFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
+ (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
+ , fFront{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
+ Attrs::EffectiveWriteMask(WriteMask)}
+ , fBackFlags{(uint16_t)(Attrs::Flags(false) | kSingleSided_StencilFlag),
+ (uint16_t)(Attrs::Flags(true) | kSingleSided_StencilFlag)}
+ , fBack{Ref, Test, Attrs::EffectiveTestMask(TestMask), PassOp, FailOp,
+ Attrs::EffectiveWriteMask(WriteMask)} {
+ }
+
+ template<uint16_t FtRef, uint16_t BkRef,
+ GrUserStencilTest FtTest, GrUserStencilTest BkTest,
+ uint16_t FtTestMask, uint16_t BkTestMask,
+ GrUserStencilOp FtPassOp, GrUserStencilOp BkPassOp,
+ GrUserStencilOp FtFailOp, GrUserStencilOp BkFailOp,
+ uint16_t FtWriteMask, uint16_t BkWriteMask,
+ typename FtAttrs = Attrs<FtTest, FtPassOp, FtFailOp>,
+ typename BkAttrs = Attrs<BkTest, BkPassOp, BkFailOp> >
+ constexpr explicit GrUserStencilSettings(
+ const InitSeparate<FtRef, BkRef, FtTest, BkTest, FtTestMask, BkTestMask,
+ FtPassOp, BkPassOp, FtFailOp, BkFailOp, FtWriteMask, BkWriteMask>&)
+ : fFrontFlags{FtAttrs::Flags(false), FtAttrs::Flags(true)}
+ , fFront{FtRef, FtTest, FtAttrs::EffectiveTestMask(FtTestMask), FtPassOp, FtFailOp,
+ FtAttrs::EffectiveWriteMask(FtWriteMask)}
+ , fBackFlags{BkAttrs::Flags(false), BkAttrs::Flags(true)}
+ , fBack{BkRef, BkTest, BkAttrs::EffectiveTestMask(BkTestMask), BkPassOp, BkFailOp,
+ BkAttrs::EffectiveWriteMask(BkWriteMask)} {}
+
+ // This struct can only be constructed with static initializers.
+ GrUserStencilSettings() = delete;
+ GrUserStencilSettings(const GrUserStencilSettings&) = delete;
+
+ const uint16_t fFrontFlags[2]; // frontFlagsForDraw = fFrontFlags[hasStencilClip].
+ const Face fFront;
+ const uint16_t fBackFlags[2]; // backFlagsForDraw = fBackFlags[hasStencilClip].
+ const Face fBack;
+
+ static const GrUserStencilSettings& kUnused;
+};
+
+template<GrUserStencilTest Test, GrUserStencilOp PassOp, GrUserStencilOp FailOp>
+struct GrUserStencilSettings::Attrs {
+ // Ensure an op that only modifies user bits isn't paired with one that modifies clip bits.
+ GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
+ (PassOp <= kLastUserOnlyStencilOp) == (FailOp <= kLastUserOnlyStencilOp));
+ // Ensure an op that only modifies clip bits isn't paired with one that modifies clip and user.
+ GR_STATIC_ASSERT(GrUserStencilOp::kKeep == PassOp || GrUserStencilOp::kKeep == FailOp ||
+ (PassOp <= kLastClipOnlyStencilOp) == (FailOp <= kLastClipOnlyStencilOp));
+
+ constexpr static bool TestAlwaysPasses(bool hasStencilClip) {
+ return (!hasStencilClip && GrUserStencilTest::kAlwaysIfInClip == Test) ||
+ GrUserStencilTest::kAlways == Test;
+ }
+ constexpr static bool DoesNotModifyStencil(bool hasStencilClip) {
+ return (GrUserStencilTest::kNever == Test || GrUserStencilOp::kKeep == PassOp) &&
+ (TestAlwaysPasses(hasStencilClip) || GrUserStencilOp::kKeep == FailOp);
+ }
+ constexpr static bool IsDisabled(bool hasStencilClip) {
+ return TestAlwaysPasses(hasStencilClip) && DoesNotModifyStencil(hasStencilClip);
+ }
+ constexpr static bool UsesWrapOps() {
+ return GrUserStencilOp::kIncWrap == PassOp || GrUserStencilOp::kDecWrap == PassOp ||
+ GrUserStencilOp::kIncWrap == FailOp || GrUserStencilOp::kDecWrap == FailOp;
+ }
+ constexpr static bool TestIgnoresRef() {
+ return (GrUserStencilTest::kAlwaysIfInClip == Test || GrUserStencilTest::kAlways == Test ||
+ GrUserStencilTest::kNever == Test);
+ }
+ constexpr static uint16_t Flags(bool hasStencilClip) {
+ return (IsDisabled(hasStencilClip) ? kDisabled_StencilFlag : 0) |
+ (DoesNotModifyStencil(hasStencilClip) ? kNoModifyStencil_StencilFlag : 0) |
+ (UsesWrapOps() ? 0 : kNoWrapOps_StencilFlag);
+ }
+ constexpr static uint16_t EffectiveTestMask(uint16_t testMask) {
+ return TestIgnoresRef() ? 0 : testMask;
+ }
+ constexpr static uint16_t EffectiveWriteMask(uint16_t writeMask) {
+ // We don't modify the mask differently when hasStencilClip=false because either the entire
+ // face gets disabled in that case (e.g. Test=kAlwaysIfInClip, PassOp=kKeep), or else the
+ // effective mask stays the same either way.
+ return DoesNotModifyStencil(true) ? 0 : writeMask;
+ }
+};
+
+#endif
« no previous file with comments | « src/gpu/GrStencilSettings.cpp ('k') | src/gpu/batches/GrDefaultPathRenderer.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698