diff options
| author | 2017-10-09 15:49:32 -0400 | |
|---|---|---|
| committer | 2017-11-08 18:55:41 +0000 | |
| commit | d495f43992c98d04cb5a4b1a7bf7917154072fb8 (patch) | |
| tree | fdd0854be6917e8a7cb5d29ebab89897ff50058e | |
| parent | 2b267dfbe967661879b54c638e1f72ab85c5b2f5 (diff) | |
Implement SkSL cache
Implement SkSL cache by reusing code and logic from egl_cache_t.
Test: Improves startup times for gmail by 15ms and 10ms for calc app.
Bug: 66740665
Change-Id: I9ba479c649ba97a2c29a48d40579ba001264c957
| -rw-r--r-- | core/java/android/view/ThreadedRenderer.java | 7 | ||||
| -rw-r--r-- | core/jni/android_view_ThreadedRenderer.cpp | 9 | ||||
| -rw-r--r-- | libs/hwui/Android.bp | 3 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/ShaderCache.cpp | 139 | ||||
| -rw-r--r-- | libs/hwui/pipeline/skia/ShaderCache.h | 148 | ||||
| -rw-r--r-- | libs/hwui/renderthread/CacheManager.cpp | 3 | ||||
| -rw-r--r-- | libs/hwui/renderthread/RenderThread.cpp | 2 | ||||
| -rw-r--r-- | libs/hwui/renderthread/VulkanManager.cpp | 5 | ||||
| -rw-r--r-- | libs/hwui/tests/unit/ShaderCacheTests.cpp | 176 |
9 files changed, 487 insertions, 5 deletions
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 2166f6e4742b..7c76bab2343d 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -70,6 +70,7 @@ public final class ThreadedRenderer { * Name of the file that holds the shaders cache. */ private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache"; + private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache"; /** * System property used to enable or disable threaded rendering profiling. @@ -272,7 +273,9 @@ public final class ThreadedRenderer { * @hide */ public static void setupDiskCache(File cacheDir) { - ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath()); + ThreadedRenderer.setupShadersDiskCache( + new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(), + new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath()); } /** @@ -1007,7 +1010,7 @@ public final class ThreadedRenderer { /** Not actually public - internal use only. This doc to make lint happy */ public static native void disableVsync(); - static native void setupShadersDiskCache(String cacheFile); + static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile); private static native void nRotateProcessStatsBuffer(); private static native void nSetProcessStatsBuffer(int fd); diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp index 57263b1c80a8..870a0c2073d8 100644 --- a/core/jni/android_view_ThreadedRenderer.cpp +++ b/core/jni/android_view_ThreadedRenderer.cpp @@ -54,6 +54,7 @@ #include <renderthread/RenderProxy.h> #include <renderthread/RenderTask.h> #include <renderthread/RenderThread.h> +#include <pipeline/skia/ShaderCache.h> namespace android { @@ -970,10 +971,14 @@ static void android_view_ThreadedRenderer_removeFrameMetricsObserver(JNIEnv* env // ---------------------------------------------------------------------------- static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz, - jstring diskCachePath) { + jstring diskCachePath, jstring skiaDiskCachePath) { const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL); android::egl_set_cache_filename(cacheArray); env->ReleaseStringUTFChars(diskCachePath, cacheArray); + + const char* skiaCacheArray = env->GetStringUTFChars(skiaDiskCachePath, NULL); + uirenderer::skiapipeline::ShaderCache::get().setFilename(skiaCacheArray); + env->ReleaseStringUTFChars(skiaDiskCachePath, skiaCacheArray); } // ---------------------------------------------------------------------------- @@ -1018,7 +1023,7 @@ static const JNINativeMethod gMethods[] = { { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending }, { "nSerializeDisplayListTree", "(J)V", (void*) android_view_ThreadedRenderer_serializeDisplayListTree }, { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo }, - { "setupShadersDiskCache", "(Ljava/lang/String;)V", + { "setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) android_view_ThreadedRenderer_setupShadersDiskCache }, { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode}, { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode}, diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 26442927a60e..24ce1e4c23d0 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -68,6 +68,7 @@ cc_defaults { ], static_libs: [ "libplatformprotos", + "libEGL_blobCache", ], } @@ -131,6 +132,7 @@ cc_defaults { "pipeline/skia/LayerDrawable.cpp", "pipeline/skia/RenderNodeDrawable.cpp", "pipeline/skia/ReorderBarrierDrawables.cpp", + "pipeline/skia/ShaderCache.cpp", "pipeline/skia/SkiaDisplayList.cpp", "pipeline/skia/SkiaOpenGLPipeline.cpp", "pipeline/skia/SkiaOpenGLReadback.cpp", @@ -346,6 +348,7 @@ cc_test { "tests/unit/RecordingCanvasTests.cpp", "tests/unit/RenderNodeTests.cpp", "tests/unit/RenderPropertiesTests.cpp", + "tests/unit/ShaderCacheTests.cpp", "tests/unit/SkiaBehaviorTests.cpp", "tests/unit/SkiaDisplayListTests.cpp", "tests/unit/SkiaPipelineTests.cpp", diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp new file mode 100644 index 000000000000..87edd6968847 --- /dev/null +++ b/libs/hwui/pipeline/skia/ShaderCache.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShaderCache.h" +#include <algorithm> +#include <log/log.h> +#include <thread> +#include "FileBlobCache.h" +#include "utils/TraceUtils.h" + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +// Cache size limits. +static const size_t maxKeySize = 1024; +static const size_t maxValueSize = 64 * 1024; +static const size_t maxTotalSize = 512 * 1024; + +ShaderCache::ShaderCache() { + // There is an "incomplete FileBlobCache type" compilation error, if ctor is moved to header. +} + +ShaderCache ShaderCache::sCache; + +ShaderCache& ShaderCache::get() { + return sCache; +} + +void ShaderCache::initShaderDiskCache() { + ATRACE_NAME("initShaderDiskCache"); + std::lock_guard<std::mutex> lock(mMutex); + if (mFilename.length() > 0) { + mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename)); + mInitialized = true; + } +} + +void ShaderCache::setFilename(const char* filename) { + std::lock_guard<std::mutex> lock(mMutex); + mFilename = filename; +} + +BlobCache* ShaderCache::getBlobCacheLocked() { + LOG_ALWAYS_FATAL_IF(!mInitialized, "ShaderCache has not been initialized"); + return mBlobCache.get(); +} + +sk_sp<SkData> ShaderCache::load(const SkData& key) { + ATRACE_NAME("ShaderCache::load"); + size_t keySize = key.size(); + std::lock_guard<std::mutex> lock(mMutex); + if (!mInitialized) { + ALOGE("ShaderCache::load not initialized"); + return nullptr; + } + + // mObservedBlobValueSize is reasonably big to avoid memory reallocation + // Allocate a buffer with malloc. SkData takes ownership of that allocation and will call free. + void* valueBuffer = malloc(mObservedBlobValueSize); + if (!valueBuffer) { + return nullptr; + } + BlobCache* bc = getBlobCacheLocked(); + size_t valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize); + int maxTries = 3; + while (valueSize > mObservedBlobValueSize && maxTries > 0) { + mObservedBlobValueSize = std::min(valueSize, maxValueSize); + valueBuffer = realloc(valueBuffer, mObservedBlobValueSize); + if (!valueBuffer) { + return nullptr; + } + valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize); + maxTries--; + } + if (!valueSize) { + free(valueBuffer); + return nullptr; + } + if (valueSize > mObservedBlobValueSize) { + ALOGE("ShaderCache::load value size is too big %d", (int) valueSize); + free(valueBuffer); + return nullptr; + } + return SkData::MakeFromMalloc(valueBuffer, valueSize); +} + +void ShaderCache::store(const SkData& key, const SkData& data) { + ATRACE_NAME("ShaderCache::store"); + std::lock_guard<std::mutex> lock(mMutex); + + if (!mInitialized) { + ALOGE("ShaderCache::store not initialized"); + return; + } + + size_t valueSize = data.size(); + size_t keySize = key.size(); + if (keySize == 0 || valueSize == 0 || valueSize >= maxValueSize) { + ALOGW("ShaderCache::store: sizes %d %d not allowed", (int)keySize, (int)valueSize); + return; + } + + const void* value = data.data(); + + BlobCache* bc = getBlobCacheLocked(); + bc->set(key.data(), keySize, value, valueSize); + + if (!mSavePending && mDeferredSaveDelay > 0) { + mSavePending = true; + std::thread deferredSaveThread([this]() { + sleep(mDeferredSaveDelay); + std::lock_guard<std::mutex> lock(mMutex); + ATRACE_NAME("ShaderCache::saveToDisk"); + if (mInitialized && mBlobCache) { + mBlobCache->writeToFile(); + } + mSavePending = false; + }); + deferredSaveThread.detach(); + } +} + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h new file mode 100644 index 000000000000..27473d67bd1a --- /dev/null +++ b/libs/hwui/pipeline/skia/ShaderCache.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <cutils/compiler.h> +#include <memory> +#include <mutex> +#include <string> +#include <vector> +#include <GrContextOptions.h> + +namespace android { + +class BlobCache; +class FileBlobCache; + +namespace uirenderer { +namespace skiapipeline { + +class ShaderCache : public GrContextOptions::PersistentCache { +public: + /** + * "get" returns a pointer to the singleton ShaderCache object. This + * singleton object will never be destroyed. + */ + ANDROID_API static ShaderCache& get(); + + /** + * "initShaderDiskCache" loads the serialized cache contents from disk and puts the ShaderCache + * into an initialized state, such that it is able to insert and retrieve entries from the + * cache. This should be called when HWUI pipeline is initialized. When not in the initialized + * state the load and store methods will return without performing any cache operations. + */ + virtual void initShaderDiskCache(); + + /** + * "setFilename" sets the name of the file that should be used to store + * cache contents from one program invocation to another. This function does not perform any + * disk operation and it should be invoked before "initShaderCache". + */ + virtual void setFilename(const char* filename); + + /** + * "load" attempts to retrieve the value blob associated with a given key + * blob from cache. This will be called by Skia, when it needs to compile a new SKSL shader. + */ + sk_sp<SkData> load(const SkData& key) override; + + /** + * "store" attempts to insert a new key/value blob pair into the cache. + * This will be called by Skia after it compiled a new SKSL shader + */ + void store(const SkData& key, const SkData& data) override; + +private: + // Creation and (the lack of) destruction is handled internally. + ShaderCache(); + + // Copying is disallowed. + ShaderCache(const ShaderCache&) = delete; + void operator=(const ShaderCache&) = delete; + + /** + * "getBlobCacheLocked" returns the BlobCache object being used to store the + * key/value blob pairs. If the BlobCache object has not yet been created, + * this will do so, loading the serialized cache contents from disk if + * possible. + */ + BlobCache* getBlobCacheLocked(); + + /** + * "mInitialized" indicates whether the ShaderCache is in the initialized + * state. It is initialized to false at construction time, and gets set to + * true when initialize is called. + * When in this state, the cache behaves as normal. When not, + * the load and store methods will return without performing any cache + * operations. + */ + bool mInitialized = false; + + /** + * "mBlobCache" is the cache in which the key/value blob pairs are stored. It + * is initially NULL, and will be initialized by getBlobCacheLocked the + * first time it's needed. + * The blob cache contains the Android build number. We treat version mismatches as an empty + * cache (logic implemented in BlobCache::unflatten). + */ + std::unique_ptr<FileBlobCache> mBlobCache; + + /** + * "mFilename" is the name of the file for storing cache contents in between + * program invocations. It is initialized to an empty string at + * construction time, and can be set with the setCacheFilename method. An + * empty string indicates that the cache should not be saved to or restored + * from disk. + */ + std::string mFilename; + + /** + * "mSavePending" indicates whether or not a deferred save operation is + * pending. Each time a key/value pair is inserted into the cache via + * load, a deferred save is initiated if one is not already pending. + * This will wait some amount of time and then trigger a save of the cache + * contents to disk. + */ + bool mSavePending = false; + + /** + * "mObservedBlobValueSize" is the maximum value size observed by the cache reading function. + */ + size_t mObservedBlobValueSize = 20*1024; + + /** + * The time in seconds to wait before saving newly inserted cache entries. + */ + unsigned int mDeferredSaveDelay = 4; + + /** + * "mMutex" is the mutex used to prevent concurrent access to the member + * variables. It must be locked whenever the member variables are accessed. + */ + mutable std::mutex mMutex; + + /** + * "sCache" is the singleton ShaderCache object. + */ + static ShaderCache sCache; + + friend class ShaderCacheTestUtils; //used for unit testing +}; + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index a33b2874e7a5..c22364b4a569 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -18,6 +18,7 @@ #include "Layer.h" #include "RenderThread.h" +#include "pipeline/skia/ShaderCache.h" #include "renderstate/RenderState.h" #include <GrContextOptions.h> @@ -127,6 +128,8 @@ void CacheManager::configureContext(GrContextOptions* contextOptions) { } contextOptions->fExecutor = mTaskProcessor.get(); } + + contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get(); } void CacheManager::trimMemory(TrimMemoryMode mode) { diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index c117cb822075..574bb0212385 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -16,6 +16,7 @@ #include "RenderThread.h" +#include "pipeline/skia/ShaderCache.h" #include "CanvasContext.h" #include "EglManager.h" #include "OpenGLReadback.h" @@ -105,6 +106,7 @@ void RenderThread::initThreadLocals() { mRenderState = new RenderState(*this); mVkManager = new VulkanManager(*this); mCacheManager = new CacheManager(mDisplayInfo); + uirenderer::skiapipeline::ShaderCache::get().initShaderDiskCache(); } void RenderThread::dumpGraphicsMemory(int fd) { diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 3272d697e222..1d8cdd656f7a 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -107,8 +107,11 @@ void VulkanManager::initialize() { mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue); + GrContextOptions options; + options.fDisableDistanceFieldPaths = true; + mRenderThread.cacheManager().configureContext(&options); mRenderThread.setGrContext( - GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get())); + GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get(), options)); DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize()); if (Properties::enablePartialUpdates && Properties::useBufferAge) { diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp new file mode 100644 index 000000000000..43080a9460b3 --- /dev/null +++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gtest/gtest.h> +#include <dirent.h> +#include <cutils/properties.h> +#include <cstdint> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> +#include <utils/Log.h> +#include "pipeline/skia/ShaderCache.h" +#include "FileBlobCache.h" + +using namespace android::uirenderer::skiapipeline; + +namespace android { +namespace uirenderer { +namespace skiapipeline { + +class ShaderCacheTestUtils { +public: + /** + * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries. + * If set to 0, then deferred save is disabled. + */ + static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) { + cache.mDeferredSaveDelay = saveDelay; + } + + /** + * "terminate" optionally stores the BlobCache on disk and release all in-memory cache. + * Next call to "initShaderDiskCache" will load again the in-memory cache from disk. + */ + static void terminate(ShaderCache& cache, bool saveContent) { + std::lock_guard<std::mutex> lock(cache.mMutex); + if (cache.mInitialized && cache.mBlobCache && saveContent) { + cache.mBlobCache->writeToFile(); + } + cache.mBlobCache = NULL; + } +}; + +} /* namespace skiapipeline */ +} /* namespace uirenderer */ +} /* namespace android */ + + +namespace { + +std::string getExternalStorageFolder() { + return getenv("EXTERNAL_STORAGE"); +} + +bool folderExist(const std::string& folderName) { + DIR* dir = opendir(folderName.c_str()); + if (dir) { + closedir(dir); + return true; + } + return false; +} + +bool checkShader(const sk_sp<SkData>& shader, const char* program) { + sk_sp<SkData> shader2 = SkData::MakeWithCString(program); + return shader->size() == shader2->size() + && 0 == memcmp(shader->data(), shader2->data(), shader->size()); +} + +bool checkShader(const sk_sp<SkData>& shader, std::vector<char>& program) { + sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size()); + return shader->size() == shader2->size() + && 0 == memcmp(shader->data(), shader2->data(), shader->size()); +} + +void setShader(sk_sp<SkData>& shader, const char* program) { + shader = SkData::MakeWithCString(program); +} + +void setShader(sk_sp<SkData>& shader, std::vector<char>& program) { + shader = SkData::MakeWithCopy(program.data(), program.size()); +} + + + +#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get()) + +TEST(ShaderCacheTest, testWriteAndRead) { + if (!folderExist(getExternalStorageFolder())) { + //don't run the test if external storage folder is not available + return; + } + std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1"; + std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2"; + + //remove any test files from previous test run + int deleteFile = remove(cacheFile1.c_str()); + ASSERT_TRUE(0 == deleteFile || ENOENT == errno); + + //read the cache from a file that does not exist + ShaderCache::get().setFilename(cacheFile1.c_str()); + ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save + ShaderCache::get().initShaderDiskCache(); + + //read a key - should not be found since the cache is empty + sk_sp<SkData> outVS; + ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); + + //write to the in-memory cache without storing on disk and verify we read the same values + sk_sp<SkData> inVS; + setShader(inVS, "sassas"); + ShaderCache::get().store(GrProgramDescTest(100), *inVS.get()); + setShader(inVS, "someVS"); + ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); + ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>()); + ASSERT_TRUE(checkShader(outVS, "sassas")); + ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); + ASSERT_TRUE(checkShader(outVS, "someVS")); + + //store content to disk and release in-memory cache + ShaderCacheTestUtils::terminate(ShaderCache::get(), true); + + //change to a file that does not exist and verify load fails + ShaderCache::get().setFilename(cacheFile2.c_str()); + ShaderCache::get().initShaderDiskCache(); + ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>()); + ShaderCacheTestUtils::terminate(ShaderCache::get(), false); + + //load again content from disk from an existing file and check the data is read correctly + ShaderCache::get().setFilename(cacheFile1.c_str()); + ShaderCache::get().initShaderDiskCache(); + sk_sp<SkData> outVS2; + ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); + ASSERT_TRUE(checkShader(outVS2, "someVS")); + + //change data, store to disk, read back again and verify data has been changed + setShader(inVS, "ewData1"); + ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); + ShaderCacheTestUtils::terminate(ShaderCache::get(), true); + ShaderCache::get().initShaderDiskCache(); + ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); + ASSERT_TRUE(checkShader(outVS2, "ewData1")); + + + //write and read big data chunk (50K) + size_t dataSize = 50*1024; + std::vector<char> dataBuffer(dataSize); + for (size_t i = 0; i < dataSize; i++) { + dataBuffer[0] = dataSize % 256; + } + setShader(inVS, dataBuffer); + ShaderCache::get().store(GrProgramDescTest(432), *inVS.get()); + ShaderCacheTestUtils::terminate(ShaderCache::get(), true); + ShaderCache::get().initShaderDiskCache(); + ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>()); + ASSERT_TRUE(checkShader(outVS2, dataBuffer)); + + ShaderCacheTestUtils::terminate(ShaderCache::get(), false); + remove(cacheFile1.c_str()); +} + +} // namespace |