blob: beef9edc70231790b3db8ec00b03e6c3b0506793 [file] [log] [blame]
Brian Salomon00a5eb82018-07-11 15:32:05 -04001/*
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
Brian Osman5aa11fb2019-04-08 16:40:36 -04008#include "GrPersistentCacheUtils.h"
Brian Salomon00a5eb82018-07-11 15:32:05 -04009#include "MemoryCache.h"
10#include "SkBase64.h"
Brian Osman5aa11fb2019-04-08 16:40:36 -040011#include "SkJSONWriter.h"
12#include "SkMD5.h"
13#include "SkTHash.h"
Brian Salomon00a5eb82018-07-11 15:32:05 -040014
15// Change this to 1 to log cache hits/misses/stores using SkDebugf.
16#define LOG_MEMORY_CACHE 0
17
18static SkString data_to_str(const SkData& data) {
19 size_t encodeLength = SkBase64::Encode(data.data(), data.size(), nullptr);
20 SkString str;
21 str.resize(encodeLength);
22 SkBase64::Encode(data.data(), data.size(), str.writable_str());
23 static constexpr size_t kMaxLength = 60;
24 static constexpr char kTail[] = "...";
25 static const size_t kTailLen = strlen(kTail);
26 bool overlength = encodeLength > kMaxLength;
27 if (overlength) {
28 str = SkString(str.c_str(), kMaxLength - kTailLen);
29 str.append(kTail);
30 }
31 return str;
32}
33
34namespace sk_gpu_test {
35
36sk_sp<SkData> MemoryCache::load(const SkData& key) {
37 auto result = fMap.find(key);
38 if (result == fMap.end()) {
39 if (LOG_MEMORY_CACHE) {
40 SkDebugf("Load Key: %s\n\tNot Found.\n\n", data_to_str(key).c_str());
41 }
42 ++fCacheMissCnt;
43 return nullptr;
44 }
45 if (LOG_MEMORY_CACHE) {
46 SkDebugf("Load Key: %s\n\tFound Data: %s\n\n", data_to_str(key).c_str(),
Brian Osman5aa11fb2019-04-08 16:40:36 -040047 data_to_str(*result->second.fData).c_str());
Brian Salomon00a5eb82018-07-11 15:32:05 -040048 }
Brian Osman5aa11fb2019-04-08 16:40:36 -040049 result->second.fHitCount++;
50 return result->second.fData;
Brian Salomon00a5eb82018-07-11 15:32:05 -040051}
52
53void MemoryCache::store(const SkData& key, const SkData& data) {
54 if (LOG_MEMORY_CACHE) {
55 SkDebugf("Store Key: %s\n\tData: %s\n\n", data_to_str(key).c_str(),
56 data_to_str(data).c_str());
57 }
Brian Osman5aa11fb2019-04-08 16:40:36 -040058 fMap[Key(key)] = Value(data);
59}
60
61void MemoryCache::writeShadersToDisk(const char* path, GrBackendApi api) {
62 if (GrBackendApi::kOpenGL != api) {
63 // TODO: Add SPIRV support, too.
64 return;
65 }
66
67 // Default extensions detected by the Mali Offline Compiler
68 const char* extensions[kGrShaderTypeCount] = { "vert", "geom", "frag" };
69
70 // For now, we only dump fragment shaders. They are the biggest factor in performance, and
71 // the shaders for other stages tend to be heavily reused.
72 SkString jsonPath = SkStringPrintf("%s/%s.json", path, extensions[kFragment_GrShaderType]);
73 SkFILEWStream jsonFile(jsonPath.c_str());
74 SkJSONWriter writer(&jsonFile, SkJSONWriter::Mode::kPretty);
75 writer.beginArray();
76
77 for (auto it = fMap.begin(); it != fMap.end(); ++it) {
78 SkMD5 hash;
79 hash.write(it->first.fKey->bytes(), it->first.fKey->size());
80 SkMD5::Digest digest = hash.finish();
81 SkString md5;
82 for (int i = 0; i < 16; ++i) {
83 md5.appendf("%02x", digest.data[i]);
84 }
85
86 // Write [ hash, hitCount ] to JSON digest
87 writer.beginArray(nullptr, false);
88 writer.appendString(md5.c_str());
89 writer.appendS32(it->second.fHitCount);
90 writer.endArray();
91
Brian Osman5aa11fb2019-04-08 16:40:36 -040092 SkSL::Program::Inputs inputsIgnored;
93 SkSL::String glsl[kGrShaderTypeCount];
Brian Osmane6ef03d2019-04-11 14:38:27 -040094 GrPersistentCacheUtils::UnpackCachedGLSL(it->second.fData.get(), &inputsIgnored, glsl);
Brian Osman5aa11fb2019-04-08 16:40:36 -040095
96 SkString filename = SkStringPrintf("%s/%s.%s", path, md5.c_str(),
97 extensions[kFragment_GrShaderType]);
98 SkFILEWStream file(filename.c_str());
99 file.write(glsl[kFragment_GrShaderType].c_str(), glsl[kFragment_GrShaderType].size());
100 }
101
102 writer.endArray();
Brian Salomon00a5eb82018-07-11 15:32:05 -0400103}
104
105} // namespace sk_gpu_test