1d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev/* 2d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * Copyright (C) 2017 The Android Open Source Project 3d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * 4d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * Licensed under the Apache License, Version 2.0 (the "License"); 5d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * you may not use this file except in compliance with the License. 6d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * You may obtain a copy of the License at 7d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * 8d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * http://www.apache.org/licenses/LICENSE-2.0 9d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * 10d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * Unless required by applicable law or agreed to in writing, software 11d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * distributed under the License is distributed on an "AS IS" BASIS, 12d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * See the License for the specific language governing permissions and 14d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * limitations under the License. 15d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev */ 16d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 17d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <gtest/gtest.h> 18d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <dirent.h> 19d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <cutils/properties.h> 20d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <cstdint> 21d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <errno.h> 22d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <stdio.h> 23d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <stdlib.h> 24d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <sys/types.h> 25d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include <utils/Log.h> 26d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include "pipeline/skia/ShaderCache.h" 27d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#include "FileBlobCache.h" 28d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 29d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievusing namespace android::uirenderer::skiapipeline; 30d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 31d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievnamespace android { 32d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievnamespace uirenderer { 33d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievnamespace skiapipeline { 34d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 35d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievclass ShaderCacheTestUtils { 36d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievpublic: 37d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev /** 38d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries. 39d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * If set to 0, then deferred save is disabled. 40d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev */ 41d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) { 42d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev cache.mDeferredSaveDelay = saveDelay; 43d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev } 44d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 45d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev /** 46d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * "terminate" optionally stores the BlobCache on disk and release all in-memory cache. 47d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev * Next call to "initShaderDiskCache" will load again the in-memory cache from disk. 48d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev */ 49d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev static void terminate(ShaderCache& cache, bool saveContent) { 50d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev std::lock_guard<std::mutex> lock(cache.mMutex); 51d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev if (cache.mInitialized && cache.mBlobCache && saveContent) { 52d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev cache.mBlobCache->writeToFile(); 53d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev } 54d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev cache.mBlobCache = NULL; 55d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev } 56d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev}; 57d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 58d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} /* namespace skiapipeline */ 59d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} /* namespace uirenderer */ 60d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} /* namespace android */ 61d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 62d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 63d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievnamespace { 64d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 65d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievstd::string getExternalStorageFolder() { 66d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev return getenv("EXTERNAL_STORAGE"); 67d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} 68d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 69d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievbool folderExist(const std::string& folderName) { 70d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev DIR* dir = opendir(folderName.c_str()); 71d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev if (dir) { 72d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev closedir(dir); 73d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev return true; 74d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev } 75d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev return false; 76d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} 77d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 78d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievbool checkShader(const sk_sp<SkData>& shader, const char* program) { 79d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev sk_sp<SkData> shader2 = SkData::MakeWithCString(program); 80d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev return shader->size() == shader2->size() 81d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev && 0 == memcmp(shader->data(), shader2->data(), shader->size()); 82d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} 83d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 84d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievbool checkShader(const sk_sp<SkData>& shader, std::vector<char>& program) { 85d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size()); 86d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev return shader->size() == shader2->size() 87d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev && 0 == memcmp(shader->data(), shader2->data(), shader->size()); 88d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} 89d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 90d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievvoid setShader(sk_sp<SkData>& shader, const char* program) { 91d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev shader = SkData::MakeWithCString(program); 92d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} 93d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 94d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Ilievvoid setShader(sk_sp<SkData>& shader, std::vector<char>& program) { 95d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev shader = SkData::MakeWithCopy(program.data(), program.size()); 96d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} 97d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 98d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 99d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 100d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get()) 101d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 102d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan IlievTEST(ShaderCacheTest, testWriteAndRead) { 103d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev if (!folderExist(getExternalStorageFolder())) { 104d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //don't run the test if external storage folder is not available 105d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev return; 106d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev } 107d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; 108d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; 109d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 110d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //remove any test files from previous test run 111d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev int deleteFile = remove(cacheFile1.c_str()); 112d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_TRUE(0 == deleteFile || ENOENT == errno); 113d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 114d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //read the cache from a file that does not exist 115d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().setFilename(cacheFile1.c_str()); 116d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save 117d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().initShaderDiskCache(); 118d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 119d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //read a key - should not be found since the cache is empty 120d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev sk_sp<SkData> outVS; 121d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); 122d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 123d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //write to the in-memory cache without storing on disk and verify we read the same values 124d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev sk_sp<SkData> inVS; 125d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev setShader(inVS, "sassas"); 126d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().store(GrProgramDescTest(100), *inVS.get()); 127d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev setShader(inVS, "someVS"); 128d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); 129d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>()); 130d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_TRUE(checkShader(outVS, "sassas")); 131d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 132d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_TRUE(checkShader(outVS, "someVS")); 133d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 134d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //store content to disk and release in-memory cache 135d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCacheTestUtils::terminate(ShaderCache::get(), true); 136d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 137d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //change to a file that does not exist and verify load fails 138d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().setFilename(cacheFile2.c_str()); 139d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().initShaderDiskCache(); 140d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); 141d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCacheTestUtils::terminate(ShaderCache::get(), false); 142d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 143d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //load again content from disk from an existing file and check the data is read correctly 144d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().setFilename(cacheFile1.c_str()); 145d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().initShaderDiskCache(); 146d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev sk_sp<SkData> outVS2; 147d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 148d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_TRUE(checkShader(outVS2, "someVS")); 149d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 150d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //change data, store to disk, read back again and verify data has been changed 151d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev setShader(inVS, "ewData1"); 152d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); 153d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCacheTestUtils::terminate(ShaderCache::get(), true); 154d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().initShaderDiskCache(); 155d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 156d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_TRUE(checkShader(outVS2, "ewData1")); 157d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 158d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 159d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev //write and read big data chunk (50K) 160d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev size_t dataSize = 50*1024; 161d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev std::vector<char> dataBuffer(dataSize); 162d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev for (size_t i = 0; i < dataSize; i++) { 163d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev dataBuffer[0] = dataSize % 256; 164d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev } 165d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev setShader(inVS, dataBuffer); 166d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); 167d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCacheTestUtils::terminate(ShaderCache::get(), true); 168d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCache::get().initShaderDiskCache(); 169d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); 170d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ASSERT_TRUE(checkShader(outVS2, dataBuffer)); 171d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 172d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev ShaderCacheTestUtils::terminate(ShaderCache::get(), false); 173d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev remove(cacheFile1.c_str()); 174d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} 175d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev 176d495f43992c98d04cb5a4b1a7bf7917154072fb8Stan Iliev} // namespace 177