blob: 2ed570d923a337081cb9ee54c075fd2f00720786 [file]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef skgpu_graphite_render_CommonDepthStencilSettings_DEFINED
#define skgpu_graphite_render_CommonDepthStencilSettings_DEFINED
#include "src/gpu/graphite/DrawTypes.h"
namespace skgpu::graphite {
/**
* "stencil" pass DepthStencilSettings reusable for RenderSteps following some form of
* stencil-then-cover multi-pass algorithm.
*/
// Increments stencil value on clockwise triangles. Used for "winding" fill.
constexpr StencilSettings::Face kIncrementCW = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kIncWrap,
/*compare=*/ CompareOp::kAlways
};
// Decrements stencil value on counterclockwise triangles. Used for "winding" fill.
constexpr StencilSettings::Face kDecrementCCW = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kDecWrap,
/*compare=*/ CompareOp::kAlways
};
// Increments the stencil value whenever a triangle is encountered. Used for storing a stroked
// path in the stencil buffer.
constexpr StencilSettings::Face kIncrementAlways = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kIncClamp,
/*compare=*/ CompareOp::kAlways
};
// Toggles the bottom stencil bit. Used for "even-odd" fill.
constexpr StencilSettings::Face kToggle = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kInvert,
/*compare=*/ CompareOp::kAlways
};
// Stencil settings to use for a standard Redbook "stencil" pass corresponding to a "winding"
// fill rule (regular or inverse is selected by a follow-up pass).
constexpr StencilSettings kWindingStencilPass = {
/*front=*/ kIncrementCW,
/*back=*/ kDecrementCCW,
/*stencilRef=*/ 0,
/*stencilReadMask=*/ 0xffffffff,
/*stencilWriteMask=*/0xffffffff
};
// Stencil settings to use for a standard Redbook "stencil" pass corresponding to an "even-odd"
// fill rule (regular or inverse is selected by a follow-up pass).
constexpr StencilSettings kEvenOddStencilPass = {
/*front=*/ kToggle,
/*back=*/ kToggle,
/*stencilRef=*/ 0,
/*stencilReadMask=*/ 0xffffffff,
/*stencilWriteMask=*/0x00000001
};
// Stencil settings to use for always stenciling out any triangle encountered, useful for stroked
// paths. Since kIncrementAlways uses kIncClamp, these settings can effectively compute the
// union of a fill and stroke as long as the stroke is rendered second.
//
// When combined with a preceding kEvenOddStencilPass, pixels inside the fill will be set to 1 and
// will either remain 1 (if not also part of the stroke) or bump up to 2 (which is still seen as
// non-zero by the cover pass settings). Pixels outside the even-odd fill will start out as 0 and
// either remain 0 (if not part of the stroke), or bump up to 1.
//
// When combined with a preceding kWindingStencilPass, pixels outside of the fill are set to 0 and
// either remain 0 (outside the stroke) or bump up to 1. Pixels inside the fill start with a
// non-zero and get incremented. When the winding was positive, the stroke's increment will clamp
// to the max value and remain non-zero. When the winding was negative, the stencil value will be
// near the max value (due to wrapping) and the stroke's increment will still clamp to the max.
// Since this clamps, there's no possibility to increment a -1 winding up to 0, which would not
// correctly represent the union.
//
// An alternative way to represent strokes in the stencil buffer would be to use the kReplace op
// combined with a stencilRef = 1. However, that would mean platforms with dynamic state would need
// to be switching the stencil reference state periodically and it seems beneficial to only ever
// use a ref of 0.
constexpr StencilSettings kIncrementStencilPass = {
/*front=*/ kIncrementAlways,
/*back=*/ kIncrementAlways,
/*stencilRef=*/ 0,
/*stencilReadMask=*/ 0xffffffff,
/*stencilWriteMask=*/0xffffffff
};
/**
* "cover" pass DepthStencilSettings reusable for RenderSteps following some form of
* stencil-then-cover multi-pass algorithm.
*/
// Resets non-zero bits to 0, passes when not zero. We set depthFail to kZero because if we
// encounter that case, the kNotEqual=0 stencil test passed, so it does need to be set back to 0
// and the dsPass op won't be run. In practice, since the stencil steps will fail the same depth
// test, the stencil value will likely not be non-zero, but best to be explicit.
constexpr StencilSettings::Face kPassNonZero = {
/*stencilFail=*/ StencilOp::kKeep,
/*depthFail=*/ StencilOp::kZero,
/*dsPass=*/ StencilOp::kZero,
/*compare=*/ CompareOp::kNotEqual
};
// Resets non-zero bits to 0, passes when zero.
constexpr StencilSettings::Face kPassZero = {
/*stencilFail=*/ StencilOp::kZero,
/*depthFail=*/ StencilOp::kKeep,
/*dsPass=*/ StencilOp::kKeep,
/*compare=*/ CompareOp::kEqual
};
// Stencil settings to use for a standard Redbook "cover" pass for a regular fill, assuming that the
// stencil buffer has been modified by either kWindingStencilPass or kEvenOddStencilPass.
constexpr StencilSettings kRegularCoverPass = {
/*front=*/ kPassNonZero,
/*back=*/ kPassNonZero,
/*stencilRef=*/ 0,
/*stencilReadMask=*/ 0xffffffff,
/*stencilWriteMask=*/0xffffffff
};
// Stencil settings to use for a standard Redbook "cover" pass for inverse fills, assuming that the
// stencil buffer has been modified by either kWindingStencilPass or kEvenOddStencilPass.
constexpr StencilSettings kInverseCoverPass = {
/*front=*/ kPassZero,
/*back=*/ kPassZero,
/*stencilRef=*/ 0,
/*stencilReadMask=*/ 0xffffffff,
/*stencilWriteMask=*/0xffffffff
};
} // namespace skgpu::graphite
#endif // skgpu_graphite_render_CommonDepthStencilSettings_DEFINED