blob: 87981f115763cb441cce57093f08eec9a905d1dd [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
Stan Ilievd495f432017-10-09 15:49:32 -040017#include <cutils/properties.h>
John Reck283bb462018-12-13 16:40:14 -080018#include <dirent.h>
Stan Ilievd495f432017-10-09 15:49:32 -040019#include <errno.h>
John Reck283bb462018-12-13 16:40:14 -080020#include <gtest/gtest.h>
Stan Ilievd495f432017-10-09 15:49:32 -040021#include <stdio.h>
22#include <stdlib.h>
23#include <sys/types.h>
24#include <utils/Log.h>
John Reck283bb462018-12-13 16:40:14 -080025#include <cstdint>
Stan Ilievd495f432017-10-09 15:49:32 -040026#include "FileBlobCache.h"
John Reck283bb462018-12-13 16:40:14 -080027#include "pipeline/skia/ShaderCache.h"
Stan Ilievd495f432017-10-09 15:49:32 -040028
29using namespace android::uirenderer::skiapipeline;
30
31namespace android {
32namespace uirenderer {
33namespace skiapipeline {
34
35class ShaderCacheTestUtils {
36public:
37 /**
38 * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries.
39 * If set to 0, then deferred save is disabled.
40 */
41 static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) {
42 cache.mDeferredSaveDelay = saveDelay;
43 }
44
45 /**
46 * "terminate" optionally stores the BlobCache on disk and release all in-memory cache.
47 * Next call to "initShaderDiskCache" will load again the in-memory cache from disk.
48 */
49 static void terminate(ShaderCache& cache, bool saveContent) {
50 std::lock_guard<std::mutex> lock(cache.mMutex);
Yichi Chen9f959552018-03-29 21:21:54 +080051 cache.mSavePending = saveContent;
52 cache.saveToDiskLocked();
Stan Ilievd495f432017-10-09 15:49:32 -040053 cache.mBlobCache = NULL;
54 }
Yichi Chen9f959552018-03-29 21:21:54 +080055
56 /**
57 *
58 */
59 template <typename T>
60 static bool validateCache(ShaderCache& cache, std::vector<T> hash) {
61 return cache.validateCache(hash.data(), hash.size() * sizeof(T));
62 }
Stan Ilievd495f432017-10-09 15:49:32 -040063};
64
65} /* namespace skiapipeline */
66} /* namespace uirenderer */
67} /* namespace android */
68
Stan Ilievd495f432017-10-09 15:49:32 -040069namespace {
70
71std::string getExternalStorageFolder() {
72 return getenv("EXTERNAL_STORAGE");
73}
74
75bool folderExist(const std::string& folderName) {
76 DIR* dir = opendir(folderName.c_str());
77 if (dir) {
78 closedir(dir);
79 return true;
80 }
81 return false;
82}
83
John Reck283bb462018-12-13 16:40:14 -080084inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
85 return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() &&
86 0 == memcmp(shader1->data(), shader2->data(), shader1->size());
Stan Ilievd495f432017-10-09 15:49:32 -040087}
88
John Reck283bb462018-12-13 16:40:14 -080089inline bool checkShader(const sk_sp<SkData>& shader, const char* program) {
Yichi Chen9f959552018-03-29 21:21:54 +080090 sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
91 return checkShader(shader, shader2);
92}
93
94template <typename T>
95bool checkShader(const sk_sp<SkData>& shader, std::vector<T>& program) {
96 sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size() * sizeof(T));
97 return checkShader(shader, shader2);
Stan Ilievd495f432017-10-09 15:49:32 -040098}
99
100void setShader(sk_sp<SkData>& shader, const char* program) {
101 shader = SkData::MakeWithCString(program);
102}
103
Yichi Chen9f959552018-03-29 21:21:54 +0800104template <typename T>
105void setShader(sk_sp<SkData>& shader, std::vector<T>& buffer) {
106 shader = SkData::MakeWithCopy(buffer.data(), buffer.size() * sizeof(T));
Stan Ilievd495f432017-10-09 15:49:32 -0400107}
108
Yichi Chen9f959552018-03-29 21:21:54 +0800109template <typename T>
110void genRandomData(std::vector<T>& buffer) {
111 for (auto& data : buffer) {
112 data = T(std::rand());
113 }
114}
Stan Ilievd495f432017-10-09 15:49:32 -0400115
Stan Ilievd495f432017-10-09 15:49:32 -0400116#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
117
118TEST(ShaderCacheTest, testWriteAndRead) {
119 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800120 // don't run the test if external storage folder is not available
Stan Ilievd495f432017-10-09 15:49:32 -0400121 return;
122 }
John Reck283bb462018-12-13 16:40:14 -0800123 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
124 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Stan Ilievd495f432017-10-09 15:49:32 -0400125
John Reck283bb462018-12-13 16:40:14 -0800126 // remove any test files from previous test run
Stan Ilievd495f432017-10-09 15:49:32 -0400127 int deleteFile = remove(cacheFile1.c_str());
128 ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
Yichi Chen9f959552018-03-29 21:21:54 +0800129 std::srand(0);
Stan Ilievd495f432017-10-09 15:49:32 -0400130
John Reck283bb462018-12-13 16:40:14 -0800131 // read the cache from a file that does not exist
Stan Ilievd495f432017-10-09 15:49:32 -0400132 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800133 ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
Stan Ilievd495f432017-10-09 15:49:32 -0400134 ShaderCache::get().initShaderDiskCache();
135
John Reck283bb462018-12-13 16:40:14 -0800136 // read a key - should not be found since the cache is empty
Stan Ilievd495f432017-10-09 15:49:32 -0400137 sk_sp<SkData> outVS;
138 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
139
John Reck283bb462018-12-13 16:40:14 -0800140 // write to the in-memory cache without storing on disk and verify we read the same values
Stan Ilievd495f432017-10-09 15:49:32 -0400141 sk_sp<SkData> inVS;
142 setShader(inVS, "sassas");
143 ShaderCache::get().store(GrProgramDescTest(100), *inVS.get());
144 setShader(inVS, "someVS");
145 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
146 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
147 ASSERT_TRUE(checkShader(outVS, "sassas"));
148 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
149 ASSERT_TRUE(checkShader(outVS, "someVS"));
150
John Reck283bb462018-12-13 16:40:14 -0800151 // store content to disk and release in-memory cache
Stan Ilievd495f432017-10-09 15:49:32 -0400152 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
153
John Reck283bb462018-12-13 16:40:14 -0800154 // change to a file that does not exist and verify load fails
Stan Ilievd495f432017-10-09 15:49:32 -0400155 ShaderCache::get().setFilename(cacheFile2.c_str());
156 ShaderCache::get().initShaderDiskCache();
157 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
158 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
159
John Reck283bb462018-12-13 16:40:14 -0800160 // load again content from disk from an existing file and check the data is read correctly
Stan Ilievd495f432017-10-09 15:49:32 -0400161 ShaderCache::get().setFilename(cacheFile1.c_str());
162 ShaderCache::get().initShaderDiskCache();
163 sk_sp<SkData> outVS2;
164 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
165 ASSERT_TRUE(checkShader(outVS2, "someVS"));
166
John Reck283bb462018-12-13 16:40:14 -0800167 // change data, store to disk, read back again and verify data has been changed
Stan Ilievd495f432017-10-09 15:49:32 -0400168 setShader(inVS, "ewData1");
169 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
170 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
171 ShaderCache::get().initShaderDiskCache();
172 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
173 ASSERT_TRUE(checkShader(outVS2, "ewData1"));
174
John Reck283bb462018-12-13 16:40:14 -0800175 // write and read big data chunk (50K)
176 size_t dataSize = 50 * 1024;
Yichi Chen9f959552018-03-29 21:21:54 +0800177 std::vector<uint8_t> dataBuffer(dataSize);
178 genRandomData(dataBuffer);
Stan Ilievd495f432017-10-09 15:49:32 -0400179 setShader(inVS, dataBuffer);
180 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
181 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
182 ShaderCache::get().initShaderDiskCache();
183 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
184 ASSERT_TRUE(checkShader(outVS2, dataBuffer));
185
186 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
187 remove(cacheFile1.c_str());
188}
189
Yichi Chen9f959552018-03-29 21:21:54 +0800190TEST(ShaderCacheTest, testCacheValidation) {
191 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800192 // don't run the test if external storage folder is not available
Yichi Chen9f959552018-03-29 21:21:54 +0800193 return;
194 }
John Reck283bb462018-12-13 16:40:14 -0800195 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
196 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Yichi Chen9f959552018-03-29 21:21:54 +0800197
John Reck283bb462018-12-13 16:40:14 -0800198 // remove any test files from previous test run
Yichi Chen9f959552018-03-29 21:21:54 +0800199 int deleteFile = remove(cacheFile1.c_str());
200 ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
201 std::srand(0);
202
John Reck283bb462018-12-13 16:40:14 -0800203 // generate identity and read the cache from a file that does not exist
Yichi Chen9f959552018-03-29 21:21:54 +0800204 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800205 ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
Yichi Chen9f959552018-03-29 21:21:54 +0800206 std::vector<uint8_t> identity(1024);
207 genRandomData(identity);
John Reck283bb462018-12-13 16:40:14 -0800208 ShaderCache::get().initShaderDiskCache(
209 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800210
211 // generate random content in cache and store to disk
212 constexpr size_t numBlob(10);
213 constexpr size_t keySize(1024);
214 constexpr size_t dataSize(50 * 1024);
215
John Reck283bb462018-12-13 16:40:14 -0800216 std::vector<std::pair<sk_sp<SkData>, sk_sp<SkData>>> blobVec(numBlob);
Yichi Chen9f959552018-03-29 21:21:54 +0800217 for (auto& blob : blobVec) {
218 std::vector<uint8_t> keyBuffer(keySize);
219 std::vector<uint8_t> dataBuffer(dataSize);
220 genRandomData(keyBuffer);
221 genRandomData(dataBuffer);
222
223 sk_sp<SkData> key, data;
224 setShader(key, keyBuffer);
225 setShader(data, dataBuffer);
226
227 blob = std::make_pair(key, data);
228 ShaderCache::get().store(*key.get(), *data.get());
229 }
230 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
231
232 // change to a file that does not exist and verify validation fails
233 ShaderCache::get().setFilename(cacheFile2.c_str());
234 ShaderCache::get().initShaderDiskCache();
John Reck283bb462018-12-13 16:40:14 -0800235 ASSERT_FALSE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800236 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
237
238 // restore the original file and verify validation succeeds
239 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800240 ShaderCache::get().initShaderDiskCache(
241 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
242 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800243 for (const auto& blob : blobVec) {
244 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800245 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800246 }
247
248 // generate error identity and verify load fails
249 ShaderCache::get().initShaderDiskCache(identity.data(), -1);
250 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800251 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800252 }
John Reck283bb462018-12-13 16:40:14 -0800253 ShaderCache::get().initShaderDiskCache(
254 nullptr, identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800255 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800256 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800257 }
258
259 // verify the cache validation again after load fails
John Reck283bb462018-12-13 16:40:14 -0800260 ShaderCache::get().initShaderDiskCache(
261 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
262 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800263 for (const auto& blob : blobVec) {
264 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800265 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800266 }
267
268 // generate another identity and verify load fails
269 for (auto& data : identity) {
270 data += std::rand();
271 }
John Reck283bb462018-12-13 16:40:14 -0800272 ShaderCache::get().initShaderDiskCache(
273 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800274 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800275 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800276 }
277
278 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
279 remove(cacheFile1.c_str());
280}
281
Stan Ilievd495f432017-10-09 15:49:32 -0400282} // namespace