blob: 0f8bd1368f5a3297f618955dbcb79b32b5ec2057 [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();
Matt Buckleye278da12023-06-20 22:51:05 +000052 std::lock_guard lock(cache.mMutex), newLock(newCache.mMutex);
Nolan Scobie193cd962023-02-08 20:03:31 -050053 // 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) {
Matt Buckleye278da12023-06-20 22:51:05 +000075 std::lock_guard lock(cache.mMutex);
Nolan Scobie193cd962023-02-08 20:03:31 -050076 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) {
Matt Buckleye278da12023-06-20 22:51:05 +000084 std::lock_guard 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) {
Matt Buckleye278da12023-06-20 22:51:05 +000096 std::lock_guard lock(cache.mMutex);
Yichi Chen9f959552018-03-29 21:21:54 +080097 return cache.validateCache(hash.data(), hash.size() * sizeof(T));
98 }
Nolan Scobie193cd962023-02-08 20:03:31 -050099
100 /**
101 * Waits until cache::mSavePending is false, checking every 0.1 ms *while the mutex is free*.
102 *
103 * Fails if there was no save pending, or if the cache was already being written to disk, or if
104 * timeoutMs is exceeded.
105 *
106 * Note: timeoutMs only guards against mSavePending getting stuck like in b/268205519, and
107 * cannot protect against mutex-based deadlock. Reaching timeoutMs implies something is broken,
108 * so setting it to a sufficiently large value will not delay execution in the happy state.
109 */
110 static void waitForPendingSave(ShaderCache& cache, const int timeoutMs = 50) {
111 {
Matt Buckleye278da12023-06-20 22:51:05 +0000112 std::lock_guard lock(cache.mMutex);
Nolan Scobie193cd962023-02-08 20:03:31 -0500113 ASSERT_TRUE(cache.mSavePending);
114 }
115 bool saving = true;
116 float elapsedMilliseconds = 0;
117 while (saving) {
118 if (elapsedMilliseconds >= timeoutMs) {
119 FAIL() << "Timed out after waiting " << timeoutMs << " ms for a pending save";
120 }
121 // This small (0.1 ms) delay is to avoid working too much while waiting for
122 // deferredSaveThread to take the mutex and start the disk write.
123 const int delayMicroseconds = 100;
124 usleep(delayMicroseconds);
125 elapsedMilliseconds += (float)delayMicroseconds / 1000;
126
Matt Buckleye278da12023-06-20 22:51:05 +0000127 std::lock_guard lock(cache.mMutex);
Nolan Scobie193cd962023-02-08 20:03:31 -0500128 saving = cache.mSavePending;
129 }
130 }
Stan Ilievd495f432017-10-09 15:49:32 -0400131};
132
133} /* namespace skiapipeline */
134} /* namespace uirenderer */
135} /* namespace android */
136
Stan Ilievd495f432017-10-09 15:49:32 -0400137namespace {
138
139std::string getExternalStorageFolder() {
140 return getenv("EXTERNAL_STORAGE");
141}
142
143bool folderExist(const std::string& folderName) {
144 DIR* dir = opendir(folderName.c_str());
145 if (dir) {
146 closedir(dir);
147 return true;
148 }
149 return false;
150}
151
Nolan Scobie193cd962023-02-08 20:03:31 -0500152/**
153 * Attempts to delete the given file, and asserts that either:
154 * 1. Deletion was successful, OR
155 * 2. The file did not exist.
156 *
157 * Tip: wrap calls to this in ASSERT_NO_FATAL_FAILURE(x) if a test should exit early if this fails.
158 */
159void deleteFileAssertSuccess(const std::string& filePath) {
160 int deleteResult = remove(filePath.c_str());
161 ASSERT_TRUE(0 == deleteResult || ENOENT == errno);
162}
163
John Reck283bb462018-12-13 16:40:14 -0800164inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
165 return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() &&
166 0 == memcmp(shader1->data(), shader2->data(), shader1->size());
Stan Ilievd495f432017-10-09 15:49:32 -0400167}
168
John Reck283bb462018-12-13 16:40:14 -0800169inline bool checkShader(const sk_sp<SkData>& shader, const char* program) {
Yichi Chen9f959552018-03-29 21:21:54 +0800170 sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
171 return checkShader(shader, shader2);
172}
173
Nolan Scobie193cd962023-02-08 20:03:31 -0500174inline bool checkShader(const sk_sp<SkData>& shader, const std::string& program) {
175 return checkShader(shader, program.c_str());
176}
177
Yichi Chen9f959552018-03-29 21:21:54 +0800178template <typename T>
179bool checkShader(const sk_sp<SkData>& shader, std::vector<T>& program) {
180 sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size() * sizeof(T));
181 return checkShader(shader, shader2);
Stan Ilievd495f432017-10-09 15:49:32 -0400182}
183
184void setShader(sk_sp<SkData>& shader, const char* program) {
185 shader = SkData::MakeWithCString(program);
186}
187
Nolan Scobie193cd962023-02-08 20:03:31 -0500188void setShader(sk_sp<SkData>& shader, const std::string& program) {
189 setShader(shader, program.c_str());
190}
191
Yichi Chen9f959552018-03-29 21:21:54 +0800192template <typename T>
193void setShader(sk_sp<SkData>& shader, std::vector<T>& buffer) {
194 shader = SkData::MakeWithCopy(buffer.data(), buffer.size() * sizeof(T));
Stan Ilievd495f432017-10-09 15:49:32 -0400195}
196
Yichi Chen9f959552018-03-29 21:21:54 +0800197template <typename T>
198void genRandomData(std::vector<T>& buffer) {
199 for (auto& data : buffer) {
200 data = T(std::rand());
201 }
202}
Stan Ilievd495f432017-10-09 15:49:32 -0400203
Stan Ilievd495f432017-10-09 15:49:32 -0400204#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
205
206TEST(ShaderCacheTest, testWriteAndRead) {
207 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800208 // don't run the test if external storage folder is not available
Stan Ilievd495f432017-10-09 15:49:32 -0400209 return;
210 }
John Reck283bb462018-12-13 16:40:14 -0800211 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
212 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Stan Ilievd495f432017-10-09 15:49:32 -0400213
John Reck283bb462018-12-13 16:40:14 -0800214 // remove any test files from previous test run
Nolan Scobie193cd962023-02-08 20:03:31 -0500215 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
216 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
Yichi Chen9f959552018-03-29 21:21:54 +0800217 std::srand(0);
Stan Ilievd495f432017-10-09 15:49:32 -0400218
John Reck283bb462018-12-13 16:40:14 -0800219 // read the cache from a file that does not exist
Stan Ilievd495f432017-10-09 15:49:32 -0400220 ShaderCache::get().setFilename(cacheFile1.c_str());
Nolan Scobie193cd962023-02-08 20:03:31 -0500221 ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save
Stan Ilievd495f432017-10-09 15:49:32 -0400222 ShaderCache::get().initShaderDiskCache();
223
John Reck283bb462018-12-13 16:40:14 -0800224 // read a key - should not be found since the cache is empty
Stan Ilievd495f432017-10-09 15:49:32 -0400225 sk_sp<SkData> outVS;
226 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
227
John Reck283bb462018-12-13 16:40:14 -0800228 // write to the in-memory cache without storing on disk and verify we read the same values
Stan Ilievd495f432017-10-09 15:49:32 -0400229 sk_sp<SkData> inVS;
230 setShader(inVS, "sassas");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400231 ShaderCache::get().store(GrProgramDescTest(100), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400232 setShader(inVS, "someVS");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400233 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400234 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
235 ASSERT_TRUE(checkShader(outVS, "sassas"));
236 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
237 ASSERT_TRUE(checkShader(outVS, "someVS"));
238
John Reck283bb462018-12-13 16:40:14 -0800239 // store content to disk and release in-memory cache
Stan Ilievd495f432017-10-09 15:49:32 -0400240 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
241
John Reck283bb462018-12-13 16:40:14 -0800242 // change to a file that does not exist and verify load fails
Stan Ilievd495f432017-10-09 15:49:32 -0400243 ShaderCache::get().setFilename(cacheFile2.c_str());
244 ShaderCache::get().initShaderDiskCache();
245 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
246 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
247
John Reck283bb462018-12-13 16:40:14 -0800248 // load again content from disk from an existing file and check the data is read correctly
Stan Ilievd495f432017-10-09 15:49:32 -0400249 ShaderCache::get().setFilename(cacheFile1.c_str());
250 ShaderCache::get().initShaderDiskCache();
251 sk_sp<SkData> outVS2;
252 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
253 ASSERT_TRUE(checkShader(outVS2, "someVS"));
254
John Reck283bb462018-12-13 16:40:14 -0800255 // change data, store to disk, read back again and verify data has been changed
Stan Ilievd495f432017-10-09 15:49:32 -0400256 setShader(inVS, "ewData1");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400257 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400258 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
259 ShaderCache::get().initShaderDiskCache();
260 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
261 ASSERT_TRUE(checkShader(outVS2, "ewData1"));
262
John Reck283bb462018-12-13 16:40:14 -0800263 // write and read big data chunk (50K)
264 size_t dataSize = 50 * 1024;
Yichi Chen9f959552018-03-29 21:21:54 +0800265 std::vector<uint8_t> dataBuffer(dataSize);
266 genRandomData(dataBuffer);
Stan Ilievd495f432017-10-09 15:49:32 -0400267 setShader(inVS, dataBuffer);
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400268 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400269 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
270 ShaderCache::get().initShaderDiskCache();
271 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
272 ASSERT_TRUE(checkShader(outVS2, dataBuffer));
273
274 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
Nolan Scobie193cd962023-02-08 20:03:31 -0500275 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
276 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
Stan Ilievd495f432017-10-09 15:49:32 -0400277}
278
Yichi Chen9f959552018-03-29 21:21:54 +0800279TEST(ShaderCacheTest, testCacheValidation) {
280 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800281 // don't run the test if external storage folder is not available
Yichi Chen9f959552018-03-29 21:21:54 +0800282 return;
283 }
John Reck283bb462018-12-13 16:40:14 -0800284 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
285 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Yichi Chen9f959552018-03-29 21:21:54 +0800286
John Reck283bb462018-12-13 16:40:14 -0800287 // remove any test files from previous test run
Nolan Scobie193cd962023-02-08 20:03:31 -0500288 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
289 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
Yichi Chen9f959552018-03-29 21:21:54 +0800290 std::srand(0);
291
John Reck283bb462018-12-13 16:40:14 -0800292 // generate identity and read the cache from a file that does not exist
Yichi Chen9f959552018-03-29 21:21:54 +0800293 ShaderCache::get().setFilename(cacheFile1.c_str());
Nolan Scobie193cd962023-02-08 20:03:31 -0500294 ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 0); // disable deferred save
Yichi Chen9f959552018-03-29 21:21:54 +0800295 std::vector<uint8_t> identity(1024);
296 genRandomData(identity);
John Reck283bb462018-12-13 16:40:14 -0800297 ShaderCache::get().initShaderDiskCache(
298 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800299
300 // generate random content in cache and store to disk
301 constexpr size_t numBlob(10);
302 constexpr size_t keySize(1024);
303 constexpr size_t dataSize(50 * 1024);
304
John Reck283bb462018-12-13 16:40:14 -0800305 std::vector<std::pair<sk_sp<SkData>, sk_sp<SkData>>> blobVec(numBlob);
Yichi Chen9f959552018-03-29 21:21:54 +0800306 for (auto& blob : blobVec) {
307 std::vector<uint8_t> keyBuffer(keySize);
308 std::vector<uint8_t> dataBuffer(dataSize);
309 genRandomData(keyBuffer);
310 genRandomData(dataBuffer);
311
312 sk_sp<SkData> key, data;
313 setShader(key, keyBuffer);
314 setShader(data, dataBuffer);
315
316 blob = std::make_pair(key, data);
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400317 ShaderCache::get().store(*key.get(), *data.get(), SkString());
Yichi Chen9f959552018-03-29 21:21:54 +0800318 }
319 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
320
321 // change to a file that does not exist and verify validation fails
322 ShaderCache::get().setFilename(cacheFile2.c_str());
323 ShaderCache::get().initShaderDiskCache();
John Reck283bb462018-12-13 16:40:14 -0800324 ASSERT_FALSE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800325 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
326
327 // restore the original file and verify validation succeeds
328 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800329 ShaderCache::get().initShaderDiskCache(
330 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
331 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800332 for (const auto& blob : blobVec) {
333 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800334 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800335 }
336
337 // generate error identity and verify load fails
338 ShaderCache::get().initShaderDiskCache(identity.data(), -1);
339 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800340 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800341 }
John Reck283bb462018-12-13 16:40:14 -0800342 ShaderCache::get().initShaderDiskCache(
343 nullptr, identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800344 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800345 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800346 }
347
348 // verify the cache validation again after load fails
John Reck283bb462018-12-13 16:40:14 -0800349 ShaderCache::get().initShaderDiskCache(
350 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
351 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800352 for (const auto& blob : blobVec) {
353 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800354 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800355 }
356
357 // generate another identity and verify load fails
358 for (auto& data : identity) {
359 data += std::rand();
360 }
John Reck283bb462018-12-13 16:40:14 -0800361 ShaderCache::get().initShaderDiskCache(
362 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800363 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800364 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800365 }
366
367 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
Nolan Scobie193cd962023-02-08 20:03:31 -0500368 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile1));
369 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile2));
370}
371
372using namespace android::uirenderer;
John Reck1efef7b2023-07-17 23:29:30 -0400373RENDERTHREAD_TEST(ShaderCacheTest, testOnVkFrameFlushed) {
Nolan Scobie193cd962023-02-08 20:03:31 -0500374 if (Properties::getRenderPipelineType() != RenderPipelineType::SkiaVulkan) {
John Reck1efef7b2023-07-17 23:29:30 -0400375 // RENDERTHREAD_TEST declares both SkiaVK and SkiaGL variants.
Nolan Scobie193cd962023-02-08 20:03:31 -0500376 GTEST_SKIP() << "This test is only applicable to RenderPipelineType::SkiaVulkan";
377 }
378 if (!folderExist(getExternalStorageFolder())) {
379 // Don't run the test if external storage folder is not available
380 return;
381 }
382 std::string cacheFile = getExternalStorageFolder() + "/shaderCacheTest";
383 GrDirectContext* grContext = renderThread.getGrContext();
384
385 // Remove any test files from previous test run
386 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile));
387
388 // The first iteration of this loop is to save an initial VkPipelineCache data blob to disk,
389 // which sets up the second iteration for a common scenario of comparing a "new" VkPipelineCache
390 // blob passed to "store" against the same blob that's already in the persistent cache from a
391 // previous launch. "reinitializeAllFields" is critical to emulate each iteration being as close
392 // to the state of a freshly launched app as possible, as the initial values of member variables
393 // like mInStoreVkPipelineInProgress and mOldPipelineCacheSize are critical to catch issues
394 // such as b/268205519
395 for (int flushIteration = 1; flushIteration <= 2; flushIteration++) {
396 SCOPED_TRACE("Frame flush iteration " + std::to_string(flushIteration));
397 // Reset *all* in-memory data and reload the cache from disk.
398 ShaderCacheTestUtils::reinitializeAllFields(ShaderCache::get());
399 ShaderCacheTestUtils::setSaveDelayMs(ShaderCache::get(), 10); // Delay must be > 0 to save.
400 ShaderCache::get().setFilename(cacheFile.c_str());
401 ShaderCache::get().initShaderDiskCache();
402
403 // 1st iteration: store pipeline data to be read back on a subsequent "boot" of the "app".
404 // 2nd iteration: ensure that an initial frame flush (without storing any shaders) given the
405 // same pipeline data that's already on disk doesn't break the cache.
406 ShaderCache::get().onVkFrameFlushed(grContext);
407 ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get()));
408 }
409
410 constexpr char shader1[] = "sassas";
411 constexpr char shader2[] = "someVS";
412 constexpr int numIterations = 3;
413 // Also do n iterations of separate "store some shaders then flush the frame" pairs to just
414 // double-check the cache also doesn't get stuck from that use case.
415 for (int saveIteration = 1; saveIteration <= numIterations; saveIteration++) {
416 SCOPED_TRACE("Shader save iteration " + std::to_string(saveIteration));
417 // Write twice to the in-memory cache, which should start a deferred save with both queued.
418 sk_sp<SkData> inVS;
419 setShader(inVS, shader1 + std::to_string(saveIteration));
420 ShaderCache::get().store(GrProgramDescTest(100), *inVS.get(), SkString());
421 setShader(inVS, shader2 + std::to_string(saveIteration));
422 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
423
424 // Simulate flush to also save latest pipeline info.
425 ShaderCache::get().onVkFrameFlushed(grContext);
426 ASSERT_NO_FATAL_FAILURE(ShaderCacheTestUtils::waitForPendingSave(ShaderCache::get()));
427 }
428
429 // Reload from disk to ensure saving succeeded.
430 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
431 ShaderCache::get().initShaderDiskCache();
432
433 // Read twice, ensure equal to last store.
434 sk_sp<SkData> outVS;
435 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
436 ASSERT_TRUE(checkShader(outVS, shader1 + std::to_string(numIterations)));
437 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
438 ASSERT_TRUE(checkShader(outVS, shader2 + std::to_string(numIterations)));
439
440 // Clean up.
441 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
442 ASSERT_NO_FATAL_FAILURE(deleteFileAssertSuccess(cacheFile));
Yichi Chen9f959552018-03-29 21:21:54 +0800443}
444
Stan Ilievd495f432017-10-09 15:49:32 -0400445} // namespace