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
This commit is contained in:
parent
3e11da7fa9
commit
e19aecdd13
@ -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',
|
||||
|
@ -62,7 +62,7 @@ static void draw_non_aa_rect(GrDrawTarget* drawTarget,
|
||||
// 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 @@ bool GrClipMaskManager::PathNeedsSWRenderer(GrContext* context,
|
||||
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 @@ GrPathRenderer* GrClipMaskManager::GetPathRenderer(GrContext* context,
|
||||
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 GrClipMaskManager::UseSWOnlyPath(GrContext* context,
|
||||
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 @@ static void add_rect_to_clip(const GrClip& clip, const SkRect& devRect, GrClip*
|
||||
}
|
||||
|
||||
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 @@ bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilde
|
||||
|
||||
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 @@ bool GrClipMaskManager::setupScissorClip(const GrPipelineBuilder& pipelineBuilde
|
||||
// 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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
const GrClip& clip = doDevBoundsClip ? devBoundsClip : pipelineBuilder.clip();
|
||||
|
||||
if (clip.isWideOpen(clipSpaceRTIBounds)) {
|
||||
this->setPipelineBuilderStencil(pipelineBuilder, ars);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -390,7 +396,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
if (elements.isEmpty()) {
|
||||
if (GrReducedClip::kAllIn_InitialState == initialState) {
|
||||
if (clipSpaceIBounds == clipSpaceRTIBounds) {
|
||||
this->setPipelineBuilderStencil(pipelineBuilder, ars);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@ -427,8 +434,6 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
} 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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
// 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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
!SkRect::Make(scissorSpaceIBounds).contains(*devBounds)) {
|
||||
out->fScissorState.set(scissorSpaceIBounds);
|
||||
}
|
||||
this->setPipelineBuilderStencil(pipelineBuilder, ars);
|
||||
out->fClipCoverageFP.reset(clipFP);
|
||||
return true;
|
||||
}
|
||||
@ -502,6 +508,7 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
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 @@ bool GrClipMaskManager::setupClipping(const GrPipelineBuilder& pipelineBuilder,
|
||||
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 @@ GrTexture* GrClipMaskManager::CreateAlphaClipMask(GrContext* context,
|
||||
|
||||
// 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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
||||
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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
||||
clipPath.toggleInverseFillType();
|
||||
}
|
||||
|
||||
SkASSERT(!pipelineBuilder.hasUserStencilSettings());
|
||||
SkASSERT(pipelineBuilder.getStencil().isDisabled());
|
||||
|
||||
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
||||
canDrawArgs.fShaderCaps = this->getContext()->caps()->shaderCaps();
|
||||
@ -800,7 +806,7 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
||||
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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
||||
// 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 @@ bool GrClipMaskManager::createStencilClipMask(GrRenderTarget* rt,
|
||||
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 @@ GrTexture* GrClipMaskManager::CreateSoftwareClipMask(GrContext* context,
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void GrClipMaskManager::adjustPathStencilParams(const GrStencilAttachment* stencilAttachment,
|
||||
GrStencilSettings* settings) {
|
||||
if (stencilAttachment) {
|
||||
int stencilBits = stencilAttachment->bits();
|
||||
this->adjustStencilParams(settings, fClipMode, stencilBits);
|
||||
}
|
||||
}
|
||||
|
@ -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 SkPath;
|
||||
*/
|
||||
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 @@ public:
|
||||
/**
|
||||
* 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 @@ private:
|
||||
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;
|
||||
|
@ -375,7 +375,7 @@ void GrDrawContext::drawRect(const GrClip& clip,
|
||||
}
|
||||
|
||||
bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
|
||||
const GrUserStencilSettings* ss,
|
||||
const GrStencilSettings& ss,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
bool doAA,
|
||||
@ -397,7 +397,7 @@ bool GrDrawContextPriv::drawAndStencilRect(const SkIRect* scissorRect,
|
||||
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 @@ void GrDrawContext::drawPath(const GrClip& clip,
|
||||
}
|
||||
|
||||
bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
||||
const GrUserStencilSettings* ss,
|
||||
const GrStencilSettings& ss,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
bool doAA,
|
||||
@ -880,7 +880,7 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
||||
// 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 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
||||
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 @@ bool GrDrawContextPriv::drawAndStencilPath(const SkIRect* scissorRect,
|
||||
}
|
||||
|
||||
GrPipelineBuilder pipelineBuilder(paint, fDrawContext->accessRenderTarget(), clip);
|
||||
pipelineBuilder.setUserStencil(ss);
|
||||
pipelineBuilder.setStencil(ss);
|
||||
|
||||
GrPathRenderer::DrawPathArgs args;
|
||||
args.fTarget = fDrawContext->getDrawTarget();
|
||||
@ -939,7 +939,7 @@ void GrDrawContext::internalDrawPath(const GrClip& clip,
|
||||
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 @@ void GrDrawContext::internalDrawPath(const GrClip& clip,
|
||||
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)
|
||||
|
@ -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 @@ struct GrUserStencilSettings;
|
||||
class GrDrawContextPriv {
|
||||
public:
|
||||
bool drawAndStencilRect(const SkIRect* scissorRect,
|
||||
const GrUserStencilSettings*,
|
||||
const GrStencilSettings&,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
bool doAA,
|
||||
@ -26,7 +26,7 @@ public:
|
||||
const SkRect&);
|
||||
|
||||
bool drawAndStencilPath(const SkIRect* scissorRect,
|
||||
const GrUserStencilSettings*,
|
||||
const GrStencilSettings&,
|
||||
SkRegion::Op op,
|
||||
bool invert,
|
||||
bool doAA,
|
||||
|
@ -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 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
|
||||
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 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
|
||||
}
|
||||
|
||||
GrPipeline::CreateArgs args;
|
||||
if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(),
|
||||
clip.hasStencilClip(), batch)) {
|
||||
if (!this->installPipelineInDrawBatch(&pipelineBuilder, &clip.scissorState(), batch)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -270,36 +269,34 @@ void GrDrawTarget::drawBatch(const GrPipelineBuilder& pipelineBuilder,
|
||||
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 @@ void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
|
||||
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 @@ void GrDrawTarget::stencilPath(const GrPipelineBuilder& pipelineBuilder,
|
||||
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 @@ void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
|
||||
// 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 @@ void GrDrawTarget::drawPathBatch(const GrPipelineBuilder& pipelineBuilder,
|
||||
}
|
||||
|
||||
// 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 @@ void GrDrawTarget::forwardCombine() {
|
||||
|
||||
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) {
|
||||
|
@ -223,7 +223,6 @@ private:
|
||||
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 @@ private:
|
||||
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.
|
||||
|
@ -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 GrPipeline;
|
||||
class GrPrimitiveProcessor;
|
||||
class GrRenderTarget;
|
||||
class GrStencilAttachment;
|
||||
class GrStencilSettings;
|
||||
class GrSurface;
|
||||
class GrTexture;
|
||||
|
||||
@ -485,6 +485,17 @@ public:
|
||||
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);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define GrPathRenderer_DEFINED
|
||||
|
||||
#include "GrDrawTarget.h"
|
||||
#include "GrStencil.h"
|
||||
#include "GrStyle.h"
|
||||
|
||||
#include "SkDrawProcs.h"
|
||||
@ -81,7 +82,7 @@ public:
|
||||
bool fAntiAlias;
|
||||
|
||||
// These next two are only used by GrStencilAndCoverPathRenderer
|
||||
bool fHasUserStencilSettings;
|
||||
bool fIsStencilDisabled;
|
||||
bool fIsStencilBufferMSAA;
|
||||
|
||||
void validate() const {
|
||||
@ -154,11 +155,11 @@ public:
|
||||
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 @@ private:
|
||||
* 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;
|
||||
|
@ -20,35 +20,9 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
|
||||
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 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
|
||||
&args.fDstTexture,
|
||||
*args.fCaps));
|
||||
if (!xferProcessor) {
|
||||
pipeline->~GrPipeline();
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
@ -78,7 +51,7 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
|
||||
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 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
|
||||
// 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 @@ GrPipeline* GrPipeline::CreateAt(void* memory, const CreateArgs& args,
|
||||
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
|
||||
|
@ -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 @@ public:
|
||||
const GrCaps* fCaps;
|
||||
GrPipelineOptimizations fOpts;
|
||||
const GrScissorState* fScissor;
|
||||
int fNumStencilBits;
|
||||
bool fHasStencilClip;
|
||||
GrXferProcessor::DstTexture fDstTexture;
|
||||
};
|
||||
|
||||
|
@ -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 @@ GrPipelineBuilder::GrPipelineBuilder(const GrPaint& paint, GrRenderTarget* rt, c
|
||||
|
||||
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,
|
||||
|
@ -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 @@ public:
|
||||
/// @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 @@ private:
|
||||
|
||||
SkAutoTUnref<GrRenderTarget> fRenderTarget;
|
||||
uint32_t fFlags;
|
||||
const GrUserStencilSettings* fUserStencilSettings;
|
||||
GrStencilSettings fStencilSettings;
|
||||
DrawFace fDrawFace;
|
||||
mutable SkAutoTUnref<const GrXPFactory> fXPFactory;
|
||||
FragmentProcessorArray fColorFragmentProcessors;
|
||||
|
403
src/gpu/GrStencil.cpp
Normal file
403
src/gpu/GrStencil.cpp
Normal file
@ -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));
|
||||
}
|
369
src/gpu/GrStencil.h
Normal file
369
src/gpu/GrStencil.h
Normal file
@ -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
|
@ -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));
|
||||
}
|
@ -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
|
@ -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
|
@ -443,11 +443,11 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
|
||||
// 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 @@ bool GrDefaultPathRenderer::internalDrawPath(GrDrawTarget* target,
|
||||
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)) {
|
||||
|
@ -28,10 +28,7 @@ public:
|
||||
|
||||
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,
|
||||
|
@ -578,11 +578,11 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
|
||||
// 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 @@ bool GrMSAAPathRenderer::internalDrawPath(GrDrawTarget* target,
|
||||
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)) {
|
||||
|
@ -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 @@ static constexpr GrUserStencilSettings gInvEOColorPass(
|
||||
// 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
|
||||
|
@ -36,7 +36,7 @@ bool GrStencilAndCoverPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) c
|
||||
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 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
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 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
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 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
|
||||
&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;
|
||||
}
|
||||
|
@ -21,14 +21,11 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
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) {
|
||||
|
@ -2874,38 +2874,40 @@ namespace {
|
||||
|
||||
|
||||
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 @@ void GrGLGpu::flushStencil(const GrStencilSettings& stencilSettings) {
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
@ -70,9 +70,9 @@ static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
|
||||
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 @@ void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath*
|
||||
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 @@ void GrGLPathRendering::onDrawPath(const GrPipeline& pipeline,
|
||||
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 @@ void GrGLPathRendering::onDrawPaths(const GrPipeline& pipeline,
|
||||
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 @@ void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stenci
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
|
@ -334,26 +334,27 @@ GrGLRenderer GrGLGetRenderer(const GrGLInterface* gl) {
|
||||
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];
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "gl/GrGLInterface.h"
|
||||
#include "GrGLDefines.h"
|
||||
#include "GrStencilSettings.h"
|
||||
#include "GrStencil.h"
|
||||
|
||||
class SkMatrix;
|
||||
|
||||
@ -205,7 +205,7 @@ void GrGLClearErr(const GrGLInterface* gl);
|
||||
// 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
|
||||
|
@ -610,17 +610,15 @@ void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
|
||||
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()) {
|
||||
|
@ -100,51 +100,51 @@ static void setup_input_assembly_state(GrPrimitiveType primitiveType,
|
||||
|
||||
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 @@ void setup_depth_stencil_state(const GrVkGpu* gpu,
|
||||
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;
|
||||
|
@ -9,7 +9,6 @@
|
||||
#ifndef GrVkPipelineState_DEFINED
|
||||
#define GrVkPipelineState_DEFINED
|
||||
|
||||
#include "GrStencilSettings.h"
|
||||
#include "GrVkImage.h"
|
||||
#include "GrVkProgramDesc.h"
|
||||
#include "GrVkPipelineStateDataManager.h"
|
||||
|
@ -277,29 +277,25 @@ static void set_random_state(GrPipelineBuilder* pipelineBuilder, SkRandom* rando
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user