• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 
16 #include "shader_cache.h"
17 
18 #include <algorithm>
19 #include <array>
20 #include <openssl/sha.h>
21 #include <random>
22 #include <thread>
23 #include "rs_trace.h"
24 #include "utils/log.h"
25 
26 namespace OHOS {
27 namespace Rosen {
Instance()28 ShaderCache& ShaderCache::Instance()
29 {
30     static ShaderCache cache_;
31     return cache_;
32 }
33 
~ShaderCache()34 ShaderCache::~ShaderCache()
35 {
36     LOGE("ShaderCache: destroying Shadercache");
37 }
38 
InitShaderCache(const char * identity,const size_t size,bool isUni)39 void ShaderCache::InitShaderCache(const char* identity, const size_t size, bool isUni)
40 {
41     std::lock_guard<std::mutex> lock(mutex_);
42 
43     if (filePath_.length() <= 0) {
44         LOGE("abandon, illegal cacheDir length");
45         return;
46     }
47     cacheData_.reset();
48     size_t totalSize = isUni ? MAX_UNIRENDER_SIZE : MAX_TOTAL_SIZE;
49     cacheData_ = std::make_unique<CacheData>(MAX_KEY_SIZE, MAX_VALUE_SIZE, totalSize, filePath_);
50     cacheData_->ReadFromFile();
51     if (identity == nullptr || size == 0) {
52         LOGE("abandon, illegal cacheDir length");
53         cacheData_->Clear();
54     }
55 
56     SHA256_CTX sha256Ctx;
57     SHA256_Init(&sha256Ctx);
58     SHA256_Update(&sha256Ctx, identity, size);
59     idHash_.resize(SHA256_DIGEST_LENGTH);
60     SHA256_Final(idHash_.data(), &sha256Ctx);
61     std::array<uint8_t, SHA256_DIGEST_LENGTH> shaArray;
62     auto key = ID_KEY;
63 
64     auto loaded = cacheData_->Get(&key, sizeof(key), shaArray.data(), shaArray.size());
65     if (!(loaded && std::equal(shaArray.begin(), shaArray.end(), idHash_.begin()))) {
66         cacheData_->Clear();
67         LOGW("abandon, bad hash value, cleared for future regeneration");
68     }
69 
70     LOGI("shadercache initiation success");
71     initialized_ = true;
72 }
73 
SetFilePath(const std::string & filename)74 void ShaderCache::SetFilePath(const std::string& filename)
75 {
76     if (filename.size() == 0) {
77         LOGE("abandon, empty filename");
78         return;
79     }
80     std::lock_guard<std::mutex> lock(mutex_);
81     filePath_ = filename + "/shader_cache";
82 }
83 
84 #ifndef USE_ROSEN_DRAWING
load(const SkData & key)85 sk_sp<SkData> ShaderCache::load(const SkData& key)
86 #else
87 std::shared_ptr<Drawing::Data> ShaderCache::Load(const Drawing::Data& key)
88 #endif
89 {
90 #ifndef USE_ROSEN_DRAWING
91     RS_TRACE_NAME("load shader");
92     size_t keySize = key.size();
93 #else
94     RS_TRACE_NAME("Load shader");
95     size_t keySize = key.GetSize();
96 #endif
97     std::lock_guard<std::mutex> lock(mutex_);
98     if (!initialized_) {
99         LOGW("load: failed because ShaderCache is not initialized");
100         return nullptr;
101     }
102 
103     void* valueBuffer = malloc(bufferSize_);
104     if (!valueBuffer) {
105         LOGE("load: failed because unable to map memory");
106         return nullptr;
107     }
108     if (!cacheData_) {
109         LOGE("load: cachedata has been destructed");
110         free(valueBuffer);
111         valueBuffer = nullptr;
112         return nullptr;
113     }
114 
115 #ifndef USE_ROSEN_DRAWING
116     size_t valueSize = cacheData_->Get(key.data(), keySize, valueBuffer, bufferSize_);
117 #else
118     size_t valueSize = cacheData_->Get(key.GetData(), keySize, valueBuffer, bufferSize_);
119 #endif
120     if (!valueSize) {
121         free(valueBuffer);
122         valueBuffer = nullptr;
123         void* newValueBuffer = realloc(valueBuffer, MAX_VALUE_SIZE);
124         if (!newValueBuffer) {
125             LOGE("load: failed to reallocate maxValueSize");
126             return nullptr;
127         }
128         valueBuffer = newValueBuffer;
129 #ifndef USE_ROSEN_DRAWING
130         valueSize = cacheData_->Get(key.data(), keySize, valueBuffer, bufferSize_);
131 #else
132         valueSize = cacheData_->Get(key.GetData(), keySize, valueBuffer, bufferSize_);
133 #endif
134     }
135 
136     if (!valueSize || valueSize > bufferSize_) {
137         LOGE("load: failed to get the cache value with the given key");
138         free(valueBuffer);
139         valueBuffer = nullptr;
140         return nullptr;
141     }
142 #ifndef USE_ROSEN_DRAWING
143     return SkData::MakeFromMalloc(valueBuffer, valueSize);
144 #else
145     auto data = std::make_shared<Drawing::Data>();
146     if (!data->BuildFromMalloc(valueBuffer, valueSize)) {
147         LOGE("load: failed to build drawing data");
148         free(valueBuffer);
149         valueBuffer = nullptr;
150         return nullptr;
151     }
152     return data;
153 #endif
154 }
155 
WriteToDisk()156 void ShaderCache::WriteToDisk()
157 {
158     if (!(initialized_ && cacheData_ && savePending_)) {
159         LOGE("abandon: failed to check prerequisites");
160         return;
161     }
162     if (!idHash_.size()) {
163         LOGE("abandon: illegal hash size");
164         return;
165     }
166     auto key = ID_KEY;
167     cacheData_->Rewrite(&key, sizeof(key), idHash_.data(), idHash_.size());
168     cacheData_->WriteToFile();
169     savePending_ = false;
170 }
171 
172 #ifndef USE_ROSEN_DRAWING
store(const SkData & key,const SkData & data)173 void ShaderCache::store(const SkData& key, const SkData& data)
174 {
175     RS_TRACE_NAME("store shader");
176 #else
177 void ShaderCache::Store(const Drawing::Data& key, const Drawing::Data& data)
178 {
179     RS_TRACE_NAME("Store shader");
180 #endif
181     std::lock_guard<std::mutex> lock(mutex_);
182 
183     if (!initialized_) {
184         LOGW("stored: failed because ShaderCache is not initialized");
185         return;
186     }
187 
188 #ifndef USE_ROSEN_DRAWING
189     size_t valueSize = data.size();
190     size_t keySize = key.size();
191 #else
192     size_t valueSize = data.GetSize();
193     size_t keySize = key.GetSize();
194 #endif
195     if (keySize == 0 || valueSize == 0 || valueSize >= MAX_VALUE_SIZE) {
196         LOGE("store: failed because of illegal cache sizes");
197         return;
198     }
199 
200 #ifndef USE_ROSEN_DRAWING
201     const void* value = data.data();
202 #else
203     const void* value = data.GetData();
204 #endif
205     cacheDirty_ = true;
206     if (!cacheData_) {
207         LOGE("store: cachedata has been destructed");
208         return;
209     }
210 #ifndef USE_ROSEN_DRAWING
211     cacheData_->Rewrite(key.data(), keySize, value, valueSize);
212 #else
213     cacheData_->Rewrite(key.GetData(), keySize, value, valueSize);
214 #endif
215 
216     if (!savePending_ && saveDelaySeconds_ > 0) {
217         savePending_ = true;
218         std::thread deferredSaveThread([this]() {
219             sleep(saveDelaySeconds_);
220             std::lock_guard<std::mutex> lock(mutex_);
221             WriteToDisk();
222             cacheDirty_ = false;
223         });
224         deferredSaveThread.detach();
225     }
226 }
227 }   // namespace Rosen
228 }   // namespace OHOS