blob: 7bcd45c6b64325b69165d03bd83c21e08793a1f0 [file] [log] [blame]
Stan Ilievd495f432017-10-09 15:49:32 -04001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Nolan Scobie193cd962023-02-08 20:03:31 -050017#include <GrDirectContext.h>
18#include <Properties.h>
19#include <SkData.h>
20#include <SkRefCnt.h>
Stan Ilievd495f432017-10-09 15:49:32 -040021#include <cutils/properties.h>
John Reck283bb462018-12-13 16:40:14 -080022#include <dirent.h>
Stan Ilievd495f432017-10-09 15:49:32 -040023#include <errno.h>
John Reck283bb462018-12-13 16:40:14 -080024#include <gtest/gtest.h>
Stan Ilievd495f432017-10-09 15:49:32 -040025#include <stdio.h>
26#include <stdlib.h>
27#include <sys/types.h>
28#include <utils/Log.h>
Nolan Scobie193cd962023-02-08 20:03:31 -050029
John Reck283bb462018-12-13 16:40:14 -080030#include <cstdint>
Nolan Scobie193cd962023-02-08 20:03:31 -050031
Stan Ilievd495f432017-10-09 15:49:32 -040032#include "FileBlobCache.h"
John Reck283bb462018-12-13 16:40:14 -080033#include "pipeline/skia/ShaderCache.h"
Nolan Scobie193cd962023-02-08 20:03:31 -050034#include "tests/common/TestUtils.h"
Stan Ilievd495f432017-10-09 15:49:32 -040035
36using namespace android::uirenderer::skiapipeline;
37
38namespace android {
39namespace uirenderer {
40namespace skiapipeline {
41
42class ShaderCacheTestUtils {
43public:
44 /**
Nolan Scobie193cd962023-02-08 20:03:31 -050045 * Hack to reset all member variables of the given cache to their default / initial values.
46 *
47 * WARNING: this must be kept up to date manually, since ShaderCache's parent disables just
48 * reassigning a new instance.
Stan Ilievd495f432017-10-09 15:49:32 -040049 */
Nolan Scobie193cd962023-02-08 20:03:31 -050050 static void reinitializeAllFields(ShaderCache& cache) {
51 ShaderCache newCache = ShaderCache();
52 std::lock_guard<std::mutex> lock(cache.mMutex);
53 // By order of declaration
54 cache.mInitialized = newCache.mInitialized;
55 cache.mBlobCache.reset(nullptr);
56 cache.mFilename = newCache.mFilename;
57 cache.mIDHash.clear();
58 cache.mSavePending = newCache.mSavePending;
59 cache.mObservedBlobValueSize = newCache.mObservedBlobValueSize;
60 cache.mDeferredSaveDelayMs = newCache.mDeferredSaveDelayMs;
61 cache.mTryToStorePipelineCache = newCache.mTryToStorePipelineCache;
62 cache.mInStoreVkPipelineInProgress = newCache.mInStoreVkPipelineInProgress;
63 cache.mNewPipelineCacheSize = newCache.mNewPipelineCacheSize;
64 cache.mOldPipelineCacheSize = newCache.mOldPipelineCacheSize;
65 cache.mCacheDirty = newCache.mCacheDirty;
66 cache.mNumShadersCachedInRam = newCache.mNumShadersCachedInRam;
67 }
68
69 /**
70 * "setSaveDelayMs" sets the time in milliseconds to wait before saving newly inserted cache
71 * entries. If set to 0, then deferred save is disabled, and "saveToDiskLocked" must be called
72 * manually, as seen in the "terminate" testing helper function.
73 */
74 static void setSaveDelayMs(ShaderCache& cache, unsigned int saveDelayMs) {
75 std::lock_guard<std::mutex> lock(cache.mMutex);
76 cache.mDeferredSaveDelayMs = saveDelayMs;
Stan Ilievd495f432017-10-09 15:49:32 -040077 }
78
79 /**
80 * "terminate" optionally stores the BlobCache on disk and release all in-memory cache.
81 * Next call to "initShaderDiskCache" will load again the in-memory cache from disk.
82 */
83 static void terminate(ShaderCache& cache, bool saveContent) {
84 std::lock_guard<std::mutex> lock(cache.mMutex);
Nolan Scobie193cd962023-02-08 20:03:31 -050085 if (saveContent) {
86 cache.saveToDiskLocked();
87 }
Stan Ilievd495f432017-10-09 15:49:32 -040088 cache.mBlobCache = NULL;
89 }
Yichi Chen9f959552018-03-29 21:21:54 +080090
91 /**
92 *
93 */
94 template <typename T>
95 static bool validateCache(ShaderCache& cache, std::vector<T> hash) {
96 return cache.validateCache(hash.data(), hash.size() * sizeof(T));
97 }
Nolan Scobie193cd962023-02-08 20:03:31 -050098
99 /**
100 * Waits until cache::mSavePending is false, checking every 0.1 ms *while the mutex is free*.
101 *
102 * Fails if there was no save pending, or if the cache was already being written to disk, or if
103 * timeoutMs is exceeded.
104 *
105 * Note: timeoutMs only guards against mSavePending getting stuck like in b/268205519, and
106 * cannot protect against mutex-based deadlock. Reaching timeoutMs implies something is broken,
107 * so setting it to a sufficiently large value will not delay execution in the happy state.
108 */
109 static void waitForPendingSave(ShaderCache& cache, const int timeoutMs = 50) {
110 {
111 std::lock_guard<std::mutex> lock(cache.mMutex);
112 ASSERT_TRUE(cache.mSavePending);
113 }
114 bool saving = true;
115 float elapsedMilliseconds = 0;
116 while (saving) {
117 if (elapsedMilliseconds >= timeoutMs) {
118 FAIL() << "Timed out after waiting " << timeoutMs << " ms for a pending save";
119 }
120 // This small (0.1 ms) delay is to avoid working too much while waiting for
121 // deferredSaveThread to take the mutex and start the disk write.
122 const int delayMicroseconds = 100;
123 usleep(delayMicroseconds);
124 elapsedMilliseconds += (float)delayMicroseconds / 1000;
125
126 std::lock_guard<std::mutex> lock(cache.mMutex);
127 saving = cache.mSavePending;
128 }
129 }
Stan Ilievd495f432017-10-09 15:49:32 -0400130};
131
132} /* namespace skiapipeline */
133} /* namespace uirenderer */
134} /* namespace android */
135
Stan Ilievd495f432017-10-09 15:49:32 -0400136namespace {
137
138std::string getExternalStorageFolder() {
139 return getenv("EXTERNAL_STORAGE");
140}
141
142bool folderExist(const std::string& folderName) {
143 DIR* dir = opendir(folderName.c_str());
144 if (dir) {
145 closedir(dir);
146 return true;
147 }
148 return false;
149}
150
Nolan Scobie193cd962023-02-08 20:03:31 -0500151/**
152 * Attempts to delete the given file, and asserts that either:
153 * 1. Deletion was successful, OR
154 * 2. The file did not exist.
155 *
156 * Tip: wrap calls to this in ASSERT_NO_FATAL_FAILURE(x) if a test should exit early if this fails.
157 */
158void deleteFileAssertSuccess(const std::string& filePath) {
159 int deleteResult = remove(filePath.c_str());
160 ASSERT_TRUE(0 == deleteResult || ENOENT == errno);
161}
162
John Reck283bb462018-12-13 16:40:14 -0800163inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
164 return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() &&
165 0 == memcmp(shader1->data(), shader2->data(), shader1->size());
Stan Ilievd495f432017-10-09 15:49:32 -0400166}
167
John Reck283bb462018-12-13 16:40:14 -0800168inline bool checkShader(const sk_sp<SkData>& shader, const char* program) {
Yichi Chen9f959552018-03-29 21:21:54 +0800169 sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
170 return checkShader(shader, shader2);
171}
172
Nolan Scobie193cd962023-02-08 20:03:31 -0500173inline bool checkShader(const sk_sp<SkData>& shader, const std::string& program) {
174 return checkShader(shader, program.c_str());
175}
176
Yichi Chen9f959552018-03-29 21:21:54 +0800177template <typename T>
178bool checkShader(const sk_sp<SkData>& shader, std::vector<T>& program) {
179 sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size() * sizeof(T));
180 return checkShader(shader, shader2);
Stan Ilievd495f432017-10-09 15:49:32 -0400181}
182
183void setShader(sk_sp<SkData>& shader, const char* program) {
184 shader = SkData::MakeWithCString(program);
185}
186
Nolan Scobie193cd962023-02-08 20:03:31 -0500187void setShader(sk_sp<SkData>& shader, const std::string& program) {
188 setShader(shader, program.c_str());
189}
190
Yichi Chen9f959552018-03-29 21:21:54 +0800191template <typename T>
192void setShader(sk_sp<SkData>& shader, std::vector<T>& buffer) {
193 shader = SkData::MakeWithCopy(buffer.data(), buffer.size() * sizeof(T));
Stan Ilievd495f432017-10-09 15:49:32 -0400194}
195
Yichi Chen9f959552018-03-29 21:21:54 +0800196template <typename T>
197void genRandomData(std::vector<T>& buffer) {
198 for (auto& data : buffer) {
199 data = T(std::rand());
200 }
201}
Stan Ilievd495f432017-10-09 15:49:32 -0400202
Stan Ilievd495f432017-10-09 15:49:32 -0400203#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
204
205TEST(ShaderCacheTest, testWriteAndRead) {
206 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800207 // don't run the test if external storage folder is not available
Stan Ilievd495f432017-10-09 15:49:32 -0400208 return;
209 }
John Reck283bb462018-12-13 16:40:14 -0800210 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
211 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Stan Ilievd495f432017-10-09 15:49:32 -0400212
John Reck283bb462018-12-13 16:40:14 -0800213 // remove any test files from previous test run
Nolan Scobie193cd962023-02-08 20:03:31 -0500214 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
215 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
Yichi Chen9f959552018-03-29 21:21:54 +0800216 std::srand(0);
Stan Ilievd495f432017-10-09 15:49:32 -0400217
John Reck283bb462018-12-13 16:40:14 -0800218 // read the cache from a file that does not exist
Stan Ilievd495f432017-10-09 15:49:32 -0400219 ShaderCache::get().setFilename(cacheFile1.c_str());
Nolan Scobie193cd962023-02-08 20:03:31 -0500220 ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save
Stan Ilievd495f432017-10-09 15:49:32 -0400221 ShaderCache::get().initShaderDiskCache();
222
John Reck283bb462018-12-13 16:40:14 -0800223 // read a key - should not be found since the cache is empty
Stan Ilievd495f432017-10-09 15:49:32 -0400224 sk_sp<SkData> outVS;
225 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
226
John Reck283bb462018-12-13 16:40:14 -0800227 // write to the in-memory cache without storing on disk and verify we read the same values
Stan Ilievd495f432017-10-09 15:49:32 -0400228 sk_sp<SkData> inVS;
229 setShader(inVS, "sassas");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400230 ShaderCache::get().store(GrProgramDescTest(100), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400231 setShader(inVS, "someVS");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400232 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400233 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
234 ASSERT_TRUE(checkShader(outVS, "sassas"));
235 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
236 ASSERT_TRUE(checkShader(outVS, "someVS"));
237
John Reck283bb462018-12-13 16:40:14 -0800238 // store content to disk and release in-memory cache
Stan Ilievd495f432017-10-09 15:49:32 -0400239 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
240
John Reck283bb462018-12-13 16:40:14 -0800241 // change to a file that does not exist and verify load fails
Stan Ilievd495f432017-10-09 15:49:32 -0400242 ShaderCache::get().setFilename(cacheFile2.c_str());
243 ShaderCache::get().initShaderDiskCache();
244 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
245 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
246
John Reck283bb462018-12-13 16:40:14 -0800247 // load again content from disk from an existing file and check the data is read correctly
Stan Ilievd495f432017-10-09 15:49:32 -0400248 ShaderCache::get().setFilename(cacheFile1.c_str());
249 ShaderCache::get().initShaderDiskCache();
250 sk_sp<SkData> outVS2;
251 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
252 ASSERT_TRUE(checkShader(outVS2, "someVS"));
253
John Reck283bb462018-12-13 16:40:14 -0800254 // change data, store to disk, read back again and verify data has been changed
Stan Ilievd495f432017-10-09 15:49:32 -0400255 setShader(inVS, "ewData1");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400256 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400257 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
258 ShaderCache::get().initShaderDiskCache();
259 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
260 ASSERT_TRUE(checkShader(outVS2, "ewData1"));
261
John Reck283bb462018-12-13 16:40:14 -0800262 // write and read big data chunk (50K)
263 size_t dataSize = 50 * 1024;
Yichi Chen9f959552018-03-29 21:21:54 +0800264 std::vector<uint8_t> dataBuffer(dataSize);
265 genRandomData(dataBuffer);
Stan Ilievd495f432017-10-09 15:49:32 -0400266 setShader(inVS, dataBuffer);
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400267 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400268 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
269 ShaderCache::get().initShaderDiskCache();
270 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
271 ASSERT_TRUE(checkShader(outVS2, dataBuffer));
272
273 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
Nolan Scobie193cd962023-02-08 20:03:31 -0500274 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
275 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
Stan Ilievd495f432017-10-09 15:49:32 -0400276}
277
Yichi Chen9f959552018-03-29 21:21:54 +0800278TEST(ShaderCacheTest, testCacheValidation) {
279 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800280 // don't run the test if external storage folder is not available
Yichi Chen9f959552018-03-29 21:21:54 +0800281 return;
282 }
John Reck283bb462018-12-13 16:40:14 -0800283 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
284 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Yichi Chen9f959552018-03-29 21:21:54 +0800285
John Reck283bb462018-12-13 16:40:14 -0800286 // remove any test files from previous test run
Nolan Scobie193cd962023-02-08 20:03:31 -0500287 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
288 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
Yichi Chen9f959552018-03-29 21:21:54 +0800289 std::srand(0);
290
John Reck283bb462018-12-13 16:40:14 -0800291 // generate identity and read the cache from a file that does not exist
Yichi Chen9f959552018-03-29 21:21:54 +0800292 ShaderCache::get().setFilename(cacheFile1.c_str());
Nolan Scobie193cd962023-02-08 20:03:31 -0500293 ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save
Yichi Chen9f959552018-03-29 21:21:54 +0800294 std::vector<uint8_t> identity(1024);
295 genRandomData(identity);
John Reck283bb462018-12-13 16:40:14 -0800296 ShaderCache::get().initShaderDiskCache(
297 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800298
299 // generate random content in cache and store to disk
300 constexpr size_t numBlob(10);
301 constexpr size_t keySize(1024);
302 constexpr size_t dataSize(50 * 1024);
303
John Reck283bb462018-12-13 16:40:14 -0800304 std::vector<std::pair<sk_sp<SkData>, sk_sp<SkData>>> blobVec(numBlob);
Yichi Chen9f959552018-03-29 21:21:54 +0800305 for (auto& blob : blobVec) {
306 std::vector<uint8_t> keyBuffer(keySize);
307 std::vector<uint8_t> dataBuffer(dataSize);
308 genRandomData(keyBuffer);
309 genRandomData(dataBuffer);
310
311 sk_sp<SkData> key, data;
312 setShader(key, keyBuffer);
313 setShader(data, dataBuffer);
314
315 blob = std::make_pair(key, data);
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400316 ShaderCache::get().store(*key.get(), *data.get(), SkString());
Yichi Chen9f959552018-03-29 21:21:54 +0800317 }
318 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
319
320 // change to a file that does not exist and verify validation fails
321 ShaderCache::get().setFilename(cacheFile2.c_str());
322 ShaderCache::get().initShaderDiskCache();
John Reck283bb462018-12-13 16:40:14 -0800323 ASSERT_FALSE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800324 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
325
326 // restore the original file and verify validation succeeds
327 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800328 ShaderCache::get().initShaderDiskCache(
329 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
330 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800331 for (const auto& blob : blobVec) {
332 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800333 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800334 }
335
336 // generate error identity and verify load fails
337 ShaderCache::get().initShaderDiskCache(identity.data(), -1);
338 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800339 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800340 }
John Reck283bb462018-12-13 16:40:14 -0800341 ShaderCache::get().initShaderDiskCache(
342 nullptr, identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800343 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800344 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800345 }
346
347 // verify the cache validation again after load fails
John Reck283bb462018-12-13 16:40:14 -0800348 ShaderCache::get().initShaderDiskCache(
349 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
350 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800351 for (const auto& blob : blobVec) {
352 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800353 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800354 }
355
356 // generate another identity and verify load fails
357 for (auto& data : identity) {
358 data += std::rand();
359 }
John Reck283bb462018-12-13 16:40:14 -0800360 ShaderCache::get().initShaderDiskCache(
361 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800362 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800363 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800364 }
365
366 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
Nolan Scobie193cd962023-02-08 20:03:31 -0500367 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
368 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
369}
370
371using namespace android::uirenderer;
372RENDERTHREAD_SKIA_PIPELINE_TEST(ShaderCacheTest, testOnVkFrameFlushed) {
373 if (Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan) {
374 // RENDERTHREAD_SKIA_PIPELINE_TEST declares both SkiaVK and SkiaGL variants.
375 GTEST_SKIP() << "This test is only applicable to RenderPipelineType::SkiaVulkan";
376 }
377 if (!folderExist(getExternalStorageFolder())) {
378 // Don't run the test if external storage folder is not available
379 return;
380 }
381 std::string cacheFile = getExternalStorageFolder() + "/shaderCacheTest";
382 GrDirectContext* grContext = renderThread.getGrContext();
383
384 // Remove any test files from previous test run
385 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile));
386
387 // The first iteration of this loop is to save an initial VkPipelineCache data blob to disk,
388 // which sets up the second iteration for a common scenario of comparing a "new" VkPipelineCache
389 // blob passed to "store" against the same blob that's already in the persistent cache from a
390 // previous launch. "reinitializeAllFields" is critical to emulate each iteration being as close
391 // to the state of a freshly launched app as possible, as the initial values of member variables
392 // like mInStoreVkPipelineInProgress and mOldPipelineCacheSize are critical to catch issues
393 // such as b/268205519
394 for (int flushIteration = 1; flushIteration <= 2; flushIteration++) {
395 SCOPED_TRACE("Frame flush iteration " + std::to_string(flushIteration));
396 // Reset *all* in-memory data and reload the cache from disk.
397 ShaderCacheTestUtils::reinitializeAllFields(ShaderCache::get());
398 ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 10); // Delay must be > 0 to save.
399 ShaderCache::get().setFilename(cacheFile.c_str());
400 ShaderCache::get().initShaderDiskCache();
401
402 // 1st iteration: store pipeline data to be read back on a subsequent "boot" of the "app".
403 // 2nd iteration: ensure that an initial frame flush (without storing any shaders) given the
404 // same pipeline data that's already on disk doesn't break the cache.
405 ShaderCache::get().onVkFrameFlushed(grContext);
406 ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get()));
407 }
408
409 constexpr char shader1[] = "sassas";
410 constexpr char shader2[] = "someVS";
411 constexpr int numIterations = 3;
412 // Also do n iterations of separate "store some shaders then flush the frame" pairs to just
413 // double-check the cache also doesn't get stuck from that use case.
414 for (int saveIteration = 1; saveIteration <= numIterations; saveIteration++) {
415 SCOPED_TRACE("Shader save iteration " + std::to_string(saveIteration));
416 // Write twice to the in-memory cache, which should start a deferred save with both queued.
417 sk_sp<SkData> inVS;
418 setShader(inVS, shader1 + std::to_string(saveIteration));
419 ShaderCache::get().store(GrProgramDescTest(100), *inVS.get(), SkString());
420 setShader(inVS, shader2 + std::to_string(saveIteration));
421 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
422
423 // Simulate flush to also save latest pipeline info.
424 ShaderCache::get().onVkFrameFlushed(grContext);
425 ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get()));
426 }
427
428 // Reload from disk to ensure saving succeeded.
429 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
430 ShaderCache::get().initShaderDiskCache();
431
432 // Read twice, ensure equal to last store.
433 sk_sp<SkData> outVS;
434 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
435 ASSERT_TRUE(checkShader(outVS, shader1 + std::to_string(numIterations)));
436 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
437 ASSERT_TRUE(checkShader(outVS, shader2 + std::to_string(numIterations)));
438
439 // Clean up.
440 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
441 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile));
Yichi Chen9f959552018-03-29 21:21:54 +0800442}
443
Stan Ilievd495f432017-10-09 15:49:32 -0400444} // namespace