Separate user and raw stencil settings

Adds a new GrUserStencilSettings class that describes in abstract terms
how a draw will use the stencil (e.g. kAlwaysIfInClip, kSetClipBit,
etc.). GrPipelineBuilder now only defines the GrUserStencilSettings.
When the GrPipeline is finalized, the user stencil settings are then
translated into concrete GrStencilSettings.

At this point, GrClipMaskManager only needs to tell the GrAppliedClip
whether or not there is a stencil clip. It does not need to modify
stencil settings and GrPipelineBuilder does not need
AutoRestoreStencil.

This is one step of the stencil overhaul. In the future it will also
allow us to clean up the special case handling for nvpr and the
stateful fClipMode member of GrClipMaskManager.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1962243002

Committed: https://skia.googlesource.com/skia/+/12dbb3947e1aaf205b4fcf13b40e54e50650eb37

Review-Url: https://codereview.chromium.org/1962243002
diff --git a/src/gpu/GrUserStencilSettings.h b/src/gpu/GrUserStencilSettings.h
new file mode 100644
index 0000000..a07a083
--- /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