skia2/tests/GpuDrawPathTest.cpp
bsalomon aa840647fc Don't compute path keys for volatile paths in GrShape.
Otherwise, we will compute cache keys for internally transformed paths that don't repeat (e.g. clip paths transformed into device space with a changing view matrix).

BUG=chromium:649562
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2369513002

Review-Url: https://codereview.chromium.org/2369513002
2016-09-23 12:09:16 -07:00

168 lines
5.6 KiB
C++

/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "SkTypes.h"
#if SK_SUPPORT_GPU
#include "GrContext.h"
#include "GrPath.h"
#include "GrShape.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColor.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkDashPathEffect.h"
#include "SkRRect.h"
#include "SkRect.h"
#include "SkSurface.h"
#include "Test.h"
#include <initializer_list>
static void test_drawPathEmpty(skiatest::Reporter*, SkCanvas* canvas) {
// Filling an empty path should not crash.
SkPaint paint;
SkRect emptyRect = SkRect::MakeEmpty();
canvas->drawRect(emptyRect, paint);
canvas->drawPath(SkPath(), paint);
canvas->drawOval(emptyRect, paint);
canvas->drawRect(emptyRect, paint);
canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
// Stroking an empty path should not crash.
paint.setAntiAlias(true);
paint.setStyle(SkPaint::kStroke_Style);
paint.setColor(SK_ColorGRAY);
paint.setStrokeWidth(SkIntToScalar(20));
paint.setStrokeJoin(SkPaint::kRound_Join);
canvas->drawRect(emptyRect, paint);
canvas->drawPath(SkPath(), paint);
canvas->drawOval(emptyRect, paint);
canvas->drawRect(emptyRect, paint);
canvas->drawRRect(SkRRect::MakeRect(emptyRect), paint);
}
static void fill_and_stroke(SkCanvas* canvas, const SkPath& p1, const SkPath& p2,
sk_sp<SkPathEffect> effect) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setPathEffect(effect);
canvas->drawPath(p1, paint);
canvas->drawPath(p2, paint);
paint.setStyle(SkPaint::kStroke_Style);
canvas->drawPath(p1, paint);
canvas->drawPath(p2, paint);
}
static void test_drawSameRectOvals(skiatest::Reporter*, SkCanvas* canvas) {
// Drawing ovals with similar bounds but different points order should not crash.
SkPath oval1, oval2;
const SkRect rect = SkRect::MakeWH(100, 50);
oval1.addOval(rect, SkPath::kCW_Direction);
oval2.addOval(rect, SkPath::kCCW_Direction);
fill_and_stroke(canvas, oval1, oval2, nullptr);
const SkScalar intervals[] = { 1, 1 };
fill_and_stroke(canvas, oval1, oval2, SkDashPathEffect::Make(intervals, 2, 0));
}
DEF_GPUTEST_FOR_ALL_GL_CONTEXTS(GpuDrawPath, reporter, ctxInfo) {
for (auto& test_func : { &test_drawPathEmpty, &test_drawSameRectOvals }) {
for (auto& sampleCount : {0, 4, 16}) {
SkImageInfo info = SkImageInfo::MakeN32Premul(255, 255);
auto surface(
SkSurface::MakeRenderTarget(ctxInfo.grContext(), SkBudgeted::kNo, info,
sampleCount, nullptr));
if (!surface) {
continue;
}
test_func(reporter, surface->getCanvas());
}
}
}
DEF_GPUTEST(GrPathKeys, reporter, /*factory*/) {
SkPaint strokePaint;
strokePaint.setStyle(SkPaint::kStroke_Style);
strokePaint.setStrokeWidth(10.f);
GrStyle styles[] = {
GrStyle::SimpleFill(),
GrStyle::SimpleHairline(),
GrStyle(strokePaint)
};
for (const GrStyle& style : styles) {
// Keys should not ignore conic weights.
SkPath path1, path2;
SkPoint p0 = SkPoint::Make(100, 0);
SkPoint p1 = SkPoint::Make(100, 100);
path1.conicTo(p0, p1, .5f);
path2.conicTo(p0, p1, .7f);
GrUniqueKey key1, key2;
// We expect these small paths to be keyed based on their data.
bool isVolatile;
GrPath::ComputeKey(GrShape(path1, GrStyle::SimpleFill()), &key1, &isVolatile);
REPORTER_ASSERT(reporter, !isVolatile);
REPORTER_ASSERT(reporter, key1.isValid());
GrPath::ComputeKey(GrShape(path2, GrStyle::SimpleFill()), &key2, &isVolatile);
REPORTER_ASSERT(reporter, !isVolatile);
REPORTER_ASSERT(reporter, key1.isValid());
REPORTER_ASSERT(reporter, key1 != key2);
{
GrUniqueKey tempKey;
path1.setIsVolatile(true);
GrPath::ComputeKey(GrShape(path1, style), &key1, &isVolatile);
REPORTER_ASSERT(reporter, isVolatile);
REPORTER_ASSERT(reporter, !tempKey.isValid());
}
// Ensure that recreating the GrShape doesn't change the key.
{
GrUniqueKey tempKey;
GrPath::ComputeKey(GrShape(path2, GrStyle::SimpleFill()), &tempKey, &isVolatile);
REPORTER_ASSERT(reporter, key2 == tempKey);
}
// Try a large path that is too big to be keyed off its data.
SkPath path3;
SkPath path4;
for (int i = 0; i < 1000; ++i) {
SkScalar s = SkIntToScalar(i);
path3.conicTo(s, 3.f * s / 4, s + 1.f, s, 0.5f + s / 2000.f);
path4.conicTo(s, 3.f * s / 4, s + 1.f, s, 0.3f + s / 2000.f);
}
GrUniqueKey key3, key4;
// These aren't marked volatile and so should have keys
GrPath::ComputeKey(GrShape(path3, style), &key3, &isVolatile);
REPORTER_ASSERT(reporter, !isVolatile);
REPORTER_ASSERT(reporter, key3.isValid());
GrPath::ComputeKey(GrShape(path4, style), &key4, &isVolatile);
REPORTER_ASSERT(reporter, !isVolatile);
REPORTER_ASSERT(reporter, key4.isValid());
REPORTER_ASSERT(reporter, key3 != key4);
{
GrUniqueKey tempKey;
path3.setIsVolatile(true);
GrPath::ComputeKey(GrShape(path3, style), &key1, &isVolatile);
REPORTER_ASSERT(reporter, isVolatile);
REPORTER_ASSERT(reporter, !tempKey.isValid());
}
}
}
#endif