1 /* 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 17 #include <gtest/gtest.h> 18 #include <dirent.h> 19 #include <cutils/properties.h> 20 #include <cstdint> 21 #include <errno.h> 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <sys/types.h> 25 #include <utils/Log.h> 26 #include "pipeline/skia/ShaderCache.h" 27 #include "FileBlobCache.h" 28 29 using namespace android::uirenderer::skiapipeline; 30 31 namespace android { 32 namespace uirenderer { 33 namespace skiapipeline { 34 35 class ShaderCacheTestUtils { 36 public: 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); 51 if (cache.mInitialized && cache.mBlobCache && saveContent) { 52 cache.mBlobCache->writeToFile(); 53 } 54 cache.mBlobCache = NULL; 55 } 56 }; 57 58 } /* namespace skiapipeline */ 59 } /* namespace uirenderer */ 60 } /* namespace android */ 61 62 63 namespace { 64 65 std::string getExternalStorageFolder() { 66 return getenv("EXTERNAL_STORAGE"); 67 } 68 69 bool folderExist(const std::string& folderName) { 70 DIR* dir = opendir(folderName.c_str()); 71 if (dir) { 72 closedir(dir); 73 return true; 74 } 75 return false; 76 } 77 78 bool checkShader(const sk_sp<SkData>& shader, const char* program) { 79 sk_sp<SkData> shader2 = SkData::MakeWithCString(program); 80 return shader->size() == shader2->size() 81 && 0 == memcmp(shader->data(), shader2->data(), shader->size()); 82 } 83 84 bool checkShader(const sk_sp<SkData>& shader, std::vector<char>& program) { 85 sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size()); 86 return shader->size() == shader2->size() 87 && 0 == memcmp(shader->data(), shader2->data(), shader->size()); 88 } 89 90 void setShader(sk_sp<SkData>& shader, const char* program) { 91 shader = SkData::MakeWithCString(program); 92 } 93 94 void setShader(sk_sp<SkData>& shader, std::vector<char>& program) { 95 shader = SkData::MakeWithCopy(program.data(), program.size()); 96 } 97 98 99 100 #define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get()) 101 102 TEST(ShaderCacheTest, testWriteAndRead) { 103 if (!folderExist(getExternalStorageFolder())) { 104 //don't run the test if external storage folder is not available 105 return; 106 } 107 std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; 108 std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; 109 110 //remove any test files from previous test run 111 int deleteFile = remove(cacheFile1.c_str()); 112 ASSERT_TRUE(0 == deleteFile || ENOENT == errno); 113 114 //read the cache from a file that does not exist 115 ShaderCache::get().setFilename(cacheFile1.c_str()); 116 ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save 117 ShaderCache::get().initShaderDiskCache(); 118 119 //read a key - should not be found since the cache is empty 120 sk_sp<SkData> outVS; 121 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); 122 123 //write to the in-memory cache without storing on disk and verify we read the same values 124 sk_sp<SkData> inVS; 125 setShader(inVS, "sassas"); 126 ShaderCache::get().store(GrProgramDescTest(100), *inVS.get()); 127 setShader(inVS, "someVS"); 128 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); 129 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>()); 130 ASSERT_TRUE(checkShader(outVS, "sassas")); 131 ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 132 ASSERT_TRUE(checkShader(outVS, "someVS")); 133 134 //store content to disk and release in-memory cache 135 ShaderCacheTestUtils::terminate(ShaderCache::get(), true); 136 137 //change to a file that does not exist and verify load fails 138 ShaderCache::get().setFilename(cacheFile2.c_str()); 139 ShaderCache::get().initShaderDiskCache(); 140 ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); 141 ShaderCacheTestUtils::terminate(ShaderCache::get(), false); 142 143 //load again content from disk from an existing file and check the data is read correctly 144 ShaderCache::get().setFilename(cacheFile1.c_str()); 145 ShaderCache::get().initShaderDiskCache(); 146 sk_sp<SkData> outVS2; 147 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 148 ASSERT_TRUE(checkShader(outVS2, "someVS")); 149 150 //change data, store to disk, read back again and verify data has been changed 151 setShader(inVS, "ewData1"); 152 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); 153 ShaderCacheTestUtils::terminate(ShaderCache::get(), true); 154 ShaderCache::get().initShaderDiskCache(); 155 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 156 ASSERT_TRUE(checkShader(outVS2, "ewData1")); 157 158 159 //write and read big data chunk (50K) 160 size_t dataSize = 50*1024; 161 std::vector<char> dataBuffer(dataSize); 162 for (size_t i = 0; i < dataSize; i++) { 163 dataBuffer[0] = dataSize % 256; 164 } 165 setShader(inVS, dataBuffer); 166 ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); 167 ShaderCacheTestUtils::terminate(ShaderCache::get(), true); 168 ShaderCache::get().initShaderDiskCache(); 169 ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 170 ASSERT_TRUE(checkShader(outVS2, dataBuffer)); 171 172 ShaderCacheTestUtils::terminate(ShaderCache::get(), false); 173 remove(cacheFile1.c_str()); 174 } 175 176 } // namespace 177