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:
robertphillips 2016-05-11 05:21:56 -07:00 committed by Commit bot
parent 3e11da7fa9
commit e19aecdd13
33 changed files with 1479 additions and 1366 deletions

View File

@ -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',

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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)

View File

@ -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,

View File

@ -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) {

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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;
};

View File

@ -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,

View File

@ -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
View 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
View 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

View File

@ -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));
}

View File

@ -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

View File

@ -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

View File

@ -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)) {

View File

@ -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,

View File

@ -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)) {

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
/**

View File

@ -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];
}

View File

@ -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

View File

@ -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()) {

View File

@ -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;

View File

@ -9,7 +9,6 @@
#ifndef GrVkPipelineState_DEFINED
#define GrVkPipelineState_DEFINED
#include "GrStencilSettings.h"
#include "GrVkImage.h"
#include "GrVkProgramDesc.h"
#include "GrVkPipelineStateDataManager.h"

View File

@ -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);
}
}