blob: 097bee2c793891c2df9f97fd3a77b74e93f9eb10 [file] [log] [blame]
Brian Osmanf6f7cf62017-09-25 16:49:55 -04001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "tests/Test.h"
Brian Osmanf6f7cf62017-09-25 16:49:55 -04009
Mike Kleinc0bd9f92019-04-23 12:05:21 -050010#include "include/core/SkPath.h"
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040011#include "include/gpu/GrDirectContext.h"
12#include "include/gpu/GrRecordingContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrContextPriv.h"
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040014#include "src/gpu/GrRecordingContextPriv.h"
Michael Ludwig7c12e282020-05-29 09:54:07 -040015#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "src/gpu/GrResourceCache.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrSoftwarePathRenderer.h"
18#include "src/gpu/GrStyle.h"
19#include "src/gpu/effects/GrPorterDuffXferProcessor.h"
Michael Ludwig2686d692020-04-17 20:21:37 +000020#include "src/gpu/geometry/GrStyledShape.h"
Chris Dalton17dc4182020-03-25 16:18:16 -060021#include "src/gpu/ops/GrTriangulatingPathRenderer.h"
Brian Osmanf6f7cf62017-09-25 16:49:55 -040022
23static SkPath create_concave_path() {
24 SkPath path;
25 path.moveTo(100, 0);
26 path.lineTo(200, 200);
27 path.lineTo(100, 150);
28 path.lineTo(0, 200);
29 path.close();
30 return path;
31}
32
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040033static void draw_path(GrRecordingContext* rContext,
Brian Osmanf6f7cf62017-09-25 16:49:55 -040034 GrRenderTargetContext* renderTargetContext,
35 const SkPath& path,
36 GrPathRenderer* pr,
Chris Dalton6ce447a2019-06-23 18:07:38 -060037 GrAAType aaType,
Brian Salomon9f004942020-02-25 09:14:08 -050038 const GrStyle& style,
39 float scaleX = 1.f) {
Brian Osmanf6f7cf62017-09-25 16:49:55 -040040 GrPaint paint;
41 paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc));
42
Brian Osmanf6f7cf62017-09-25 16:49:55 -040043 SkIRect clipConservativeBounds = SkIRect::MakeWH(renderTargetContext->width(),
44 renderTargetContext->height());
Michael Ludwig2686d692020-04-17 20:21:37 +000045 GrStyledShape shape(path, style);
Brian Osmanf6f7cf62017-09-25 16:49:55 -040046 if (shape.style().applies()) {
47 shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, 1.0f);
48 }
49 SkMatrix matrix = SkMatrix::I();
Brian Salomon9f004942020-02-25 09:14:08 -050050 matrix.setScaleX(scaleX);
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040051 GrPathRenderer::DrawPathArgs args{rContext,
Brian Osmanf6f7cf62017-09-25 16:49:55 -040052 std::move(paint),
53 &GrUserStencilSettings::kUnused,
54 renderTargetContext,
Michael Ludwig7c12e282020-05-29 09:54:07 -040055 nullptr,
Brian Osmanf6f7cf62017-09-25 16:49:55 -040056 &clipConservativeBounds,
57 &matrix,
58 &shape,
Chris Dalton6ce447a2019-06-23 18:07:38 -060059 aaType,
Brian Osmanf6f7cf62017-09-25 16:49:55 -040060 false};
61 pr->drawPath(args);
62}
63
Brian Osmane9242ca2017-09-26 14:05:19 -040064static bool cache_non_scratch_resources_equals(GrResourceCache* cache, int expected) {
65#if GR_CACHE_STATS
66 GrResourceCache::Stats stats;
67 cache->getStats(&stats);
68 return (stats.fTotal - stats.fScratch) == expected;
69#else
70 return true;
71#endif
72}
73
Brian Osmanf6f7cf62017-09-25 16:49:55 -040074static void test_path(skiatest::Reporter* reporter,
75 std::function<SkPath(void)> createPath,
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040076 std::function<GrPathRenderer*(GrRecordingContext*)> createPathRenderer,
Brian Osman5fcd3912017-10-04 14:45:04 -040077 int expected,
Brian Salomon9f004942020-02-25 09:14:08 -050078 bool checkListeners,
Chris Dalton6ce447a2019-06-23 18:07:38 -060079 GrAAType aaType = GrAAType::kNone,
Brian Osmanf6f7cf62017-09-25 16:49:55 -040080 GrStyle style = GrStyle(SkStrokeRec::kFill_InitStyle)) {
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040081 sk_sp<GrDirectContext> dContext = GrDirectContext::MakeMock(nullptr);
Brian Osman5fcd3912017-10-04 14:45:04 -040082 // The cache needs to be big enough that nothing gets flushed, or our expectations can be wrong
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040083 dContext->setResourceCacheLimit(8000000);
84 GrResourceCache* cache = dContext->priv().getResourceCache();
Brian Osmanf6f7cf62017-09-25 16:49:55 -040085
Greg Daniele20fcad2020-01-08 11:52:34 -050086 auto rtc = GrRenderTargetContext::Make(
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040087 dContext.get(), GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox, {800, 800}, 1,
Greg Daniele20fcad2020-01-08 11:52:34 -050088 GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin);
Brian Osmanf6f7cf62017-09-25 16:49:55 -040089 if (!rtc) {
90 return;
91 }
92
Robert Phillips0c5bb2f2020-07-17 15:40:13 -040093 sk_sp<GrPathRenderer> pathRenderer(createPathRenderer(dContext.get()));
Brian Osmanf6f7cf62017-09-25 16:49:55 -040094 SkPath path = createPath();
95
96 // Initially, cache only has the render target context
Brian Osmane9242ca2017-09-26 14:05:19 -040097 REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, 0));
Brian Osmanf6f7cf62017-09-25 16:49:55 -040098
99 // Draw the path, check that new resource count matches expectations
Robert Phillips0c5bb2f2020-07-17 15:40:13 -0400100 draw_path(dContext.get(), rtc.get(), path, pathRenderer.get(), aaType, style);
101 dContext->flushAndSubmit();
Brian Osman5fcd3912017-10-04 14:45:04 -0400102 REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, expected));
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400103
104 // Nothing should be purgeable yet
105 cache->purgeAsNeeded();
Brian Osman5fcd3912017-10-04 14:45:04 -0400106 REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, expected));
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400107
Brian Osman5fcd3912017-10-04 14:45:04 -0400108 // Reset the path to change the GenID, which should invalidate one resource in the cache.
109 // Some path renderers may leave other unique-keyed resources in the cache, though.
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400110 path.reset();
111 cache->purgeAsNeeded();
Brian Osman5fcd3912017-10-04 14:45:04 -0400112 REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, expected - 1));
Brian Salomon9f004942020-02-25 09:14:08 -0500113
114 if (!checkListeners) {
115 return;
116 }
117
118 // Test that purging the cache of masks also removes listeners from the path.
119 path = createPath();
120 REPORTER_ASSERT(reporter, SkPathPriv::GenIDChangeListenersCount(path) == 0);
121 for (int i = 0; i < 20; ++i) {
122 float scaleX = 1 + ((float)i + 1)/20.f;
Robert Phillips0c5bb2f2020-07-17 15:40:13 -0400123 draw_path(dContext.get(), rtc.get(), path, pathRenderer.get(), aaType, style, scaleX);
Brian Salomon9f004942020-02-25 09:14:08 -0500124 }
Robert Phillips0c5bb2f2020-07-17 15:40:13 -0400125 dContext->flushAndSubmit();
Brian Salomon9f004942020-02-25 09:14:08 -0500126 REPORTER_ASSERT(reporter, SkPathPriv::GenIDChangeListenersCount(path) == 20);
127 cache->purgeAllUnlocked();
128 // The listeners don't actually purge until we try to add another one.
Robert Phillips0c5bb2f2020-07-17 15:40:13 -0400129 draw_path(dContext.get(), rtc.get(), path, pathRenderer.get(), aaType, style);
Brian Salomon9f004942020-02-25 09:14:08 -0500130 REPORTER_ASSERT(reporter, SkPathPriv::GenIDChangeListenersCount(path) == 1);
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400131}
132
133// Test that deleting the original path invalidates the VBs cached by the tessellating path renderer
Chris Dalton17dc4182020-03-25 16:18:16 -0600134DEF_GPUTEST(TriangulatingPathRendererCacheTest, reporter, /* options */) {
Robert Phillips0c5bb2f2020-07-17 15:40:13 -0400135 auto createPR = [](GrRecordingContext*) {
Chris Dalton17dc4182020-03-25 16:18:16 -0600136 return new GrTriangulatingPathRenderer();
Brian Osmane9242ca2017-09-26 14:05:19 -0400137 };
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400138
Chris Dalton17dc4182020-03-25 16:18:16 -0600139 // Triangulating path renderer creates a single vertex buffer for non-AA paths. No other
Brian Osman5fcd3912017-10-04 14:45:04 -0400140 // resources should be created.
141 const int kExpectedResources = 1;
142
Brian Salomon9f004942020-02-25 09:14:08 -0500143 test_path(reporter, create_concave_path, createPR, kExpectedResources, false);
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400144
Brian Osmane9242ca2017-09-26 14:05:19 -0400145 // Test with a style that alters the path geometry. This needs to attach the invalidation logic
146 // to the original path, not the modified path produced by the style.
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400147 SkPaint paint;
148 paint.setStyle(SkPaint::kStroke_Style);
149 paint.setStrokeWidth(1);
150 GrStyle style(paint);
Brian Salomon9f004942020-02-25 09:14:08 -0500151 test_path(reporter, create_concave_path, createPR, kExpectedResources, false, GrAAType::kNone,
152 style);
Brian Osmane9242ca2017-09-26 14:05:19 -0400153}
154
155// Test that deleting the original path invalidates the textures cached by the SW path renderer
Brian Salomondcfca432017-11-15 15:48:03 -0500156DEF_GPUTEST(SoftwarePathRendererCacheTest, reporter, /* options */) {
Robert Phillips0c5bb2f2020-07-17 15:40:13 -0400157 auto createPR = [](GrRecordingContext* rContext) {
158 return new GrSoftwarePathRenderer(rContext->priv().proxyProvider(), true);
Brian Osmane9242ca2017-09-26 14:05:19 -0400159 };
160
Michael Ludwig72ab3462018-12-10 12:43:36 -0500161 // Software path renderer creates a mask texture and renders with a non-AA rect, but the flush
162 // only contains a single quad so GrFillRectOp doesn't need to use the shared index buffer.
163 const int kExpectedResources = 1;
Brian Osman5fcd3912017-10-04 14:45:04 -0400164
Brian Salomon9f004942020-02-25 09:14:08 -0500165 test_path(reporter, create_concave_path, createPR, kExpectedResources, true,
166 GrAAType::kCoverage);
Brian Osmane9242ca2017-09-26 14:05:19 -0400167
168 // Test with a style that alters the path geometry. This needs to attach the invalidation logic
169 // to the original path, not the modified path produced by the style.
170 SkPaint paint;
171 paint.setStyle(SkPaint::kStroke_Style);
172 paint.setStrokeWidth(1);
173 GrStyle style(paint);
Brian Salomon9f004942020-02-25 09:14:08 -0500174 test_path(reporter, create_concave_path, createPR, kExpectedResources, true,
175 GrAAType::kCoverage, style);
Brian Osmanf6f7cf62017-09-25 16:49:55 -0400176}