Revert of Separate user and raw stencil settings (patchset #8 id:140001 of https://codereview.chromium.org/1962243002/ )
Reason for revert:
This seems to be breaking nanobench on the Windows bots with:
Caught exception 3221225477 EXCEPTION_ACCESS_VIOLATION
GrDrawTarget::stencilPath +c7
GrStencilAndCoverPathRenderer::onDrawPath +fd
GrDrawContext::internalDrawPath +509
GrDrawContext::drawPath +223
GrBlurUtils::drawPathWithMaskFilter +250
SkGpuDevice::drawPath +2ea
SkCanvas::onDrawPath +2e3
SkRecordDraw +2e6
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkRecordDraw +2e6
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkRecordDraw +261
SkBigPicture::playback +e5
SkCanvas::onDrawPicture +12c
SkCanvas::drawPicture +145
SkMultiPictureDraw::draw +bf
SKPBench::drawMPDPicture +1e0
SKPBench::onDraw +34
Benchmark::draw +32
time +92
setup_gpu_bench +6e
nanobench_main +77b
Original issue's description:
> 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
TBR=bsalomon@google.com,cdalton@nvidia.com
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:
Review-Url: https://codereview.chromium.org/1969693003
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index dc16c2c..48f1c85 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -170,10 +170,10 @@
'<(skia_src_path)/gpu/GrResourceProvider.h',
'<(skia_src_path)/gpu/GrShape.cpp',
'<(skia_src_path)/gpu/GrShape.h',
+ '<(skia_src_path)/gpu/GrStencil.cpp',
+ '<(skia_src_path)/gpu/GrStencil.h',
'<(skia_src_path)/gpu/GrStencilAttachment.cpp',
'<(skia_src_path)/gpu/GrStencilAttachment.h',
- '<(skia_src_path)/gpu/GrStencilSettings.cpp',
- '<(skia_src_path)/gpu/GrStencilSettings.h',
'<(skia_src_path)/gpu/GrStyle.cpp',
'<(skia_src_path)/gpu/GrStyle.h',
'<(skia_src_path)/gpu/GrTessellator.cpp',
@@ -200,7 +200,6 @@
'<(skia_src_path)/gpu/GrTextureToYUVPlanes.h',
'<(skia_src_path)/gpu/GrTextureAccess.cpp',
'<(skia_src_path)/gpu/GrTRecorder.h',
- '<(skia_src_path)/gpu/GrUserStencilSettings.h',
'<(skia_src_path)/gpu/GrXferProcessor.cpp',
'<(skia_src_path)/gpu/GrYUVProvider.cpp',
'<(skia_src_path)/gpu/GrYUVProvider.h',
diff --git a/src/gpu/GrClipMaskManager.cpp b/src/gpu/GrClipMaskManager.cpp
index c7b88ca..56c0ee6 100644
--- a/src/gpu/GrClipMaskManager.cpp
+++ b/src/gpu/GrClipMaskManager.cpp
@@ -62,7 +62,7 @@
// optionally, set 'prOut' to NULL. If not, return false (and, optionally, set
// 'prOut' to the non-SW path renderer that will do the job).
bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
- bool hasUserStencilSettings,
+ bool isStencilDisabled,
const GrRenderTarget* rt,
const SkMatrix& viewMatrix,
const Element* element,
@@ -104,7 +104,7 @@
canDrawArgs.fPath = &path;
canDrawArgs.fStyle = &GrStyle::SimpleFill();
canDrawArgs.fAntiAlias = element->isAA();
- canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
+ canDrawArgs.fIsStencilDisabled = isStencilDisabled;
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
// the 'false' parameter disallows use of the SW path renderer
@@ -124,10 +124,10 @@
const SkMatrix& viewMatrix,
const SkClipStack::Element* element) {
GrPathRenderer* pr;
- constexpr bool kNeedsStencil = true;
- constexpr bool kHasUserStencilSettings = false;
+ static const bool kNeedsStencil = true;
+ static const bool kStencilIsDisabled = true;
PathNeedsSWRenderer(context,
- kHasUserStencilSettings,
+ kStencilIsDisabled,
texture->asRenderTarget(),
viewMatrix,
element,
@@ -179,7 +179,7 @@
bool needsStencil = invert ||
SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op;
- if (PathNeedsSWRenderer(context, pipelineBuilder.hasUserStencilSettings(),
+ if (PathNeedsSWRenderer(context, pipelineBuilder.getStencil().isDisabled(),
rt, translate, element, nullptr, needsStencil)) {
return true;
}
@@ -317,11 +317,13 @@
}
bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
+ GrPipelineBuilder::AutoRestoreStencil* ars,
const SkIRect& clipScissor,
const SkRect* devBounds,
GrAppliedClip* out) {
- SkASSERT(kModifyClip_StencilClipMode != fClipMode); // TODO: Remove fClipMode.
- fClipMode = kIgnoreClip_StencilClipMode;
+ if (kRespectClip_StencilClipMode == fClipMode) {
+ fClipMode = kIgnoreClip_StencilClipMode;
+ }
GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
@@ -338,11 +340,13 @@
if (scissor->contains(clipSpaceRTIBounds)) {
// This counts as wide open
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
return true;
}
if (clipSpaceRTIBounds.intersect(*scissor)) {
out->fScissorState.set(clipSpaceRTIBounds);
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
return true;
}
return false;
@@ -352,6 +356,7 @@
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
+ GrPipelineBuilder::AutoRestoreStencil* ars,
const SkRect* devBounds,
GrAppliedClip* out) {
if (kRespectClip_StencilClipMode == fClipMode) {
@@ -377,6 +382,7 @@
const GrClip& clip = doDevBoundsClip ? devBoundsClip : pipelineBuilder.clip();
if (clip.isWideOpen(clipSpaceRTIBounds)) {
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
return true;
}
@@ -390,7 +396,7 @@
SkIRect scissor = clip.irect();
if (scissor.intersect(clipSpaceRTIBounds)) {
out->fScissorState.set(scissor);
- out->fHasStencilClip = kIgnoreClip_StencilClipMode != fClipMode;
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
return true;
}
return false;
@@ -418,6 +424,7 @@
if (elements.isEmpty()) {
if (GrReducedClip::kAllIn_InitialState == initialState) {
if (clipSpaceIBounds == clipSpaceRTIBounds) {
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
return true;
}
} else {
@@ -427,8 +434,6 @@
} break;
}
- SkASSERT(kIgnoreClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode.
-
// An element count of 4 was chosen because of the common pattern in Blink of:
// isect RR
// diff RR
@@ -448,7 +453,7 @@
// color buffer anyway, so we may as well use coverage AA if nothing else in the pipe
// is multisampled.
disallowAnalyticAA = pipelineBuilder.isHWAntialias() ||
- pipelineBuilder.hasUserStencilSettings();
+ !pipelineBuilder.getStencil().isDisabled();
}
const GrFragmentProcessor* clipFP = nullptr;
if (elements.isEmpty() ||
@@ -461,6 +466,7 @@
!SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) {
out->fScissorState.set(scissorSpaceIBounds);
}
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
out->fClipCoverageFP.reset(clipFP);
return true;
}
@@ -502,6 +508,7 @@
SkIRect rtSpaceMaskBounds = clipSpaceIBounds;
rtSpaceMaskBounds.offset(-clip.origin());
out->fClipCoverageFP.reset(create_fp_for_mask(result, rtSpaceMaskBounds));
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
return true;
}
// if alpha clip mask creation fails fall through to the non-AA code paths
@@ -522,14 +529,13 @@
SkIRect scissorSpaceIBounds(clipSpaceIBounds);
scissorSpaceIBounds.offset(clipSpaceToStencilSpaceOffset);
out->fScissorState.set(scissorSpaceIBounds);
- SkASSERT(kRespectClip_StencilClipMode == fClipMode); // TODO: Remove fClipMode.
- out->fHasStencilClip = true;
+ this->setPipelineBuilderStencil(pipelineBuilder, ars);
return true;
}
static bool stencil_element(GrDrawContext* dc,
const SkIRect* scissorRect,
- const GrUserStencilSettings* ss,
+ const GrStencilSettings& ss,
const SkMatrix& viewMatrix,
const SkClipStack::Element* element) {
@@ -675,32 +681,28 @@
// draw directly into the result with the stencil set to make the pixels affected
// by the clip shape be non-zero.
- static constexpr GrUserStencilSettings kStencilInElement(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kReplace,
- GrUserStencilOp::kReplace,
- 0xffff>()
- );
- if (!stencil_element(dc.get(), &maskSpaceIBounds, &kStencilInElement,
+ static constexpr GrStencilSettings kStencilInElement(
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+ if (!stencil_element(dc.get(), &maskSpaceIBounds, kStencilInElement,
translate, element)) {
texture->resourcePriv().removeUniqueKey();
return nullptr;
}
// Draw to the exterior pixels (those with a zero stencil value).
- static constexpr GrUserStencilSettings kDrawOutsideElement(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kZero,
- 0xffff>()
- );
- if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, &kDrawOutsideElement,
+ static constexpr GrStencilSettings kDrawOutsideElement(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
+ if (!dc->drawContextPriv().drawAndStencilRect(&maskSpaceIBounds, kDrawOutsideElement,
op, !invert, false,
translate,
SkRect::Make(clipSpaceIBounds))) {
@@ -751,6 +753,10 @@
stencilSpaceIBounds.offset(clipSpaceToStencilOffset);
GrClip clip(stencilSpaceIBounds);
+ int clipBit = stencilAttachment->bits();
+ SkASSERT((clipBit <= 16) && "Ganesh only handles 16b or smaller stencil buffers");
+ clipBit = (1 << (clipBit-1));
+
fDrawTarget->cmmAccess().clearStencilClip(stencilSpaceIBounds,
GrReducedClip::kAllIn_InitialState == initialState, rt);
@@ -792,7 +798,7 @@
clipPath.toggleInverseFillType();
}
- SkASSERT(!pipelineBuilder.hasUserStencilSettings());
+ SkASSERT(pipelineBuilder.getStencil().isDisabled());
GrPathRenderer::CanDrawPathArgs canDrawArgs;
canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
@@ -800,7 +806,7 @@
canDrawArgs.fPath = &clipPath;
canDrawArgs.fStyle = &GrStyle::SimpleFill();
canDrawArgs.fAntiAlias = false;
- canDrawArgs.fHasUserStencilSettings = pipelineBuilder.hasUserStencilSettings();
+ canDrawArgs.fIsStencilDisabled = pipelineBuilder.getStencil().isDisabled();
canDrawArgs.fIsStencilBufferMSAA = rt->isStencilBufferMultisampled();
pr = this->getContext()->drawingManager()->getPathRenderer(canDrawArgs, false,
@@ -811,36 +817,40 @@
}
}
+ int passes;
+ GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];
+
bool canRenderDirectToStencil =
GrPathRenderer::kNoRestriction_StencilSupport == stencilSupport;
- bool drawDirectToClip; // Given the renderer, the element,
- // fill rule, and set operation should
- // we render the element directly to
- // stencil bit used for clipping.
- GrUserStencilSettings const* const* stencilPasses =
- GrStencilSettings::GetClipPasses(op, canRenderDirectToStencil, fillInverted,
- &drawDirectToClip);
+ bool canDrawDirectToClip; // Given the renderer, the element,
+ // fill rule, and set operation can
+ // we render the element directly to
+ // stencil bit used for clipping.
+ canDrawDirectToClip = GrStencilSettings::GetClipPasses(op,
+ canRenderDirectToStencil,
+ clipBit,
+ fillInverted,
+ &passes,
+ stencilSettings);
// draw the element to the client stencil bits if necessary
- if (!drawDirectToClip) {
- static constexpr GrUserStencilSettings kDrawToStencil(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kIncMaybeClamp,
- GrUserStencilOp::kIncMaybeClamp,
- 0xffff>()
- );
+ if (!canDrawDirectToClip) {
+ static constexpr GrStencilSettings kDrawToStencil(
+ kIncClamp_StencilOp,
+ kIncClamp_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
if (Element::kRect_Type == element->getType()) {
- pipelineBuilder.setUserStencil(&kDrawToStencil);
+ *pipelineBuilder.stencil() = kDrawToStencil;
draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix,
element->getRect());
} else {
if (!clipPath.isEmpty()) {
if (canRenderDirectToStencil) {
- pipelineBuilder.setUserStencil(&kDrawToStencil);
+ *pipelineBuilder.stencil() = kDrawToStencil;
GrPathRenderer::DrawPathArgs args;
args.fTarget = fDrawTarget;
@@ -869,10 +879,10 @@
// now we modify the clip bit by rendering either the clip
// element directly or a bounding rect of the entire clip.
fClipMode = kModifyClip_StencilClipMode;
- for (GrUserStencilSettings const* const* pass = stencilPasses; *pass; ++pass) {
- pipelineBuilder.setUserStencil(*pass);
+ for (int p = 0; p < passes; ++p) {
+ *pipelineBuilder.stencil() = stencilSettings[p];
- if (drawDirectToClip) {
+ if (canDrawDirectToClip) {
if (Element::kRect_Type == element->getType()) {
draw_non_aa_rect(fDrawTarget, pipelineBuilder, GrColor_WHITE, viewMatrix,
element->getRect());
@@ -902,6 +912,165 @@
return true;
}
+// mapping of clip-respecting stencil funcs to normal stencil funcs
+// mapping depends on whether stencil-clipping is in effect.
+static const GrStencilFunc
+ gSpecialToBasicStencilFunc[2][kClipStencilFuncCnt] = {
+ {// Stencil-Clipping is DISABLED, we are effectively always inside the clip
+ // In the Clip Funcs
+ kAlways_StencilFunc, // kAlwaysIfInClip_StencilFunc
+ kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
+ kLess_StencilFunc, // kLessIfInClip_StencilFunc
+ kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
+ // Special in the clip func that forces user's ref to be 0.
+ kNotEqual_StencilFunc, // kNonZeroIfInClip_StencilFunc
+ // make ref 0 and do normal nequal.
+ },
+ {// Stencil-Clipping is ENABLED
+ // In the Clip Funcs
+ kEqual_StencilFunc, // kAlwaysIfInClip_StencilFunc
+ // eq stencil clip bit, mask
+ // out user bits.
+
+ kEqual_StencilFunc, // kEqualIfInClip_StencilFunc
+ // add stencil bit to mask and ref
+
+ kLess_StencilFunc, // kLessIfInClip_StencilFunc
+ kLEqual_StencilFunc, // kLEqualIfInClip_StencilFunc
+ // for both of these we can add
+ // the clip bit to the mask and
+ // ref and compare as normal
+ // Special in the clip func that forces user's ref to be 0.
+ kLess_StencilFunc, // kNonZeroIfInClip_StencilFunc
+ // make ref have only the clip bit set
+ // and make comparison be less
+ // 10..0 < 1..user_bits..
+ }
+};
+
+void GrClipMaskManager::setPipelineBuilderStencil(const GrPipelineBuilder& pipelineBuilder,
+ GrPipelineBuilder::AutoRestoreStencil* ars) {
+ // We make two copies of the StencilSettings here (except in the early
+ // exit scenario. One copy from draw state to the stack var. Then another
+ // from the stack var to the gpu. We could make this class hold a ptr to
+ // GrGpu's fStencilSettings and eliminate the stack copy here.
+
+ // use stencil for clipping if clipping is enabled and the clip
+ // has been written into the stencil.
+ GrStencilSettings settings;
+
+ // The GrGpu client may not be using the stencil buffer but we may need to
+ // enable it in order to respect a stencil clip.
+ if (pipelineBuilder.getStencil().isDisabled()) {
+ if (GrClipMaskManager::kRespectClip_StencilClipMode == fClipMode) {
+ static constexpr GrStencilSettings kBasicApplyClipSettings(
+ kKeep_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0x0000,
+ 0x0000,
+ 0x0000);
+ settings = kBasicApplyClipSettings;
+ } else {
+ return;
+ }
+ } else {
+ settings = pipelineBuilder.getStencil();
+ }
+
+ int stencilBits = 0;
+ GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
+ GrStencilAttachment* stencilAttachment = this->resourceProvider()->attachStencilAttachment(rt);
+ if (stencilAttachment) {
+ stencilBits = stencilAttachment->bits();
+ }
+
+ SkASSERT(this->caps()->stencilWrapOpsSupport() || !settings.usesWrapOp());
+ SkASSERT(this->caps()->twoSidedStencilSupport() || !settings.isTwoSided());
+ this->adjustStencilParams(&settings, fClipMode, stencilBits);
+ ars->set(&pipelineBuilder);
+ ars->setStencil(settings);
+}
+
+void GrClipMaskManager::adjustStencilParams(GrStencilSettings* settings,
+ StencilClipMode mode,
+ int stencilBitCnt) {
+ SkASSERT(stencilBitCnt > 0);
+
+ if (kModifyClip_StencilClipMode == mode) {
+ // We assume that this clip manager itself is drawing to the GrGpu and
+ // has already setup the correct values.
+ return;
+ }
+
+ unsigned int clipBit = (1 << (stencilBitCnt - 1));
+ unsigned int userBits = clipBit - 1;
+
+ GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
+ bool twoSided = this->caps()->twoSidedStencilSupport();
+
+ bool finished = false;
+ while (!finished) {
+ GrStencilFunc func = settings->func(face);
+ uint16_t writeMask = settings->writeMask(face);
+ uint16_t funcMask = settings->funcMask(face);
+ uint16_t funcRef = settings->funcRef(face);
+
+ SkASSERT((unsigned) func < kStencilFuncCnt);
+
+ writeMask &= userBits;
+
+ if (func >= kBasicStencilFuncCnt) {
+ int respectClip = kRespectClip_StencilClipMode == mode;
+ if (respectClip) {
+ switch (func) {
+ case kAlwaysIfInClip_StencilFunc:
+ funcMask = clipBit;
+ funcRef = clipBit;
+ break;
+ case kEqualIfInClip_StencilFunc:
+ case kLessIfInClip_StencilFunc:
+ case kLEqualIfInClip_StencilFunc:
+ funcMask = (funcMask & userBits) | clipBit;
+ funcRef = (funcRef & userBits) | clipBit;
+ break;
+ case kNonZeroIfInClip_StencilFunc:
+ funcMask = (funcMask & userBits) | clipBit;
+ funcRef = clipBit;
+ break;
+ default:
+ SkFAIL("Unknown stencil func");
+ }
+ } else {
+ funcMask &= userBits;
+ funcRef &= userBits;
+ }
+ const GrStencilFunc* table =
+ gSpecialToBasicStencilFunc[respectClip];
+ func = table[func - kBasicStencilFuncCnt];
+ SkASSERT(func >= 0 && func < kBasicStencilFuncCnt);
+ } else {
+ funcMask &= userBits;
+ funcRef &= userBits;
+ }
+
+ settings->setFunc(face, func);
+ settings->setWriteMask(face, writeMask);
+ settings->setFuncMask(face, funcMask);
+ settings->setFuncRef(face, funcRef);
+
+ if (GrStencilSettings::kFront_Face == face) {
+ face = GrStencilSettings::kBack_Face;
+ finished = !twoSided;
+ } else {
+ finished = true;
+ }
+ }
+ if (!twoSided) {
+ settings->copyFrontSettingsToBack();
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
int32_t elementsGenID,
@@ -979,3 +1148,13 @@
return result;
}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stencilAttachment,
+ GrStencilSettings* settings) {
+ if (stencilAttachment) {
+ int stencilBits = stencilAttachment->bits();
+ this->adjustStencilParams(settings, fClipMode, stencilBits);
+ }
+}
diff --git a/src/gpu/GrClipMaskManager.h b/src/gpu/GrClipMaskManager.h
index 096dafd..ef0c2be 100644
--- a/src/gpu/GrClipMaskManager.h
+++ b/src/gpu/GrClipMaskManager.h
@@ -9,6 +9,7 @@
#include "GrPipelineBuilder.h"
#include "GrReducedClip.h"
+#include "GrStencil.h"
#include "GrTexture.h"
#include "SkClipStack.h"
#include "SkDeque.h"
@@ -32,15 +33,13 @@
*/
class GrAppliedClip : public SkNoncopyable {
public:
- GrAppliedClip() : fHasStencilClip(false) {}
+ GrAppliedClip() {}
const GrFragmentProcessor* clipCoverageFragmentProcessor() const { return fClipCoverageFP; }
const GrScissorState& scissorState() const { return fScissorState; }
- bool hasStencilClip() const { return fHasStencilClip; }
private:
SkAutoTUnref<const GrFragmentProcessor> fClipCoverageFP;
GrScissorState fScissorState;
- bool fHasStencilClip;
friend class GrClipMaskManager;
typedef SkNoncopyable INHERITED;
@@ -61,23 +60,30 @@
/**
* Creates a clip mask if necessary as a stencil buffer or alpha texture
* and sets the GrGpu's scissor and stencil state. If the return is false
- * then the draw can be skipped. devBounds is optional but can help optimize
- * clipping.
+ * then the draw can be skipped. The AutoRestoreEffects is initialized by
+ * the manager when it must install additional effects to implement the
+ * clip. devBounds is optional but can help optimize clipping.
*/
- bool setupClipping(const GrPipelineBuilder&, const SkRect* devBounds, GrAppliedClip*);
+ bool setupClipping(const GrPipelineBuilder&,
+ GrPipelineBuilder::AutoRestoreStencil*,
+ const SkRect* devBounds,
+ GrAppliedClip*);
bool setupScissorClip(const GrPipelineBuilder& pipelineBuilder,
+ GrPipelineBuilder::AutoRestoreStencil* ars,
const SkIRect& scissor,
const SkRect* devBounds,
GrAppliedClip* out);
+ void adjustPathStencilParams(const GrStencilAttachment*, GrStencilSettings*);
+
private:
inline GrContext* getContext();
inline const GrCaps* caps() const;
inline GrResourceProvider* resourceProvider();
static bool PathNeedsSWRenderer(GrContext* context,
- bool hasUserStencilSettings,
+ bool isStencilDisabled,
const GrRenderTarget* rt,
const SkMatrix& viewMatrix,
const SkClipStack::Element* element,
@@ -144,6 +150,21 @@
const SkVector& clipToMaskOffset,
const GrReducedClip::ElementList& elements);
+ /**
+ * Called prior to return control back the GrGpu in setupClipping. It updates the
+ * GrPipelineBuilder with stencil settings that account for stencil-based clipping.
+ */
+ void setPipelineBuilderStencil(const GrPipelineBuilder&,
+ GrPipelineBuilder::AutoRestoreStencil*);
+
+ /**
+ * Adjusts the stencil settings to account for interaction with stencil
+ * clipping.
+ */
+ void adjustStencilParams(GrStencilSettings* settings,
+ StencilClipMode mode,
+ int stencilBitCnt);
+
GrTexture* createCachedMask(int width, int height, const GrUniqueKey& key, bool renderTarget);
static const int kMaxAnalyticElements = 4;
diff --git a/src/gpu/GrDrawContext.cpp b/src/gpu/GrDrawContext.cpp
index 7f5cdc7..a7c7f6a 100644
--- a/src/gpu/GrDrawContext.cpp
+++ b/src/gpu/GrDrawContext.cpp
@@ -375,7 +375,7 @@
}
bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
- const GrUserStencilSettings* ss,
+ const GrStencilSettings& ss,
SkRegion::Op op,
bool invert,
bool doAA,
@@ -397,7 +397,7 @@
GrPipelineBuilder pipelineBuilder(paint,
fDrawContext->accessRenderTarget(),
GrClip::WideOpen());
- pipelineBuilder.setUserStencil(ss);
+ pipelineBuilder.setStencil(ss);
fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, batch, scissorRect);
return true;
@@ -855,7 +855,7 @@
}
bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
- const GrUserStencilSettings* ss,
+ const GrStencilSettings& ss,
SkRegion::Op op,
bool invert,
bool doAA,
@@ -880,7 +880,7 @@
// aa. If we have some future driver-mojo path AA that can do the right
// thing WRT to the blend then we'll need some query on the PR.
bool useCoverageAA = doAA && !fDrawContext->fRenderTarget->isUnifiedMultisampled();
- bool hasUserStencilSettings = (&GrUserStencilSettings::kUnused != ss);
+ bool isStencilDisabled = true;
bool isStencilBufferMSAA = fDrawContext->fRenderTarget->isStencilBufferMultisampled();
const GrPathRendererChain::DrawType type =
@@ -893,7 +893,7 @@
canDrawArgs.fPath = &path;
canDrawArgs.fStyle = &GrStyle::SimpleFill();
canDrawArgs.fAntiAlias = useCoverageAA;
- canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
+ canDrawArgs.fIsStencilDisabled = isStencilDisabled;
canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
// Don't allow the SW renderer
@@ -913,7 +913,7 @@
}
GrPipelineBuilder pipelineBuilder(paint, fDrawContext->accessRenderTarget(), clip);
- pipelineBuilder.setUserStencil(ss);
+ pipelineBuilder.setStencil(ss);
GrPathRenderer::DrawPathArgs args;
args.fTarget = fDrawContext->getDrawTarget();
@@ -939,7 +939,7 @@
SkASSERT(!origPath.isEmpty());
bool useCoverageAA = should_apply_coverage_aa(paint, fRenderTarget.get());
- constexpr bool kHasUserStencilSettings = false;
+ const bool isStencilDisabled = true;
bool isStencilBufferMSAA = fRenderTarget->isStencilBufferMultisampled();
const GrPathRendererChain::DrawType type =
@@ -955,7 +955,7 @@
canDrawArgs.fPath = &origPath;
canDrawArgs.fStyle = &origStyle;
canDrawArgs.fAntiAlias = useCoverageAA;
- canDrawArgs.fHasUserStencilSettings = kHasUserStencilSettings;
+ canDrawArgs.fIsStencilDisabled = isStencilDisabled;
canDrawArgs.fIsStencilBufferMSAA = isStencilBufferMSAA;
// Try a 1st time without applying any of the style to the geometry (and barring sw)
diff --git a/src/gpu/GrDrawContextPriv.h b/src/gpu/GrDrawContextPriv.h
index 973315b..4482e35 100644
--- a/src/gpu/GrDrawContextPriv.h
+++ b/src/gpu/GrDrawContextPriv.h
@@ -10,7 +10,7 @@
#include "GrDrawContext.h"
-struct GrUserStencilSettings;
+class GrStencilSettings;
/** Class that adds methods to GrDrawContext that are only intended for use internal to Skia.
This class is purely a privileged window into GrDrawContext. It should never have additional
@@ -18,7 +18,7 @@
class GrDrawContextPriv {
public:
bool drawAndStencilRect(const SkIRect* scissorRect,
- const GrUserStencilSettings*,
+ const GrStencilSettings&,
SkRegion::Op op,
bool invert,
bool doAA,
@@ -26,7 +26,7 @@
const SkRect&);
bool drawAndStencilPath(const SkIRect* scissorRect,
- const GrUserStencilSettings*,
+ const GrStencilSettings&,
SkRegion::Op op,
bool invert,
bool doAA,
diff --git a/src/gpu/GrDrawTarget.cpp b/src/gpu/GrDrawTarget.cpp
index f824c81..0f180dc 100644
--- a/src/gpu/GrDrawTarget.cpp
+++ b/src/gpu/GrDrawTarget.cpp
@@ -16,7 +16,6 @@
#include "GrRenderTarget.h"
#include "GrResourceProvider.h"
#include "GrRenderTargetPriv.h"
-#include "GrStencilAttachment.h"
#include "GrSurfacePriv.h"
#include "GrTexture.h"
#include "gl/GrGLRenderTarget.h"
@@ -236,16 +235,17 @@
GrDrawBatch* batch,
const SkIRect* scissorRect) {
// Setup clip
+ GrPipelineBuilder::AutoRestoreStencil ars;
GrAppliedClip clip;
if (scissorRect) {
SkASSERT(GrClip::kWideOpen_ClipType == pipelineBuilder.clip().clipType());
- if (!fClipMaskManager->setupScissorClip(pipelineBuilder, *scissorRect,
+ if (!fClipMaskManager->setupScissorClip(pipelineBuilder, &ars, *scissorRect,
&batch->bounds(), &clip)) {
return;
}
} else {
- if (!fClipMaskManager->setupClipping(pipelineBuilder, &batch->bounds(), &clip)) {
+ if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
return;
}
}
@@ -257,8 +257,7 @@
}
GrPipeline::CreateArgs args;
- if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(),
- clip.hasStencilClip(), batch)) {
+ if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
return;
}
@@ -270,36 +269,34 @@
this->recordBatch(batch);
}
-inline static const GrUserStencilSettings& get_path_stencil_settings_for_fill(
- GrPathRendering::FillType fill) {
- static constexpr GrUserStencilSettings kWindingStencilSettings(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kIncMaybeClamp, // TODO: Use wrap ops for NVPR.
- GrUserStencilOp::kIncMaybeClamp,
- 0xffff>()
+void GrDrawTarget::getPathStencilSettingsForFilltype(GrPathRendering::FillType fill,
+ const GrStencilAttachment* sb,
+ GrStencilSettings* outStencilSettings) {
+ static constexpr GrStencilSettings kWindingStencilSettings(
+ kIncClamp_StencilOp,
+ kIncClamp_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xFFFF, 0xFFFF, 0xFFFF
);
- static constexpr GrUserStencilSettings kEvenOddStencilSettings(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kInvert,
- GrUserStencilOp::kInvert,
- 0xffff>()
+ static constexpr GrStencilSettings kEvenODdStencilSettings(
+ kInvert_StencilOp,
+ kInvert_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xFFFF, 0xFFFF, 0xFFFF
);
switch (fill) {
default:
SkFAIL("Unexpected path fill.");
case GrPathRendering::kWinding_FillType:
- return kWindingStencilSettings;
+ *outStencilSettings = kWindingStencilSettings;
+ break;
case GrPathRendering::kEvenOdd_FillType:
- return kEvenOddStencilSettings;
+ *outStencilSettings = kEvenODdStencilSettings;
+ break;
}
+ fClipMaskManager->adjustPathStencilParams(sb, outStencilSettings);
}
void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
@@ -311,8 +308,9 @@
SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
// Setup clip
+ GrPipelineBuilder::AutoRestoreStencil ars;
GrAppliedClip clip;
- if (!fClipMaskManager->setupClipping(pipelineBuilder, nullptr, &clip)) {
+ if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, nullptr, &clip)) {
return;
}
@@ -322,16 +320,15 @@
arfps.addCoverageFragmentProcessor(clip.clipCoverageFragmentProcessor());
}
+ // set stencil settings for path
+ GrStencilSettings stencilSettings;
GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
- GrStencilAttachment* stencilAttachment = rt->renderTargetPriv().getStencilAttachment();
- SkASSERT(stencilAttachment)
+ GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
+ this->getPathStencilSettingsForFilltype(fill, sb, &stencilSettings);
GrBatch* batch = GrStencilPathBatch::Create(viewMatrix,
pipelineBuilder.isHWAntialias(),
- get_path_stencil_settings_for_fill(fill),
- clip.hasStencilClip(),
- stencilAttachment->bits(),
- clip.scissorState(),
+ stencilSettings, clip.scissorState(),
pipelineBuilder.getRenderTarget(),
path);
this->recordBatch(batch);
@@ -346,8 +343,9 @@
// batches.
SkASSERT(this->caps()->shaderCaps()->pathRenderingSupport());
+ GrPipelineBuilder::AutoRestoreStencil ars;
GrAppliedClip clip;
- if (!fClipMaskManager->setupClipping(pipelineBuilder, &batch->bounds(), &clip)) {
+ if (!fClipMaskManager->setupClipping(pipelineBuilder, &ars, &batch->bounds(), &clip)) {
return;
}
@@ -358,16 +356,14 @@
}
// Ensure the render target has a stencil buffer and get the stencil settings.
+ GrStencilSettings stencilSettings;
GrRenderTarget* rt = pipelineBuilder.getRenderTarget();
GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
- // TODO: Move this step into GrDrawPathPath::onPrepare().
- batch->setStencilSettings(get_path_stencil_settings_for_fill(batch->fillType()),
- clip.hasStencilClip(),
- sb->bits());
+ this->getPathStencilSettingsForFilltype(batch->fillType(), sb, &stencilSettings);
+ batch->setStencilSettings(stencilSettings);
GrPipeline::CreateArgs args;
- if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(),
- clip.hasStencilClip(), batch)) {
+ if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
return;
}
@@ -551,20 +547,11 @@
bool GrDrawTarget::installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
const GrScissorState* scissor,
- bool hasStencilClip,
GrDrawBatch* batch) {
GrPipeline::CreateArgs args;
args.fPipelineBuilder = pipelineBuilder;
args.fCaps = this->caps();
args.fScissor = scissor;
- if (pipelineBuilder->hasUserStencilSettings() || hasStencilClip) {
- GrRenderTarget* rt = pipelineBuilder->getRenderTarget();
- GrStencilAttachment* sb = fResourceProvider->attachStencilAttachment(rt);
- args.fNumStencilBits = sb->bits();
- } else {
- args.fNumStencilBits = 0;
- }
- args.fHasStencilClip = hasStencilClip;
batch->getPipelineOptimizations(&args.fOpts);
GrScissorState finalScissor;
if (args.fOpts.fOverrides.fUsePLSDstRead) {
diff --git a/src/gpu/GrDrawTarget.h b/src/gpu/GrDrawTarget.h
index 907fc1f..c863b45 100644
--- a/src/gpu/GrDrawTarget.h
+++ b/src/gpu/GrDrawTarget.h
@@ -223,7 +223,6 @@
void forwardCombine();
bool installPipelineInDrawBatch(const GrPipelineBuilder* pipelineBuilder,
const GrScissorState* scissor,
- bool hasStencilClip,
GrDrawBatch* batch);
// Makes a copy of the dst if it is necessary for the draw. Returns false if a copy is required
@@ -234,6 +233,11 @@
GrXferProcessor::DstTexture*,
const SkRect& batchBounds);
+ // Check to see if this set of draw commands has been sent out
+ void getPathStencilSettingsForFilltype(GrPathRendering::FillType,
+ const GrStencilAttachment*,
+ GrStencilSettings*);
+
void addDependency(GrDrawTarget* dependedOn);
// Used only by CMM.
diff --git a/src/gpu/GrGpu.h b/src/gpu/GrGpu.h
index 63a56dd..e38b913 100644
--- a/src/gpu/GrGpu.h
+++ b/src/gpu/GrGpu.h
@@ -10,6 +10,7 @@
#include "GrPipelineBuilder.h"
#include "GrProgramDesc.h"
+#include "GrStencil.h"
#include "GrSwizzle.h"
#include "GrAllocator.h"
#include "GrTextureParamsAdjuster.h"
@@ -33,7 +34,6 @@
class GrPrimitiveProcessor;
class GrRenderTarget;
class GrStencilAttachment;
-class GrStencilSettings;
class GrSurface;
class GrTexture;
@@ -485,6 +485,17 @@
virtual void resetShaderCacheForTesting() const {}
protected:
+ // Functions used to map clip-respecting stencil tests into normal
+ // stencil funcs supported by GPUs.
+ static GrStencilFunc ConvertStencilFunc(bool stencilInClip,
+ GrStencilFunc func);
+ static void ConvertStencilFuncAndMask(GrStencilFunc func,
+ bool clipInStencil,
+ unsigned int clipBit,
+ unsigned int userBits,
+ unsigned int* ref,
+ unsigned int* mask);
+
static void ElevateDrawPreference(GrGpu::DrawPreference* preference,
GrGpu::DrawPreference elevation) {
GR_STATIC_ASSERT(GrGpu::kCallerPrefersDraw_DrawPreference > GrGpu::kNoDraw_DrawPreference);
diff --git a/src/gpu/GrPathRenderer.h b/src/gpu/GrPathRenderer.h
index a7609db..3bc0230 100644
--- a/src/gpu/GrPathRenderer.h
+++ b/src/gpu/GrPathRenderer.h
@@ -9,6 +9,7 @@
#define GrPathRenderer_DEFINED
#include "GrDrawTarget.h"
+#include "GrStencil.h"
#include "GrStyle.h"
#include "SkDrawProcs.h"
@@ -81,7 +82,7 @@
bool fAntiAlias;
// These next two are only used by GrStencilAndCoverPathRenderer
- bool fHasUserStencilSettings;
+ bool fIsStencilDisabled;
bool fIsStencilBufferMSAA;
void validate() const {
@@ -154,11 +155,11 @@
canArgs.fStyle = args.fStyle;
canArgs.fAntiAlias = args.fAntiAlias;
- canArgs.fHasUserStencilSettings = args.fPipelineBuilder->hasUserStencilSettings();
+ canArgs.fIsStencilDisabled = args.fPipelineBuilder->getStencil().isDisabled();
canArgs.fIsStencilBufferMSAA =
args.fPipelineBuilder->getRenderTarget()->isStencilBufferMultisampled();
SkASSERT(this->canDrawPath(canArgs));
- if (args.fPipelineBuilder->hasUserStencilSettings()) {
+ if (!args.fPipelineBuilder->getStencil().isDisabled()) {
SkASSERT(kNoRestriction_StencilSupport == this->getStencilSupport(*args.fPath));
SkASSERT(args.fStyle->isSimpleFill());
}
@@ -259,16 +260,14 @@
* kStencilOnly in onGetStencilSupport().
*/
virtual void onStencilPath(const StencilPathArgs& args) {
- static constexpr GrUserStencilSettings kIncrementStencil(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kReplace,
- GrUserStencilOp::kReplace,
- 0xffff>()
- );
- args.fPipelineBuilder->setUserStencil(&kIncrementStencil);
+ static constexpr GrStencilSettings kIncrementStencil(
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+ args.fPipelineBuilder->setStencil(kIncrementStencil);
args.fPipelineBuilder->setDisableColorXPFactory();
DrawPathArgs drawArgs;
drawArgs.fTarget = args.fTarget;
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index 761a876..8d384ef 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -20,35 +20,9 @@
GrXPOverridesForBatch* overrides) {
const GrPipelineBuilder& builder = *args.fPipelineBuilder;
- GrPipeline* pipeline = new (memory) GrPipeline;
- pipeline->fRenderTarget.reset(builder.fRenderTarget.get());
- SkASSERT(pipeline->fRenderTarget);
- pipeline->fScissorState = *args.fScissor;
- if (builder.hasUserStencilSettings() || args.fHasStencilClip) {
- SkASSERT(args.fNumStencilBits);
- pipeline->fStencilSettings.reset(*builder.getUserStencil(), args.fHasStencilClip,
- args.fNumStencilBits);
- SkASSERT(!pipeline->fStencilSettings.usesWrapOp() || args.fCaps->stencilWrapOpsSupport());
- }
- pipeline->fDrawFace = builder.getDrawFace();
-
- pipeline->fFlags = 0;
- if (builder.isHWAntialias()) {
- pipeline->fFlags |= kHWAA_Flag;
- }
- if (builder.snapVerticesToPixelCenters()) {
- pipeline->fFlags |= kSnapVertices_Flag;
- }
- if (builder.getDisableOutputConversionToSRGB()) {
- pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag;
- }
- if (builder.getAllowSRGBInputs()) {
- pipeline->fFlags |= kAllowSRGBInputs_Flag;
- }
-
// Create XferProcessor from DS's XPFactory
bool hasMixedSamples = builder.getRenderTarget()->hasMixedSamples() &&
- (builder.isHWAntialias() || !pipeline->fStencilSettings.isDisabled());
+ (builder.isHWAntialias() || !builder.getStencil().isDisabled());
const GrXPFactory* xpFactory = builder.getXPFactory();
SkAutoTUnref<GrXferProcessor> xferProcessor;
if (xpFactory) {
@@ -57,7 +31,6 @@
&args.fDstTexture,
*args.fCaps));
if (!xferProcessor) {
- pipeline->~GrPipeline();
return nullptr;
}
} else {
@@ -78,7 +51,7 @@
const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() :
&GrPorterDuffXPFactory::SimpleSrcOverXP();
optFlags = xpForOpts->getOptimizations(args.fOpts,
- pipeline->fStencilSettings.doesWrite(),
+ builder.getStencil().doesWrite(),
&overrideColor,
*args.fCaps);
@@ -86,7 +59,6 @@
// so we must check the draw type. In cases where we will skip drawing we simply return a
// null GrPipeline.
if (GrXferProcessor::kSkipDraw_OptFlag & optFlags) {
- pipeline->~GrPipeline();
return nullptr;
}
@@ -95,8 +67,29 @@
overrideColor = GrColor_ILLEGAL;
}
+ GrPipeline* pipeline = new (memory) GrPipeline;
pipeline->fXferProcessor.reset(xferProcessor);
+ pipeline->fRenderTarget.reset(builder.fRenderTarget.get());
+ SkASSERT(pipeline->fRenderTarget);
+ pipeline->fScissorState = *args.fScissor;
+ pipeline->fStencilSettings = builder.getStencil();
+ pipeline->fDrawFace = builder.getDrawFace();
+
+ pipeline->fFlags = 0;
+ if (builder.isHWAntialias()) {
+ pipeline->fFlags |= kHWAA_Flag;
+ }
+ if (builder.snapVerticesToPixelCenters()) {
+ pipeline->fFlags |= kSnapVertices_Flag;
+ }
+ if (builder.getDisableOutputConversionToSRGB()) {
+ pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag;
+ }
+ if (builder.getAllowSRGBInputs()) {
+ pipeline->fFlags |= kAllowSRGBInputs_Flag;
+ }
+
int firstColorProcessorIdx = args.fOpts.fColorPOI.firstEffectiveProcessorIndex();
// TODO: Once we can handle single or four channel input into coverage GrFragmentProcessors
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index ff1905b..f64b875 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -15,7 +15,7 @@
#include "GrPendingProgramElement.h"
#include "GrPrimitiveProcessor.h"
#include "GrProgramDesc.h"
-#include "GrStencilSettings.h"
+#include "GrStencil.h"
#include "GrTypesPriv.h"
#include "SkMatrix.h"
#include "SkRefCnt.h"
@@ -51,8 +51,6 @@
const GrCaps* fCaps;
GrPipelineOptimizations fOpts;
const GrScissorState* fScissor;
- int fNumStencilBits;
- bool fHasStencilClip;
GrXferProcessor::DstTexture fDstTexture;
};
diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index 4731cbb..1fd568e 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -16,14 +16,11 @@
#include "effects/GrPorterDuffXferProcessor.h"
GrPipelineBuilder::GrPipelineBuilder()
- : fFlags(0x0),
- fUserStencilSettings(&GrUserStencilSettings::kUnused),
- fDrawFace(kBoth_DrawFace) {
+ : fFlags(0x0), fDrawFace(kBoth_DrawFace) {
SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
}
-GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, const GrClip& clip)
- : GrPipelineBuilder() {
+GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, const GrClip& clip) {
SkDEBUGCODE(fBlockEffectRemovalCnt = 0;)
for (int i = 0; i < paint.numColorFragmentProcessors(); ++i) {
@@ -38,6 +35,11 @@
this->setRenderTarget(rt);
+ // These have no equivalent in GrPaint, set them to defaults
+ fDrawFace = kBoth_DrawFace;
+ fStencilSettings.setDisabled();
+ fFlags = 0;
+
fClip = clip;
this->setState(GrPipelineBuilder::kHWAntialias_Flag,
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index 18f817b..2f78fc5 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -14,7 +14,7 @@
#include "GrGpuResourceRef.h"
#include "GrProcOptInfo.h"
#include "GrRenderTarget.h"
-#include "GrUserStencilSettings.h"
+#include "GrStencil.h"
#include "GrXferProcessor.h"
#include "SkMatrix.h"
#include "effects/GrCoverageSetOpXP.h"
@@ -199,20 +199,57 @@
/// @name Stencil
////
- bool hasUserStencilSettings() const {
- return &GrUserStencilSettings::kUnused != fUserStencilSettings;
- }
- const GrUserStencilSettings* getUserStencil() const { return fUserStencilSettings; }
+ const GrStencilSettings& getStencil() const { return fStencilSettings; }
/**
- * Sets the user stencil settings for the next draw.
- * This class only stores pointers to stencil settings objects.
- * The caller guarantees the pointer will remain valid until it
- * changes or goes out of scope.
+ * Sets the stencil settings to use for the next draw.
+ * Changing the clip has the side-effect of possibly zeroing
+ * out the client settable stencil bits. So multipass algorithms
+ * using stencil should not change the clip between passes.
* @param settings the stencil settings to use.
*/
- void setUserStencil(const GrUserStencilSettings* settings) { fUserStencilSettings = settings; }
- void disableUserStencil() { fUserStencilSettings = &GrUserStencilSettings::kUnused; }
+ void setStencil(const GrStencilSettings& settings) { fStencilSettings = settings; }
+
+ GrStencilSettings* stencil() { return &fStencilSettings; }
+
+ /**
+ * AutoRestoreStencil
+ *
+ * This simple struct saves and restores the stencil settings
+ * This class can transiently modify its "const" GrPipelineBuilder object but will restore it
+ * when done - so it is notionally "const" correct.
+ */
+ class AutoRestoreStencil : public ::SkNoncopyable {
+ public:
+ AutoRestoreStencil() : fPipelineBuilder(nullptr) {}
+
+ AutoRestoreStencil(const GrPipelineBuilder& ds) : fPipelineBuilder(nullptr) { this->set(&ds); }
+
+ ~AutoRestoreStencil() { this->set(nullptr); }
+
+ void set(const GrPipelineBuilder* ds) {
+ if (fPipelineBuilder) {
+ fPipelineBuilder->setStencil(fStencilSettings);
+ }
+ fPipelineBuilder = const_cast<GrPipelineBuilder*>(ds);
+ if (ds) {
+ fStencilSettings = ds->getStencil();
+ }
+ }
+
+ bool isSet() const { return SkToBool(fPipelineBuilder); }
+
+ void setStencil(const GrStencilSettings& settings) {
+ SkASSERT(this->isSet());
+ fPipelineBuilder->setStencil(settings);
+ }
+
+ private:
+ // notionally const (as marginalia)
+ GrPipelineBuilder* fPipelineBuilder;
+ GrStencilSettings fStencilSettings;
+ };
+
/// @}
@@ -334,7 +371,7 @@
SkAutoTUnref<GrRenderTarget> fRenderTarget;
uint32_t fFlags;
- const GrUserStencilSettings* fUserStencilSettings;
+ GrStencilSettings fStencilSettings;
DrawFace fDrawFace;
mutable SkAutoTUnref<const GrXPFactory> fXPFactory;
FragmentProcessorArray fColorFragmentProcessors;
diff --git a/src/gpu/GrStencil.cpp b/src/gpu/GrStencil.cpp
new file mode 100644
index 0000000..94559ab
--- /dev/null
+++ b/src/gpu/GrStencil.cpp
@@ -0,0 +1,403 @@
+/*
+ * 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 "GrStencil.h"
+
+#include "GrProcessor.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// Stencil Rules for Merging user stencil space into clip
+
+// We can't include the clip bit in the ref or mask values because the division
+// between user and clip bits in the stencil depends on the number of stencil
+// bits in the runtime. Comments below indicate what the code should do to
+// incorporate the clip bit into these settings.
+
+///////
+// Replace
+
+// set the ref to be the clip bit, but mask it out for the test
+static constexpr GrStencilSettings gUserToClipReplace(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipReplace(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Intersect
+static constexpr GrStencilSettings gUserToClipIsect(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipIsect(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Difference
+static constexpr GrStencilSettings gUserToClipDiff(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipDiff(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Union
+
+// first pass makes all the passing cases >= just clip bit set.
+static constexpr GrStencilSettings gUserToClipUnionPass0(
+ kReplace_StencilOp,
+ kKeep_StencilOp,
+ kLEqual_StencilFunc,
+ 0xffff,
+ 0x0001, // set clip bit
+ 0xffff);
+
+// second pass allows anything greater than just clip bit set to pass
+static constexpr GrStencilSettings gUserToClipUnionPass1(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+// first pass finds zeros in the user bits and if found sets
+// the clip bit to 1
+static constexpr GrStencilSettings gInvUserToClipUnionPass0(
+ kReplace_StencilOp,
+ kKeep_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0x0000 // set clip bit
+);
+
+// second pass zeros the user bits
+static constexpr GrStencilSettings gInvUserToClipUnionPass1(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff // unset clip bit
+);
+
+///////
+// Xor
+static constexpr GrStencilSettings gUserToClipXorPass0(
+ kInvert_StencilOp,
+ kKeep_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000,
+ 0xffff);
+
+static constexpr GrStencilSettings gUserToClipXorPass1(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kGreater_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipXorPass0(
+ kInvert_StencilOp,
+ kKeep_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000,
+ 0xffff);
+
+static constexpr GrStencilSettings gInvUserToClipXorPass1(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0xffff);
+
+///////
+// Reverse Diff
+static constexpr GrStencilSettings gUserToClipRDiffPass0(
+ kInvert_StencilOp,
+ kZero_StencilOp,
+ kLess_StencilFunc,
+ 0xffff, // unset clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+static constexpr GrStencilSettings gUserToClipRDiffPass1(
+ kReplace_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0x0000, // set clip bit
+ 0x0000, // set clip bit
+ 0xffff);
+
+// We are looking for stencil values that are all zero. The first pass sets the
+// clip bit if the stencil is all zeros. The second pass clears the user bits.
+static constexpr GrStencilSettings gInvUserToClipRDiffPass0(
+ kInvert_StencilOp,
+ kZero_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0x0000 // set clip bit
+);
+
+static constexpr GrStencilSettings gInvUserToClipRDiffPass1(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff // unset clip bit
+);
+
+///////
+// Direct to Stencil
+
+// We can render a clip element directly without first writing to the client
+// portion of the clip when the fill is not inverse and the set operation will
+// only modify the in/out status of samples covered by the clip element.
+
+// this one only works if used right after stencil clip was cleared.
+// Our clip mask creation code doesn't allow midstream replace ops.
+static constexpr GrStencilSettings gReplaceClip(
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0x0000 // set clipBit
+);
+
+static constexpr GrStencilSettings gUnionClip(
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000, // set clip bit
+ 0x0000 // set clip bit
+);
+
+static constexpr GrStencilSettings gXorClip(
+ kInvert_StencilOp,
+ kInvert_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0x0000 // set clip bit
+);
+
+static constexpr GrStencilSettings gDiffClip(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0x0000 // set clip bit
+);
+
+bool GrStencilSettings::GetClipPasses(
+ SkRegion::Op op,
+ bool canBeDirect,
+ unsigned int stencilClipMask,
+ bool invertedFill,
+ int* numPasses,
+ GrStencilSettings settings[kMaxStencilClipPasses]) {
+ if (canBeDirect && !invertedFill) {
+ *numPasses = 0;
+ switch (op) {
+ case SkRegion::kReplace_Op:
+ *numPasses = 1;
+ settings[0] = gReplaceClip;
+ break;
+ case SkRegion::kUnion_Op:
+ *numPasses = 1;
+ settings[0] = gUnionClip;
+ break;
+ case SkRegion::kXOR_Op:
+ *numPasses = 1;
+ settings[0] = gXorClip;
+ break;
+ case SkRegion::kDifference_Op:
+ *numPasses = 1;
+ settings[0] = gDiffClip;
+ break;
+ default: // suppress warning
+ break;
+ }
+ if (1 == *numPasses) {
+ settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
+ settings[0].fFuncRefs[kBack_Face] =
+ settings[0].fFuncRefs[kFront_Face];
+ settings[0].fWriteMasks[kBack_Face] =
+ settings[0].fWriteMasks[kFront_Face];
+ return true;
+ }
+ }
+ switch (op) {
+ // if we make the path renderer go to stencil we always give it a
+ // non-inverted fill and we use the stencil rules on the client->clipbit
+ // pass to select either the zeros or nonzeros.
+ case SkRegion::kReplace_Op:
+ *numPasses= 1;
+ settings[0] = invertedFill ? gInvUserToClipReplace :
+ gUserToClipReplace;
+ settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+ settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[0].fFuncMasks[kBack_Face] =
+ settings[0].fFuncMasks[kFront_Face];
+ settings[0].fFuncRefs[kBack_Face] =
+ settings[0].fFuncRefs[kFront_Face];
+ break;
+ case SkRegion::kIntersect_Op:
+ *numPasses = 1;
+ settings[0] = invertedFill ? gInvUserToClipIsect : gUserToClipIsect;
+ settings[0].fFuncRefs[kFront_Face] = stencilClipMask;
+ settings[0].fFuncRefs[kBack_Face] =
+ settings[0].fFuncRefs[kFront_Face];
+ break;
+ case SkRegion::kUnion_Op:
+ *numPasses = 2;
+ if (invertedFill) {
+ settings[0] = gInvUserToClipUnionPass0;
+ settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+ settings[0].fFuncMasks[kBack_Face] =
+ settings[0].fFuncMasks[kFront_Face];
+ settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[0].fFuncRefs[kBack_Face] =
+ settings[0].fFuncRefs[kFront_Face];
+ settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
+ settings[0].fWriteMasks[kBack_Face] =
+ settings[0].fWriteMasks[kFront_Face];
+
+ settings[1] = gInvUserToClipUnionPass1;
+ settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask;
+ settings[1].fWriteMasks[kBack_Face] &=
+ settings[1].fWriteMasks[kFront_Face];
+
+ } else {
+ settings[0] = gUserToClipUnionPass0;
+ settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+ settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[0].fFuncMasks[kBack_Face] =
+ settings[0].fFuncMasks[kFront_Face];
+ settings[0].fFuncRefs[kBack_Face] =
+ settings[0].fFuncRefs[kFront_Face];
+
+ settings[1] = gUserToClipUnionPass1;
+ settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[1].fFuncRefs[kBack_Face] =
+ settings[1].fFuncRefs[kFront_Face];
+ }
+ break;
+ case SkRegion::kXOR_Op:
+ *numPasses = 2;
+ if (invertedFill) {
+ settings[0] = gInvUserToClipXorPass0;
+ settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+ settings[0].fFuncMasks[kBack_Face] =
+ settings[0].fFuncMasks[kFront_Face];
+
+ settings[1] = gInvUserToClipXorPass1;
+ settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[1].fFuncRefs[kBack_Face] =
+ settings[1].fFuncRefs[kFront_Face];
+ } else {
+ settings[0] = gUserToClipXorPass0;
+ settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+ settings[0].fFuncMasks[kBack_Face] =
+ settings[0].fFuncMasks[kFront_Face];
+
+ settings[1] = gUserToClipXorPass1;
+ settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[1].fFuncRefs[kBack_Face] =
+ settings[1].fFuncRefs[kFront_Face];
+ }
+ break;
+ case SkRegion::kDifference_Op:
+ *numPasses = 1;
+ settings[0] = invertedFill ? gInvUserToClipDiff : gUserToClipDiff;
+ settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[0].fFuncRefs[kBack_Face] =
+ settings[0].fFuncRefs[kFront_Face];
+ break;
+ case SkRegion::kReverseDifference_Op:
+ if (invertedFill) {
+ *numPasses = 2;
+ settings[0] = gInvUserToClipRDiffPass0;
+ settings[0].fWriteMasks[kFront_Face] |= stencilClipMask;
+ settings[0].fWriteMasks[kBack_Face] =
+ settings[0].fWriteMasks[kFront_Face];
+ settings[1] = gInvUserToClipRDiffPass1;
+ settings[1].fWriteMasks[kFront_Face] &= ~stencilClipMask;
+ settings[1].fWriteMasks[kBack_Face] =
+ settings[1].fWriteMasks[kFront_Face];
+ } else {
+ *numPasses = 2;
+ settings[0] = gUserToClipRDiffPass0;
+ settings[0].fFuncMasks[kFront_Face] &= ~stencilClipMask;
+ settings[0].fFuncMasks[kBack_Face] =
+ settings[0].fFuncMasks[kFront_Face];
+ settings[0].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[0].fFuncRefs[kBack_Face] =
+ settings[0].fFuncRefs[kFront_Face];
+
+ settings[1] = gUserToClipRDiffPass1;
+ settings[1].fFuncMasks[kFront_Face] |= stencilClipMask;
+ settings[1].fFuncRefs[kFront_Face] |= stencilClipMask;
+ settings[1].fFuncMasks[kBack_Face] =
+ settings[1].fFuncMasks[kFront_Face];
+ settings[1].fFuncRefs[kBack_Face] =
+ settings[1].fFuncRefs[kFront_Face];
+ }
+ break;
+ default:
+ SkFAIL("Unknown set op");
+ }
+ return false;
+}
+
+void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
+ static const int kCount = sizeof(GrStencilSettings) / sizeof(uint32_t);
+ GR_STATIC_ASSERT(0 == sizeof(GrStencilSettings) % sizeof(uint32_t));
+ uint32_t* key = b->add32n(kCount);
+ memcpy(key, this, sizeof(GrStencilSettings));
+}
diff --git a/src/gpu/GrStencil.h b/src/gpu/GrStencil.h
new file mode 100644
index 0000000..075eb1e
--- /dev/null
+++ b/src/gpu/GrStencil.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef GrStencil_DEFINED
+#define GrStencil_DEFINED
+
+#include "GrTypes.h"
+#include "SkRegion.h"
+
+class GrProcessorKeyBuilder;
+
+/**
+ * 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 (clients). Client code can
+ * modify these bits. GrDrawTarget will ignore ref, mask, and writemask bits
+ * provided by clients that overlap the bits used to implement clipping.
+ *
+ * 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 client bits.
+ * > Client can assume all client 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 client bits that were modifed (both inside and outside the
+ * clip).
+ */
+
+/**
+ * Determines which pixels pass / fail the stencil test.
+ * Stencil test passes if (ref & mask) FUNC (stencil & mask) is true
+ */
+enum GrStencilFunc {
+ kAlways_StencilFunc = 0,
+ kNever_StencilFunc,
+ kGreater_StencilFunc,
+ kGEqual_StencilFunc,
+ kLess_StencilFunc,
+ kLEqual_StencilFunc,
+ kEqual_StencilFunc,
+ kNotEqual_StencilFunc,
+
+ // Gr stores the current clip in the
+ // stencil buffer in the high bits that
+ // are not directly accessible modifiable
+ // via the GrDrawTarget interface. The below
+ // stencil funcs test against the current
+ // clip in addition to the GrDrawTarget
+ // client's stencil bits.
+
+ // pass if inside the clip
+ kAlwaysIfInClip_StencilFunc,
+ kEqualIfInClip_StencilFunc,
+ kLessIfInClip_StencilFunc,
+ kLEqualIfInClip_StencilFunc,
+ kNonZeroIfInClip_StencilFunc, // this one forces the ref to be 0
+
+ kLast_StencilFunc = kNonZeroIfInClip_StencilFunc
+};
+
+static const int kStencilFuncCnt = kLast_StencilFunc + 1;
+static const int kClipStencilFuncCnt =
+ kNonZeroIfInClip_StencilFunc - kAlwaysIfInClip_StencilFunc + 1;
+static const int kBasicStencilFuncCnt = kStencilFuncCnt - kClipStencilFuncCnt;
+
+/**
+ * Operations to perform based on whether stencil test passed failed.
+ */
+enum GrStencilOp {
+ kKeep_StencilOp = 0, // preserve existing stencil value
+ kReplace_StencilOp, // replace with reference value from stencl test
+ kIncWrap_StencilOp, // increment and wrap at max
+ kIncClamp_StencilOp, // increment and clamp at max
+ kDecWrap_StencilOp, // decrement and wrap at 0
+ kDecClamp_StencilOp, // decrement and clamp at 0
+ kZero_StencilOp, // zero stencil bits
+ kInvert_StencilOp, // invert stencil bits
+ kLast_StencilOp = kInvert_StencilOp
+};
+static const int kStencilOpCnt = kLast_StencilOp + 1;
+
+/**
+ * Class representing stencil state.
+ */
+class GrStencilSettings {
+public:
+ enum Face {
+ kFront_Face = 0,
+ kBack_Face = 1,
+ };
+
+ constexpr GrStencilSettings(GrStencilOp passOp,
+ GrStencilOp failOp,
+ GrStencilFunc func,
+ unsigned short funcMask,
+ unsigned short funcRef,
+ unsigned short writeMask)
+ : fPassOps{(uint8_t)passOp, (uint8_t)passOp}
+ , fFailOps{(uint8_t)failOp, (uint8_t)failOp}
+ , fFuncs{(uint8_t)func, (uint8_t)func}
+ , fPad0(0)
+ , fPad1(0)
+ , fFuncMasks{funcMask, funcMask}
+ , fFuncRefs{funcRef, funcRef}
+ , fWriteMasks{writeMask, writeMask}
+ , fFlags(ComputeFlags(passOp, passOp,
+ failOp, failOp,
+ func, func,
+ writeMask, writeMask)) {
+ }
+
+ constexpr GrStencilSettings(GrStencilOp frontPassOp, GrStencilOp backPassOp,
+ GrStencilOp frontFailOp, GrStencilOp backFailOp,
+ GrStencilFunc frontFunc, GrStencilFunc backFunc,
+ uint16_t frontFuncMask, uint16_t backFuncMask,
+ uint16_t frontFuncRef, uint16_t backFuncRef,
+ uint16_t frontWriteMask, uint16_t backWriteMask)
+ : fPassOps{(uint8_t)frontPassOp, (uint8_t)backPassOp}
+ , fFailOps{(uint8_t)frontFailOp, (uint8_t)backFailOp}
+ , fFuncs{(uint8_t)frontFunc, (uint8_t)backFunc}
+ , fPad0(0)
+ , fPad1(0)
+ , fFuncMasks{frontFuncMask, backFuncMask}
+ , fFuncRefs{frontFuncRef, backFuncRef}
+ , fWriteMasks{frontWriteMask, backWriteMask}
+ , fFlags(ComputeFlags(frontPassOp, backPassOp,
+ frontFailOp, backFailOp,
+ frontFunc, backFunc,
+ frontWriteMask, backWriteMask)) {
+ }
+
+ GrStencilSettings() {
+ fPad0 = fPad1 = 0;
+ this->setDisabled();
+ }
+
+ GrStencilOp passOp(Face f) const { return static_cast<GrStencilOp>(fPassOps[f]); }
+ GrStencilOp failOp(Face f) const { return static_cast<GrStencilOp>(fFailOps[f]); }
+ GrStencilFunc func(Face f) const { return static_cast<GrStencilFunc>(fFuncs[f]); }
+ uint16_t funcMask(Face f) const { return fFuncMasks[f]; }
+ uint16_t funcRef(Face f) const { return fFuncRefs[f]; }
+ uint16_t writeMask(Face f) const { return fWriteMasks[f]; }
+
+ void setPassOp(Face f, GrStencilOp op) { fPassOps[f] = op; fFlags = 0;}
+ void setFailOp(Face f, GrStencilOp op) { fFailOps[f] = op; fFlags = 0;}
+ void setFunc(Face f, GrStencilFunc func) { fFuncs[f] = func; fFlags = 0;}
+ void setFuncMask(Face f, unsigned short mask) { fFuncMasks[f] = mask; }
+ void setFuncRef(Face f, unsigned short ref) { fFuncRefs[f] = ref; }
+ void setWriteMask(Face f, unsigned short writeMask) { fWriteMasks[f] = writeMask; }
+
+ void copyFrontSettingsToBack() {
+ fPassOps[kBack_Face] = fPassOps[kFront_Face];
+ fFailOps[kBack_Face] = fFailOps[kFront_Face];
+ fFuncs[kBack_Face] = fFuncs[kFront_Face];
+ fFuncMasks[kBack_Face] = fFuncMasks[kFront_Face];
+ fFuncRefs[kBack_Face] = fFuncRefs[kFront_Face];
+ fWriteMasks[kBack_Face] = fWriteMasks[kFront_Face];
+ fFlags = 0;
+ }
+
+ void setDisabled() {
+ memset(this, 0, sizeof(*this));
+ GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+ GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+ fFlags = kIsDisabled_StencilFlag | kDoesNotWrite_StencilFlag;
+ }
+
+ bool isTwoSided() const {
+ return fPassOps[kFront_Face] != fPassOps[kBack_Face] ||
+ fFailOps[kFront_Face] != fFailOps[kBack_Face] ||
+ fFuncs[kFront_Face] != fFuncs[kBack_Face] ||
+ fFuncMasks[kFront_Face] != fFuncMasks[kBack_Face] ||
+ fFuncRefs[kFront_Face] != fFuncRefs[kBack_Face] ||
+ fWriteMasks[kFront_Face] != fWriteMasks[kBack_Face];
+ }
+
+ bool usesWrapOp() const {
+ return kIncWrap_StencilOp == fPassOps[kFront_Face] ||
+ kDecWrap_StencilOp == fPassOps[kFront_Face] ||
+ kIncWrap_StencilOp == fPassOps[kBack_Face] ||
+ kDecWrap_StencilOp == fPassOps[kBack_Face] ||
+ kIncWrap_StencilOp == fFailOps[kFront_Face] ||
+ kDecWrap_StencilOp == fFailOps[kFront_Face] ||
+ kIncWrap_StencilOp == fFailOps[kBack_Face] ||
+ kDecWrap_StencilOp == fFailOps[kBack_Face];
+ }
+
+ bool isDisabled() const {
+ if (fFlags & kIsDisabled_StencilFlag) {
+ return true;
+ }
+ if (fFlags & kNotDisabled_StencilFlag) {
+ return false;
+ }
+ bool disabled = this->computeIsDisabled();
+ fFlags |= disabled ? kIsDisabled_StencilFlag : kNotDisabled_StencilFlag;
+ return disabled;
+ }
+
+ bool doesWrite() const {
+ if (fFlags & kDoesWrite_StencilFlag) {
+ return true;
+ }
+ if (fFlags & kDoesNotWrite_StencilFlag) {
+ return false;
+ }
+ bool writes = this->computeDoesWrite();
+ fFlags |= writes ? kDoesWrite_StencilFlag : kDoesNotWrite_StencilFlag;
+ return writes;
+ }
+
+ void invalidate() {
+ // write an illegal value to the first member
+ fPassOps[0] = kStencilOpCnt;
+ fFlags = 0;
+ }
+
+ bool isValid() const { return fPassOps[0] < kStencilOpCnt; }
+
+ void genKey(GrProcessorKeyBuilder* b) const;
+
+ bool operator==(const GrStencilSettings& s) const {
+ static const size_t gCompareSize = sizeof(GrStencilSettings) -
+ sizeof(fFlags);
+ SkASSERT((const char*)&fFlags + sizeof(fFlags) ==
+ (const char*)this + sizeof(GrStencilSettings));
+ if (this->isDisabled() & s.isDisabled()) { // using & not &&
+ return true;
+ }
+ return 0 == memcmp(this, &s, gCompareSize);
+ }
+
+ bool operator!=(const GrStencilSettings& s) const {
+ return !(*this == s);
+ }
+
+ GrStencilSettings& operator=(const GrStencilSettings& s) {
+ memcpy(this, &s, sizeof(GrStencilSettings));
+ return *this;
+ }
+
+private:
+ friend class GrClipMaskManager;
+
+ enum {
+ kMaxStencilClipPasses = 2 // maximum number of passes to add a clip
+ // element to the stencil buffer.
+ };
+
+ /**
+ * 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.
+ * 4. The fill rule that should actually be used to render (will
+ * always be non-inverted).
+ *
+ * @param op the set op to combine this element with the
+ * existing clip
+ * @param stencilClipMask mask with just the stencil bit used for clipping
+ * enabled.
+ * @param invertedFill is this path inverted
+ * @param numPasses out: the number of passes needed to add the
+ * element to the clip.
+ * @param settings out: the stencil settings to use for each pass
+ *
+ * @return true if the clip element's geometry can be drawn directly to the
+ * stencil clip bit. Will only be true if canBeDirect is true.
+ * numPasses will be 1 if return value is true.
+ */
+ static bool GetClipPasses(SkRegion::Op op,
+ bool canBeDirect,
+ unsigned int stencilClipMask,
+ bool invertedFill,
+ int* numPasses,
+ GrStencilSettings settings[kMaxStencilClipPasses]);
+
+ constexpr static bool IsDisabled(GrStencilOp frontPassOp, GrStencilOp backPassOp,
+ GrStencilOp frontFailOp, GrStencilOp backFailOp,
+ GrStencilFunc frontFunc, GrStencilFunc backFunc) {
+ return (((frontPassOp == kKeep_StencilOp && frontFailOp == kKeep_StencilOp)) &&
+ ((backPassOp == kKeep_StencilOp && backFailOp == kKeep_StencilOp)) &&
+ frontFunc == kAlways_StencilFunc &&
+ backFunc == kAlways_StencilFunc);
+ }
+
+ constexpr static bool DoesWrite(GrStencilOp frontPassOp, GrStencilOp backPassOp,
+ GrStencilOp frontFailOp, GrStencilOp backFailOp,
+ GrStencilFunc frontFunc, GrStencilFunc backFunc,
+ uint16_t frontWriteMask, uint16_t backWriteMask) {
+ return (0 != (frontWriteMask | backWriteMask)) &&
+ // Can we write due to a front face passing the stencil test?
+ ((frontFunc != kNever_StencilFunc && frontPassOp != kKeep_StencilOp) ||
+ // Can we write due to a back face passing the stencil test?
+ (backFunc != kNever_StencilFunc && backPassOp != kKeep_StencilOp) ||
+ // Can we write due to a front face failing the stencil test?
+ (frontFunc != kAlways_StencilFunc && frontFailOp != kKeep_StencilOp) ||
+ // Can we write due to a back face failing the stencil test?
+ (backFunc != kAlways_StencilFunc && backFailOp != kKeep_StencilOp));
+ }
+
+ constexpr static uint32_t ComputeFlags(GrStencilOp frontPassOp, GrStencilOp backPassOp,
+ GrStencilOp frontFailOp, GrStencilOp backFailOp,
+ GrStencilFunc frontFunc, GrStencilFunc backFunc,
+ uint16_t frontWriteMask, uint16_t backWriteMask) {
+ return (IsDisabled(frontPassOp, backPassOp, frontFailOp, backFailOp,
+ frontFunc, backFunc)
+ ? kIsDisabled_StencilFlag
+ : kNotDisabled_StencilFlag) |
+ (DoesWrite(frontPassOp, backPassOp, frontFailOp, backFailOp,
+ frontFunc, backFunc, frontWriteMask, backWriteMask)
+ ? kDoesWrite_StencilFlag
+ : kDoesNotWrite_StencilFlag);
+ }
+
+ bool computeIsDisabled() const {
+ return IsDisabled((GrStencilOp) fPassOps[kFront_Face], (GrStencilOp) fPassOps[kBack_Face],
+ (GrStencilOp) fFailOps[kFront_Face], (GrStencilOp) fFailOps[kBack_Face],
+ (GrStencilFunc) fFuncs[kFront_Face], (GrStencilFunc) fFuncs[kBack_Face]);
+ }
+ bool computeDoesWrite() const {
+ return DoesWrite((GrStencilOp)fPassOps[kFront_Face], (GrStencilOp)fPassOps[kBack_Face],
+ (GrStencilOp)fFailOps[kFront_Face], (GrStencilOp)fFailOps[kBack_Face],
+ (GrStencilFunc)fFuncs[kFront_Face], (GrStencilFunc)fFuncs[kBack_Face],
+ fWriteMasks[kFront_Face], fWriteMasks[kBack_Face]);
+ }
+
+ enum GrStencilFlags {
+ kIsDisabled_StencilFlag = 0x1,
+ kNotDisabled_StencilFlag = 0x2,
+ kDoesWrite_StencilFlag = 0x4,
+ kDoesNotWrite_StencilFlag = 0x8,
+ };
+
+ uint8_t fPassOps[2]; // op to perform when faces pass (GrStencilOp)
+ uint8_t fFailOps[2]; // op to perform when faces fail (GrStencilOp)
+ uint8_t fFuncs[2]; // test function for faces (GrStencilFunc)
+ uint8_t fPad0;
+ uint8_t fPad1;
+ uint16_t fFuncMasks[2]; // mask for face tests
+ uint16_t fFuncRefs[2]; // reference values for face tests
+ uint16_t fWriteMasks[2]; // stencil write masks
+ mutable uint32_t fFlags;
+
+};
+
+// We rely on this being packed and aligned (memcmp'ed and memcpy'ed)
+GR_STATIC_ASSERT(sizeof(GrStencilSettings) % 4 == 0);
+GR_STATIC_ASSERT(sizeof(GrStencilSettings) ==
+ 4*sizeof(uint8_t) + // ops
+ 2*sizeof(uint8_t) + // funcs
+ 2*sizeof(uint8_t) + // pads
+ 2*sizeof(uint16_t) + // func masks
+ 2*sizeof(uint16_t) + // ref values
+ 2*sizeof(uint16_t) + // write masks
+ sizeof(uint32_t)); // flags
+
+#endif
diff --git a/src/gpu/GrStencilSettings.cpp b/src/gpu/GrStencilSettings.cpp
deleted file mode 100644
index ae8b03b..0000000
--- a/src/gpu/GrStencilSettings.cpp
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * 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 "GrStencilSettings.h"
-
-#include "GrProcessor.h"
-
-constexpr const GrUserStencilSettings gUnused(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kKeep,
- GrUserStencilOp::kKeep,
- 0x0000>()
-);
-
-GR_STATIC_ASSERT(kAll_StencilFlags == (gUnused.fFrontFlags[0] & gUnused.fBackFlags[0]));
-
-const GrUserStencilSettings& GrUserStencilSettings::kUnused = gUnused;
-
-void GrStencilSettings::reset(const GrUserStencilSettings& user, bool hasStencilClip,
- int numStencilBits) {
- uint16_t frontFlags = user.fFrontFlags[hasStencilClip];
- if (frontFlags & kSingleSided_StencilFlag) {
- fFlags = frontFlags;
- if (!this->isDisabled()) {
- fFront.reset(user.fFront, hasStencilClip, numStencilBits);
- }
- return;
- }
-
- uint16_t backFlags = user.fBackFlags[hasStencilClip];
- fFlags = frontFlags & backFlags;
- if (this->isDisabled()) {
- return;
- }
- if (!(frontFlags & kDisabled_StencilFlag)) {
- fFront.reset(user.fFront, hasStencilClip, numStencilBits);
- } else {
- fFront.setDisabled();
- }
- if (!(backFlags & kDisabled_StencilFlag)) {
- fBack.reset(user.fBack, hasStencilClip, numStencilBits);
- } else {
- fBack.setDisabled();
- }
-}
-
-void GrStencilSettings::reset(const GrStencilSettings& that) {
- fFlags = that.fFlags;
- if ((kInvalid_PrivateFlag | kDisabled_StencilFlag) & fFlags) {
- return;
- }
- if (!this->isTwoSided()) {
- memcpy(&fFront, &that.fFront, sizeof(Face));
- } else {
- memcpy(&fFront, &that.fFront, 2 * sizeof(Face));
- GR_STATIC_ASSERT(sizeof(Face) ==
- offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
- }
-}
-
-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(&fFront, &that.fFront, sizeof(Face)); // Both are single sided.
- } else {
- return 0 == memcmp(&fFront, &that.fFront, 2 * sizeof(Face));
- GR_STATIC_ASSERT(sizeof(Face) ==
- offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
- }
- // memcmp relies on GrStencilSettings::Face being tightly packed.
- GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
- GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
- GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
- GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
- GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
- GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
- GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
- GR_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
-};
-
-GR_STATIC_ASSERT(0 == (int)GrUserStencilTest::kAlwaysIfInClip);
-GR_STATIC_ASSERT(1 == (int)GrUserStencilTest::kEqualIfInClip);
-GR_STATIC_ASSERT(2 == (int)GrUserStencilTest::kLessIfInClip);
-GR_STATIC_ASSERT(3 == (int)GrUserStencilTest::kLEqualIfInClip);
-GR_STATIC_ASSERT(4 == (int)GrUserStencilTest::kAlways);
-GR_STATIC_ASSERT(5 == (int)GrUserStencilTest::kNever);
-GR_STATIC_ASSERT(6 == (int)GrUserStencilTest::kGreater);
-GR_STATIC_ASSERT(7 == (int)GrUserStencilTest::kGEqual);
-GR_STATIC_ASSERT(8 == (int)GrUserStencilTest::kLess);
-GR_STATIC_ASSERT(9 == (int)GrUserStencilTest::kLEqual);
-GR_STATIC_ASSERT(10 == (int)GrUserStencilTest::kEqual);
-GR_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.
-};
-
-GR_STATIC_ASSERT(0 == (int)GrUserStencilOp::kKeep);
-GR_STATIC_ASSERT(1 == (int)GrUserStencilOp::kZero);
-GR_STATIC_ASSERT(2 == (int)GrUserStencilOp::kReplace);
-GR_STATIC_ASSERT(3 == (int)GrUserStencilOp::kInvert);
-GR_STATIC_ASSERT(4 == (int)GrUserStencilOp::kIncWrap);
-GR_STATIC_ASSERT(5 == (int)GrUserStencilOp::kDecWrap);
-GR_STATIC_ASSERT(6 == (int)GrUserStencilOp::kIncMaybeClamp);
-GR_STATIC_ASSERT(7 == (int)GrUserStencilOp::kDecMaybeClamp);
-GR_STATIC_ASSERT(8 == (int)GrUserStencilOp::kZeroClipBit);
-GR_STATIC_ASSERT(9 == (int)GrUserStencilOp::kSetClipBit);
-GR_STATIC_ASSERT(10 == (int)GrUserStencilOp::kInvertClipBit);
-GR_STATIC_ASSERT(11 == (int)GrUserStencilOp::kSetClipAndReplaceUserBits);
-GR_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 <= 16);
- int clipBit = 1 << (numStencilBits - 1);
- int userMask = clipBit - 1;
-
- GrUserStencilOp maxOp = SkTMax(user.fPassOp, user.fFailOp);
- SkDEBUGCODE(GrUserStencilOp otherOp = SkTMin(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));
- GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
- GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Stencil Rules for Merging user stencil space into clip
-//
-
-///////
-// Replace
-static constexpr GrUserStencilSettings gUserToClipReplace(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipReplace(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
-);
-
-///////
-// Intersect
-static constexpr GrUserStencilSettings gUserToClipIsect(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kLessIfInClip, // "0 < userBits" is equivalent to "0 != userBits".
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
-);
-
-///////
-// Difference
-static constexpr GrUserStencilSettings gUserToClipDiff(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqualIfInClip,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kZeroClipAndUserBits,
- 0xffff>()
-);
-
-///////
-// Union
-static constexpr GrUserStencilSettings gUserToClipUnion(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kSetClipAndReplaceUserBits,
- GrUserStencilOp::kKeep,
- 0xffff>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipUnionPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kSetClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
-);
-
-///////
-// Xor
-static constexpr GrUserStencilSettings gUserToClipXorPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipXorPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
-);
-
-///////
-// Reverse Diff
-static constexpr GrUserStencilSettings gUserToClipRDiffPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kZeroClipBit,
- 0x0000>()
-);
-
-static constexpr GrUserStencilSettings gInvUserToClipRDiffPass0( // Does not zero user bits.
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kZeroClipBit,
- 0x0000>()
-);
-
-///////
-// Second pass to clear user bits (only needed sometimes)
-static constexpr GrUserStencilSettings gZeroUserBits(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kKeep,
- 0xffff>()
-);
-
-static constexpr const GrUserStencilSettings* gUserToClipTable[2][1 + SkRegion::kLastOp][3] = {
- { /* Normal fill. */
- {&gUserToClipDiff, nullptr, nullptr}, // kDifference_Op.
- {&gUserToClipIsect, nullptr, nullptr}, // kIntersect_Op.
- {&gUserToClipUnion, nullptr, nullptr}, // kUnion_Op.
- {&gUserToClipXorPass0, &gZeroUserBits, nullptr}, // kXOR_Op.
- {&gUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // kReverseDifference_Op.
- {&gUserToClipReplace, nullptr, nullptr} // kReplace_Op.
-
- }, /* Inverse fill. */ {
- {&gUserToClipIsect, nullptr, nullptr}, // ~diff (aka isect).
- {&gUserToClipDiff, nullptr, nullptr}, // ~isect (aka diff).
- {&gInvUserToClipUnionPass0, &gZeroUserBits, nullptr}, // ~union.
- {&gInvUserToClipXorPass0, &gZeroUserBits, nullptr}, // ~xor.
- {&gInvUserToClipRDiffPass0, &gZeroUserBits, nullptr}, // ~reverse diff.
- {&gInvUserToClipReplace, nullptr, nullptr} // ~replace.
- }
-};
-
-GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
-GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
-GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
-GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
-GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
-GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
-
-///////
-// Direct to Stencil
-
-// We can render a clip element directly without first writing to the client
-// portion of the clip when the fill is not inverse and the set operation will
-// only modify the in/out status of samples covered by the clip element.
-
-// this one only works if used right after stencil clip was cleared.
-// Our clip mask creation code doesn't allow midstream replace ops.
-static constexpr GrUserStencilSettings gReplaceClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kSetClipBit,
- GrUserStencilOp::kSetClipBit,
- 0x0000>()
-);
-
-static constexpr GrUserStencilSettings gUnionClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kKeep,
- GrUserStencilOp::kSetClipBit,
- 0x0000>()
-);
-
-static constexpr GrUserStencilSettings gXorClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kInvertClipBit,
- GrUserStencilOp::kInvertClipBit,
- 0x0000>()
-);
-
-static constexpr GrUserStencilSettings gDiffClip(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kZeroClipBit,
- GrUserStencilOp::kKeep,
- 0x0000>()
-);
-
-static constexpr const GrUserStencilSettings* gDirectDrawTable[1 + SkRegion::kLastOp][2] = {
- {&gDiffClip, nullptr}, // kDifference_Op.
- {nullptr, nullptr}, // kIntersect_Op.
- {&gUnionClip, nullptr}, // kUnion_Op.
- {&gXorClip, nullptr}, // kXOR_Op.
- {nullptr, nullptr}, // kReverseDifference_Op.
- {&gReplaceClip, nullptr} // kReplace_Op.
-};
-
-GR_STATIC_ASSERT(0 == SkRegion::kDifference_Op);
-GR_STATIC_ASSERT(1 == SkRegion::kIntersect_Op);
-GR_STATIC_ASSERT(2 == SkRegion::kUnion_Op);
-GR_STATIC_ASSERT(3 == SkRegion::kXOR_Op);
-GR_STATIC_ASSERT(4 == SkRegion::kReverseDifference_Op);
-GR_STATIC_ASSERT(5 == SkRegion::kReplace_Op);
-
-GrUserStencilSettings const* const* GrStencilSettings::GetClipPasses(SkRegion::Op op,
- bool canBeDirect,
- bool invertedFill,
- bool* drawDirectToClip) {
- SkASSERT((unsigned)op <= SkRegion::kLastOp);
- if (canBeDirect && !invertedFill) { // TODO: inverse fill + intersect op can be direct.
- GrUserStencilSettings const* const* directPass = gDirectDrawTable[op];
- if (directPass[0]) {
- *drawDirectToClip = true;
- return directPass;
- }
- }
- *drawDirectToClip = false;
- return gUserToClipTable[invertedFill][op];
-}
-
-void GrStencilSettings::genKey(GrProcessorKeyBuilder* b) const {
- b->add32(fFlags);
- if (this->isDisabled()) {
- return;
- }
- if (!this->isTwoSided()) {
- constexpr int kCount16 = sizeof(Face) / sizeof(uint16_t);
- GR_STATIC_ASSERT(0 == sizeof(Face) % sizeof(uint16_t));
- uint16_t* key = reinterpret_cast<uint16_t*>(b->add32n((kCount16 + 1) / 2));
- memcpy(key, &fFront, sizeof(Face));
- key[kCount16] = 0;
- GR_STATIC_ASSERT(1 == kCount16 % 2);
- } else {
- constexpr int kCount32 = (2 * sizeof(Face)) / sizeof(uint32_t);
- GR_STATIC_ASSERT(0 == (2 * sizeof(Face)) % sizeof(uint32_t));
- uint32_t* key = b->add32n(kCount32);
- memcpy(key, &fFront, 2 * sizeof(Face));
- GR_STATIC_ASSERT(sizeof(Face) ==
- offsetof(GrStencilSettings, fBack) - offsetof(GrStencilSettings, fFront));
- }
- // We rely on GrStencilSettings::Face being tightly packed for the key to be reliable.
- GR_STATIC_ASSERT(0 == offsetof(Face, fRef));
- GR_STATIC_ASSERT(2 == sizeof(Face::fRef));
- GR_STATIC_ASSERT(2 == offsetof(Face, fTest));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTest));
- GR_STATIC_ASSERT(4 == offsetof(Face, fTestMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fTestMask));
- GR_STATIC_ASSERT(6 == offsetof(Face, fPassOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fPassOp));
- GR_STATIC_ASSERT(7 == offsetof(Face, fFailOp));
- GR_STATIC_ASSERT(1 == sizeof(Face::fFailOp));
- GR_STATIC_ASSERT(8 == offsetof(Face, fWriteMask));
- GR_STATIC_ASSERT(2 == sizeof(Face::fWriteMask));
- GR_STATIC_ASSERT(10 == sizeof(Face));
-}
diff --git a/src/gpu/GrStencilSettings.h b/src/gpu/GrStencilSettings.h
deleted file mode 100644
index 15a8cac..0000000
--- a/src/gpu/GrStencilSettings.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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
diff --git a/src/gpu/GrUserStencilSettings.h b/src/gpu/GrUserStencilSettings.h
deleted file mode 100644
index a07a083..0000000
--- a/src/gpu/GrUserStencilSettings.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * 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
diff --git a/src/gpu/batches/GrDefaultPathRenderer.cpp b/src/gpu/batches/GrDefaultPathRenderer.cpp
index 747be2d..9994b26 100644
--- a/src/gpu/batches/GrDefaultPathRenderer.cpp
+++ b/src/gpu/batches/GrDefaultPathRenderer.cpp
@@ -443,11 +443,11 @@
// face culling doesn't make sense here
SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
- int passCount = 0;
- const GrUserStencilSettings* passes[3];
- GrPipelineBuilder::DrawFace drawFace[3];
- bool reverse = false;
- bool lastPassIsBounds;
+ int passCount = 0;
+ const GrStencilSettings* passes[3];
+ GrPipelineBuilder::DrawFace drawFace[3];
+ bool reverse = false;
+ bool lastPassIsBounds;
if (isHairline) {
passCount = 1;
@@ -544,7 +544,7 @@
for (int p = 0; p < passCount; ++p) {
pipelineBuilder->setDrawFace(drawFace[p]);
if (passes[p]) {
- pipelineBuilder->setUserStencil(passes[p]);
+ *pipelineBuilder->stencil() = *passes[p];
}
if (lastPassIsBounds && (p == passCount-1)) {
diff --git a/src/gpu/batches/GrDrawPathBatch.h b/src/gpu/batches/GrDrawPathBatch.h
index 55fe31a..d29d046 100644
--- a/src/gpu/batches/GrDrawPathBatch.h
+++ b/src/gpu/batches/GrDrawPathBatch.h
@@ -28,10 +28,7 @@
GrPathRendering::FillType fillType() const { return fFillType; }
- void setStencilSettings(const GrUserStencilSettings& stencil, bool hasStencilClip,
- int numStencilBits) {
- fStencilSettings.reset(stencil, hasStencilClip, numStencilBits);
- }
+ void setStencilSettings(const GrStencilSettings& stencil) { fStencilSettings = stencil; }
protected:
GrDrawPathBatchBase(uint32_t classID, const SkMatrix& viewMatrix, GrColor initialColor,
diff --git a/src/gpu/batches/GrMSAAPathRenderer.cpp b/src/gpu/batches/GrMSAAPathRenderer.cpp
index 8b1319b..6e0076c 100644
--- a/src/gpu/batches/GrMSAAPathRenderer.cpp
+++ b/src/gpu/batches/GrMSAAPathRenderer.cpp
@@ -578,11 +578,11 @@
// face culling doesn't make sense here
SkASSERT(GrPipelineBuilder::kBoth_DrawFace == pipelineBuilder->getDrawFace());
- int passCount = 0;
- const GrUserStencilSettings* passes[3];
- GrPipelineBuilder::DrawFace drawFace[3];
- bool reverse = false;
- bool lastPassIsBounds;
+ int passCount = 0;
+ const GrStencilSettings* passes[3];
+ GrPipelineBuilder::DrawFace drawFace[3];
+ bool reverse = false;
+ bool lastPassIsBounds;
if (single_pass_path(path)) {
passCount = 1;
@@ -647,7 +647,7 @@
for (int p = 0; p < passCount; ++p) {
pipelineBuilder->setDrawFace(drawFace[p]);
if (passes[p]) {
- pipelineBuilder->setUserStencil(passes[p]);
+ *pipelineBuilder->stencil() = *passes[p];
}
if (lastPassIsBounds && (p == passCount-1)) {
diff --git a/src/gpu/batches/GrPathStencilSettings.h b/src/gpu/batches/GrPathStencilSettings.h
index f37d1b2..dd930a0d 100644
--- a/src/gpu/batches/GrPathStencilSettings.h
+++ b/src/gpu/batches/GrPathStencilSettings.h
@@ -8,44 +8,36 @@
#ifndef GrPathStencilSettings_DEFINED
#define GrPathStencilSettings_DEFINED
-#include "GrUserStencilSettings.h"
-
////////////////////////////////////////////////////////////////////////////////
// Stencil rules for paths
////// Even/Odd
-static constexpr GrUserStencilSettings gEOStencilPass(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kInvert,
- GrUserStencilOp::kKeep,
- 0xffff>()
-);
+static constexpr GrStencilSettings gEOStencilPass(
+ kInvert_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
// ok not to check clip b/c stencil pass only wrote inside clip
-static constexpr GrUserStencilSettings gEOColorPass(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kZero,
- 0xffff>()
-);
+static constexpr GrStencilSettings gEOColorPass(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kNotEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
// have to check clip b/c outside clip will always be zero.
-static constexpr GrUserStencilSettings gInvEOColorPass(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqualIfInClip,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kZero,
- 0xffff>()
-);
+static constexpr GrStencilSettings gInvEOColorPass(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kEqualIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
////// Winding
@@ -53,108 +45,90 @@
// when we don't have wrap incr and decr we use the stencil test to simulate
// them.
-static constexpr GrUserStencilSettings gWindStencilSeparateWithWrap(
- GrUserStencilSettings::StaticInitSeparate<
- 0xffff, 0xffff,
- GrUserStencilTest::kAlwaysIfInClip, GrUserStencilTest::kAlwaysIfInClip,
- 0xffff, 0xffff,
- GrUserStencilOp::kIncWrap, GrUserStencilOp::kDecWrap,
- GrUserStencilOp::kKeep, GrUserStencilOp::kKeep,
- 0xffff, 0xffff>()
-);
+static constexpr GrStencilSettings gWindStencilSeparateWithWrap(
+ kIncWrap_StencilOp, kDecWrap_StencilOp,
+ kKeep_StencilOp, kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc, kAlwaysIfInClip_StencilFunc,
+ 0xffff, 0xffff,
+ 0xffff, 0xffff,
+ 0xffff, 0xffff);
// if inc'ing the max value, invert to make 0
// if dec'ing zero invert to make all ones.
// we can't avoid touching the stencil on both passing and
// failing, so we can't resctrict ourselves to the clip.
-static constexpr GrUserStencilSettings gWindStencilSeparateNoWrap(
- GrUserStencilSettings::StaticInitSeparate<
- 0xffff, 0x0000,
- GrUserStencilTest::kEqual, GrUserStencilTest::kEqual,
- 0xffff, 0xffff,
- GrUserStencilOp::kInvert, GrUserStencilOp::kInvert,
- GrUserStencilOp::kIncMaybeClamp, GrUserStencilOp::kDecMaybeClamp,
- 0xffff, 0xffff>()
-);
+static constexpr GrStencilSettings gWindStencilSeparateNoWrap(
+ kInvert_StencilOp, kInvert_StencilOp,
+ kIncClamp_StencilOp, kDecClamp_StencilOp,
+ kEqual_StencilFunc, kEqual_StencilFunc,
+ 0xffff, 0xffff,
+ 0xffff, 0x0000,
+ 0xffff, 0xffff);
// When there are no separate faces we do two passes to setup the winding rule
// stencil. First we draw the front faces and inc, then we draw the back faces
// and dec. These are same as the above two split into the incrementing and
// decrementing passes.
-static constexpr GrUserStencilSettings gWindSingleStencilWithWrapInc(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kIncWrap,
- GrUserStencilOp::kKeep,
- 0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilWithWrapInc(
+ kIncWrap_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
-static constexpr GrUserStencilSettings gWindSingleStencilWithWrapDec(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kDecWrap,
- GrUserStencilOp::kKeep,
- 0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilWithWrapDec(
+ kDecWrap_StencilOp,
+ kKeep_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
-static constexpr GrUserStencilSettings gWindSingleStencilNoWrapInc(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kInvert,
- GrUserStencilOp::kIncMaybeClamp,
- 0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilNoWrapInc(
+ kInvert_StencilOp,
+ kIncClamp_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
-static constexpr GrUserStencilSettings gWindSingleStencilNoWrapDec(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqual,
- 0xffff,
- GrUserStencilOp::kInvert,
- GrUserStencilOp::kDecMaybeClamp,
- 0xffff>()
-);
+static constexpr GrStencilSettings gWindSingleStencilNoWrapDec(
+ kInvert_StencilOp,
+ kDecClamp_StencilOp,
+ kEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
// Color passes are the same whether we use the two-sided stencil or two passes
-static constexpr GrUserStencilSettings gWindColorPass(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kLessIfInClip, // "0 < stencil" is equivalent to "0 != stencil".
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kZero,
- 0xffff>()
-);
+static constexpr GrStencilSettings gWindColorPass(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kNonZeroIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
-static constexpr GrUserStencilSettings gInvWindColorPass(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kEqualIfInClip,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kZero,
- 0xffff>()
-);
+static constexpr GrStencilSettings gInvWindColorPass(
+ kZero_StencilOp,
+ kZero_StencilOp,
+ kEqualIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
////// Normal render to stencil
// Sometimes the default path renderer can draw a path directly to the stencil
// buffer without having to first resolve the interior / exterior.
-static constexpr GrUserStencilSettings gDirectToStencil(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kAlwaysIfInClip,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kIncMaybeClamp,
- 0xffff>()
-);
+static constexpr GrStencilSettings gDirectToStencil(
+ kZero_StencilOp,
+ kIncClamp_StencilOp,
+ kAlwaysIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
#endif
diff --git a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
index 1309ded..ddba1c8 100644
--- a/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
+++ b/src/gpu/batches/GrStencilAndCoverPathRenderer.cpp
@@ -36,7 +36,7 @@
if (args.fStyle->hasNonDashPathEffect() || args.fStyle->strokeRec().isHairlineStyle()) {
return false;
}
- if (args.fHasUserStencilSettings) {
+ if (!args.fIsStencilDisabled) {
return false;
}
if (args.fAntiAlias) {
@@ -80,7 +80,7 @@
GrPipelineBuilder* pipelineBuilder = args.fPipelineBuilder;
const SkMatrix& viewMatrix = *args.fViewMatrix;
- SkASSERT(!pipelineBuilder->hasUserStencilSettings());
+ SkASSERT(pipelineBuilder->getStencil().isDisabled());
if (args.fAntiAlias) {
SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled());
@@ -90,21 +90,18 @@
SkAutoTUnref<GrPath> p(get_gr_path(fResourceProvider, path, *args.fStyle));
if (path.isInverseFillType()) {
- static constexpr GrUserStencilSettings kInvertedCoverPass(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- // We know our rect will hit pixels outside the clip and the user bits will be 0
- // outside the clip. So we can't just fill where the user bits are 0. We also need
- // to check that the clip bit is set.
- GrUserStencilTest::kEqualIfInClip,
- 0xffff,
- GrUserStencilOp::kKeep,
- GrUserStencilOp::kZero,
- 0xffff>()
- );
+ static constexpr GrStencilSettings kInvertedStencilPass(
+ kKeep_StencilOp,
+ kZero_StencilOp,
+ // We know our rect will hit pixels outside the clip and the user bits will be 0
+ // outside the clip. So we can't just fill where the user bits are 0. We also need to
+ // check that the clip bit is set.
+ kEqualIfInClip_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
-
- pipelineBuilder->setUserStencil(&kInvertedCoverPass);
+ pipelineBuilder->setStencil(kInvertedStencilPass);
// fake inverse with a stencil and cover
args.fTarget->stencilPath(*pipelineBuilder, viewMatrix, p, p->getFillType());
@@ -136,22 +133,20 @@
&invert));
args.fTarget->drawBatch(*pipelineBuilder, batch);
} else {
- static constexpr GrUserStencilSettings kCoverPass(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual,
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kKeep,
- 0xffff>()
- );
+ static constexpr GrStencilSettings kStencilPass(
+ kZero_StencilOp,
+ kKeep_StencilOp,
+ kNotEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
- pipelineBuilder->setUserStencil(&kCoverPass);
+ pipelineBuilder->setStencil(kStencilPass);
SkAutoTUnref<GrDrawPathBatchBase> batch(
GrDrawPathBatch::Create(viewMatrix, args.fColor, p->getFillType(), p));
args.fTarget->drawPathBatch(*pipelineBuilder, batch);
}
- pipelineBuilder->disableUserStencil();
+ pipelineBuilder->stencil()->setDisabled();
return true;
}
diff --git a/src/gpu/batches/GrStencilPathBatch.h b/src/gpu/batches/GrStencilPathBatch.h
index 8477822..33189c2 100644
--- a/src/gpu/batches/GrStencilPathBatch.h
+++ b/src/gpu/batches/GrStencilPathBatch.h
@@ -21,14 +21,11 @@
static GrBatch* Create(const SkMatrix& viewMatrix,
bool useHWAA,
- const GrUserStencilSettings& userStencil,
- bool hasStencilClip,
- int numStencilBits,
+ const GrStencilSettings& stencil,
const GrScissorState& scissor,
GrRenderTarget* renderTarget,
const GrPath* path) {
- return new GrStencilPathBatch(viewMatrix, useHWAA, userStencil, hasStencilClip,
- numStencilBits, scissor, renderTarget, path);
+ return new GrStencilPathBatch(viewMatrix, useHWAA, stencil, scissor, renderTarget, path);
}
const char* name() const override { return "StencilPath"; }
@@ -45,16 +42,14 @@
private:
GrStencilPathBatch(const SkMatrix& viewMatrix,
bool useHWAA,
- const GrUserStencilSettings& userStencil,
- bool hasStencilClip,
- int numStencilBits,
+ const GrStencilSettings& stencil,
const GrScissorState& scissor,
GrRenderTarget* renderTarget,
const GrPath* path)
: INHERITED(ClassID())
, fViewMatrix(viewMatrix)
, fUseHWAA(useHWAA)
- , fStencil(userStencil, hasStencilClip, numStencilBits)
+ , fStencil(stencil)
, fScissor(scissor)
, fRenderTarget(renderTarget)
, fPath(path) {
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index 6b03df3..004a4a9 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2874,38 +2874,40 @@
GrGLenum gr_to_gl_stencil_op(GrStencilOp op) {
- static const GrGLenum gTable[kGrStencilOpCount] = {
- GR_GL_KEEP, // kKeep
- GR_GL_ZERO, // kZero
- GR_GL_REPLACE, // kReplace
- GR_GL_INVERT, // kInvert
- GR_GL_INCR_WRAP, // kIncWrap
- GR_GL_DECR_WRAP, // kDecWrap
- GR_GL_INCR, // kIncClamp
- GR_GL_DECR, // kDecClamp
+ static const GrGLenum gTable[] = {
+ GR_GL_KEEP, // kKeep_StencilOp
+ GR_GL_REPLACE, // kReplace_StencilOp
+ GR_GL_INCR_WRAP, // kIncWrap_StencilOp
+ GR_GL_INCR, // kIncClamp_StencilOp
+ GR_GL_DECR_WRAP, // kDecWrap_StencilOp
+ GR_GL_DECR, // kDecClamp_StencilOp
+ GR_GL_ZERO, // kZero_StencilOp
+ GR_GL_INVERT, // kInvert_StencilOp
};
- GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
- GR_STATIC_ASSERT(1 == (int)GrStencilOp::kZero);
- GR_STATIC_ASSERT(2 == (int)GrStencilOp::kReplace);
- GR_STATIC_ASSERT(3 == (int)GrStencilOp::kInvert);
- GR_STATIC_ASSERT(4 == (int)GrStencilOp::kIncWrap);
- GR_STATIC_ASSERT(5 == (int)GrStencilOp::kDecWrap);
- GR_STATIC_ASSERT(6 == (int)GrStencilOp::kIncClamp);
- GR_STATIC_ASSERT(7 == (int)GrStencilOp::kDecClamp);
- SkASSERT(op < (GrStencilOp)kGrStencilOpCount);
- return gTable[(int)op];
+ GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kStencilOpCnt);
+ GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+ GR_STATIC_ASSERT(1 == kReplace_StencilOp);
+ GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
+ GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
+ GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
+ GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
+ GR_STATIC_ASSERT(6 == kZero_StencilOp);
+ GR_STATIC_ASSERT(7 == kInvert_StencilOp);
+ SkASSERT((unsigned) op < kStencilOpCnt);
+ return gTable[op];
}
void set_gl_stencil(const GrGLInterface* gl,
- const GrStencilSettings::Face& face,
- GrGLenum glFace) {
- GrGLenum glFunc = GrToGLStencilFunc(face.fTest);
- GrGLenum glFailOp = gr_to_gl_stencil_op(face.fFailOp);
- GrGLenum glPassOp = gr_to_gl_stencil_op(face.fPassOp);
+ const GrStencilSettings& settings,
+ GrGLenum glFace,
+ GrStencilSettings::Face grFace) {
+ GrGLenum glFunc = GrToGLStencilFunc(settings.func(grFace));
+ GrGLenum glFailOp = gr_to_gl_stencil_op(settings.failOp(grFace));
+ GrGLenum glPassOp = gr_to_gl_stencil_op(settings.passOp(grFace));
- GrGLint ref = face.fRef;
- GrGLint mask = face.fTestMask;
- GrGLint writeMask = face.fWriteMask;
+ GrGLint ref = settings.funcRef(grFace);
+ GrGLint mask = settings.funcMask(grFace);
+ GrGLint writeMask = settings.writeMask(grFace);
if (GR_GL_FRONT_AND_BACK == glFace) {
// we call the combined func just in case separate stencil is not
@@ -2935,18 +2937,20 @@
}
}
if (!stencilSettings.isDisabled()) {
- if (stencilSettings.isTwoSided()) {
- SkASSERT(this->caps()->twoSidedStencilSupport());
+ if (this->caps()->twoSidedStencilSupport()) {
set_gl_stencil(this->glInterface(),
- stencilSettings.front(),
- GR_GL_FRONT);
+ stencilSettings,
+ GR_GL_FRONT,
+ GrStencilSettings::kFront_Face);
set_gl_stencil(this->glInterface(),
- stencilSettings.back(),
- GR_GL_BACK);
+ stencilSettings,
+ GR_GL_BACK,
+ GrStencilSettings::kBack_Face);
} else {
set_gl_stencil(this->glInterface(),
- stencilSettings.front(),
- GR_GL_FRONT_AND_BACK);
+ stencilSettings,
+ GR_GL_FRONT_AND_BACK,
+ GrStencilSettings::kFront_Face);
}
}
fHWStencilSettings = stencilSettings;
diff --git a/src/gpu/gl/GrGLPathRendering.cpp b/src/gpu/gl/GrGLPathRendering.cpp
index 66648d8..5616f9d 100644
--- a/src/gpu/gl/GrGLPathRendering.cpp
+++ b/src/gpu/gl/GrGLPathRendering.cpp
@@ -70,9 +70,9 @@
default:
SkFAIL("Unexpected path fill.");
/* fallthrough */;
- case GrStencilOp::kIncClamp:
+ case kIncClamp_StencilOp:
return GR_GL_COUNT_UP;
- case GrStencilOp::kInvert:
+ case kInvert_StencilOp:
return GR_GL_INVERT;
}
}
@@ -133,9 +133,9 @@
this->flushPathStencilSettings(*args.fStencil);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
- GrGLenum fillMode =
- gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
- GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
+ GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
+ fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+ GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
if (glPath->shouldFill()) {
GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
@@ -157,9 +157,9 @@
this->flushPathStencilSettings(stencil);
SkASSERT(!fHWPathStencilSettings.isTwoSided());
- GrGLenum fillMode =
- gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
- GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
+ GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
+ fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+ GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
if (glPath->shouldStroke()) {
if (glPath->shouldFill()) {
@@ -191,8 +191,10 @@
const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
GrGLenum fillMode =
- gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
- GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
+ gr_stencil_op_to_gl_path_rendering_fill_mode(
+ fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
+ GrGLint writeMask =
+ fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
if (glPathRange->shouldStroke()) {
if (glPathRange->shouldFill()) {
@@ -320,15 +322,16 @@
SkASSERT(stencilSettings.isValid());
// Just the func, ref, and mask is set here. The op and write mask are params to the call
// that draws the path to the SB (glStencilFillPath)
- uint16_t ref = stencilSettings.front().fRef;
- GrStencilTest test = stencilSettings.front().fTest;
- uint16_t testMask = stencilSettings.front().fTestMask;
+ const GrStencilSettings::Face kFront_Face = GrStencilSettings::kFront_Face;
+ GrStencilFunc func = stencilSettings.func(kFront_Face);
+ uint16_t funcRef = stencilSettings.funcRef(kFront_Face);
+ uint16_t funcMask = stencilSettings.funcMask(kFront_Face);
if (!fHWPathStencilSettings.isValid() ||
- ref != fHWPathStencilSettings.front().fRef ||
- test != fHWPathStencilSettings.front().fTest ||
- testMask != fHWPathStencilSettings.front().fTestMask) {
- GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
+ func != fHWPathStencilSettings.func(kFront_Face) ||
+ funcRef != fHWPathStencilSettings.funcRef(kFront_Face) ||
+ funcMask != fHWPathStencilSettings.funcMask(kFront_Face)) {
+ GL_CALL(PathStencilFunc(GrToGLStencilFunc(func), funcRef, funcMask));
}
fHWPathStencilSettings = stencilSettings;
}
diff --git a/src/gpu/gl/GrGLPathRendering.h b/src/gpu/gl/GrGLPathRendering.h
index 40f72cc..8fb699d 100644
--- a/src/gpu/gl/GrGLPathRendering.h
+++ b/src/gpu/gl/GrGLPathRendering.h
@@ -10,12 +10,12 @@
#include "SkRefCnt.h"
#include "GrPathRendering.h"
+#include "GrStencil.h"
#include "gl/GrGLTypes.h"
#include "glsl/GrGLSLUtil.h"
class GrGLNameAllocator;
class GrGLGpu;
-class GrStencilSettings;
class GrStyle;
/**
diff --git a/src/gpu/gl/GrGLUtil.cpp b/src/gpu/gl/GrGLUtil.cpp
index ecc587b..46b58f1 100644
--- a/src/gpu/gl/GrGLUtil.cpp
+++ b/src/gpu/gl/GrGLUtil.cpp
@@ -334,26 +334,27 @@
return GrGLGetRendererFromString((const char*) v);
}
-GrGLenum GrToGLStencilFunc(GrStencilTest test) {
- static const GrGLenum gTable[kGrStencilTestCount] = {
- GR_GL_ALWAYS, // kAlways
- GR_GL_NEVER, // kNever
- GR_GL_GREATER, // kGreater
- GR_GL_GEQUAL, // kGEqual
- GR_GL_LESS, // kLess
- GR_GL_LEQUAL, // kLEqual
- GR_GL_EQUAL, // kEqual
- GR_GL_NOTEQUAL, // kNotEqual
+GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc) {
+ static const GrGLenum gTable[] = {
+ GR_GL_ALWAYS, // kAlways_StencilFunc
+ GR_GL_NEVER, // kNever_StencilFunc
+ GR_GL_GREATER, // kGreater_StencilFunc
+ GR_GL_GEQUAL, // kGEqual_StencilFunc
+ GR_GL_LESS, // kLess_StencilFunc
+ GR_GL_LEQUAL, // kLEqual_StencilFunc,
+ GR_GL_EQUAL, // kEqual_StencilFunc,
+ GR_GL_NOTEQUAL, // kNotEqual_StencilFunc,
};
- GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
- GR_STATIC_ASSERT(1 == (int)GrStencilTest::kNever);
- GR_STATIC_ASSERT(2 == (int)GrStencilTest::kGreater);
- GR_STATIC_ASSERT(3 == (int)GrStencilTest::kGEqual);
- GR_STATIC_ASSERT(4 == (int)GrStencilTest::kLess);
- GR_STATIC_ASSERT(5 == (int)GrStencilTest::kLEqual);
- GR_STATIC_ASSERT(6 == (int)GrStencilTest::kEqual);
- GR_STATIC_ASSERT(7 == (int)GrStencilTest::kNotEqual);
- SkASSERT(test < (GrStencilTest)kGrStencilTestCount);
+ GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCnt);
+ GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+ GR_STATIC_ASSERT(1 == kNever_StencilFunc);
+ GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
+ GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
+ GR_STATIC_ASSERT(4 == kLess_StencilFunc);
+ GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
+ GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
+ GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
+ SkASSERT((unsigned) basicFunc < kBasicStencilFuncCnt);
- return gTable[(int)test];
+ return gTable[basicFunc];
}
diff --git a/src/gpu/gl/GrGLUtil.h b/src/gpu/gl/GrGLUtil.h
index 98f738b..c30ee93 100644
--- a/src/gpu/gl/GrGLUtil.h
+++ b/src/gpu/gl/GrGLUtil.h
@@ -10,7 +10,7 @@
#include "gl/GrGLInterface.h"
#include "GrGLDefines.h"
-#include "GrStencilSettings.h"
+#include "GrStencil.h"
class SkMatrix;
@@ -205,7 +205,7 @@
// call glGetError without doing a redundant error check or logging.
#define GR_GL_GET_ERROR(IFACE) (IFACE)->fFunctions.fGetError()
-GrGLenum GrToGLStencilFunc(GrStencilTest test);
+GrGLenum GrToGLStencilFunc(GrStencilFunc basicFunc);
#endif
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index bce0716..cc01884 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -610,17 +610,15 @@
if (fInstanceData->count()) {
pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.isAntiAlias());
- static constexpr GrUserStencilSettings kCoverPass(
- GrUserStencilSettings::StaticInit<
- 0x0000,
- GrUserStencilTest::kNotEqual, // Stencil pass accounts for clip.
- 0xffff,
- GrUserStencilOp::kZero,
- GrUserStencilOp::kKeep,
- 0xffff>()
- );
+ static constexpr GrStencilSettings kStencilPass(
+ kZero_StencilOp,
+ kKeep_StencilOp,
+ kNotEqual_StencilFunc,
+ 0xffff,
+ 0x0000,
+ 0xffff);
- pipelineBuilder->setUserStencil(&kCoverPass);
+ *pipelineBuilder->stencil() = kStencilPass;
SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
diff --git a/src/gpu/vk/GrVkPipeline.cpp b/src/gpu/vk/GrVkPipeline.cpp
index 8227e12..2a9c6e2 100644
--- a/src/gpu/vk/GrVkPipeline.cpp
+++ b/src/gpu/vk/GrVkPipeline.cpp
@@ -100,51 +100,51 @@
VkStencilOp stencil_op_to_vk_stencil_op(GrStencilOp op) {
static const VkStencilOp gTable[] = {
- VK_STENCIL_OP_KEEP, // kKeep
- VK_STENCIL_OP_ZERO, // kZero
- VK_STENCIL_OP_REPLACE, // kReplace
- VK_STENCIL_OP_INVERT, // kInvert
- VK_STENCIL_OP_INCREMENT_AND_WRAP, // kIncWrap
- VK_STENCIL_OP_DECREMENT_AND_WRAP, // kDecWrap
- VK_STENCIL_OP_INCREMENT_AND_CLAMP, // kIncClamp
- VK_STENCIL_OP_DECREMENT_AND_CLAMP, // kDecClamp
+ VK_STENCIL_OP_KEEP, // kKeep_StencilOp
+ VK_STENCIL_OP_REPLACE, // kReplace_StencilOp
+ VK_STENCIL_OP_INCREMENT_AND_WRAP, // kIncWrap_StencilOp
+ VK_STENCIL_OP_INCREMENT_AND_CLAMP, // kIncClamp_StencilOp
+ VK_STENCIL_OP_DECREMENT_AND_WRAP, // kDecWrap_StencilOp
+ VK_STENCIL_OP_DECREMENT_AND_CLAMP, // kDecClamp_StencilOp
+ VK_STENCIL_OP_ZERO, // kZero_StencilOp
+ VK_STENCIL_OP_INVERT, // kInvert_StencilOp
};
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kGrStencilOpCount);
- GR_STATIC_ASSERT(0 == (int)GrStencilOp::kKeep);
- GR_STATIC_ASSERT(1 == (int)GrStencilOp::kZero);
- GR_STATIC_ASSERT(2 == (int)GrStencilOp::kReplace);
- GR_STATIC_ASSERT(3 == (int)GrStencilOp::kInvert);
- GR_STATIC_ASSERT(4 == (int)GrStencilOp::kIncWrap);
- GR_STATIC_ASSERT(5 == (int)GrStencilOp::kDecWrap);
- GR_STATIC_ASSERT(6 == (int)GrStencilOp::kIncClamp);
- GR_STATIC_ASSERT(7 == (int)GrStencilOp::kDecClamp);
- SkASSERT(op < (GrStencilOp)kGrStencilOpCount);
- return gTable[(int)op];
+ GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kStencilOpCnt);
+ GR_STATIC_ASSERT(0 == kKeep_StencilOp);
+ GR_STATIC_ASSERT(1 == kReplace_StencilOp);
+ GR_STATIC_ASSERT(2 == kIncWrap_StencilOp);
+ GR_STATIC_ASSERT(3 == kIncClamp_StencilOp);
+ GR_STATIC_ASSERT(4 == kDecWrap_StencilOp);
+ GR_STATIC_ASSERT(5 == kDecClamp_StencilOp);
+ GR_STATIC_ASSERT(6 == kZero_StencilOp);
+ GR_STATIC_ASSERT(7 == kInvert_StencilOp);
+ SkASSERT((unsigned)op < kStencilOpCnt);
+ return gTable[op];
}
-VkCompareOp stencil_func_to_vk_compare_op(GrStencilTest test) {
+VkCompareOp stencil_func_to_vk_compare_op(GrStencilFunc basicFunc) {
static const VkCompareOp gTable[] = {
- VK_COMPARE_OP_ALWAYS, // kAlways
- VK_COMPARE_OP_NEVER, // kNever
- VK_COMPARE_OP_GREATER, // kGreater
- VK_COMPARE_OP_GREATER_OR_EQUAL, // kGEqual
- VK_COMPARE_OP_LESS, // kLess
- VK_COMPARE_OP_LESS_OR_EQUAL, // kLEqual
- VK_COMPARE_OP_EQUAL, // kEqual
- VK_COMPARE_OP_NOT_EQUAL, // kNotEqual
+ VK_COMPARE_OP_ALWAYS, // kAlways_StencilFunc
+ VK_COMPARE_OP_NEVER, // kNever_StencilFunc
+ VK_COMPARE_OP_GREATER, // kGreater_StencilFunc
+ VK_COMPARE_OP_GREATER_OR_EQUAL, // kGEqual_StencilFunc
+ VK_COMPARE_OP_LESS, // kLess_StencilFunc
+ VK_COMPARE_OP_LESS_OR_EQUAL, // kLEqual_StencilFunc,
+ VK_COMPARE_OP_EQUAL, // kEqual_StencilFunc,
+ VK_COMPARE_OP_NOT_EQUAL, // kNotEqual_StencilFunc,
};
- GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kGrStencilTestCount);
- GR_STATIC_ASSERT(0 == (int)GrStencilTest::kAlways);
- GR_STATIC_ASSERT(1 == (int)GrStencilTest::kNever);
- GR_STATIC_ASSERT(2 == (int)GrStencilTest::kGreater);
- GR_STATIC_ASSERT(3 == (int)GrStencilTest::kGEqual);
- GR_STATIC_ASSERT(4 == (int)GrStencilTest::kLess);
- GR_STATIC_ASSERT(5 == (int)GrStencilTest::kLEqual);
- GR_STATIC_ASSERT(6 == (int)GrStencilTest::kEqual);
- GR_STATIC_ASSERT(7 == (int)GrStencilTest::kNotEqual);
- SkASSERT(test < (GrStencilTest)kGrStencilTestCount);
+ GR_STATIC_ASSERT(SK_ARRAY_COUNT(gTable) == kBasicStencilFuncCnt);
+ GR_STATIC_ASSERT(0 == kAlways_StencilFunc);
+ GR_STATIC_ASSERT(1 == kNever_StencilFunc);
+ GR_STATIC_ASSERT(2 == kGreater_StencilFunc);
+ GR_STATIC_ASSERT(3 == kGEqual_StencilFunc);
+ GR_STATIC_ASSERT(4 == kLess_StencilFunc);
+ GR_STATIC_ASSERT(5 == kLEqual_StencilFunc);
+ GR_STATIC_ASSERT(6 == kEqual_StencilFunc);
+ GR_STATIC_ASSERT(7 == kNotEqual_StencilFunc);
+ SkASSERT((unsigned)basicFunc < kBasicStencilFuncCnt);
- return gTable[(int)test];
+ return gTable[basicFunc];
}
void setup_depth_stencil_state(const GrVkGpu* gpu,
@@ -162,28 +162,24 @@
stencilInfo->stencilTestEnable = !stencilSettings.isDisabled();
if (!stencilSettings.isDisabled()) {
// Set front face
- const GrStencilSettings::Face& front = stencilSettings.front();
- stencilInfo->front.failOp = stencil_op_to_vk_stencil_op(front.fFailOp);
- stencilInfo->front.passOp = stencil_op_to_vk_stencil_op(front.fPassOp);
+ GrStencilSettings::Face face = GrStencilSettings::kFront_Face;
+ stencilInfo->front.failOp = stencil_op_to_vk_stencil_op(stencilSettings.failOp(face));
+ stencilInfo->front.passOp = stencil_op_to_vk_stencil_op(stencilSettings.passOp(face));
stencilInfo->front.depthFailOp = stencilInfo->front.failOp;
- stencilInfo->front.compareOp = stencil_func_to_vk_compare_op(front.fTest);
- stencilInfo->front.compareMask = front.fTestMask;
- stencilInfo->front.writeMask = front.fWriteMask;
- stencilInfo->front.reference = front.fRef;
+ stencilInfo->front.compareOp = stencil_func_to_vk_compare_op(stencilSettings.func(face));
+ stencilInfo->front.compareMask = stencilSettings.funcMask(face);
+ stencilInfo->front.writeMask = stencilSettings.writeMask(face);
+ stencilInfo->front.reference = stencilSettings.funcRef(face);
// Set back face
- if (!stencilSettings.isTwoSided()) {
- stencilInfo->back = stencilInfo->front;
- } else {
- const GrStencilSettings::Face& back = stencilSettings.back();
- stencilInfo->back.failOp = stencil_op_to_vk_stencil_op(back.fFailOp);
- stencilInfo->back.passOp = stencil_op_to_vk_stencil_op(back.fPassOp);
- stencilInfo->back.depthFailOp = stencilInfo->front.failOp;
- stencilInfo->back.compareOp = stencil_func_to_vk_compare_op(back.fTest);
- stencilInfo->back.compareMask = back.fTestMask;
- stencilInfo->back.writeMask = back.fWriteMask;
- stencilInfo->back.reference = back.fRef;
- }
+ face = GrStencilSettings::kBack_Face;
+ stencilInfo->back.failOp = stencil_op_to_vk_stencil_op(stencilSettings.failOp(face));
+ stencilInfo->back.passOp = stencil_op_to_vk_stencil_op(stencilSettings.passOp(face));
+ stencilInfo->back.depthFailOp = stencilInfo->front.failOp;
+ stencilInfo->back.compareOp = stencil_func_to_vk_compare_op(stencilSettings.func(face));
+ stencilInfo->back.compareMask = stencilSettings.funcMask(face);
+ stencilInfo->back.writeMask = stencilSettings.writeMask(face);
+ stencilInfo->back.reference = stencilSettings.funcRef(face);
}
stencilInfo->minDepthBounds = 0.0f;
stencilInfo->maxDepthBounds = 1.0f;
diff --git a/src/gpu/vk/GrVkPipelineState.h b/src/gpu/vk/GrVkPipelineState.h
index d0b0f56..b7f954c 100644
--- a/src/gpu/vk/GrVkPipelineState.h
+++ b/src/gpu/vk/GrVkPipelineState.h
@@ -9,7 +9,6 @@
#ifndef GrVkPipelineState_DEFINED
#define GrVkPipelineState_DEFINED
-#include "GrStencilSettings.h"
#include "GrVkImage.h"
#include "GrVkProgramDesc.h"
#include "GrVkPipelineStateDataManager.h"
diff --git a/tests/GLProgramsTest.cpp b/tests/GLProgramsTest.cpp
index 3cbc76c..c5d61d8 100644
--- a/tests/GLProgramsTest.cpp
+++ b/tests/GLProgramsTest.cpp
@@ -277,29 +277,25 @@
// right now, the only thing we seem to care about in drawState's stencil is 'doesWrite()'
static void set_random_stencil(GrPipelineBuilder* pipelineBuilder, SkRandom* random) {
- static constexpr GrUserStencilSettings kDoesWriteStencil(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kAlways,
- 0xffff,
- GrUserStencilOp::kReplace,
- GrUserStencilOp::kReplace,
- 0xffff>()
- );
- static constexpr GrUserStencilSettings kDoesNotWriteStencil(
- GrUserStencilSettings::StaticInit<
- 0xffff,
- GrUserStencilTest::kNever,
- 0xffff,
- GrUserStencilOp::kKeep,
- GrUserStencilOp::kKeep,
- 0xffff>()
- );
+ static constexpr GrStencilSettings kDoesWriteStencil(
+ kReplace_StencilOp,
+ kReplace_StencilOp,
+ kAlways_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
+ static constexpr GrStencilSettings kDoesNotWriteStencil(
+ kKeep_StencilOp,
+ kKeep_StencilOp,
+ kNever_StencilFunc,
+ 0xffff,
+ 0xffff,
+ 0xffff);
if (random->nextBool()) {
- pipelineBuilder->setUserStencil(&kDoesWriteStencil);
+ pipelineBuilder->setStencil(kDoesWriteStencil);
} else {
- pipelineBuilder->setUserStencil(&kDoesNotWriteStencil);
+ pipelineBuilder->setStencil(kDoesNotWriteStencil);
}
}