/* * 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 GrStencilSettings_DEFINED #define GrStencilSettings_DEFINED #include "GrUserStencilSettings.h" #include "SkRegion.h" class GrProcessorKeyBuilder; enum class GrStencilTest : uint16_t { kAlways, kNever, kGreater, kGEqual, kLess, kLEqual, kEqual, kNotEqual }; static constexpr int kGrStencilTestCount = 1 + (int)GrStencilTest::kNotEqual; enum class GrStencilOp : uint8_t { kKeep, kZero, kReplace, // Replace stencil value with fRef (only the bits enabled in fWriteMask). kInvert, kIncWrap, kDecWrap, // NOTE: clamping occurs before the write mask. So if the MSB is zero and masked out, stencil // values will still wrap when using clamping ops. kIncClamp, kDecClamp }; static constexpr int kGrStencilOpCount = 1 + (int)GrStencilOp::kDecClamp; /** * This class defines concrete stencil settings that map directly to the underlying hardware. It * is deduced from user stencil settings, stencil clip status, and the number of bits in the * target stencil buffer. */ class GrStencilSettings { public: GrStencilSettings() { this->setDisabled(); } GrStencilSettings(const GrUserStencilSettings& user, bool hasStencilClip, int numStencilBits) { this->reset(user, hasStencilClip, numStencilBits); } GrStencilSettings(const GrStencilSettings& that) { this->reset(that); } GrStencilSettings& operator=(const GrStencilSettings& that) { this->reset(that); return *this; } void invalidate() { fFlags |= kInvalid_PrivateFlag; } void setDisabled() { fFlags = kAll_StencilFlags; } void reset(const GrUserStencilSettings&, bool hasStencilClip, int numStencilBits); void reset(const GrStencilSettings&); bool isValid() const { return !(fFlags & kInvalid_PrivateFlag); } bool isDisabled() const { SkASSERT(this->isValid()); return fFlags & kDisabled_StencilFlag; } bool doesWrite() const { SkASSERT(this->isValid()); return !(fFlags & kNoModifyStencil_StencilFlag); } bool isTwoSided() const { SkASSERT(this->isValid()); return !(fFlags & kSingleSided_StencilFlag); } bool usesWrapOp() const { SkASSERT(this->isValid()); return !(fFlags & kNoWrapOps_StencilFlag); } void genKey(GrProcessorKeyBuilder* b) const; bool operator!=(const GrStencilSettings& that) const { return !(*this == that); } bool operator==(const GrStencilSettings&) const; struct Face : public GrTStencilFaceSettings<GrStencilTest, GrStencilOp> { void reset(const GrUserStencilSettings::Face&, bool useStencilClip, int numStencilBits); void setDisabled(); }; const Face& front() const { SkASSERT(!this->isDisabled()); return fFront; } const Face& back() const { SkASSERT(this->isTwoSided()); return fBack; } /** * Given a thing to draw into the stencil clip, a fill type, and a set op * this function determines: * 1. Whether the thing can be draw directly to the stencil clip or * needs to be drawn to the client portion of the stencil first. * 2. How many passes are needed. * 3. What those passes are. * * @param op the set op to combine this element with the existing clip * @param canBeDirect can the caller draw this element directly (without using stencil)? * @param invertedFill is this path inverted * @param drawDirectToClip out: true if caller should draw the element directly, false if it * should draw it into the user stencil bits first. * * @return a null-terminated array of settings for stencil passes. * * If drawDirectToClip is false, the caller must first draw the element into the user * stencil bits, and then cover the clip area with multiple passes using the returned * stencil settings. * * If drawDirectToClip is true, the returned array will only have one pass and the * caller should use those stencil settings while drawing the element directly. */ static GrUserStencilSettings const* const* GetClipPasses(SkRegion::Op op, bool canBeDirect, bool invertedFill, bool* drawDirectToClip); private: // Internal flag for backends to optionally mark their tracked stencil state as invalid. enum { kInvalid_PrivateFlag = (kLast_StencilFlag << 1) }; uint32_t fFlags; Face fFront; Face fBack; }; #endif