Reland "Fold analytic clip FPs into GrReducedClip"
This is a reland of 4355b26b35
Original change's description:
> Fold analytic clip FPs into GrReducedClip
>
> Perf result on Pixel phone (sorted by impact):
>
> GEOMEAN 7.44 -> 6.92 ms [ 93%]
>
> keymobi_cnn_com.skp 3.55 -> 3.59 ms [101%]
> keymobi_theverge_com.skp 4.08 -> 4.13 ms [101%]
> desk_skbug6850autoscroll.skp 1.21 -> 1.22 ms [101%]
> ...
> top25desk_weather_com.skp 14.2 -> 11.5 ms [ 81%]
> keymobi_androidpolice_com_2012_.skp 3.84 -> 2.95 ms [ 77%]
> keymobi_shop_mobileweb_ebay_com.skp 2.94 -> 2.26 ms [ 77%]
> keymobi_boingboing_net.skp 3.08 -> 2.24 ms [ 73%]
> desk_jsfiddlebigcar.skp 1.90 -> 1.25 ms [ 66%]
> keymobi_m_youtube_com_watch_v_9.skp 13.5 -> 8.84 ms [ 65%]
> keymobi_sfgate_com_.skp 8.55 -> 5.55 ms [ 65%]
> keymobi_blogger.skp 4.01 -> 2.60 ms [ 65%]
>
> Cleaner code, improved skps, slightly better geometric mean time.
>
> Pixel C is mostly unaffected, presumably because it uses window
> rectangles.
>
> Bug: skia:7190
> Change-Id: Ia93f68b2f971ea66b3ab19dc73557ea602932a92
> Reviewed-on: https://skia-review.googlesource.com/67424
> Commit-Queue: Chris Dalton <csmartdalton@google.com>
> Reviewed-by: Brian Salomon <bsalomon@google.com>
TBR=bsalomon@google.com
Bug: skia:7190
Change-Id: I92f1ed21b6292feb3209fcbd1725487784d420da
Reviewed-on: https://skia-review.googlesource.com/72562
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
parent
47c8ed3c06
commit
584a79a1d5
@ -143,6 +143,10 @@ public:
|
||||
|
||||
int maxWindowRectangles() const { return fMaxWindowRectangles; }
|
||||
|
||||
// A tuned, platform-specific value for the maximum number of analytic fragment processors we
|
||||
// should use to implement a clip, before falling back on a mask.
|
||||
int maxClipAnalyticFPs() const { return fMaxClipAnalyticFPs; }
|
||||
|
||||
virtual bool isConfigTexturable(GrPixelConfig) const = 0;
|
||||
virtual bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const = 0;
|
||||
// Returns whether a texture of the given config can be copied to a texture of the same config.
|
||||
@ -241,6 +245,7 @@ protected:
|
||||
int fMaxStencilSampleCount;
|
||||
int fMaxRasterSamples;
|
||||
int fMaxWindowRectangles;
|
||||
int fMaxClipAnalyticFPs;
|
||||
|
||||
private:
|
||||
virtual void onApplyOptionsOverrides(const GrContextOptions&) {}
|
||||
|
@ -69,6 +69,14 @@ GrCaps::GrCaps(const GrContextOptions& options) {
|
||||
fMaxRasterSamples = 0;
|
||||
fMaxWindowRectangles = 0;
|
||||
|
||||
// An default count of 4 was chosen because of the common pattern in Blink of:
|
||||
// isect RR
|
||||
// diff RR
|
||||
// isect convex_poly
|
||||
// isect convex_poly
|
||||
// when drawing rounded div borders.
|
||||
fMaxClipAnalyticFPs = 4;
|
||||
|
||||
fSuppressPrints = options.fSuppressPrints;
|
||||
#if GR_TEST_UTILS
|
||||
fWireframeMode = options.fWireframeMode;
|
||||
@ -161,6 +169,7 @@ void GrCaps::dumpJSON(SkJSONWriter* writer) const {
|
||||
writer->appendS32("Max Stencil Sample Count", fMaxStencilSampleCount);
|
||||
writer->appendS32("Max Raster Samples", fMaxRasterSamples);
|
||||
writer->appendS32("Max Window Rectangles", fMaxWindowRectangles);
|
||||
writer->appendS32("Max Clip Analytic Fragment Processors", fMaxClipAnalyticFPs);
|
||||
|
||||
static const char* kInstancedSupportNames[] = {
|
||||
"None",
|
||||
|
@ -30,7 +30,6 @@ typedef SkClipStack::Element Element;
|
||||
typedef GrReducedClip::InitialState InitialState;
|
||||
typedef GrReducedClip::ElementList ElementList;
|
||||
|
||||
static const int kMaxAnalyticElements = 4;
|
||||
const char GrClipStackClip::kMaskTestTag[] = "clip_mask";
|
||||
|
||||
bool GrClipStackClip::quickContains(const SkRect& rect) const {
|
||||
@ -176,80 +175,6 @@ bool GrClipStackClip::UseSWOnlyPath(GrContext* context,
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool get_analytic_clip_processor(const ElementList& elements,
|
||||
bool abortIfAA,
|
||||
const SkRect& drawDevBounds,
|
||||
std::unique_ptr<GrFragmentProcessor>* resultFP) {
|
||||
SkASSERT(elements.count() <= kMaxAnalyticElements);
|
||||
SkSTArray<kMaxAnalyticElements, std::unique_ptr<GrFragmentProcessor>> fps;
|
||||
ElementList::Iter iter(elements);
|
||||
while (iter.get()) {
|
||||
SkClipOp op = iter.get()->getOp();
|
||||
bool invert;
|
||||
bool skip = false;
|
||||
switch (op) {
|
||||
case kReplace_SkClipOp:
|
||||
SkASSERT(iter.get() == elements.head());
|
||||
// Fallthrough, handled same as intersect.
|
||||
case kIntersect_SkClipOp:
|
||||
invert = false;
|
||||
if (iter.get()->contains(drawDevBounds)) {
|
||||
skip = true;
|
||||
}
|
||||
break;
|
||||
case kDifference_SkClipOp:
|
||||
invert = true;
|
||||
// We don't currently have a cheap test for whether a rect is fully outside an
|
||||
// element's primitive, so don't attempt to set skip.
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (!skip) {
|
||||
GrClipEdgeType edgeType;
|
||||
if (iter.get()->isAA()) {
|
||||
if (abortIfAA) {
|
||||
return false;
|
||||
}
|
||||
edgeType =
|
||||
invert ? GrClipEdgeType::kInverseFillAA : GrClipEdgeType::kFillAA;
|
||||
} else {
|
||||
edgeType =
|
||||
invert ? GrClipEdgeType::kInverseFillBW : GrClipEdgeType::kFillBW;
|
||||
}
|
||||
|
||||
switch (iter.get()->getDeviceSpaceType()) {
|
||||
case SkClipStack::Element::DeviceSpaceType::kPath:
|
||||
fps.emplace_back(
|
||||
GrConvexPolyEffect::Make(edgeType, iter.get()->getDeviceSpacePath()));
|
||||
break;
|
||||
case SkClipStack::Element::DeviceSpaceType::kRRect: {
|
||||
fps.emplace_back(
|
||||
GrRRectEffect::Make(edgeType, iter.get()->getDeviceSpaceRRect()));
|
||||
break;
|
||||
}
|
||||
case SkClipStack::Element::DeviceSpaceType::kRect: {
|
||||
fps.emplace_back(
|
||||
GrConvexPolyEffect::Make(edgeType, iter.get()->getDeviceSpaceRect()));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!fps.back()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
iter.next();
|
||||
}
|
||||
|
||||
*resultFP = nullptr;
|
||||
if (fps.count()) {
|
||||
*resultFP = GrFragmentProcessor::RunInSeries(fps.begin(), fps.count());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// sort out what kind of clip mask needs to be created: alpha, stencil,
|
||||
// scissor, or entirely software
|
||||
@ -265,8 +190,19 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
return true;
|
||||
}
|
||||
|
||||
const GrReducedClip reducedClip(*fStack, devBounds,
|
||||
renderTargetContext->priv().maxWindowRectangles());
|
||||
int maxAnalyticFPs = context->caps()->maxClipAnalyticFPs();
|
||||
if (GrFSAAType::kNone != renderTargetContext->fsaaType()) {
|
||||
// With mixed samples (non-msaa color buffer), any coverage info is lost from color once it
|
||||
// hits the color buffer anyway, so we may as well use coverage AA if nothing else in the
|
||||
// pipe is multisampled.
|
||||
if (renderTargetContext->numColorSamples() > 0 || useHWAA || hasUserStencilSettings) {
|
||||
maxAnalyticFPs = 0;
|
||||
}
|
||||
SkASSERT(!context->caps()->avoidStencilBuffers()); // We disable MSAA when avoiding stencil.
|
||||
}
|
||||
|
||||
GrReducedClip reducedClip(*fStack, devBounds, renderTargetContext->priv().maxWindowRectangles(),
|
||||
maxAnalyticFPs);
|
||||
|
||||
if (reducedClip.hasScissor() && !GrClip::IsInsideClip(reducedClip.scissor(), devBounds)) {
|
||||
out->hardClip().addScissor(reducedClip.scissor(), bounds);
|
||||
@ -277,6 +213,10 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
GrWindowRectsState::Mode::kExclusive);
|
||||
}
|
||||
|
||||
if (std::unique_ptr<GrFragmentProcessor> clipFPs = reducedClip.detachAnalyticFPs()) {
|
||||
out->addCoverageFP(std::move(clipFPs));
|
||||
}
|
||||
|
||||
if (reducedClip.maskElements().isEmpty()) {
|
||||
return InitialState::kAllIn == reducedClip.initialState();
|
||||
}
|
||||
@ -289,41 +229,9 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
SkASSERT(rtIBounds.contains(scissor)); // Mask shouldn't be larger than the RT.
|
||||
#endif
|
||||
|
||||
bool avoidStencilBuffers = context->caps()->avoidStencilBuffers();
|
||||
|
||||
// An element count of 4 was chosen because of the common pattern in Blink of:
|
||||
// isect RR
|
||||
// diff RR
|
||||
// isect convex_poly
|
||||
// isect convex_poly
|
||||
// when drawing rounded div borders. This could probably be tuned based on a
|
||||
// configuration's relative costs of switching RTs to generate a mask vs
|
||||
// longer shaders.
|
||||
if (reducedClip.maskElements().count() <= kMaxAnalyticElements) {
|
||||
// When there are multiple samples we want to do per-sample clipping, not compute a
|
||||
// fractional pixel coverage.
|
||||
bool disallowAnalyticAA =
|
||||
GrFSAAType::kNone != renderTargetContext->fsaaType() && !avoidStencilBuffers;
|
||||
if (disallowAnalyticAA && !renderTargetContext->numColorSamples()) {
|
||||
// With a single color sample, any coverage info is lost from color once it hits the
|
||||
// color buffer anyway, so we may as well use coverage AA if nothing else in the pipe
|
||||
// is multisampled.
|
||||
disallowAnalyticAA = useHWAA || hasUserStencilSettings;
|
||||
}
|
||||
std::unique_ptr<GrFragmentProcessor> clipFP;
|
||||
if ((reducedClip.maskRequiresAA() || avoidStencilBuffers) &&
|
||||
get_analytic_clip_processor(reducedClip.maskElements(), disallowAnalyticAA, devBounds,
|
||||
&clipFP)) {
|
||||
if (clipFP) {
|
||||
out->addCoverageFP(std::move(clipFP));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the stencil buffer is multisampled we can use it to do everything.
|
||||
if ((GrFSAAType::kNone == renderTargetContext->fsaaType() && reducedClip.maskRequiresAA()) ||
|
||||
avoidStencilBuffers) {
|
||||
context->caps()->avoidStencilBuffers()) {
|
||||
sk_sp<GrTextureProxy> result;
|
||||
if (UseSWOnlyPath(context, hasUserStencilSettings, renderTargetContext, reducedClip)) {
|
||||
// The clip geometry is complex enough that it will be more efficient to create it
|
||||
@ -343,7 +251,8 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
// If alpha or software clip mask creation fails, fall through to the stencil code paths,
|
||||
// unless stencils are disallowed.
|
||||
if (context->caps()->avoidStencilBuffers()) {
|
||||
SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. Clip will be ignored.\n");
|
||||
SkDebugf("WARNING: Clip mask requires stencil, but stencil unavailable. "
|
||||
"Clip will be ignored.\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -353,11 +262,14 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
// This relies on the property that a reduced sub-rect of the last clip will contain all the
|
||||
// relevant window rectangles that were in the last clip. This subtle requirement will go away
|
||||
// after clipping is overhauled.
|
||||
if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(),
|
||||
reducedClip.scissor())) {
|
||||
if (renderTargetContext->priv().mustRenderClip(reducedClip.maskGenID(), reducedClip.scissor(),
|
||||
reducedClip.numAnalyticFPs())) {
|
||||
reducedClip.drawStencilClipMask(context, renderTargetContext);
|
||||
renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor());
|
||||
renderTargetContext->priv().setLastClip(reducedClip.maskGenID(), reducedClip.scissor(),
|
||||
reducedClip.numAnalyticFPs());
|
||||
}
|
||||
// GrAppliedClip doesn't need to figure numAnalyticFPs into its key (used by operator==) because
|
||||
// it verifies the FPs are also equal.
|
||||
out->hardClip().addStencilClip(reducedClip.maskGenID());
|
||||
return true;
|
||||
}
|
||||
@ -365,14 +277,16 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Create a 8-bit clip mask in alpha
|
||||
|
||||
static void create_clip_mask_key(uint32_t clipGenID, const SkIRect& bounds, GrUniqueKey* key) {
|
||||
static void create_clip_mask_key(uint32_t clipGenID, const SkIRect& bounds, int numAnalyticFPs,
|
||||
GrUniqueKey* key) {
|
||||
static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
|
||||
GrUniqueKey::Builder builder(key, kDomain, 3, GrClipStackClip::kMaskTestTag);
|
||||
GrUniqueKey::Builder builder(key, kDomain, 4, GrClipStackClip::kMaskTestTag);
|
||||
builder[0] = clipGenID;
|
||||
// SkToS16 because image filters outset layers to a size indicated by the filter, which can
|
||||
// sometimes result in negative coordinates from device space.
|
||||
builder[1] = SkToS16(bounds.fLeft) | (SkToS16(bounds.fRight) << 16);
|
||||
builder[2] = SkToS16(bounds.fTop) | (SkToS16(bounds.fBottom) << 16);
|
||||
builder[3] = numAnalyticFPs;
|
||||
}
|
||||
|
||||
static void add_invalidate_on_pop_message(const SkClipStack& stack, uint32_t clipGenID,
|
||||
@ -393,7 +307,8 @@ sk_sp<GrTextureProxy> GrClipStackClip::createAlphaClipMask(GrContext* context,
|
||||
const GrReducedClip& reducedClip) const {
|
||||
GrResourceProvider* resourceProvider = context->resourceProvider();
|
||||
GrUniqueKey key;
|
||||
create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), &key);
|
||||
create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
|
||||
reducedClip.numAnalyticFPs(), &key);
|
||||
|
||||
sk_sp<GrTextureProxy> proxy(resourceProvider->findOrCreateProxyByUniqueKey(
|
||||
key, kBottomLeft_GrSurfaceOrigin));
|
||||
@ -505,7 +420,8 @@ sk_sp<GrTextureProxy> GrClipStackClip::createSoftwareClipMask(
|
||||
GrContext* context, const GrReducedClip& reducedClip,
|
||||
GrRenderTargetContext* renderTargetContext) const {
|
||||
GrUniqueKey key;
|
||||
create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(), &key);
|
||||
create_clip_mask_key(reducedClip.maskGenID(), reducedClip.scissor(),
|
||||
reducedClip.numAnalyticFPs(), &key);
|
||||
|
||||
sk_sp<GrTextureProxy> proxy(context->resourceProvider()->findOrCreateProxyByUniqueKey(
|
||||
key, kTopLeft_GrSurfaceOrigin));
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include "GrStyle.h"
|
||||
#include "GrUserStencilSettings.h"
|
||||
#include "SkClipOpPriv.h"
|
||||
#include "effects/GrConvexPolyEffect.h"
|
||||
#include "effects/GrRRectEffect.h"
|
||||
|
||||
/**
|
||||
* There are plenty of optimizations that could be added here. Maybe flips could be folded into
|
||||
@ -30,8 +32,11 @@
|
||||
* take a rect in case the caller knows a bound on what is to be drawn through this clip.
|
||||
*/
|
||||
GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds,
|
||||
int maxWindowRectangles) {
|
||||
int maxWindowRectangles, int maxAnalyticFPs)
|
||||
: fMaxWindowRectangles(maxWindowRectangles)
|
||||
, fMaxAnalyticFPs(maxAnalyticFPs) {
|
||||
SkASSERT(!queryBounds.isEmpty());
|
||||
SkASSERT(fMaxWindowRectangles <= GrWindowRectangles::kMaxWindows);
|
||||
fHasScissor = false;
|
||||
fAAClipRectGenID = SK_InvalidGenID;
|
||||
|
||||
@ -97,12 +102,13 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
|
||||
}
|
||||
fHasScissor = true;
|
||||
|
||||
// Now that we have determined the bounds to use and filtered out the trivial cases, call the
|
||||
// helper that actually walks the stack.
|
||||
this->walkStack(stack, tighterQuery, maxWindowRectangles);
|
||||
// Now that we have determined the bounds to use and filtered out the trivial cases, call
|
||||
// the helper that actually walks the stack.
|
||||
this->walkStack(stack, tighterQuery);
|
||||
}
|
||||
|
||||
if (SK_InvalidGenID != fAAClipRectGenID) { // Is there an AA clip rect?
|
||||
if (SK_InvalidGenID != fAAClipRectGenID && // Is there an AA clip rect?
|
||||
ClipResult::kNotClipped == this->addAnalyticFP(fAAClipRect, Invert::kNo, true)) {
|
||||
if (fMaskElements.isEmpty()) {
|
||||
// Use a replace since it is faster than intersect.
|
||||
fMaskElements.addToHead(fAAClipRect, SkMatrix::I(), kReplace_SkClipOp, true /*doAA*/);
|
||||
@ -112,12 +118,10 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds
|
||||
}
|
||||
fMaskRequiresAA = true;
|
||||
fMaskGenID = fAAClipRectGenID;
|
||||
fAAClipRectGenID = SK_InvalidGenID;
|
||||
}
|
||||
}
|
||||
|
||||
void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBounds,
|
||||
int maxWindowRectangles) {
|
||||
void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBounds) {
|
||||
// walk backwards until we get to:
|
||||
// a) the beginning
|
||||
// b) an operation that is known to make the bounds all inside/outside
|
||||
@ -180,7 +184,7 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound
|
||||
} else if (GrClip::IsOutsideClip(element->getBounds(), queryBounds)) {
|
||||
skippable = true;
|
||||
} else if (!embiggens) {
|
||||
ClipResult result = this->clipOutsideElement(element, maxWindowRectangles);
|
||||
ClipResult result = this->clipOutsideElement(element);
|
||||
if (ClipResult::kMadeEmpty == result) {
|
||||
return;
|
||||
}
|
||||
@ -480,34 +484,43 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* elemen
|
||||
return ClipResult::kClipped;
|
||||
|
||||
case Element::DeviceSpaceType::kRRect:
|
||||
return this->addAnalyticFP(element->getDeviceSpaceRRect(), Invert::kNo,
|
||||
element->isAA());
|
||||
|
||||
case Element::DeviceSpaceType::kPath:
|
||||
return ClipResult::kNotClipped;
|
||||
return this->addAnalyticFP(element->getDeviceSpacePath(), Invert::kNo, element->isAA());
|
||||
}
|
||||
|
||||
SK_ABORT("Unexpected DeviceSpaceType");
|
||||
return ClipResult::kNotClipped;
|
||||
}
|
||||
|
||||
GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* element,
|
||||
int maxWindowRectangles) {
|
||||
if (fWindowRects.count() >= maxWindowRectangles) {
|
||||
return ClipResult::kNotClipped;
|
||||
}
|
||||
|
||||
GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* element) {
|
||||
switch (element->getDeviceSpaceType()) {
|
||||
case Element::DeviceSpaceType::kEmpty:
|
||||
return ClipResult::kMadeEmpty;
|
||||
|
||||
case Element::DeviceSpaceType::kRect:
|
||||
// Clip out the inside of every rect. We won't be able to entirely skip the AA ones, but
|
||||
// it saves processing time.
|
||||
this->addWindowRectangle(element->getDeviceSpaceRect(), element->isAA());
|
||||
return !element->isAA() ? ClipResult::kClipped : ClipResult::kNotClipped;
|
||||
if (fWindowRects.count() < fMaxWindowRectangles) {
|
||||
// Clip out the inside of every rect. We won't be able to entirely skip the AA ones,
|
||||
// but it saves processing time.
|
||||
this->addWindowRectangle(element->getDeviceSpaceRect(), element->isAA());
|
||||
if (!element->isAA()) {
|
||||
return ClipResult::kClipped;
|
||||
}
|
||||
}
|
||||
return this->addAnalyticFP(element->getDeviceSpaceRect(), Invert::kYes,
|
||||
element->isAA());
|
||||
|
||||
case Element::DeviceSpaceType::kRRect: {
|
||||
// Clip out the interiors of round rects with two window rectangles in the shape of a
|
||||
// plus. It doesn't allow us to skip the clip element, but still saves processing time.
|
||||
const SkRRect& clipRRect = element->getDeviceSpaceRRect();
|
||||
ClipResult clipResult = this->addAnalyticFP(clipRRect, Invert::kYes, element->isAA());
|
||||
if (fWindowRects.count() >= fMaxWindowRectangles) {
|
||||
return clipResult;
|
||||
}
|
||||
|
||||
// Clip out the interiors of round rects with two window rectangles in the shape of a
|
||||
// "plus". This doesn't let us skip the clip element, but still saves processing time.
|
||||
SkVector insetTL = clipRRect.radii(SkRRect::kUpperLeft_Corner);
|
||||
SkVector insetBR = clipRRect.radii(SkRRect::kLowerRight_Corner);
|
||||
if (SkRRect::kComplex_Type == clipRRect.getType()) {
|
||||
@ -521,24 +534,25 @@ GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* eleme
|
||||
const SkRect& bounds = clipRRect.getBounds();
|
||||
if (insetTL.x() + insetBR.x() >= bounds.width() ||
|
||||
insetTL.y() + insetBR.y() >= bounds.height()) {
|
||||
return ClipResult::kNotClipped; // The interior "plus" is empty.
|
||||
return clipResult; // The interior "plus" is empty.
|
||||
}
|
||||
|
||||
SkRect horzRect = SkRect::MakeLTRB(bounds.left(), bounds.top() + insetTL.y(),
|
||||
bounds.right(), bounds.bottom() - insetBR.y());
|
||||
this->addWindowRectangle(horzRect, element->isAA());
|
||||
if (fWindowRects.count() >= maxWindowRectangles) {
|
||||
return ClipResult::kNotClipped;
|
||||
|
||||
if (fWindowRects.count() < fMaxWindowRectangles) {
|
||||
SkRect vertRect = SkRect::MakeLTRB(bounds.left() + insetTL.x(), bounds.top(),
|
||||
bounds.right() - insetBR.x(), bounds.bottom());
|
||||
this->addWindowRectangle(vertRect, element->isAA());
|
||||
}
|
||||
|
||||
SkRect vertRect = SkRect::MakeLTRB(bounds.left() + insetTL.x(), bounds.top(),
|
||||
bounds.right() - insetBR.x(), bounds.bottom());
|
||||
this->addWindowRectangle(vertRect, element->isAA());
|
||||
return ClipResult::kNotClipped;
|
||||
return clipResult;
|
||||
}
|
||||
|
||||
case Element::DeviceSpaceType::kPath:
|
||||
return ClipResult::kNotClipped;
|
||||
return this->addAnalyticFP(element->getDeviceSpacePath(), Invert::kYes,
|
||||
element->isAA());
|
||||
}
|
||||
|
||||
SK_ABORT("Unexpected DeviceSpaceType");
|
||||
@ -557,6 +571,43 @@ inline void GrReducedClip::addWindowRectangle(const SkRect& elementInteriorRect,
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const T& deviceSpaceShape,
|
||||
Invert invert, bool aa) {
|
||||
if (fAnalyticFPs.count() >= fMaxAnalyticFPs) {
|
||||
return ClipResult::kNotClipped;
|
||||
}
|
||||
|
||||
GrClipEdgeType edgeType;
|
||||
if (Invert::kNo == invert) {
|
||||
edgeType = aa ? GrClipEdgeType::kFillAA : GrClipEdgeType::kFillBW;
|
||||
} else {
|
||||
edgeType = aa ? GrClipEdgeType::kInverseFillAA : GrClipEdgeType::kInverseFillBW;
|
||||
}
|
||||
|
||||
if (auto fp = make_analytic_clip_fp(edgeType, deviceSpaceShape)) {
|
||||
fAnalyticFPs.push_back(std::move(fp));
|
||||
return ClipResult::kClipped;
|
||||
}
|
||||
|
||||
return ClipResult::kNotClipped;
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType,
|
||||
const SkRect& deviceSpaceRect) {
|
||||
return GrConvexPolyEffect::Make(edgeType, deviceSpaceRect);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType,
|
||||
const SkRRect& deviceSpaceRRect) {
|
||||
return GrRRectEffect::Make(edgeType, deviceSpaceRRect);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType,
|
||||
const SkPath& deviceSpacePath) {
|
||||
return GrConvexPolyEffect::Make(edgeType, deviceSpacePath);
|
||||
}
|
||||
|
||||
void GrReducedClip::makeEmpty() {
|
||||
fHasScissor = false;
|
||||
fAAClipRectGenID = SK_InvalidGenID;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#ifndef GrReducedClip_DEFINED
|
||||
#define GrReducedClip_DEFINED
|
||||
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrWindowRectangles.h"
|
||||
#include "SkClipStack.h"
|
||||
#include "SkTLList.h"
|
||||
@ -24,7 +25,8 @@ public:
|
||||
using Element = SkClipStack::Element;
|
||||
using ElementList = SkTLList<SkClipStack::Element, 16>;
|
||||
|
||||
GrReducedClip(const SkClipStack&, const SkRect& queryBounds, int maxWindowRectangles = 0);
|
||||
GrReducedClip(const SkClipStack&, const SkRect& queryBounds,
|
||||
int maxWindowRectangles = 0, int maxAnalyticFPs = 0);
|
||||
|
||||
/**
|
||||
* If hasScissor() is true, the clip mask is not valid outside this rect and the caller must
|
||||
@ -48,6 +50,13 @@ public:
|
||||
*/
|
||||
const GrWindowRectangles& windowRectangles() const { return fWindowRects; }
|
||||
|
||||
int numAnalyticFPs() const { return fAnalyticFPs.count(); }
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> detachAnalyticFPs() {
|
||||
SkDEBUGCODE(for (const auto& fp : fAnalyticFPs) { SkASSERT(fp); })
|
||||
return GrFragmentProcessor::RunInSeries(fAnalyticFPs.begin(), fAnalyticFPs.count());
|
||||
}
|
||||
|
||||
/**
|
||||
* An ordered list of clip elements that could not be skipped or implemented by other means. If
|
||||
* nonempty, the caller must create an alpha and/or stencil mask for these elements and apply it
|
||||
@ -81,7 +90,7 @@ public:
|
||||
bool drawStencilClipMask(GrContext*, GrRenderTargetContext*) const;
|
||||
|
||||
private:
|
||||
void walkStack(const SkClipStack&, const SkRect& queryBounds, int maxWindowRectangles);
|
||||
void walkStack(const SkClipStack&, const SkRect& queryBounds);
|
||||
|
||||
enum class ClipResult {
|
||||
kNotClipped,
|
||||
@ -91,24 +100,35 @@ private:
|
||||
|
||||
// Clips the the given element's interior out of the final clip.
|
||||
// NOTE: do not call for elements followed by ops that can grow the clip.
|
||||
ClipResult clipInsideElement(const Element* element);
|
||||
ClipResult clipInsideElement(const Element*);
|
||||
|
||||
// Clips the the given element's exterior out of the final clip.
|
||||
// NOTE: do not call for elements followed by ops that can grow the clip.
|
||||
ClipResult clipOutsideElement(const Element* element, int maxWindowRectangles);
|
||||
ClipResult clipOutsideElement(const Element*);
|
||||
|
||||
void addWindowRectangle(const SkRect& elementInteriorRect, bool elementIsAA);
|
||||
|
||||
enum class Invert : bool {
|
||||
kNo,
|
||||
kYes
|
||||
};
|
||||
|
||||
template<typename T> ClipResult addAnalyticFP(const T& deviceSpaceShape, Invert, bool aa);
|
||||
|
||||
void makeEmpty();
|
||||
|
||||
SkIRect fScissor;
|
||||
bool fHasScissor;
|
||||
SkRect fAAClipRect;
|
||||
uint32_t fAAClipRectGenID; // GenID the mask will have if includes the AA clip rect.
|
||||
GrWindowRectangles fWindowRects;
|
||||
ElementList fMaskElements;
|
||||
uint32_t fMaskGenID;
|
||||
bool fMaskRequiresAA;
|
||||
InitialState fInitialState;
|
||||
const int fMaxWindowRectangles;
|
||||
const int fMaxAnalyticFPs;
|
||||
SkIRect fScissor;
|
||||
bool fHasScissor;
|
||||
SkRect fAAClipRect;
|
||||
uint32_t fAAClipRectGenID; // GenID the mask will have if includes the AA clip rect.
|
||||
GrWindowRectangles fWindowRects;
|
||||
SkSTArray<4, std::unique_ptr<GrFragmentProcessor>> fAnalyticFPs;
|
||||
ElementList fMaskElements;
|
||||
uint32_t fMaskGenID;
|
||||
bool fMaskRequiresAA;
|
||||
InitialState fInitialState;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -29,18 +29,22 @@ public:
|
||||
|
||||
// called to note the last clip drawn to the stencil buffer.
|
||||
// TODO: remove after clipping overhaul.
|
||||
void setLastClip(uint32_t clipStackGenID, const SkIRect& devClipBounds) {
|
||||
void setLastClip(uint32_t clipStackGenID, const SkIRect& devClipBounds,
|
||||
int numClipAnalyticFPs) {
|
||||
GrRenderTargetOpList* opList = fRenderTargetContext->getRTOpList();
|
||||
opList->fLastClipStackGenID = clipStackGenID;
|
||||
opList->fLastDevClipBounds = devClipBounds;
|
||||
opList->fLastClipNumAnalyticFPs = numClipAnalyticFPs;
|
||||
}
|
||||
|
||||
// called to determine if we have to render the clip into SB.
|
||||
// TODO: remove after clipping overhaul.
|
||||
bool mustRenderClip(uint32_t clipStackGenID, const SkIRect& devClipBounds) const {
|
||||
bool mustRenderClip(uint32_t clipStackGenID, const SkIRect& devClipBounds,
|
||||
int numClipAnalyticFPs) const {
|
||||
GrRenderTargetOpList* opList = fRenderTargetContext->getRTOpList();
|
||||
return opList->fLastClipStackGenID != clipStackGenID ||
|
||||
!opList->fLastDevClipBounds.contains(devClipBounds);
|
||||
!opList->fLastDevClipBounds.contains(devClipBounds) ||
|
||||
opList->fLastClipNumAnalyticFPs != numClipAnalyticFPs;
|
||||
}
|
||||
|
||||
void clear(const GrFixedClip&, const GrColor, bool canIgnoreClip);
|
||||
|
@ -156,6 +156,7 @@ private:
|
||||
|
||||
uint32_t fLastClipStackGenID;
|
||||
SkIRect fLastDevClipBounds;
|
||||
int fLastClipNumAnalyticFPs;
|
||||
|
||||
// For ops/opList we have mean: 5 stdDev: 28
|
||||
SkSTArray<5, RecordedOp, true> fRecordedOps;
|
||||
|
@ -527,6 +527,13 @@ void GrGLCaps::init(const GrContextOptions& contextOptions,
|
||||
GR_GL_GetIntegerv(gli, GR_GL_MAX_WINDOW_RECTANGLES, &fMaxWindowRectangles);
|
||||
}
|
||||
|
||||
if (kPowerVRRogue_GrGLRenderer == ctxInfo.renderer()) {
|
||||
// Temporarily disabling clip analytic fragments processors on Nexus player while we work
|
||||
// around a driver bug related to gl_FragCoord.
|
||||
// https://bugs.chromium.org/p/skia/issues/detail?id=7286
|
||||
fMaxClipAnalyticFPs = 0;
|
||||
}
|
||||
|
||||
#ifndef SK_BUILD_FOR_IOS
|
||||
if (kPowerVR54x_GrGLRenderer == ctxInfo.renderer() ||
|
||||
kPowerVRRogue_GrGLRenderer == ctxInfo.renderer() ||
|
||||
|
Loading…
Reference in New Issue
Block a user