Avoid GrEllipseEffect for small radii on devices without 32 bit float.
Also limit small radius bail in GrCircleEffect to clip out cases. Change-Id: I14ce736969b05203219d68f30283c36c84f78f3a Reviewed-on: https://skia-review.googlesource.com/80621 Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Brian Salomon <bsalomon@google.com>
This commit is contained in:
parent
bb4b20a265
commit
1447177005
@ -77,7 +77,8 @@ protected:
|
||||
|
||||
SkRRect rrect = fRRect;
|
||||
rrect.offset(SkIntToScalar(x + kGap), SkIntToScalar(y + kGap));
|
||||
std::unique_ptr<GrFragmentProcessor> fp(GrRRectEffect::Make(edgeType, rrect));
|
||||
const auto& caps = *renderTargetContext->caps()->shaderCaps();
|
||||
auto fp = GrRRectEffect::Make(edgeType, rrect, caps);
|
||||
SkASSERT(fp);
|
||||
if (fp) {
|
||||
GrPaint grPaint;
|
||||
|
@ -106,7 +106,8 @@ protected:
|
||||
SkRRect rrect = fRRects[curRRect];
|
||||
rrect.offset(SkIntToScalar(x), SkIntToScalar(y));
|
||||
GrClipEdgeType edgeType = (GrClipEdgeType) et;
|
||||
auto fp = GrRRectEffect::Make(edgeType, rrect);
|
||||
const auto& caps = *renderTargetContext->caps()->shaderCaps();
|
||||
auto fp = GrRRectEffect::Make(edgeType, rrect, caps);
|
||||
if (fp) {
|
||||
GrPaint grPaint;
|
||||
grPaint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
|
||||
|
@ -181,7 +181,8 @@ void WindowRectanglesMaskGM::onCoverClipStack(const SkClipStack& stack, SkCanvas
|
||||
return;
|
||||
}
|
||||
|
||||
const GrReducedClip reducedClip(stack, SkRect::Make(kCoverRect), kNumWindows);
|
||||
const GrReducedClip reducedClip(stack, SkRect::Make(kCoverRect), rtc->caps()->shaderCaps(),
|
||||
kNumWindows);
|
||||
|
||||
GrPaint paint;
|
||||
if (GrFSAAType::kNone == rtc->fsaaType()) {
|
||||
|
@ -201,8 +201,9 @@ bool GrClipStackClip::apply(GrContext* context, GrRenderTargetContext* renderTar
|
||||
SkASSERT(!context->caps()->avoidStencilBuffers()); // We disable MSAA when avoiding stencil.
|
||||
}
|
||||
|
||||
GrReducedClip reducedClip(*fStack, devBounds, renderTargetContext->priv().maxWindowRectangles(),
|
||||
maxAnalyticFPs);
|
||||
const auto* caps = context->caps()->shaderCaps();
|
||||
GrReducedClip reducedClip(*fStack, devBounds, caps,
|
||||
renderTargetContext->priv().maxWindowRectangles(), maxAnalyticFPs);
|
||||
|
||||
if (reducedClip.hasScissor() && !GrClip::IsInsideClip(reducedClip.scissor(), devBounds)) {
|
||||
out->hardClip().addScissor(reducedClip.scissor(), bounds);
|
||||
|
@ -32,9 +32,8 @@
|
||||
* 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 maxAnalyticFPs)
|
||||
: fMaxWindowRectangles(maxWindowRectangles)
|
||||
, fMaxAnalyticFPs(maxAnalyticFPs) {
|
||||
const GrShaderCaps* caps, int maxWindowRectangles, int maxAnalyticFPs)
|
||||
: fCaps(caps), fMaxWindowRectangles(maxWindowRectangles), fMaxAnalyticFPs(maxAnalyticFPs) {
|
||||
SkASSERT(!queryBounds.isEmpty());
|
||||
SkASSERT(fMaxWindowRectangles <= GrWindowRectangles::kMaxWindows);
|
||||
fHasScissor = false;
|
||||
@ -588,7 +587,7 @@ inline GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const T& deviceSpa
|
||||
: GrClipEdgeType::kInverseFillBW;
|
||||
}
|
||||
|
||||
if (auto fp = make_analytic_clip_fp(edgeType, deviceSpaceShape)) {
|
||||
if (auto fp = make_analytic_clip_fp(edgeType, deviceSpaceShape, *fCaps)) {
|
||||
fAnalyticFPs.push_back(std::move(fp));
|
||||
return ClipResult::kClipped;
|
||||
}
|
||||
@ -597,17 +596,20 @@ inline GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const T& deviceSpa
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType,
|
||||
const SkRect& deviceSpaceRect) {
|
||||
const SkRect& deviceSpaceRect,
|
||||
const GrShaderCaps&) {
|
||||
return GrConvexPolyEffect::Make(edgeType, deviceSpaceRect);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType,
|
||||
const SkRRect& deviceSpaceRRect) {
|
||||
return GrRRectEffect::Make(edgeType, deviceSpaceRRect);
|
||||
const SkRRect& deviceSpaceRRect,
|
||||
const GrShaderCaps& caps) {
|
||||
return GrRRectEffect::Make(edgeType, deviceSpaceRRect, caps);
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> make_analytic_clip_fp(GrClipEdgeType edgeType,
|
||||
const SkPath& deviceSpacePath) {
|
||||
const SkPath& deviceSpacePath,
|
||||
const GrShaderCaps&) {
|
||||
return GrConvexPolyEffect::Make(edgeType, deviceSpacePath);
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
using Element = SkClipStack::Element;
|
||||
using ElementList = SkTLList<SkClipStack::Element, 16>;
|
||||
|
||||
GrReducedClip(const SkClipStack&, const SkRect& queryBounds,
|
||||
GrReducedClip(const SkClipStack&, const SkRect& queryBounds, const GrShaderCaps* caps,
|
||||
int maxWindowRectangles = 0, int maxAnalyticFPs = 0);
|
||||
|
||||
/**
|
||||
@ -117,6 +117,7 @@ private:
|
||||
|
||||
void makeEmpty();
|
||||
|
||||
const GrShaderCaps* fCaps;
|
||||
const int fMaxWindowRectangles;
|
||||
const int fMaxAnalyticFPs;
|
||||
SkIRect fScissor;
|
||||
|
@ -1276,13 +1276,14 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip,
|
||||
inverseVM.reset();
|
||||
}
|
||||
|
||||
const auto& caps = *this->caps()->shaderCaps();
|
||||
// TODO these need to be a geometry processors
|
||||
std::unique_ptr<GrFragmentProcessor> innerEffect(GrRRectEffect::Make(innerEdgeType, *inner));
|
||||
auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps);
|
||||
if (!innerEffect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> outerEffect(GrRRectEffect::Make(outerEdgeType, *outer));
|
||||
auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps);
|
||||
if (!outerEffect) {
|
||||
return false;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ uniform half4 circle;
|
||||
float radius) {
|
||||
// A radius below half causes the implicit insetting done by this processor to become
|
||||
// inverted. We could handle this case by making the processor code more complicated.
|
||||
if (radius < .5f) {
|
||||
if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius));
|
||||
|
@ -24,7 +24,7 @@ public:
|
||||
float radius) {
|
||||
// A radius below half causes the implicit insetting done by this processor to become
|
||||
// inverted. We could handle this case by making the processor code more complicated.
|
||||
if (radius < .5f) {
|
||||
if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius));
|
||||
|
@ -139,7 +139,8 @@ std::unique_ptr<GrFragmentProcessor> GrEllipseEffect::TestCreate(GrProcessorTest
|
||||
do {
|
||||
et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
|
||||
} while (GrClipEdgeType::kHairlineAA == et);
|
||||
return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry));
|
||||
return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry),
|
||||
*testData->caps()->shaderCaps());
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -5,6 +5,10 @@
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
@header {
|
||||
#include "GrShaderCaps.h"
|
||||
}
|
||||
|
||||
layout(key) in GrClipEdgeType edgeType;
|
||||
in float2 center;
|
||||
in float2 radii;
|
||||
@ -18,6 +22,17 @@ uniform float4 ellipse;
|
||||
bool useScale = !sk_Caps.floatIs32Bits;
|
||||
layout(when=useScale) uniform float2 scale;
|
||||
|
||||
@make {
|
||||
static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center,
|
||||
SkPoint radii, const GrShaderCaps& caps) {
|
||||
// Small radii produce bad results on devices without full float.
|
||||
if (!caps.floatIs32Bits() && (radii.fX < 0.5f || radii.fY < 0.5f)) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrEllipseEffect(edgeType, center, radii));
|
||||
}
|
||||
}
|
||||
|
||||
@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag }
|
||||
|
||||
@setData(pdman) {
|
||||
@ -101,5 +116,6 @@ void main() {
|
||||
do {
|
||||
et = (GrClipEdgeType) testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
|
||||
} while (GrClipEdgeType::kHairlineAA == et);
|
||||
return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry));
|
||||
return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry),
|
||||
*testData->caps()->shaderCaps());
|
||||
}
|
||||
|
@ -12,6 +12,8 @@
|
||||
#define GrEllipseEffect_DEFINED
|
||||
#include "SkTypes.h"
|
||||
#if SK_SUPPORT_GPU
|
||||
|
||||
#include "GrShaderCaps.h"
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrCoordTransform.h"
|
||||
class GrEllipseEffect : public GrFragmentProcessor {
|
||||
@ -19,8 +21,13 @@ public:
|
||||
GrClipEdgeType edgeType() const { return fEdgeType; }
|
||||
SkPoint center() const { return fCenter; }
|
||||
SkPoint radii() const { return fRadii; }
|
||||
|
||||
static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center,
|
||||
SkPoint radii) {
|
||||
SkPoint radii, const GrShaderCaps& caps) {
|
||||
// Small radii produce bad results on devices without full float.
|
||||
if (!caps.floatIs32Bits() && (radii.fX < 0.5f || radii.fY < 0.5f)) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::unique_ptr<GrFragmentProcessor>(new GrEllipseEffect(edgeType, center, radii));
|
||||
}
|
||||
GrEllipseEffect(const GrEllipseEffect& src);
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "GrEllipseEffect.h"
|
||||
#include "SkRect.h"
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> GrOvalEffect::Make(GrClipEdgeType edgeType,
|
||||
const SkRect& oval) {
|
||||
std::unique_ptr<GrFragmentProcessor> GrOvalEffect::Make(GrClipEdgeType edgeType, const SkRect& oval,
|
||||
const GrShaderCaps& caps) {
|
||||
if (GrClipEdgeType::kHairlineAA == edgeType) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -26,7 +26,7 @@ std::unique_ptr<GrFragmentProcessor> GrOvalEffect::Make(GrClipEdgeType edgeType,
|
||||
w /= 2;
|
||||
h /= 2;
|
||||
return GrEllipseEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h),
|
||||
SkPoint::Make(w, h));
|
||||
SkPoint::Make(w, h), caps);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
class GrFragmentProcessor;
|
||||
class GrShaderCaps;
|
||||
struct SkRect;
|
||||
|
||||
namespace GrOvalEffect {
|
||||
@ -20,8 +21,7 @@ namespace GrOvalEffect {
|
||||
/**
|
||||
* Creates an effect that performs clipping against an oval.
|
||||
*/
|
||||
std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRect&);
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRect&, const GrShaderCaps&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -122,7 +122,7 @@ std::unique_ptr<GrFragmentProcessor> CircularRRectEffect::TestCreate(GrProcessor
|
||||
do {
|
||||
GrClipEdgeType et =
|
||||
(GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
|
||||
fp = GrRRectEffect::Make(et, rrect);
|
||||
fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps());
|
||||
} while (nullptr == fp);
|
||||
return fp;
|
||||
}
|
||||
@ -473,7 +473,7 @@ std::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::TestCreate(GrProcess
|
||||
std::unique_ptr<GrFragmentProcessor> fp;
|
||||
do {
|
||||
GrClipEdgeType et = (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt);
|
||||
fp = GrRRectEffect::Make(et, rrect);
|
||||
fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps());
|
||||
} while (nullptr == fp);
|
||||
return fp;
|
||||
}
|
||||
@ -673,13 +673,14 @@ GrGLSLFragmentProcessor* EllipticalRRectEffect::onCreateGLSLInstance() const {
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType,
|
||||
const SkRRect& rrect) {
|
||||
const SkRRect& rrect,
|
||||
const GrShaderCaps& caps) {
|
||||
if (rrect.isRect()) {
|
||||
return GrConvexPolyEffect::Make(edgeType, rrect.getBounds());
|
||||
}
|
||||
|
||||
if (rrect.isOval()) {
|
||||
return GrOvalEffect::Make(edgeType, rrect.getBounds());
|
||||
return GrOvalEffect::Make(edgeType, rrect.getBounds(), caps);
|
||||
}
|
||||
|
||||
if (rrect.isSimple()) {
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "SkRefCnt.h"
|
||||
|
||||
class GrFragmentProcessor;
|
||||
class GrShaderCaps;
|
||||
class GrProcessor;
|
||||
class SkRRect;
|
||||
|
||||
@ -22,8 +23,7 @@ namespace GrRRectEffect {
|
||||
* Creates an effect that performs anti-aliased clipping against a SkRRect. It doesn't support
|
||||
* all varieties of SkRRect so the caller must check for a nullptr return.
|
||||
*/
|
||||
std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRRect&);
|
||||
|
||||
std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRRect&, const GrShaderCaps&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1019,6 +1019,9 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
|
||||
}
|
||||
}
|
||||
|
||||
auto context = GrContext::MakeMock(nullptr);
|
||||
const auto* caps = context->caps()->shaderCaps();
|
||||
|
||||
// Zero the memory we will new the GrReducedClip into. This ensures the elements gen ID
|
||||
// will be kInvalidGenID if left uninitialized.
|
||||
SkAlignedSTStorage<1, GrReducedClip> storage;
|
||||
@ -1028,7 +1031,7 @@ static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
|
||||
// Get the reduced version of the stack.
|
||||
SkRect queryBounds = kBounds;
|
||||
queryBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
|
||||
const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, queryBounds);
|
||||
const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, queryBounds, caps);
|
||||
|
||||
REPORTER_ASSERT_MESSAGE(reporter,
|
||||
reduced->maskElements().isEmpty() ||
|
||||
@ -1087,10 +1090,13 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
|
||||
kReplace_SkClipOp, true);
|
||||
SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
|
||||
|
||||
auto context = GrContext::MakeMock(nullptr);
|
||||
const auto* caps = context->caps()->shaderCaps();
|
||||
|
||||
SkAlignedSTStorage<1, GrReducedClip> storage;
|
||||
memset(storage.get(), 0, sizeof(GrReducedClip));
|
||||
GR_STATIC_ASSERT(0 == SkClipStack::kInvalidGenID);
|
||||
const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, bounds);
|
||||
const GrReducedClip* reduced = new (storage.get()) GrReducedClip(stack, bounds, caps);
|
||||
|
||||
REPORTER_ASSERT(reporter, reduced->maskElements().count() == 1);
|
||||
// Clips will be cached based on the generation id. Make sure the gen id is valid.
|
||||
@ -1173,9 +1179,11 @@ static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
|
||||
|
||||
#undef XYWH
|
||||
#undef IXYWH
|
||||
auto context = GrContext::MakeMock(nullptr);
|
||||
const auto* caps = context->caps()->shaderCaps();
|
||||
|
||||
for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) {
|
||||
const GrReducedClip reduced(stack, testCases[i].testBounds);
|
||||
const GrReducedClip reduced(stack, testCases[i].testBounds, caps);
|
||||
REPORTER_ASSERT(reporter, reduced.maskElements().count() ==
|
||||
testCases[i].reducedClipCount);
|
||||
SkASSERT(reduced.maskElements().count() == testCases[i].reducedClipCount);
|
||||
@ -1199,8 +1207,11 @@ static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) {
|
||||
stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), kReplace_SkClipOp);
|
||||
SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
|
||||
|
||||
auto context = GrContext::MakeMock(nullptr);
|
||||
const auto* caps = context->caps()->shaderCaps();
|
||||
|
||||
// At the time, this would crash.
|
||||
const GrReducedClip reduced(stack, bounds);
|
||||
const GrReducedClip reduced(stack, bounds, caps);
|
||||
REPORTER_ASSERT(reporter, reduced.maskElements().isEmpty());
|
||||
}
|
||||
|
||||
@ -1215,9 +1226,12 @@ static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName
|
||||
const SkClipStack& stack, const SkMatrix& queryXform,
|
||||
const SkRect& preXformQuery, ClipMethod expectedMethod,
|
||||
int numExpectedElems = 0) {
|
||||
auto context = GrContext::MakeMock(nullptr);
|
||||
const auto* caps = context->caps()->shaderCaps();
|
||||
|
||||
SkRect queryBounds;
|
||||
queryXform.mapRect(&queryBounds, preXformQuery);
|
||||
const GrReducedClip reduced(stack, queryBounds);
|
||||
const GrReducedClip reduced(stack, queryBounds, caps);
|
||||
|
||||
SkClipStack::BoundsType stackBoundsType;
|
||||
SkRect stackBounds;
|
||||
@ -1377,12 +1391,15 @@ static void test_tiny_query_bounds_assertion_bug(skiatest::Reporter* reporter) {
|
||||
SkClipStack pathStack;
|
||||
pathStack.clipPath(clipPath, SkMatrix::I(), kIntersect_SkClipOp, true);
|
||||
|
||||
auto context = GrContext::MakeMock(nullptr);
|
||||
const auto* caps = context->caps()->shaderCaps();
|
||||
|
||||
for (const SkClipStack& stack : {rectStack, pathStack}) {
|
||||
for (SkRect queryBounds : {SkRect::MakeXYWH(53, 60, GrClip::kBoundsTolerance, 1000),
|
||||
SkRect::MakeXYWH(53, 60, GrClip::kBoundsTolerance/2, 1000),
|
||||
SkRect::MakeXYWH(53, 160, 1000, GrClip::kBoundsTolerance),
|
||||
SkRect::MakeXYWH(53, 160, 1000, GrClip::kBoundsTolerance/2)}) {
|
||||
const GrReducedClip reduced(stack, queryBounds);
|
||||
const GrReducedClip reduced(stack, queryBounds, caps);
|
||||
REPORTER_ASSERT(reporter, !reduced.hasScissor());
|
||||
REPORTER_ASSERT(reporter, reduced.maskElements().isEmpty());
|
||||
REPORTER_ASSERT(reporter,
|
||||
|
Loading…
Reference in New Issue
Block a user