| /* |
| * 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/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 = SkSurface::MakeRasterN32Premul(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 = SkSurface::MakeRasterN32Premul(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); |
| } |