blob: 576e9466d322d4c7e5be10f4a83bf77e185ca1ff [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"
Kevin Lubick1175dc02022-02-28 12:41:27 -050028#include <SkData.h>
29#include <SkRefCnt.h>
Stan Ilievd495f432017-10-09 15:49:32 -040030
31using namespace android::uirenderer::skiapipeline;
32
33namespace android {
34namespace uirenderer {
35namespace skiapipeline {
36
37class ShaderCacheTestUtils {
38public:
39 /**
40 * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries.
41 * If set to 0, then deferred save is disabled.
42 */
43 static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) {
44 cache.mDeferredSaveDelay = saveDelay;
45 }
46
47 /**
48 * "terminate" optionally stores the BlobCache on disk and release all in-memory cache.
49 * Next call to "initShaderDiskCache" will load again the in-memory cache from disk.
50 */
51 static void terminate(ShaderCache& cache, bool saveContent) {
52 std::lock_guard<std::mutex> lock(cache.mMutex);
Yichi Chen9f959552018-03-29 21:21:54 +080053 cache.mSavePending = saveContent;
54 cache.saveToDiskLocked();
Stan Ilievd495f432017-10-09 15:49:32 -040055 cache.mBlobCache = NULL;
56 }
Yichi Chen9f959552018-03-29 21:21:54 +080057
58 /**
59 *
60 */
61 template <typename T>
62 static bool validateCache(ShaderCache& cache, std::vector<T> hash) {
63 return cache.validateCache(hash.data(), hash.size() * sizeof(T));
64 }
Stan Ilievd495f432017-10-09 15:49:32 -040065};
66
67} /* namespace skiapipeline */
68} /* namespace uirenderer */
69} /* namespace android */
70
Stan Ilievd495f432017-10-09 15:49:32 -040071namespace {
72
73std::string getExternalStorageFolder() {
74 return getenv("EXTERNAL_STORAGE");
75}
76
77bool folderExist(const std::string& folderName) {
78 DIR* dir = opendir(folderName.c_str());
79 if (dir) {
80 closedir(dir);
81 return true;
82 }
83 return false;
84}
85
John Reck283bb462018-12-13 16:40:14 -080086inline bool checkShader(const sk_sp<SkData>& shader1, const sk_sp<SkData>& shader2) {
87 return nullptr != shader1 && nullptr != shader2 && shader1->size() == shader2->size() &&
88 0 == memcmp(shader1->data(), shader2->data(), shader1->size());
Stan Ilievd495f432017-10-09 15:49:32 -040089}
90
John Reck283bb462018-12-13 16:40:14 -080091inline bool checkShader(const sk_sp<SkData>& shader, const char* program) {
Yichi Chen9f959552018-03-29 21:21:54 +080092 sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
93 return checkShader(shader, shader2);
94}
95
96template <typename T>
97bool checkShader(const sk_sp<SkData>& shader, std::vector<T>& program) {
98 sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size() * sizeof(T));
99 return checkShader(shader, shader2);
Stan Ilievd495f432017-10-09 15:49:32 -0400100}
101
102void setShader(sk_sp<SkData>& shader, const char* program) {
103 shader = SkData::MakeWithCString(program);
104}
105
Yichi Chen9f959552018-03-29 21:21:54 +0800106template <typename T>
107void setShader(sk_sp<SkData>& shader, std::vector<T>& buffer) {
108 shader = SkData::MakeWithCopy(buffer.data(), buffer.size() * sizeof(T));
Stan Ilievd495f432017-10-09 15:49:32 -0400109}
110
Yichi Chen9f959552018-03-29 21:21:54 +0800111template <typename T>
112void genRandomData(std::vector<T>& buffer) {
113 for (auto& data : buffer) {
114 data = T(std::rand());
115 }
116}
Stan Ilievd495f432017-10-09 15:49:32 -0400117
Stan Ilievd495f432017-10-09 15:49:32 -0400118#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
119
120TEST(ShaderCacheTest, testWriteAndRead) {
121 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800122 // don't run the test if external storage folder is not available
Stan Ilievd495f432017-10-09 15:49:32 -0400123 return;
124 }
John Reck283bb462018-12-13 16:40:14 -0800125 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
126 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Stan Ilievd495f432017-10-09 15:49:32 -0400127
John Reck283bb462018-12-13 16:40:14 -0800128 // remove any test files from previous test run
Stan Ilievd495f432017-10-09 15:49:32 -0400129 int deleteFile = remove(cacheFile1.c_str());
130 ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
Yichi Chen9f959552018-03-29 21:21:54 +0800131 std::srand(0);
Stan Ilievd495f432017-10-09 15:49:32 -0400132
John Reck283bb462018-12-13 16:40:14 -0800133 // read the cache from a file that does not exist
Stan Ilievd495f432017-10-09 15:49:32 -0400134 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800135 ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
Stan Ilievd495f432017-10-09 15:49:32 -0400136 ShaderCache::get().initShaderDiskCache();
137
John Reck283bb462018-12-13 16:40:14 -0800138 // read a key - should not be found since the cache is empty
Stan Ilievd495f432017-10-09 15:49:32 -0400139 sk_sp<SkData> outVS;
140 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
141
John Reck283bb462018-12-13 16:40:14 -0800142 // write to the in-memory cache without storing on disk and verify we read the same values
Stan Ilievd495f432017-10-09 15:49:32 -0400143 sk_sp<SkData> inVS;
144 setShader(inVS, "sassas");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400145 ShaderCache::get().store(GrProgramDescTest(100), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400146 setShader(inVS, "someVS");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400147 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400148 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
149 ASSERT_TRUE(checkShader(outVS, "sassas"));
150 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
151 ASSERT_TRUE(checkShader(outVS, "someVS"));
152
John Reck283bb462018-12-13 16:40:14 -0800153 // store content to disk and release in-memory cache
Stan Ilievd495f432017-10-09 15:49:32 -0400154 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
155
John Reck283bb462018-12-13 16:40:14 -0800156 // change to a file that does not exist and verify load fails
Stan Ilievd495f432017-10-09 15:49:32 -0400157 ShaderCache::get().setFilename(cacheFile2.c_str());
158 ShaderCache::get().initShaderDiskCache();
159 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
160 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
161
John Reck283bb462018-12-13 16:40:14 -0800162 // load again content from disk from an existing file and check the data is read correctly
Stan Ilievd495f432017-10-09 15:49:32 -0400163 ShaderCache::get().setFilename(cacheFile1.c_str());
164 ShaderCache::get().initShaderDiskCache();
165 sk_sp<SkData> outVS2;
166 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
167 ASSERT_TRUE(checkShader(outVS2, "someVS"));
168
John Reck283bb462018-12-13 16:40:14 -0800169 // change data, store to disk, read back again and verify data has been changed
Stan Ilievd495f432017-10-09 15:49:32 -0400170 setShader(inVS, "ewData1");
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400171 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400172 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
173 ShaderCache::get().initShaderDiskCache();
174 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
175 ASSERT_TRUE(checkShader(outVS2, "ewData1"));
176
John Reck283bb462018-12-13 16:40:14 -0800177 // write and read big data chunk (50K)
178 size_t dataSize = 50 * 1024;
Yichi Chen9f959552018-03-29 21:21:54 +0800179 std::vector<uint8_t> dataBuffer(dataSize);
180 genRandomData(dataBuffer);
Stan Ilievd495f432017-10-09 15:49:32 -0400181 setShader(inVS, dataBuffer);
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400182 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get(), SkString());
Stan Ilievd495f432017-10-09 15:49:32 -0400183 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
184 ShaderCache::get().initShaderDiskCache();
185 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
186 ASSERT_TRUE(checkShader(outVS2, dataBuffer));
187
188 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
189 remove(cacheFile1.c_str());
190}
191
Yichi Chen9f959552018-03-29 21:21:54 +0800192TEST(ShaderCacheTest, testCacheValidation) {
193 if (!folderExist(getExternalStorageFolder())) {
John Reck283bb462018-12-13 16:40:14 -0800194 // don't run the test if external storage folder is not available
Yichi Chen9f959552018-03-29 21:21:54 +0800195 return;
196 }
John Reck283bb462018-12-13 16:40:14 -0800197 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
198 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
Yichi Chen9f959552018-03-29 21:21:54 +0800199
John Reck283bb462018-12-13 16:40:14 -0800200 // remove any test files from previous test run
Yichi Chen9f959552018-03-29 21:21:54 +0800201 int deleteFile = remove(cacheFile1.c_str());
202 ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
203 std::srand(0);
204
John Reck283bb462018-12-13 16:40:14 -0800205 // generate identity and read the cache from a file that does not exist
Yichi Chen9f959552018-03-29 21:21:54 +0800206 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800207 ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); // disable deferred save
Yichi Chen9f959552018-03-29 21:21:54 +0800208 std::vector<uint8_t> identity(1024);
209 genRandomData(identity);
John Reck283bb462018-12-13 16:40:14 -0800210 ShaderCache::get().initShaderDiskCache(
211 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800212
213 // generate random content in cache and store to disk
214 constexpr size_t numBlob(10);
215 constexpr size_t keySize(1024);
216 constexpr size_t dataSize(50 * 1024);
217
John Reck283bb462018-12-13 16:40:14 -0800218 std::vector<std::pair<sk_sp<SkData>, sk_sp<SkData>>> blobVec(numBlob);
Yichi Chen9f959552018-03-29 21:21:54 +0800219 for (auto& blob : blobVec) {
220 std::vector<uint8_t> keyBuffer(keySize);
221 std::vector<uint8_t> dataBuffer(dataSize);
222 genRandomData(keyBuffer);
223 genRandomData(dataBuffer);
224
225 sk_sp<SkData> key, data;
226 setShader(key, keyBuffer);
227 setShader(data, dataBuffer);
228
229 blob = std::make_pair(key, data);
Leon Scroggins III8cedb662022-05-02 10:38:38 -0400230 ShaderCache::get().store(*key.get(), *data.get(), SkString());
Yichi Chen9f959552018-03-29 21:21:54 +0800231 }
232 ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
233
234 // change to a file that does not exist and verify validation fails
235 ShaderCache::get().setFilename(cacheFile2.c_str());
236 ShaderCache::get().initShaderDiskCache();
John Reck283bb462018-12-13 16:40:14 -0800237 ASSERT_FALSE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800238 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
239
240 // restore the original file and verify validation succeeds
241 ShaderCache::get().setFilename(cacheFile1.c_str());
John Reck283bb462018-12-13 16:40:14 -0800242 ShaderCache::get().initShaderDiskCache(
243 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
244 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800245 for (const auto& blob : blobVec) {
246 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800247 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800248 }
249
250 // generate error identity and verify load fails
251 ShaderCache::get().initShaderDiskCache(identity.data(), -1);
252 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800253 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800254 }
John Reck283bb462018-12-13 16:40:14 -0800255 ShaderCache::get().initShaderDiskCache(
256 nullptr, identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800257 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800258 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800259 }
260
261 // verify the cache validation again after load fails
John Reck283bb462018-12-13 16:40:14 -0800262 ShaderCache::get().initShaderDiskCache(
263 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
264 ASSERT_TRUE(ShaderCacheTestUtils::validateCache(ShaderCache::get(), identity));
Yichi Chen9f959552018-03-29 21:21:54 +0800265 for (const auto& blob : blobVec) {
266 auto outVS = ShaderCache::get().load(*blob.first.get());
John Reck283bb462018-12-13 16:40:14 -0800267 ASSERT_TRUE(checkShader(outVS, blob.second));
Yichi Chen9f959552018-03-29 21:21:54 +0800268 }
269
270 // generate another identity and verify load fails
271 for (auto& data : identity) {
272 data += std::rand();
273 }
John Reck283bb462018-12-13 16:40:14 -0800274 ShaderCache::get().initShaderDiskCache(
275 identity.data(), identity.size() * sizeof(decltype(identity)::value_type));
Yichi Chen9f959552018-03-29 21:21:54 +0800276 for (const auto& blob : blobVec) {
John Reck283bb462018-12-13 16:40:14 -0800277 ASSERT_EQ(ShaderCache::get().load(*blob.first.get()), sk_sp<SkData>());
Yichi Chen9f959552018-03-29 21:21:54 +0800278 }
279
280 ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
281 remove(cacheFile1.c_str());
282}
283
Stan Ilievd495f432017-10-09 15:49:32 -0400284} // namespace