Revert "Delete GPU alpha clip masks"
This reverts commit a466228a61
.
Reason for revert: Turned up a vulkan driver bug
Original change's description:
> Delete GPU alpha clip masks
>
> The cost of switching render targets on each draw to make a custom
> clip is enormous. There are virtually no circumstances where this will
> outperform our cached, multi-threaded software mask generator. The
> tried-and-true approach to clipping on-GPU is with analytic FPs. And
> now that we support CCPR clip FPs, there ulitmately should be very few
> clip stacks that even require a mask as long as they don't use
> deprecated SkClipOps.
>
> Bug: skia:
> Change-Id: I79c5558c93c1b99179f1e933d029f69b14ad1ce3
> Reviewed-on: https://skia-review.googlesource.com/116724
> Reviewed-by: Brian Osman <brianosman@google.com>
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
TBR=robertphillips@google.com,brianosman@google.com,csmartdalton@google.com
# Not skipping CQ checks because original CL landed > 1 day ago.
Bug: skia:
Change-Id: Iba289e00ba2eca7084dc8517491cfb5f6ab6266f
Reviewed-on: https://skia-review.googlesource.com/117420
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
parent
7a002c36ce
commit
c534808ba2
@ -107,8 +107,8 @@ DEF_GM( return new WindowRectanglesGM(); )
|
|||||||
constexpr static int kNumWindows = 8;
|
constexpr static int kNumWindows = 8;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visualizes the stencil mask for a clip with several window rectangles. The purpose of this test
|
* Visualizes the mask (alpha or stencil) for a clip with several window rectangles. The purpose of
|
||||||
* is to verify that window rectangles are being used during clip mask generation, and to
|
* this test is to verify that window rectangles are being used during clip mask generation, and to
|
||||||
* visualize where the window rectangles are placed.
|
* visualize where the window rectangles are placed.
|
||||||
*
|
*
|
||||||
* We use window rectangles when generating the clip mask because there is no need to invest time
|
* We use window rectangles when generating the clip mask because there is no need to invest time
|
||||||
@ -123,6 +123,7 @@ private:
|
|||||||
constexpr static int kMaskCheckerSize = 5;
|
constexpr static int kMaskCheckerSize = 5;
|
||||||
SkString onShortName() final { return SkString("windowrectangles_mask"); }
|
SkString onShortName() final { return SkString("windowrectangles_mask"); }
|
||||||
void onCoverClipStack(const SkClipStack&, SkCanvas*) final;
|
void onCoverClipStack(const SkClipStack&, SkCanvas*) final;
|
||||||
|
void visualizeAlphaMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&, GrPaint&&);
|
||||||
void visualizeStencilMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&, GrPaint&&);
|
void visualizeStencilMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&, GrPaint&&);
|
||||||
void stencilCheckerboard(GrRenderTargetContext*, bool flip);
|
void stencilCheckerboard(GrRenderTargetContext*, bool flip);
|
||||||
void fail(SkCanvas*);
|
void fail(SkCanvas*);
|
||||||
@ -183,14 +184,48 @@ void WindowRectanglesMaskGM::onCoverClipStack(const SkClipStack& stack, SkCanvas
|
|||||||
const GrReducedClip reducedClip(stack, SkRect::Make(kCoverRect), rtc->caps()->shaderCaps(),
|
const GrReducedClip reducedClip(stack, SkRect::Make(kCoverRect), rtc->caps()->shaderCaps(),
|
||||||
kNumWindows);
|
kNumWindows);
|
||||||
|
|
||||||
GrPaint paint;
|
GrPaint paint;
|
||||||
if (GrFSAAType::kNone == rtc->fsaaType()) {
|
if (GrFSAAType::kNone == rtc->fsaaType()) {
|
||||||
// Use different colors so we don't confuse masks that don't have AA with ones that should.
|
|
||||||
paint.setColor4f(GrColor4f(0, 0.25f, 1, 1));
|
paint.setColor4f(GrColor4f(0, 0.25f, 1, 1));
|
||||||
|
this->visualizeAlphaMask(ctx, rtc, reducedClip, std::move(paint));
|
||||||
} else {
|
} else {
|
||||||
paint.setColor4f(GrColor4f(1, 0.25f, 0.25f, 1));
|
paint.setColor4f(GrColor4f(1, 0.25f, 0.25f, 1));
|
||||||
|
this->visualizeStencilMask(ctx, rtc, reducedClip, std::move(paint));
|
||||||
}
|
}
|
||||||
this->visualizeStencilMask(ctx, rtc, reducedClip, std::move(paint));
|
}
|
||||||
|
|
||||||
|
void WindowRectanglesMaskGM::visualizeAlphaMask(GrContext* ctx, GrRenderTargetContext* rtc,
|
||||||
|
const GrReducedClip& reducedClip, GrPaint&& paint) {
|
||||||
|
const int padRight = (kDeviceRect.right() - kCoverRect.right()) / 2;
|
||||||
|
const int padBottom = (kDeviceRect.bottom() - kCoverRect.bottom()) / 2;
|
||||||
|
sk_sp<GrRenderTargetContext> maskRTC(
|
||||||
|
ctx->contextPriv().makeDeferredRenderTargetContextWithFallback(
|
||||||
|
SkBackingFit::kExact,
|
||||||
|
kCoverRect.width() + padRight,
|
||||||
|
kCoverRect.height() + padBottom,
|
||||||
|
kAlpha_8_GrPixelConfig, nullptr));
|
||||||
|
if (!maskRTC) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw a checker pattern into the alpha mask so we can visualize the regions left untouched by
|
||||||
|
// the clip mask generation.
|
||||||
|
this->stencilCheckerboard(maskRTC.get(), true);
|
||||||
|
maskRTC->clear(nullptr, GrColorPackA4(0xff), GrRenderTargetContext::CanClearFullscreen::kYes);
|
||||||
|
maskRTC->priv().drawAndStencilRect(make_stencil_only_clip(), &GrUserStencilSettings::kUnused,
|
||||||
|
SkRegion::kDifference_Op, false, GrAA::kNo, SkMatrix::I(),
|
||||||
|
SkRect::MakeIWH(maskRTC->width(), maskRTC->height()));
|
||||||
|
reducedClip.drawAlphaClipMask(maskRTC.get());
|
||||||
|
|
||||||
|
int x = kCoverRect.x() - kDeviceRect.x(),
|
||||||
|
y = kCoverRect.y() - kDeviceRect.y();
|
||||||
|
|
||||||
|
// Now visualize the alpha mask by drawing a rect over the area where it is defined. The regions
|
||||||
|
// inside window rectangles or outside the scissor should still have the initial checkerboard
|
||||||
|
// intact. (This verifies we didn't spend any time modifying those pixels in the mask.)
|
||||||
|
AlphaOnlyClip clip(maskRTC->asTextureProxyRef(), x, y);
|
||||||
|
rtc->drawRect(clip, std::move(paint), GrAA::kYes, SkMatrix::I(),
|
||||||
|
SkRect::Make(SkIRect::MakeXYWH(x, y, maskRTC->width(), maskRTC->height())));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowRectanglesMaskGM::visualizeStencilMask(GrContext* ctx, GrRenderTargetContext* rtc,
|
void WindowRectanglesMaskGM::visualizeStencilMask(GrContext* ctx, GrRenderTargetContext* rtc,
|
||||||
|
@ -73,6 +73,111 @@ void GrClipStackClip::getConservativeBounds(int width, int height, SkIRect* devR
|
|||||||
devBounds.roundOut(devResult);
|
devBounds.roundOut(devResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// set up the draw state to enable the aa clipping mask.
|
||||||
|
static std::unique_ptr<GrFragmentProcessor> create_fp_for_mask(sk_sp<GrTextureProxy> mask,
|
||||||
|
const SkIRect& devBound) {
|
||||||
|
SkIRect domainTexels = SkIRect::MakeWH(devBound.width(), devBound.height());
|
||||||
|
return GrDeviceSpaceTextureDecalFragmentProcessor::Make(std::move(mask), domainTexels,
|
||||||
|
{devBound.fLeft, devBound.fTop});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Does the path in 'element' require SW rendering? If so, return true (and,
|
||||||
|
// 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 GrClipStackClip::PathNeedsSWRenderer(GrContext* context,
|
||||||
|
const SkIRect& scissorRect,
|
||||||
|
bool hasUserStencilSettings,
|
||||||
|
const GrRenderTargetContext* renderTargetContext,
|
||||||
|
const SkMatrix& viewMatrix,
|
||||||
|
const Element* element,
|
||||||
|
GrPathRenderer** prOut,
|
||||||
|
bool needsStencil) {
|
||||||
|
if (Element::DeviceSpaceType::kRect == element->getDeviceSpaceType()) {
|
||||||
|
// rects can always be drawn directly w/o using the software path
|
||||||
|
// TODO: skip rrects once we're drawing them directly.
|
||||||
|
if (prOut) {
|
||||||
|
*prOut = nullptr;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// We shouldn't get here with an empty clip element.
|
||||||
|
SkASSERT(Element::DeviceSpaceType::kEmpty != element->getDeviceSpaceType());
|
||||||
|
|
||||||
|
// the gpu alpha mask will draw the inverse paths as non-inverse to a temp buffer
|
||||||
|
SkPath path;
|
||||||
|
element->asDeviceSpacePath(&path);
|
||||||
|
if (path.isInverseFillType()) {
|
||||||
|
path.toggleInverseFillType();
|
||||||
|
}
|
||||||
|
|
||||||
|
GrPathRendererChain::DrawType type =
|
||||||
|
needsStencil ? GrPathRendererChain::DrawType::kStencilAndColor
|
||||||
|
: GrPathRendererChain::DrawType::kColor;
|
||||||
|
|
||||||
|
GrShape shape(path, GrStyle::SimpleFill());
|
||||||
|
GrPathRenderer::CanDrawPathArgs canDrawArgs;
|
||||||
|
canDrawArgs.fCaps = context->caps();
|
||||||
|
canDrawArgs.fClipConservativeBounds = &scissorRect;
|
||||||
|
canDrawArgs.fViewMatrix = &viewMatrix;
|
||||||
|
canDrawArgs.fShape = &shape;
|
||||||
|
canDrawArgs.fAAType = GrChooseAAType(GrAA(element->isAA()),
|
||||||
|
renderTargetContext->fsaaType(),
|
||||||
|
GrAllowMixedSamples::kYes,
|
||||||
|
*context->caps());
|
||||||
|
canDrawArgs.fHasUserStencilSettings = hasUserStencilSettings;
|
||||||
|
|
||||||
|
// the 'false' parameter disallows use of the SW path renderer
|
||||||
|
GrPathRenderer* pr =
|
||||||
|
context->contextPriv().drawingManager()->getPathRenderer(canDrawArgs, false, type);
|
||||||
|
if (prOut) {
|
||||||
|
*prOut = pr;
|
||||||
|
}
|
||||||
|
return SkToBool(!pr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This method traverses the clip stack to see if the GrSoftwarePathRenderer
|
||||||
|
* will be used on any element. If so, it returns true to indicate that the
|
||||||
|
* entire clip should be rendered in SW and then uploaded en masse to the gpu.
|
||||||
|
*/
|
||||||
|
bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
|
||||||
|
bool hasUserStencilSettings,
|
||||||
|
const GrRenderTargetContext* renderTargetContext,
|
||||||
|
const GrReducedClip& reducedClip) {
|
||||||
|
// TODO: generalize this function so that when
|
||||||
|
// a clip gets complex enough it can just be done in SW regardless
|
||||||
|
// of whether it would invoke the GrSoftwarePathRenderer.
|
||||||
|
|
||||||
|
// If we're avoiding stencils, always use SW:
|
||||||
|
if (context->caps()->avoidStencilBuffers())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Set the matrix so that rendered clip elements are transformed to mask space from clip
|
||||||
|
// space.
|
||||||
|
SkMatrix translate;
|
||||||
|
translate.setTranslate(SkIntToScalar(-reducedClip.left()), SkIntToScalar(-reducedClip.top()));
|
||||||
|
|
||||||
|
for (ElementList::Iter iter(reducedClip.maskElements()); iter.get(); iter.next()) {
|
||||||
|
const Element* element = iter.get();
|
||||||
|
|
||||||
|
SkClipOp op = element->getOp();
|
||||||
|
bool invert = element->isInverseFilled();
|
||||||
|
bool needsStencil = invert ||
|
||||||
|
kIntersect_SkClipOp == op || kReverseDifference_SkClipOp == op;
|
||||||
|
|
||||||
|
if (PathNeedsSWRenderer(context, reducedClip.scissor(), hasUserStencilSettings,
|
||||||
|
renderTargetContext, translate, element, nullptr, needsStencil)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// sort out what kind of clip mask needs to be created: alpha, stencil,
|
||||||
|
// scissor, or entirely software
|
||||||
bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTargetContext,
|
bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTargetContext,
|
||||||
bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out,
|
bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out,
|
||||||
SkRect* bounds) const {
|
SkRect* bounds) const {
|
||||||
@ -148,18 +253,24 @@ bool GrClipStackClip::applyClipMask(GrContext* context, GrRenderTargetContext* r
|
|||||||
// If the stencil buffer is multisampled we can use it to do everything.
|
// If the stencil buffer is multisampled we can use it to do everything.
|
||||||
if ((GrFSAAType::kNone == renderTargetContext->fsaaType() && reducedClip.maskRequiresAA()) ||
|
if ((GrFSAAType::kNone == renderTargetContext->fsaaType() && reducedClip.maskRequiresAA()) ||
|
||||||
context->caps()->avoidStencilBuffers()) {
|
context->caps()->avoidStencilBuffers()) {
|
||||||
if (auto mask = this->createSoftwareClipMask(context, reducedClip, renderTargetContext)) {
|
sk_sp<GrTextureProxy> result;
|
||||||
// The mask should fill the clip's scissor.
|
if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) {
|
||||||
SkIRect domainTexels = SkIRect::MakeWH(reducedClip.width(), reducedClip.height());
|
// The clip geometry is complex enough that it will be more efficient to create it
|
||||||
SkIPoint maskOffset = SkIPoint::Make(reducedClip.left(), reducedClip.top());
|
// entirely in software
|
||||||
out->addCoverageFP(GrDeviceSpaceTextureDecalFragmentProcessor::Make(std::move(mask),
|
result = this->createSoftwareClipMask(context, reducedClip, renderTargetContext);
|
||||||
domainTexels,
|
} else {
|
||||||
maskOffset));
|
result = this->createAlphaClipMask(context, reducedClip);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
// The mask's top left coord should be pinned to the rounded-out top left corner of
|
||||||
|
// the clip's device space bounds.
|
||||||
|
out->addCoverageFP(create_fp_for_mask(std::move(result), reducedClip.scissor()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If software clip mask creation fails, fall through to the stencil code paths, unless
|
// If alpha or software clip mask creation fails, fall through to the stencil code paths,
|
||||||
// stencils are disallowed.
|
// unless stencils are disallowed.
|
||||||
if (context->caps()->avoidStencilBuffers()) {
|
if (context->caps()->avoidStencilBuffers()) {
|
||||||
SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. "
|
SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. "
|
||||||
"Clip will be ignored.\n");
|
"Clip will be ignored.\n");
|
||||||
@ -213,6 +324,45 @@ static void add_invalidate_on_pop_message(const SkClipStack& stack, uint32_t cli
|
|||||||
SkDEBUGFAIL("Gen ID was not found in stack.");
|
SkDEBUGFAIL("Gen ID was not found in stack.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context,
|
||||||
|
const GrReducedClip& reducedClip) const {
|
||||||
|
GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
|
||||||
|
GrUniqueKey key;
|
||||||
|
create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
|
||||||
|
reducedClip.numAnalyticFPs(), &key);
|
||||||
|
|
||||||
|
sk_sp<GrTextureProxy> proxy(proxyProvider->findOrCreateProxyByUniqueKey(
|
||||||
|
key, kBottomLeft_GrSurfaceOrigin));
|
||||||
|
if (proxy) {
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_sp<GrRenderTargetContext> rtc(
|
||||||
|
context->contextPriv().makeDeferredRenderTargetContextWithFallback(SkBackingFit::kApprox,
|
||||||
|
reducedClip.width(),
|
||||||
|
reducedClip.height(),
|
||||||
|
kAlpha_8_GrPixelConfig,
|
||||||
|
nullptr));
|
||||||
|
if (!rtc) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reducedClip.drawAlphaClipMask(rtc.get())) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_sp<GrTextureProxy> result(rtc->asTextureProxyRef());
|
||||||
|
if (!result) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SkASSERT(result->origin() == kBottomLeft_GrSurfaceOrigin);
|
||||||
|
proxyProvider->assignUniqueKeyToProxy(key, result.get());
|
||||||
|
add_invalidate_on_pop_message(*fStack, reducedClip.maskGenID(), key);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,14 +37,31 @@ public:
|
|||||||
static const char kMaskTestTag[];
|
static const char kMaskTestTag[];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static bool PathNeedsSWRenderer(GrContext* context,
|
||||||
|
const SkIRect& scissorRect,
|
||||||
|
bool hasUserStencilSettings,
|
||||||
|
const GrRenderTargetContext*,
|
||||||
|
const SkMatrix& viewMatrix,
|
||||||
|
const SkClipStack::Element* element,
|
||||||
|
GrPathRenderer** prOut,
|
||||||
|
bool needsStencil);
|
||||||
|
|
||||||
bool applyClipMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&,
|
bool applyClipMask(GrContext*, GrRenderTargetContext*, const GrReducedClip&,
|
||||||
bool hasUserStencilSettings, GrAppliedClip*) const;
|
bool hasUserStencilSettings, GrAppliedClip*) const;
|
||||||
|
|
||||||
// Creates an alpha mask of the remaining reduced clip elements that could not be handled
|
// Creates an alpha mask of the clip. The mask is a rasterization of elements through the
|
||||||
// analytically on the GPU. The mask fills the reduced clip's scissor rect.
|
// rect specified by clipSpaceIBounds.
|
||||||
|
sk_sp<GrTextureProxy> createAlphaClipMask(GrContext*, const GrReducedClip&) const;
|
||||||
|
|
||||||
|
// Similar to createAlphaClipMask but it rasterizes in SW and uploads to the result texture.
|
||||||
sk_sp<GrTextureProxy> createSoftwareClipMask(GrContext*, const GrReducedClip&,
|
sk_sp<GrTextureProxy> createSoftwareClipMask(GrContext*, const GrReducedClip&,
|
||||||
GrRenderTargetContext*) const;
|
GrRenderTargetContext*) const;
|
||||||
|
|
||||||
|
static bool UseSWOnlyPath(GrContext*,
|
||||||
|
bool hasUserStencilSettings,
|
||||||
|
const GrRenderTargetContext*,
|
||||||
|
const GrReducedClip&);
|
||||||
|
|
||||||
const SkClipStack* fStack;
|
const SkClipStack* fStack;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -672,6 +672,134 @@ void GrReducedClip::makeEmpty() {
|
|||||||
fInitialState = InitialState::kAllOut;
|
fInitialState = InitialState::kAllOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Create a 8-bit clip mask in alpha
|
||||||
|
|
||||||
|
static bool stencil_element(GrRenderTargetContext* rtc,
|
||||||
|
const GrFixedClip& clip,
|
||||||
|
const GrUserStencilSettings* ss,
|
||||||
|
const SkMatrix& viewMatrix,
|
||||||
|
const SkClipStack::Element* element) {
|
||||||
|
GrAA aa = GrAA(element->isAA());
|
||||||
|
switch (element->getDeviceSpaceType()) {
|
||||||
|
case SkClipStack::Element::DeviceSpaceType::kEmpty:
|
||||||
|
SkDEBUGFAIL("Should never get here with an empty element.");
|
||||||
|
break;
|
||||||
|
case SkClipStack::Element::DeviceSpaceType::kRect:
|
||||||
|
return rtc->priv().drawAndStencilRect(clip, ss, (SkRegion::Op)element->getOp(),
|
||||||
|
element->isInverseFilled(), aa, viewMatrix,
|
||||||
|
element->getDeviceSpaceRect());
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
SkPath path;
|
||||||
|
element->asDeviceSpacePath(&path);
|
||||||
|
if (path.isInverseFillType()) {
|
||||||
|
path.toggleInverseFillType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element->getOp(),
|
||||||
|
element->isInverseFilled(), aa, viewMatrix, path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_element(GrRenderTargetContext* rtc,
|
||||||
|
const GrClip& clip, // TODO: can this just always be WideOpen?
|
||||||
|
GrPaint&& paint,
|
||||||
|
GrAA aa,
|
||||||
|
const SkMatrix& viewMatrix,
|
||||||
|
const SkClipStack::Element* element) {
|
||||||
|
// TODO: Draw rrects directly here.
|
||||||
|
switch (element->getDeviceSpaceType()) {
|
||||||
|
case SkClipStack::Element::DeviceSpaceType::kEmpty:
|
||||||
|
SkDEBUGFAIL("Should never get here with an empty element.");
|
||||||
|
break;
|
||||||
|
case SkClipStack::Element::DeviceSpaceType::kRect:
|
||||||
|
rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect());
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
SkPath path;
|
||||||
|
element->asDeviceSpacePath(&path);
|
||||||
|
if (path.isInverseFillType()) {
|
||||||
|
path.toggleInverseFillType();
|
||||||
|
}
|
||||||
|
|
||||||
|
rtc->drawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const {
|
||||||
|
// The texture may be larger than necessary, this rect represents the part of the texture
|
||||||
|
// we populate with a rasterization of the clip.
|
||||||
|
GrFixedClip clip(SkIRect::MakeWH(fScissor.width(), fScissor.height()));
|
||||||
|
|
||||||
|
if (!fWindowRects.empty()) {
|
||||||
|
clip.setWindowRectangles(fWindowRects.makeOffset(-fScissor.left(), -fScissor.top()),
|
||||||
|
GrWindowRectsState::Mode::kExclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The scratch texture that we are drawing into can be substantially larger than the mask. Only
|
||||||
|
// clear the part that we care about.
|
||||||
|
GrColor initialCoverage = InitialState::kAllIn == this->initialState() ? -1 : 0;
|
||||||
|
rtc->priv().clear(clip, initialCoverage, GrRenderTargetContext::CanClearFullscreen::kYes);
|
||||||
|
|
||||||
|
// Set the matrix so that rendered clip elements are transformed to mask space from clip space.
|
||||||
|
SkMatrix translate;
|
||||||
|
translate.setTranslate(SkIntToScalar(-fScissor.left()), SkIntToScalar(-fScissor.top()));
|
||||||
|
|
||||||
|
// walk through each clip element and perform its set op
|
||||||
|
for (ElementList::Iter iter(fMaskElements); iter.get(); iter.next()) {
|
||||||
|
const Element* element = iter.get();
|
||||||
|
SkRegion::Op op = (SkRegion::Op)element->getOp();
|
||||||
|
GrAA aa = GrAA(element->isAA());
|
||||||
|
bool invert = element->isInverseFilled();
|
||||||
|
if (invert || SkRegion::kIntersect_Op == op || SkRegion::kReverseDifference_Op == op) {
|
||||||
|
// 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(rtc, clip, &kStencilInElement, translate, element)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 (!rtc->priv().drawAndStencilRect(clip, &kDrawOutsideElement, op, !invert, GrAA::kNo,
|
||||||
|
translate, SkRect::Make(fScissor))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// all the remaining ops can just be directly draw into the accumulation buffer
|
||||||
|
GrPaint paint;
|
||||||
|
paint.setCoverageSetOpXPFactory(op, false);
|
||||||
|
|
||||||
|
draw_element(rtc, clip, std::move(paint), aa, translate, element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Create a 1-bit clip mask in the stencil buffer.
|
// Create a 1-bit clip mask in the stencil buffer.
|
||||||
|
|
||||||
|
@ -83,6 +83,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool maskRequiresAA() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskRequiresAA; }
|
bool maskRequiresAA() const { SkASSERT(!fMaskElements.isEmpty()); return fMaskRequiresAA; }
|
||||||
|
|
||||||
|
bool drawAlphaClipMask(GrRenderTargetContext*) const;
|
||||||
bool drawStencilClipMask(GrContext*, GrRenderTargetContext*) const;
|
bool drawStencilClipMask(GrContext*, GrRenderTargetContext*) const;
|
||||||
|
|
||||||
int numAnalyticFPs() const { return fAnalyticFPs.count() + fCCPRClipPaths.count(); }
|
int numAnalyticFPs() const { return fAnalyticFPs.count() + fCCPRClipPaths.count(); }
|
||||||
|
Loading…
Reference in New Issue
Block a user