skia2/tests/GpuDrawPathTest.cpp
Brian Salomon dcfca431e3 Use GrContextFactories that produce a single GrContext in unit tests.
This is to alleviate problems due to the command buffer getting bent out of shape when the current
OpenGL context is switched out from under it (because we ran a test with a native GL context). This,
however is not a full solution. More changes will be required to ensure that after running each
command buffer or native test we bind the null context. This does allow us to take a step in that
direction without breaking anything too badly. Moreover, there is no real benefit to reusing a
GrContextFactory.

Modifies DEF_GPUTEST to take GrContextOptions rather than a factory to use. Tests were already using
their own factories anyway.

In tests that use GrContextFactory the factory instance is moved to the inner loop.

Modifies gpucts and skia_test to not use persistent GrContextFactories.

Change-Id: Ie7a36793545c775f2f30653ead6fec93a3d22717
Reviewed-on: https://skia-review.googlesource.com/71861
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
2017-11-15 22:03:07 +00: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, /* options */) {
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