1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2017 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "tests/Test.h" 9cb93a386Sopenharmony_ci 10cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 11cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h" 12cb93a386Sopenharmony_ci#include "include/gpu/GrRecordingContext.h" 13cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h" 14cb93a386Sopenharmony_ci#include "src/gpu/GrRecordingContextPriv.h" 15cb93a386Sopenharmony_ci#include "src/gpu/GrResourceCache.h" 16cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h" 17cb93a386Sopenharmony_ci#include "src/gpu/effects/GrPorterDuffXferProcessor.h" 18cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h" 19cb93a386Sopenharmony_ci#include "src/gpu/ops/SoftwarePathRenderer.h" 20cb93a386Sopenharmony_ci#include "src/gpu/ops/TriangulatingPathRenderer.h" 21cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h" 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_cistatic SkPath create_concave_path() { 24cb93a386Sopenharmony_ci SkPath path; 25cb93a386Sopenharmony_ci path.moveTo(100, 0); 26cb93a386Sopenharmony_ci path.lineTo(200, 200); 27cb93a386Sopenharmony_ci path.lineTo(100, 150); 28cb93a386Sopenharmony_ci path.lineTo(0, 200); 29cb93a386Sopenharmony_ci path.close(); 30cb93a386Sopenharmony_ci return path; 31cb93a386Sopenharmony_ci} 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_cistatic void draw_path(GrRecordingContext* rContext, 34cb93a386Sopenharmony_ci skgpu::v1::SurfaceDrawContext* sdc, 35cb93a386Sopenharmony_ci const SkPath& path, 36cb93a386Sopenharmony_ci skgpu::v1::PathRenderer* pr, 37cb93a386Sopenharmony_ci GrAAType aaType, 38cb93a386Sopenharmony_ci const GrStyle& style, 39cb93a386Sopenharmony_ci float scaleX = 1.f) { 40cb93a386Sopenharmony_ci GrPaint paint; 41cb93a386Sopenharmony_ci paint.setXPFactory(GrPorterDuffXPFactory::Get(SkBlendMode::kSrc)); 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci SkIRect clipConservativeBounds = SkIRect::MakeWH(sdc->width(), 44cb93a386Sopenharmony_ci sdc->height()); 45cb93a386Sopenharmony_ci GrStyledShape shape(path, style); 46cb93a386Sopenharmony_ci if (shape.style().applies()) { 47cb93a386Sopenharmony_ci shape = shape.applyStyle(GrStyle::Apply::kPathEffectAndStrokeRec, 1.0f); 48cb93a386Sopenharmony_ci } 49cb93a386Sopenharmony_ci SkMatrix matrix = SkMatrix::I(); 50cb93a386Sopenharmony_ci matrix.setScaleX(scaleX); 51cb93a386Sopenharmony_ci skgpu::v1::PathRenderer::DrawPathArgs args{rContext, 52cb93a386Sopenharmony_ci std::move(paint), 53cb93a386Sopenharmony_ci &GrUserStencilSettings::kUnused, 54cb93a386Sopenharmony_ci sdc, 55cb93a386Sopenharmony_ci nullptr, 56cb93a386Sopenharmony_ci &clipConservativeBounds, 57cb93a386Sopenharmony_ci &matrix, 58cb93a386Sopenharmony_ci &shape, 59cb93a386Sopenharmony_ci aaType, 60cb93a386Sopenharmony_ci false}; 61cb93a386Sopenharmony_ci pr->drawPath(args); 62cb93a386Sopenharmony_ci} 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_cistatic bool cache_non_scratch_resources_equals(GrResourceCache* cache, int expected) { 65cb93a386Sopenharmony_ci#if GR_CACHE_STATS 66cb93a386Sopenharmony_ci GrResourceCache::Stats stats; 67cb93a386Sopenharmony_ci cache->getStats(&stats); 68cb93a386Sopenharmony_ci return (stats.fTotal - stats.fScratch) == expected; 69cb93a386Sopenharmony_ci#else 70cb93a386Sopenharmony_ci return true; 71cb93a386Sopenharmony_ci#endif 72cb93a386Sopenharmony_ci} 73cb93a386Sopenharmony_ci 74cb93a386Sopenharmony_cistatic void test_path(skiatest::Reporter* reporter, 75cb93a386Sopenharmony_ci std::function<SkPath(void)> createPath, 76cb93a386Sopenharmony_ci std::function<skgpu::v1::PathRenderer*(GrRecordingContext*)> makePathRenderer, 77cb93a386Sopenharmony_ci int expected, 78cb93a386Sopenharmony_ci bool checkListeners, 79cb93a386Sopenharmony_ci GrAAType aaType = GrAAType::kNone, 80cb93a386Sopenharmony_ci GrStyle style = GrStyle(SkStrokeRec::kFill_InitStyle)) { 81cb93a386Sopenharmony_ci sk_sp<GrDirectContext> dContext = GrDirectContext::MakeMock(nullptr); 82cb93a386Sopenharmony_ci // The cache needs to be big enough that nothing gets flushed, or our expectations can be wrong 83cb93a386Sopenharmony_ci dContext->setResourceCacheLimit(8000000); 84cb93a386Sopenharmony_ci GrResourceCache* cache = dContext->priv().getResourceCache(); 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ci auto sdc = skgpu::v1::SurfaceDrawContext::Make( 87cb93a386Sopenharmony_ci dContext.get(), GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox, {800, 800}, 88cb93a386Sopenharmony_ci SkSurfaceProps(), 1, GrMipmapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin); 89cb93a386Sopenharmony_ci if (!sdc) { 90cb93a386Sopenharmony_ci return; 91cb93a386Sopenharmony_ci } 92cb93a386Sopenharmony_ci 93cb93a386Sopenharmony_ci sk_sp<skgpu::v1::PathRenderer> pathRenderer(makePathRenderer(dContext.get())); 94cb93a386Sopenharmony_ci SkPath path = createPath(); 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci // Initially, cache only has the render target context 97cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, 0)); 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci // Draw the path, check that new resource count matches expectations 100cb93a386Sopenharmony_ci draw_path(dContext.get(), sdc.get(), path, pathRenderer.get(), aaType, style); 101cb93a386Sopenharmony_ci dContext->flushAndSubmit(); 102cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, expected)); 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci // Nothing should be purgeable yet 105cb93a386Sopenharmony_ci cache->purgeAsNeeded(); 106cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, expected)); 107cb93a386Sopenharmony_ci 108cb93a386Sopenharmony_ci // Reset the path to change the GenID, which should invalidate one resource in the cache. 109cb93a386Sopenharmony_ci // Some path renderers may leave other unique-keyed resources in the cache, though. 110cb93a386Sopenharmony_ci path.reset(); 111cb93a386Sopenharmony_ci cache->purgeAsNeeded(); 112cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, cache_non_scratch_resources_equals(cache, expected - 1)); 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci if (!checkListeners) { 115cb93a386Sopenharmony_ci return; 116cb93a386Sopenharmony_ci } 117cb93a386Sopenharmony_ci 118cb93a386Sopenharmony_ci // Test that purging the cache of masks also removes listeners from the path. 119cb93a386Sopenharmony_ci path = createPath(); 120cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkPathPriv::GenIDChangeListenersCount(path) == 0); 121cb93a386Sopenharmony_ci for (int i = 0; i < 20; ++i) { 122cb93a386Sopenharmony_ci float scaleX = 1 + ((float)i + 1)/20.f; 123cb93a386Sopenharmony_ci draw_path(dContext.get(), sdc.get(), path, pathRenderer.get(), aaType, style, scaleX); 124cb93a386Sopenharmony_ci } 125cb93a386Sopenharmony_ci dContext->flushAndSubmit(); 126cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkPathPriv::GenIDChangeListenersCount(path) == 20); 127cb93a386Sopenharmony_ci cache->purgeUnlockedResources(); 128cb93a386Sopenharmony_ci // The listeners don't actually purge until we try to add another one. 129cb93a386Sopenharmony_ci draw_path(dContext.get(), sdc.get(), path, pathRenderer.get(), aaType, style); 130cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, SkPathPriv::GenIDChangeListenersCount(path) == 1); 131cb93a386Sopenharmony_ci} 132cb93a386Sopenharmony_ci 133cb93a386Sopenharmony_ci// Test that deleting the original path invalidates the VBs cached by the tessellating path renderer 134cb93a386Sopenharmony_ciDEF_GPUTEST(TriangulatingPathRendererCacheTest, reporter, /* options */) { 135cb93a386Sopenharmony_ci auto createPR = [](GrRecordingContext*) { 136cb93a386Sopenharmony_ci return new skgpu::v1::TriangulatingPathRenderer(); 137cb93a386Sopenharmony_ci }; 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci // Triangulating path renderer creates a single vertex buffer for non-AA paths. No other 140cb93a386Sopenharmony_ci // resources should be created. 141cb93a386Sopenharmony_ci const int kExpectedResources = 1; 142cb93a386Sopenharmony_ci 143cb93a386Sopenharmony_ci test_path(reporter, create_concave_path, createPR, kExpectedResources, false); 144cb93a386Sopenharmony_ci 145cb93a386Sopenharmony_ci // Test with a style that alters the path geometry. This needs to attach the invalidation logic 146cb93a386Sopenharmony_ci // to the original path, not the modified path produced by the style. 147cb93a386Sopenharmony_ci SkPaint paint; 148cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 149cb93a386Sopenharmony_ci paint.setStrokeWidth(1); 150cb93a386Sopenharmony_ci GrStyle style(paint); 151cb93a386Sopenharmony_ci test_path(reporter, create_concave_path, createPR, kExpectedResources, false, GrAAType::kNone, 152cb93a386Sopenharmony_ci style); 153cb93a386Sopenharmony_ci} 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci// Test that deleting the original path invalidates the textures cached by the SW path renderer 156cb93a386Sopenharmony_ciDEF_GPUTEST(SoftwarePathRendererCacheTest, reporter, /* options */) { 157cb93a386Sopenharmony_ci auto createPR = [](GrRecordingContext* rContext) { 158cb93a386Sopenharmony_ci return new skgpu::v1::SoftwarePathRenderer(rContext->priv().proxyProvider(), true); 159cb93a386Sopenharmony_ci }; 160cb93a386Sopenharmony_ci 161cb93a386Sopenharmony_ci // Software path renderer creates a mask texture and renders with a non-AA rect, but the flush 162cb93a386Sopenharmony_ci // only contains a single quad so FillRectOp doesn't need to use the shared index buffer. 163cb93a386Sopenharmony_ci const int kExpectedResources = 1; 164cb93a386Sopenharmony_ci 165cb93a386Sopenharmony_ci test_path(reporter, create_concave_path, createPR, kExpectedResources, true, 166cb93a386Sopenharmony_ci GrAAType::kCoverage); 167cb93a386Sopenharmony_ci 168cb93a386Sopenharmony_ci // Test with a style that alters the path geometry. This needs to attach the invalidation logic 169cb93a386Sopenharmony_ci // to the original path, not the modified path produced by the style. 170cb93a386Sopenharmony_ci SkPaint paint; 171cb93a386Sopenharmony_ci paint.setStyle(SkPaint::kStroke_Style); 172cb93a386Sopenharmony_ci paint.setStrokeWidth(1); 173cb93a386Sopenharmony_ci GrStyle style(paint); 174cb93a386Sopenharmony_ci test_path(reporter, create_concave_path, createPR, kExpectedResources, true, 175cb93a386Sopenharmony_ci GrAAType::kCoverage, style); 176cb93a386Sopenharmony_ci} 177