|  | /* | 
|  | * Copyright 2014 Google Inc. | 
|  | * | 
|  | * Use of this source code is governed by a BSD-style license that can be | 
|  | * found in the LICENSE file. | 
|  | */ | 
|  |  | 
|  | #include "include/core/SkCanvas.h" | 
|  | #include "include/core/SkColor.h" | 
|  | #include "include/core/SkImageInfo.h" | 
|  | #include "include/core/SkPaint.h" | 
|  | #include "include/core/SkPicture.h" | 
|  | #include "include/core/SkPictureRecorder.h" | 
|  | #include "include/core/SkRefCnt.h" | 
|  | #include "include/core/SkSamplingOptions.h" | 
|  | #include "include/core/SkSurface.h" | 
|  | #include "include/core/SkTileMode.h" | 
|  | #include "src/core/SkPicturePriv.h" | 
|  | #include "src/core/SkResourceCache.h" | 
|  | #include "tests/Test.h" | 
|  |  | 
|  | #include <cstdint> | 
|  | #include <initializer_list> | 
|  |  | 
|  | // Test that the SkPictureShader cache is purged on shader deletion. | 
|  | DEF_TEST(PictureShader_caching, reporter) { | 
|  | auto makePicture = [] () { | 
|  | SkPictureRecorder recorder; | 
|  | recorder.beginRecording(100, 100)->drawColor(SK_ColorGREEN); | 
|  | return recorder.finishRecordingAsPicture(); | 
|  | }; | 
|  |  | 
|  | sk_sp<SkPicture> picture = makePicture(); | 
|  | REPORTER_ASSERT(reporter, picture->unique()); | 
|  |  | 
|  | sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)); | 
|  |  | 
|  | { | 
|  | SkPaint paint; | 
|  | paint.setShader(picture->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, | 
|  | SkFilterMode::kNearest)); | 
|  | surface->getCanvas()->drawPaint(paint); | 
|  |  | 
|  | // We should have about 3 refs by now: local + shader + shader cache. | 
|  | REPORTER_ASSERT(reporter, !picture->unique()); | 
|  | } | 
|  |  | 
|  | // Draw another picture shader to have a chance to purge. | 
|  | { | 
|  | SkPaint paint; | 
|  | paint.setShader(makePicture()->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, | 
|  | SkFilterMode::kNearest)); | 
|  | surface->getCanvas()->drawPaint(paint); | 
|  |  | 
|  | } | 
|  |  | 
|  | // All but the local ref should be gone now. | 
|  | REPORTER_ASSERT(reporter, picture->unique()); | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  Check caching of picture-shaders | 
|  | *  - we do cache the underlying image (i.e. there is a cache entry) | 
|  | *  - there is only 1 entry, even with differing tile modes | 
|  | *  - after deleting the picture, the cache entry is purged | 
|  | */ | 
|  | DEF_TEST(PictureShader_caching2, reporter) { | 
|  | auto picture = []() { | 
|  | SkPictureRecorder recorder; | 
|  | recorder.beginRecording(100, 100)->drawColor(SK_ColorGREEN); | 
|  | return recorder.finishRecordingAsPicture(); | 
|  | }(); | 
|  | REPORTER_ASSERT(reporter, picture->unique()); | 
|  |  | 
|  | struct Data { | 
|  | uint64_t sharedID; | 
|  | int counter; | 
|  | } data = { | 
|  | SkPicturePriv::MakeSharedID(picture->uniqueID()), | 
|  | 0, | 
|  | }; | 
|  |  | 
|  | auto counter = [](const SkResourceCache::Rec& rec, void* dataPtr) { | 
|  | if (rec.getKey().getSharedID() == ((Data*)dataPtr)->sharedID) { | 
|  | ((Data*)dataPtr)->counter += 1; | 
|  | } | 
|  | }; | 
|  |  | 
|  | SkResourceCache::VisitAll(counter, &data); | 
|  | REPORTER_ASSERT(reporter, data.counter == 0); | 
|  |  | 
|  | // Draw with a view variants of picture-shaders that all use the same picture. | 
|  | // Only expect 1 cache entry for all (since same CTM for all). | 
|  | sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100)); | 
|  | for (SkTileMode m : { | 
|  | SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kRepeat, SkTileMode::kDecal | 
|  | }) { | 
|  | SkPaint paint; | 
|  | paint.setShader(picture->makeShader(m, m, SkFilterMode::kNearest)); | 
|  | surface->getCanvas()->drawPaint(paint); | 
|  | } | 
|  |  | 
|  | // Don't expect any additional refs on the picture | 
|  | REPORTER_ASSERT(reporter, picture->unique()); | 
|  |  | 
|  | // Check that we did cache something, but only 1 thing | 
|  | data.counter = 0; | 
|  | SkResourceCache::VisitAll(counter, &data); | 
|  | REPORTER_ASSERT(reporter, data.counter == 1); | 
|  |  | 
|  | // Now delete the picture, and check the we purge the cache entry | 
|  |  | 
|  | picture.reset(); | 
|  | SkResourceCache::CheckMessages(); | 
|  |  | 
|  | data.counter = 0; | 
|  | SkResourceCache::VisitAll(counter, &data); | 
|  | REPORTER_ASSERT(reporter, data.counter == 0); | 
|  | } |