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