Revert of Optimized implementation of quickReject() (patchset #12 id:260001 of https://codereview.chromium.org/2225393002/ )
Reason for revert: New assert triggering in the Chrome roll, https://build.chromium.org/p/tryserver.chromium.linux/builders/linux_chromium_asan_rel_ng/builds/208750/steps/webkit_unit_tests%20%28with%20patch%29%20on%20Ubuntu-12.04/logs/FrameThrottlingTest.SynchronousLayoutInAnimationFrameCallback and breaks the SKNX_NO_SIMD bot, https://codereview.chromium.org/2236363004 Original issue's description: > Optimized implementation of quickReject() > > Impl Overview > (1) Keep the device clip bounds up to date. This > requires minimal additional work in a few places > throughout canvas. > (2) Keep track of if the ctm isScaleTranslate. Yes, > there's a function that does this, but it's slow > to call. > (3) Perform the src->device transform in quick reject, > then check intersection/nan. > > Other Notes: > (1) NaN and intersection checks are performed > simultaneously. > (2) We no longer quick reject infinity. > (3) Affine and perspective are both handled in the slow > case. > (4) SkRasterClip::isEmpty() is handled by the intersection > check. > > Performance on Nexus 6P: > 93.2ms -> 59.8ms > > Overall Android Jank Tests Performance Impact: > Should gain us a ms or two on some tests. > > BUG=skia: > GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2225393002 > > Committed: https://skia.googlesource.com/skia/+/d22a817ff57986407facd16af36320fc86ce02da TBR=reed@google.com,herb@google.com,msarett@google.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/2231393003
This commit is contained in:
parent
cf736d7b66
commit
5aeb2fa253
@ -1,61 +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.
|
||||
*/
|
||||
|
||||
#include "Benchmark.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkRandom.h"
|
||||
|
||||
class QuickRejectBench : public Benchmark {
|
||||
enum { N = 1000000 };
|
||||
float fFloats[N];
|
||||
int fInts [N];
|
||||
|
||||
const char* onGetName() override { return "quick_reject"; }
|
||||
bool isSuitableFor(Backend backend) override { return backend != kNonRendering_Backend; }
|
||||
|
||||
void onDelayedSetup() override {
|
||||
SkRandom rand;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
fFloats[i] = 300.0f * (rand.nextSScalar1() + 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
void onDraw(int loops, SkCanvas* canvas) override {
|
||||
while (loops --> 0) {
|
||||
for (int i = 0; i < N - 4; i++) {
|
||||
if (canvas->quickReject(*(SkRect*)(fFloats+i))) {
|
||||
fInts[i] = 11;
|
||||
} else {
|
||||
fInts[i] = 24;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
DEF_BENCH( return new QuickRejectBench; )
|
||||
|
||||
class ConcatBench : public Benchmark {
|
||||
SkMatrix fMatrix;
|
||||
|
||||
const char* onGetName() override { return "concat"; }
|
||||
bool isSuitableFor(Backend backend) override { return backend != kNonRendering_Backend; }
|
||||
|
||||
void onDelayedSetup() override {
|
||||
SkRandom r;
|
||||
fMatrix.setScale(5.0f, 5.0f);
|
||||
fMatrix.setTranslateX(10.0f);
|
||||
fMatrix.setTranslateY(10.0f);
|
||||
}
|
||||
|
||||
void onDraw(int loops, SkCanvas* canvas) override {
|
||||
while (loops --> 0) {
|
||||
canvas->setMatrix(SkMatrix::MakeScale(3.0f));
|
||||
canvas->concat(fMatrix);
|
||||
}
|
||||
}
|
||||
};
|
||||
DEF_BENCH( return new ConcatBench; )
|
@ -1609,18 +1609,25 @@ private:
|
||||
*/
|
||||
bool canDrawBitmapAsSprite(SkScalar x, SkScalar y, int w, int h, const SkPaint&);
|
||||
|
||||
|
||||
/**
|
||||
* Keep track of the device clip bounds and if the matrix is scale-translate. This allows
|
||||
* us to do a fast quick reject in the common case.
|
||||
/* These maintain a cache of the clip bounds in local coordinates,
|
||||
(converted to 2s-compliment if floats are slow).
|
||||
*/
|
||||
bool fConservativeIsScaleTranslate;
|
||||
SkRect fDeviceClipBounds;
|
||||
|
||||
mutable SkRect fCachedLocalClipBounds;
|
||||
mutable bool fCachedLocalClipBoundsDirty;
|
||||
bool fAllowSoftClip;
|
||||
bool fAllowSimplifyClip;
|
||||
const bool fConservativeRasterClip;
|
||||
|
||||
const SkRect& getLocalClipBounds() const {
|
||||
if (fCachedLocalClipBoundsDirty) {
|
||||
if (!this->getClipBounds(&fCachedLocalClipBounds)) {
|
||||
fCachedLocalClipBounds.setEmpty();
|
||||
}
|
||||
fCachedLocalClipBoundsDirty = false;
|
||||
}
|
||||
return fCachedLocalClipBounds;
|
||||
}
|
||||
|
||||
class AutoValidateClip : ::SkNoncopyable {
|
||||
public:
|
||||
explicit AutoValidateClip(SkCanvas* canvas) : fCanvas(canvas) {
|
||||
|
@ -275,18 +275,6 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* If your judgment is better than the compiler's (i.e. you've profiled it),
|
||||
* you can use SK_NEVER_INLINE to prevent inlining.
|
||||
*/
|
||||
#if !defined(SK_NEVER_INLINE)
|
||||
# if defined(SK_BUILD_FOR_WIN)
|
||||
# define SK_NEVER_INLINE __declspec(noinline)
|
||||
# else
|
||||
# define SK_NEVER_INLINE SK_ATTRIBUTE(noinline)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE1
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "SkLatticeIter.h"
|
||||
#include "SkMatrixUtils.h"
|
||||
#include "SkMetaData.h"
|
||||
#include "SkNx.h"
|
||||
#include "SkPaintPriv.h"
|
||||
#include "SkPatchUtils.h"
|
||||
#include "SkPicture.h"
|
||||
@ -633,24 +632,16 @@ bool AutoDrawLooper::doNext(SkDrawFilter::Type drawType) {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static inline SkRect qr_clip_bounds(const SkIRect& bounds) {
|
||||
// Expand bounds out by 1 in case we are anti-aliasing. We store the
|
||||
// bounds as floats to enable a faster quick reject implementation.
|
||||
SkRect dst;
|
||||
SkNx_cast<float>(Sk4i::Load(&bounds.fLeft) + Sk4i(-1,-1,1,1)).store(&dst.fLeft);
|
||||
return dst;
|
||||
}
|
||||
|
||||
void SkCanvas::resetForNextPicture(const SkIRect& bounds) {
|
||||
this->restoreToCount(1);
|
||||
fCachedLocalClipBounds.setEmpty();
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
fClipStack->reset();
|
||||
fMCRec->reset(bounds);
|
||||
|
||||
// We're peering through a lot of structs here. Only at this scope do we
|
||||
// know that the device is an SkBitmapDevice (really an SkNoPixelsBitmapDevice).
|
||||
static_cast<SkBitmapDevice*>(fMCRec->fLayer->fDevice)->setNewSize(bounds.size());
|
||||
fDeviceClipBounds = qr_clip_bounds(bounds);
|
||||
fConservativeIsScaleTranslate = true;
|
||||
}
|
||||
|
||||
SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
|
||||
@ -661,6 +652,8 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
|
||||
// const-cast.
|
||||
*const_cast<bool*>(&fConservativeRasterClip) = SkToBool(flags & kConservativeRasterClip_InitFlag);
|
||||
|
||||
fCachedLocalClipBounds.setEmpty();
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
fAllowSoftClip = true;
|
||||
fAllowSimplifyClip = false;
|
||||
fDeviceCMDirty = true;
|
||||
@ -689,10 +682,7 @@ SkBaseDevice* SkCanvas::init(SkBaseDevice* device, InitFlags flags) {
|
||||
SkASSERT(fProps.pixelGeometry() == device->surfaceProps().pixelGeometry());
|
||||
fMCRec->fLayer->fDevice = SkRef(device);
|
||||
fMCRec->fRasterClip.setRect(device->getGlobalBounds());
|
||||
fDeviceClipBounds = qr_clip_bounds(device->getGlobalBounds());
|
||||
fConservativeIsScaleTranslate = true;
|
||||
}
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
@ -1107,8 +1097,8 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlag
|
||||
// early exit if the layer's bounds are clipped out
|
||||
if (!ir.intersect(clipBounds)) {
|
||||
if (BoundsAffectsClip(saveLayerFlags)) {
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
fMCRec->fRasterClip.setEmpty();
|
||||
fDeviceClipBounds.setEmpty();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -1119,9 +1109,9 @@ bool SkCanvas::clipRectBounds(const SkRect* bounds, SaveLayerFlags saveLayerFlag
|
||||
|
||||
if (BoundsAffectsClip(saveLayerFlags)) {
|
||||
// Simplify the current clips since they will be applied properly during restore()
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
fClipStack->clipDevRect(ir, SkRegion::kReplace_Op);
|
||||
fMCRec->fRasterClip.setRect(ir);
|
||||
fDeviceClipBounds = qr_clip_bounds(ir);
|
||||
}
|
||||
|
||||
if (intersection) {
|
||||
@ -1313,6 +1303,7 @@ void SkCanvas::internalRestore() {
|
||||
SkASSERT(fMCStack.count() != 0);
|
||||
|
||||
fDeviceCMDirty = true;
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
|
||||
fClipStack->restore();
|
||||
|
||||
@ -1346,11 +1337,6 @@ void SkCanvas::internalRestore() {
|
||||
// no need to update fMCRec, 'cause we're killing the canvas
|
||||
}
|
||||
}
|
||||
|
||||
if (fMCRec) {
|
||||
fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
|
||||
fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
|
||||
}
|
||||
}
|
||||
|
||||
sk_sp<SkSurface> SkCanvas::makeSurface(const SkImageInfo& info, const SkSurfaceProps* props) {
|
||||
@ -1505,20 +1491,21 @@ void SkCanvas::concat(const SkMatrix& matrix) {
|
||||
|
||||
this->checkForDeferredSave();
|
||||
fDeviceCMDirty = true;
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
fMCRec->fMatrix.preConcat(matrix);
|
||||
fConservativeIsScaleTranslate = fMCRec->fMatrix.isScaleTranslate();
|
||||
|
||||
this->didConcat(matrix);
|
||||
}
|
||||
|
||||
void SkCanvas::internalSetMatrix(const SkMatrix& matrix) {
|
||||
fDeviceCMDirty = true;
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
fMCRec->fMatrix = matrix;
|
||||
}
|
||||
|
||||
void SkCanvas::setMatrix(const SkMatrix& matrix) {
|
||||
this->checkForDeferredSave();
|
||||
this->internalSetMatrix(matrix);
|
||||
fConservativeIsScaleTranslate = matrix.isScaleTranslate();
|
||||
this->didSetMatrix(matrix);
|
||||
}
|
||||
|
||||
@ -1590,7 +1577,6 @@ void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
|
||||
|
||||
fClipStack->clipEmpty();
|
||||
(void)fMCRec->fRasterClip.setEmpty();
|
||||
fDeviceClipBounds.setEmpty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1620,6 +1606,7 @@ void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
|
||||
AutoValidateClip avc(this);
|
||||
|
||||
fDeviceCMDirty = true;
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
|
||||
if (isScaleTrans) {
|
||||
const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;
|
||||
@ -1635,8 +1622,6 @@ void SkCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edg
|
||||
path.addRect(rect);
|
||||
this->SkCanvas::onClipPath(path, op, edgeStyle);
|
||||
}
|
||||
|
||||
fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
|
||||
}
|
||||
|
||||
void SkCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
|
||||
@ -1655,6 +1640,7 @@ void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
|
||||
AutoValidateClip avc(this);
|
||||
|
||||
fDeviceCMDirty = true;
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
if (!fAllowSoftClip) {
|
||||
edgeStyle = kHard_ClipEdgeStyle;
|
||||
}
|
||||
@ -1663,7 +1649,6 @@ void SkCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle
|
||||
|
||||
fMCRec->fRasterClip.op(transformedRRect, this->getTopLayerBounds(), op,
|
||||
kSoft_ClipEdgeStyle == edgeStyle);
|
||||
fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1711,7 +1696,6 @@ void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
|
||||
|
||||
fClipStack->clipEmpty();
|
||||
(void)fMCRec->fRasterClip.setEmpty();
|
||||
fDeviceClipBounds.setEmpty();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1720,6 +1704,7 @@ void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
|
||||
AutoValidateClip avc(this);
|
||||
|
||||
fDeviceCMDirty = true;
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
if (!fAllowSoftClip) {
|
||||
edgeStyle = kHard_ClipEdgeStyle;
|
||||
}
|
||||
@ -1750,7 +1735,6 @@ void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
|
||||
}
|
||||
|
||||
fMCRec->fRasterClip.op(devPath, this->getTopLayerBounds(), op, edgeStyle);
|
||||
fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
|
||||
}
|
||||
|
||||
void SkCanvas::clipRegion(const SkRegion& rgn, SkRegion::Op op) {
|
||||
@ -1762,13 +1746,13 @@ void SkCanvas::onClipRegion(const SkRegion& rgn, SkRegion::Op op) {
|
||||
AutoValidateClip avc(this);
|
||||
|
||||
fDeviceCMDirty = true;
|
||||
fCachedLocalClipBoundsDirty = true;
|
||||
|
||||
// todo: signal fClipStack that we have a region, and therefore (I guess)
|
||||
// we have to ignore it, and use the region directly?
|
||||
fClipStack->clipDevRect(rgn.getBounds(), op);
|
||||
|
||||
fMCRec->fRasterClip.op(rgn, op);
|
||||
fDeviceClipBounds = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
@ -1825,74 +1809,31 @@ bool SkCanvas::isClipRect() const {
|
||||
return fMCRec->fRasterClip.isRect();
|
||||
}
|
||||
|
||||
static inline bool is_nan_or_clipped(const Sk4f& devRect, const Sk4f& devClip) {
|
||||
#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
|
||||
__m128 lLtT = _mm_unpacklo_ps(devRect.fVec, devClip.fVec);
|
||||
__m128 RrBb = _mm_unpackhi_ps(devClip.fVec, devRect.fVec);
|
||||
__m128 mask = _mm_cmplt_ps(lLtT, RrBb);
|
||||
return 0xF != _mm_movemask_ps(mask);
|
||||
#elif defined(SK_ARM_HAS_NEON)
|
||||
float32x4_t lLtT = vzipq_f32(devRect.fVec, devClip.fVec).val[0];
|
||||
float32x4_t RrBb = vzipq_f32(devClip.fVec, devRect.fVec).val[1];
|
||||
uint32x4_t mask = vcltq_f32(lLtT, RrBb);
|
||||
return 0xFFFFFFFFFFFFFFFF != (uint64_t) vmovn_u32(mask);
|
||||
#else
|
||||
SkRect devRectAsRect;
|
||||
SkRect devClipAsRect;
|
||||
devRect.store(&devRectAsRect.fLeft);
|
||||
devClip.store(&devClipAsRect.fLeft);
|
||||
return !devRectAsRect.isFinite() || !devRectAsRect.intersect(devClipAsRect);
|
||||
#endif
|
||||
}
|
||||
bool SkCanvas::quickReject(const SkRect& rect) const {
|
||||
if (!rect.isFinite())
|
||||
return true;
|
||||
|
||||
// It's important for this function to not be inlined. Otherwise the compiler will share code
|
||||
// between the fast path and the slow path, resulting in two slow paths.
|
||||
static SK_NEVER_INLINE bool quick_reject_slow_path(const SkRect& src, const SkRect& deviceClip,
|
||||
const SkMatrix& matrix) {
|
||||
SkRect deviceRect;
|
||||
matrix.mapRect(&deviceRect, src);
|
||||
return !deviceRect.isFinite() || !deviceRect.intersect(deviceClip);
|
||||
}
|
||||
|
||||
bool SkCanvas::quickReject(const SkRect& src) const {
|
||||
#ifdef SK_DEBUG
|
||||
// Verify that fDeviceClipBounds are set properly.
|
||||
SkRect tmp = qr_clip_bounds(fMCRec->fRasterClip.getBounds());
|
||||
if (fMCRec->fRasterClip.isEmpty()) {
|
||||
SkASSERT(fDeviceClipBounds.isEmpty() || tmp == fDeviceClipBounds);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (fMCRec->fMatrix.hasPerspective()) {
|
||||
SkRect dst;
|
||||
fMCRec->fMatrix.mapRect(&dst, rect);
|
||||
return !SkIRect::Intersects(dst.roundOut(), fMCRec->fRasterClip.getBounds());
|
||||
} else {
|
||||
SkASSERT(tmp == fDeviceClipBounds);
|
||||
const SkRect& clipR = this->getLocalClipBounds();
|
||||
|
||||
// for speed, do the most likely reject compares first
|
||||
// TODO: should we use | instead, or compare all 4 at once?
|
||||
if (rect.fTop >= clipR.fBottom || rect.fBottom <= clipR.fTop) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Verify that fConservativeIsScaleTranslate is set properly.
|
||||
SkASSERT(!fConservativeIsScaleTranslate || fMCRec->fMatrix.isScaleTranslate());
|
||||
#endif
|
||||
|
||||
if (!fConservativeIsScaleTranslate) {
|
||||
return quick_reject_slow_path(src, fDeviceClipBounds, fMCRec->fMatrix);
|
||||
if (rect.fLeft >= clipR.fRight || rect.fRight <= clipR.fLeft) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// We inline the implementation of mapScaleTranslate() for the fast path.
|
||||
float sx = fMCRec->fMatrix.getScaleX();
|
||||
float sy = fMCRec->fMatrix.getScaleY();
|
||||
float tx = fMCRec->fMatrix.getTranslateX();
|
||||
float ty = fMCRec->fMatrix.getTranslateY();
|
||||
Sk4f scale(sx, sy, sx, sy);
|
||||
Sk4f trans(tx, ty, tx, ty);
|
||||
|
||||
// Apply matrix.
|
||||
Sk4f ltrb = Sk4f::Load(&src.fLeft) * scale + trans;
|
||||
|
||||
// Make sure left < right, top < bottom.
|
||||
Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
|
||||
Sk4f min = Sk4f::Min(ltrb, rblt);
|
||||
Sk4f max = Sk4f::Max(ltrb, rblt);
|
||||
// We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
|
||||
// ARM this sequence generates the fastest (a single instruction).
|
||||
Sk4f devRect = Sk4f(min[2], min[3], max[0], max[1]);
|
||||
|
||||
// Check if the device rect is NaN or outside the clip.
|
||||
return is_nan_or_clipped(devRect, Sk4f::Load(&fDeviceClipBounds.fLeft));
|
||||
}
|
||||
|
||||
bool SkCanvas::quickReject(const SkPath& path) const {
|
||||
|
@ -103,45 +103,7 @@ static void test_layers(skiatest::Reporter* reporter) {
|
||||
REPORTER_ASSERT(reporter, false == canvas.quickReject(SkRect::MakeWH(60, 60)));
|
||||
}
|
||||
|
||||
static void test_quick_reject(skiatest::Reporter* reporter) {
|
||||
SkCanvas canvas(100, 100);
|
||||
SkRect r0 = SkRect::MakeLTRB(-50.0f, -50.0f, 50.0f, 50.0f);
|
||||
SkRect r1 = SkRect::MakeLTRB(-50.0f, 110.0f, 50.0f, 120.0f);
|
||||
SkRect r2 = SkRect::MakeLTRB(110.0f, -50.0f, 120.0f, 50.0f);
|
||||
SkRect r3 = SkRect::MakeLTRB(-120.0f, -50.0f, 120.0f, 50.0f);
|
||||
SkRect r4 = SkRect::MakeLTRB(-50.0f, -120.0f, 50.0f, 120.0f);
|
||||
SkRect r5 = SkRect::MakeLTRB(-120.0f, -120.0f, 120.0f, 120.0f);
|
||||
SkRect r6 = SkRect::MakeLTRB(-120.0f, -120.0f, -110.0f, -110.0f);
|
||||
SkRect r7 = SkRect::MakeLTRB(SK_ScalarNaN, -50.0f, 50.0f, 50.0f);
|
||||
SkRect r8 = SkRect::MakeLTRB(-50.0f, SK_ScalarNaN, 50.0f, 50.0f);
|
||||
SkRect r9 = SkRect::MakeLTRB(-50.0f, -50.0f, SK_ScalarNaN, 50.0f);
|
||||
SkRect r10 = SkRect::MakeLTRB(-50.0f, -50.0f, 50.0f, SK_ScalarNaN);
|
||||
REPORTER_ASSERT(reporter, false == canvas.quickReject(r0));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r1));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r2));
|
||||
REPORTER_ASSERT(reporter, false == canvas.quickReject(r3));
|
||||
REPORTER_ASSERT(reporter, false == canvas.quickReject(r4));
|
||||
REPORTER_ASSERT(reporter, false == canvas.quickReject(r5));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r6));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r7));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r8));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r9));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r10));
|
||||
|
||||
SkMatrix m = SkMatrix::MakeScale(2.0f);
|
||||
m.setTranslateX(10.0f);
|
||||
m.setTranslateY(10.0f);
|
||||
canvas.setMatrix(m);
|
||||
SkRect r11 = SkRect::MakeLTRB(5.0f, 5.0f, 100.0f, 100.0f);
|
||||
SkRect r12 = SkRect::MakeLTRB(5.0f, 50.0f, 100.0f, 100.0f);
|
||||
SkRect r13 = SkRect::MakeLTRB(50.0f, 5.0f, 100.0f, 100.0f);
|
||||
REPORTER_ASSERT(reporter, false == canvas.quickReject(r11));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r12));
|
||||
REPORTER_ASSERT(reporter, true == canvas.quickReject(r13));
|
||||
}
|
||||
|
||||
DEF_TEST(QuickReject, reporter) {
|
||||
test_drawBitmap(reporter);
|
||||
test_layers(reporter);
|
||||
test_quick_reject(reporter);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user