1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2018 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/utils/SkBase64.h" 9cb93a386Sopenharmony_ci#include "src/core/SkMD5.h" 10cb93a386Sopenharmony_ci#include "src/core/SkReadBuffer.h" 11cb93a386Sopenharmony_ci#include "src/gpu/GrPersistentCacheUtils.h" 12cb93a386Sopenharmony_ci#include "tools/gpu/MemoryCache.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_ci#if defined(SK_VULKAN) 15cb93a386Sopenharmony_ci#include "src/gpu/vk/GrVkGpu.h" 16cb93a386Sopenharmony_ci#endif 17cb93a386Sopenharmony_ci 18cb93a386Sopenharmony_ci// Change this to 1 to log cache hits/misses/stores using SkDebugf. 19cb93a386Sopenharmony_ci#define LOG_MEMORY_CACHE 0 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_cistatic SkString data_to_str(const SkData& data) { 22cb93a386Sopenharmony_ci size_t encodeLength = SkBase64::Encode(data.data(), data.size(), nullptr); 23cb93a386Sopenharmony_ci SkString str; 24cb93a386Sopenharmony_ci str.resize(encodeLength); 25cb93a386Sopenharmony_ci SkBase64::Encode(data.data(), data.size(), str.writable_str()); 26cb93a386Sopenharmony_ci static constexpr size_t kMaxLength = 60; 27cb93a386Sopenharmony_ci static constexpr char kTail[] = "..."; 28cb93a386Sopenharmony_ci static const size_t kTailLen = strlen(kTail); 29cb93a386Sopenharmony_ci bool overlength = encodeLength > kMaxLength; 30cb93a386Sopenharmony_ci if (overlength) { 31cb93a386Sopenharmony_ci str = SkString(str.c_str(), kMaxLength - kTailLen); 32cb93a386Sopenharmony_ci str.append(kTail); 33cb93a386Sopenharmony_ci } 34cb93a386Sopenharmony_ci return str; 35cb93a386Sopenharmony_ci} 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_cinamespace sk_gpu_test { 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_cisk_sp<SkData> MemoryCache::load(const SkData& key) { 40cb93a386Sopenharmony_ci auto result = fMap.find(key); 41cb93a386Sopenharmony_ci if (result == fMap.end()) { 42cb93a386Sopenharmony_ci if (LOG_MEMORY_CACHE) { 43cb93a386Sopenharmony_ci SkDebugf("Load Key: %s\n\tNot Found.\n\n", data_to_str(key).c_str()); 44cb93a386Sopenharmony_ci } 45cb93a386Sopenharmony_ci ++fCacheMissCnt; 46cb93a386Sopenharmony_ci return nullptr; 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci if (LOG_MEMORY_CACHE) { 49cb93a386Sopenharmony_ci SkDebugf("Load Key: %s\n\tFound Data: %s\n\n", data_to_str(key).c_str(), 50cb93a386Sopenharmony_ci data_to_str(*result->second.fData).c_str()); 51cb93a386Sopenharmony_ci } 52cb93a386Sopenharmony_ci result->second.fHitCount++; 53cb93a386Sopenharmony_ci return result->second.fData; 54cb93a386Sopenharmony_ci} 55cb93a386Sopenharmony_ci 56cb93a386Sopenharmony_civoid MemoryCache::store(const SkData& key, const SkData& data, const SkString& description) { 57cb93a386Sopenharmony_ci if (LOG_MEMORY_CACHE) { 58cb93a386Sopenharmony_ci SkDebugf("Store Key: %s\n\tData: %s\n\n", data_to_str(key).c_str(), 59cb93a386Sopenharmony_ci data_to_str(data).c_str()); 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci ++fCacheStoreCnt; 62cb93a386Sopenharmony_ci fMap[Key(key)] = Value(data, description); 63cb93a386Sopenharmony_ci} 64cb93a386Sopenharmony_ci 65cb93a386Sopenharmony_civoid MemoryCache::writeShadersToDisk(const char* path, GrBackendApi api) { 66cb93a386Sopenharmony_ci if (GrBackendApi::kOpenGL != api && GrBackendApi::kVulkan != api) { 67cb93a386Sopenharmony_ci return; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci for (auto it = fMap.begin(); it != fMap.end(); ++it) { 71cb93a386Sopenharmony_ci SkMD5 hash; 72cb93a386Sopenharmony_ci size_t bytesToHash = it->first.fKey->size(); 73cb93a386Sopenharmony_ci#if defined(SK_VULKAN) 74cb93a386Sopenharmony_ci if (GrBackendApi::kVulkan == api) { 75cb93a386Sopenharmony_ci // Vulkan stores two kinds of data in the cache (shaders and pipelines). The last four 76cb93a386Sopenharmony_ci // bytes of the key identify which one we have. We only want to extract shaders. 77cb93a386Sopenharmony_ci // Additionally, we don't want to hash the tag bytes, so we get the same keys as GL, 78cb93a386Sopenharmony_ci // which is good for cross-checking code generation and performance. 79cb93a386Sopenharmony_ci GrVkGpu::PersistentCacheKeyType vkKeyType; 80cb93a386Sopenharmony_ci SkASSERT(bytesToHash >= sizeof(vkKeyType)); 81cb93a386Sopenharmony_ci bytesToHash -= sizeof(vkKeyType); 82cb93a386Sopenharmony_ci memcpy(&vkKeyType, it->first.fKey->bytes() + bytesToHash, sizeof(vkKeyType)); 83cb93a386Sopenharmony_ci if (vkKeyType != GrVkGpu::kShader_PersistentCacheKeyType) { 84cb93a386Sopenharmony_ci continue; 85cb93a386Sopenharmony_ci } 86cb93a386Sopenharmony_ci } 87cb93a386Sopenharmony_ci#endif 88cb93a386Sopenharmony_ci hash.write(it->first.fKey->bytes(), bytesToHash); 89cb93a386Sopenharmony_ci SkMD5::Digest digest = hash.finish(); 90cb93a386Sopenharmony_ci SkString md5; 91cb93a386Sopenharmony_ci for (int i = 0; i < 16; ++i) { 92cb93a386Sopenharmony_ci md5.appendf("%02x", digest.data[i]); 93cb93a386Sopenharmony_ci } 94cb93a386Sopenharmony_ci 95cb93a386Sopenharmony_ci SkSL::Program::Inputs inputsIgnored[kGrShaderTypeCount]; 96cb93a386Sopenharmony_ci SkSL::String shaders[kGrShaderTypeCount]; 97cb93a386Sopenharmony_ci const SkData* data = it->second.fData.get(); 98cb93a386Sopenharmony_ci const SkString& description = it->second.fDescription; 99cb93a386Sopenharmony_ci SkReadBuffer reader(data->data(), data->size()); 100cb93a386Sopenharmony_ci GrPersistentCacheUtils::GetType(&reader); // Shader type tag 101cb93a386Sopenharmony_ci GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, 102cb93a386Sopenharmony_ci inputsIgnored, kGrShaderTypeCount); 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci // Even with the SPIR-V switches, it seems like we must use .spv, or malisc tries to 105cb93a386Sopenharmony_ci // run glslang on the input. 106cb93a386Sopenharmony_ci { 107cb93a386Sopenharmony_ci const char* ext = GrBackendApi::kOpenGL == api ? "frag" : "frag.spv"; 108cb93a386Sopenharmony_ci SkString filename = SkStringPrintf("%s/%s.%s", path, md5.c_str(), ext); 109cb93a386Sopenharmony_ci SkFILEWStream file(filename.c_str()); 110cb93a386Sopenharmony_ci file.write(shaders[kFragment_GrShaderType].c_str(), 111cb93a386Sopenharmony_ci shaders[kFragment_GrShaderType].size()); 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci { 114cb93a386Sopenharmony_ci const char* ext = GrBackendApi::kOpenGL == api ? "vert" : "vert.spv"; 115cb93a386Sopenharmony_ci SkString filename = SkStringPrintf("%s/%s.%s", path, md5.c_str(), ext); 116cb93a386Sopenharmony_ci SkFILEWStream file(filename.c_str()); 117cb93a386Sopenharmony_ci file.write(shaders[kVertex_GrShaderType].c_str(), 118cb93a386Sopenharmony_ci shaders[kVertex_GrShaderType].size()); 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci if (!description.isEmpty()) { 122cb93a386Sopenharmony_ci const char* ext = "key"; 123cb93a386Sopenharmony_ci SkString filename = SkStringPrintf("%s/%s.%s", path, md5.c_str(), ext); 124cb93a386Sopenharmony_ci SkFILEWStream file(filename.c_str()); 125cb93a386Sopenharmony_ci file.write(description.c_str(), description.size()); 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci } 128cb93a386Sopenharmony_ci} 129cb93a386Sopenharmony_ci 130cb93a386Sopenharmony_ci} // namespace sk_gpu_test 131