• 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 "cache_data.h"
17 #include <cerrno>
18 #include <chrono>
19 #include <sys/mman.h>
20 #include <sys/stat.h>
21 #include <cstring>
22 #include <securec.h>
23 #include "render_context_log.h"
24 #ifdef PRELOAD_SHADER_CACHE
25 #include "shader_cache_utils.h"
26 #endif
27 
28 namespace OHOS {
29 const char* RS_CACHE_MAGIC_HEAD = "OHRS";
30 const int RS_CACHE_MAGIC_HEAD_LEN = 4;
31 const int RS_CACHE_HEAD_LEN = 8;
32 const int RS_BYTE_SIZE = 8;
33 const int SHADER_CACHE_CLEAR_LEVEL = 2;
34 const int CHECK_FRAME_FREQUENCY = 10;
35 namespace Rosen {
CacheData(const size_t maxKeySize,const size_t maxValueSize,const size_t maxTotalSize,const std::string & fileName)36 CacheData::CacheData(const size_t maxKeySize, const size_t maxValueSize,
37     const size_t maxTotalSize, const std::string& fileName)
38     : maxKeySize_(maxKeySize),
39     maxValueSize_(maxValueSize),
40     maxTotalSize_(maxTotalSize),
41     cacheDir_(fileName)
42 {
43     softLimit_ = static_cast<size_t>(SHADER_CACHE_SOFT_LIMIT * maxTotalSize);
44 }
45 
~CacheData()46 CacheData::~CacheData() {}
47 
CrcGen(const uint8_t * buffer,size_t bufferSize)48 uint32_t CacheData::CrcGen(const uint8_t *buffer, size_t bufferSize)
49 {
50     const uint32_t polynoimal = 0xEDB88320;
51     uint32_t crc = 0xFFFFFFFF;
52 
53     for (size_t i = 0; i < bufferSize ; ++i) {
54         crc ^= (static_cast<uint32_t>(buffer[i]));
55         for (size_t j = 0; j < RS_BYTE_SIZE; ++j) {
56             if (crc & 0x01) {
57                 crc = (crc >> 1) ^ polynoimal;
58             } else {
59                 crc >>= 1;
60             }
61         }
62     }
63     return crc ^ 0xFFFFFFFF;
64 }
65 
IsValidFile(uint8_t * buffer,size_t bufferSize)66 bool CacheData::IsValidFile(uint8_t *buffer, size_t bufferSize)
67 {
68     if (memcmp(buffer, RS_CACHE_MAGIC_HEAD, RS_CACHE_MAGIC_HEAD_LEN) != 0) {
69         LOGE("abandon, because of mismatched RS_CACHE_MAGIC_HEAD");
70         return false;
71     }
72 
73     uint32_t* storedCrc = reinterpret_cast<uint32_t*>(buffer + RS_CACHE_MAGIC_HEAD_LEN);
74     uint32_t computedCrc = CrcGen(buffer + RS_CACHE_HEAD_LEN, bufferSize - RS_CACHE_HEAD_LEN);
75     if (computedCrc != *storedCrc) {
76         LOGE("abandon, because of mismatched crc code");
77         DumpAbnormalCacheToFile(buffer, bufferSize);
78         return false;
79     }
80 
81     return true;
82 }
83 
DumpAbnormalCacheToFile(uint8_t * buffer,size_t bufferSize)84 void CacheData::DumpAbnormalCacheToFile(uint8_t *buffer, size_t bufferSize)
85 {
86     if (cacheDir_.length() <= 0) {
87         LOGE("dump abnormal cache failed, because of empty filename");
88         return;
89     }
90     char canonicalPath[PATH_MAX] = {0};
91     if (realpath(cacheDir_.c_str(), canonicalPath) == nullptr) {
92         LOGE("dump abnormal cache failed, because of realpath check");
93         return;
94     }
95     std::string abnormalCacheDir = canonicalPath;
96     abnormalCacheDir = abnormalCacheDir + "_abnormal";
97     int fd = open(abnormalCacheDir.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
98     if (fd == ERR_NUMBER) {
99         if (errno == EEXIST) {
100             if (unlink(abnormalCacheDir.c_str()) == ERR_NUMBER) {
101                 LOGE("dump abnormal cache failed, because unlinking the existing file fails");
102                 return;
103             }
104             fd = open(abnormalCacheDir.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
105         }
106         if (fd == ERR_NUMBER) {
107             LOGE("dump abnormal cache failed, because the file creation fails");
108             return;
109         }
110     }
111 
112     std::time_t curTime = time(nullptr);
113     char timestamp[TIME_MAX_LEN] = {0};
114     std::strftime(timestamp, TIME_MAX_LEN, "%Y-%m-%d %H:%M:%S", std::localtime(&curTime));
115     if (write(fd, timestamp, TIME_MAX_LEN) == ERR_NUMBER) {
116         LOGE("dump abnormal cache failed, because fail to write timestamp to disk");
117         close(fd);
118         unlink(abnormalCacheDir.c_str());
119         return;
120     }
121 
122     if (write(fd, buffer, bufferSize) == ERR_NUMBER) {
123         LOGE("dump abnormal cache failed, because fail to write data to disk");
124         close(fd);
125         unlink(abnormalCacheDir.c_str());
126         return;
127     }
128     fchmod(fd, S_IRUSR);
129     close(fd);
130     return;
131 }
132 
CacheReadFromFile(const std::string filePath)133 void CacheData::CacheReadFromFile(const std::string filePath)
134 {
135     if (filePath.length() <= 0) {
136         LOGD("abandon, because of empty filename.");
137         return;
138     }
139 
140     int fd = open(filePath.c_str(), O_RDONLY, 0);
141     if (fd == ERR_NUMBER) {
142         if (errno != ENOENT) {
143             LOGD("abandon, because fail to open file");
144         }
145         return;
146     }
147     struct stat statBuf;
148     if (fstat(fd, &statBuf) == ERR_NUMBER) {
149         LOGD("abandon, because fail to get the file status");
150         close(fd);
151         return;
152     }
153     if (statBuf.st_size < 0) {
154         LOGD("abandon, negative file size");
155         close(fd);
156         return;
157     }
158 
159     size_t fileSize = static_cast<size_t>(statBuf.st_size);
160     if (fileSize < RS_CACHE_HEAD_LEN || fileSize > maxTotalSize_ * maxMultipleSize_ + RS_CACHE_HEAD_LEN) {
161         LOGE("abandon, illegal file size");
162         close(fd);
163         return;
164     }
165     uint8_t *buffer = reinterpret_cast<uint8_t*>(mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fd, 0));
166     if (buffer == MAP_FAILED) {
167         LOGD("abandon, because of mmap failure:");
168         close(fd);
169         return;
170     }
171 
172     if (!IsValidFile(buffer, fileSize)) {
173         LOGE("abandon, invalid file");
174         munmap(buffer, fileSize);
175         close(fd);
176         return;
177     }
178 
179     uint8_t *shaderBuffer = reinterpret_cast<uint8_t*>(buffer + RS_CACHE_HEAD_LEN);
180     if (DeSerialize(shaderBuffer, fileSize - RS_CACHE_HEAD_LEN) < 0) {
181         LOGE("abandon, because fail to read file contents");
182     }
183     munmap(buffer, fileSize);
184     close(fd);
185 }
186 
ReadFromFile()187 void CacheData::ReadFromFile()
188 {
189 #ifdef PRELOAD_SHADER_CACHE
190     // read cache from preload cache dir
191     CacheReadFromFile(ShaderCacheUtils::GetPreloadCacheDir());
192 #endif
193     // read cache from user data dir
194     CacheReadFromFile(cacheDir_);
195 }
196 
WriteToFile()197 void CacheData::WriteToFile()
198 {
199     if (cacheDir_.length() <= 0) {
200         LOGD("abandon, because of empty filename.");
201         return;
202     }
203     int fd = open(cacheDir_.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
204     if (fd == ERR_NUMBER) {
205         if (errno == EEXIST) {
206             if (unlink(cacheDir_.c_str()) == ERR_NUMBER) {
207                 LOGD("abandon, because unlinking the existing file fails");
208                 return;
209             }
210             fd = open(cacheDir_.c_str(), O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
211         }
212         if (fd == ERR_NUMBER) {
213             LOGD("abandon, because the file creation fails");
214             return;
215         }
216     }
217     size_t cacheSize = SerializedSize();
218     if (cacheSize <= 0) {
219         LOGD("abandon, illegal serialized size");
220         close(fd);
221         return;
222     }
223     size_t bufferSize = cacheSize + RS_CACHE_HEAD_LEN;
224     uint8_t *buffer = new uint8_t[bufferSize];
225     if (!buffer) {
226         LOGD("abandon, because fail to allocate buffer for cache content");
227         close(fd);
228         unlink(cacheDir_.c_str());
229         return;
230     }
231     if (Serialize(buffer + RS_CACHE_HEAD_LEN, cacheSize) < 0) {
232         LOGD("abandon, because fail to serialize the CacheData:");
233         delete[] buffer;
234         close(fd);
235         unlink(cacheDir_.c_str());
236         return;
237     }
238 
239     // Write the file rs magic head and CRC code
240     if (memcpy_s(buffer, bufferSize, RS_CACHE_MAGIC_HEAD, RS_CACHE_MAGIC_HEAD_LEN) != 0) {
241         delete[] buffer;
242         close(fd);
243         return;
244     }
245     uint32_t *crc = reinterpret_cast<uint32_t*>(buffer + RS_CACHE_MAGIC_HEAD_LEN);
246     *crc = CrcGen(buffer + RS_CACHE_HEAD_LEN, cacheSize);
247 
248     if (write(fd, buffer, bufferSize) == ERR_NUMBER) {
249         LOGD("abandon, because fail to write to disk");
250         delete[] buffer;
251         close(fd);
252         unlink(cacheDir_.c_str());
253         return;
254     }
255     delete[] buffer;
256     fchmod(fd, S_IRUSR);
257     close(fd);
258 }
259 
Rewrite(const void * key,const size_t keySize,const void * value,const size_t valueSize)260 void CacheData::Rewrite(const void *key, const size_t keySize, const void *value, const size_t valueSize)
261 {
262     if (maxKeySize_ < keySize || maxValueSize_ < valueSize ||
263         maxTotalSize_ < keySize + valueSize || keySize == 0 || valueSize <= 0) {
264         LOGD("abandon, because of illegal content size");
265         return;
266     }
267     std::shared_ptr<DataPointer> fakeDataPointer(std::make_shared<DataPointer>(key, keySize, false));
268     ShaderPointer fakeShaderPointer(fakeDataPointer, nullptr);
269     bool isShaderFound = false;
270     size_t newTotalSize = 0;
271     while (!isShaderFound) {
272         auto index = std::lower_bound(shaderPointers_.begin(), shaderPointers_.end(), fakeShaderPointer);
273         if (index == shaderPointers_.end() || fakeShaderPointer < *index) {
274             std::shared_ptr<DataPointer> keyPointer(std::make_shared<DataPointer>(key, keySize, true));
275             std::shared_ptr<DataPointer> valuePointer(std::make_shared<DataPointer>(value, valueSize, true));
276             newTotalSize = totalSize_ + keySize + valueSize;
277             if (IfSizeValidate(newTotalSize, keySize + valueSize)) {
278                 shaderPointers_.insert(index, ShaderPointer(keyPointer, valuePointer));
279                 totalSize_ = newTotalSize;
280                 break;
281             }
282             if (IfSkipClean(keySize + valueSize)) {
283                 break;
284             }
285             if (IfCleanFinished()) {
286                 continue;
287             }
288             break;
289         } else {
290             std::shared_ptr<DataPointer> valuePointer(std::make_shared<DataPointer>(value, valueSize, true));
291             std::shared_ptr<DataPointer> oldValuePointer(index->GetValuePointer());
292             newTotalSize = totalSize_ + valueSize - oldValuePointer->GetSize();
293             size_t addedSize = (valueSize > oldValuePointer->GetSize()) ? valueSize - oldValuePointer->GetSize() : 0;
294             if (IfSizeValidate(newTotalSize, addedSize)) {
295                 index->SetValue(valuePointer);
296                 totalSize_ = newTotalSize;
297                 break;
298             }
299             if (IfSkipClean(addedSize)) {
300                 break;
301             }
302             if (IfCleanFinished()) {
303                 continue;
304             }
305             break;
306         }
307         isShaderFound = true;
308     }
309     cleanThreshold_ = 0;
310 }
311 
Get(const void * key,const size_t keySize,void * value,const size_t valueSize)312 std::tuple<CacheData::ErrorCode, size_t> CacheData::Get(const void *key, const size_t keySize,
313     void *value, const size_t valueSize)
314 {
315     if (maxKeySize_ < keySize) {
316         LOGD("abandon, because the key is too large");
317         return {ErrorCode::VALUE_SIZE_OVER_MAX_SIZE, 0};
318     }
319     std::shared_ptr<DataPointer> fakeDataPointer(std::make_shared<DataPointer>(key, keySize, false));
320     ShaderPointer fakeShaderPointer(fakeDataPointer, nullptr);
321     auto index = std::lower_bound(shaderPointers_.begin(), shaderPointers_.end(), fakeShaderPointer);
322     if (index == shaderPointers_.end() || fakeShaderPointer < *index) {
323         LOGD("abandon, because no key is found");
324         return {ErrorCode::KEY_NOT_FOUND, 0};
325     }
326     std::shared_ptr <DataPointer> valuePointer(index->GetValuePointer());
327     size_t valuePointerSize = valuePointer->GetSize();
328     if (valuePointerSize > valueSize) {
329         LOGD("abandon, because of insufficient buffer space");
330         return {ErrorCode::VALUE_SIZE_TOO_SAMLL, valuePointerSize};
331     }
332     if (memcpy_s(value, valueSize, valuePointer->GetData(), valuePointerSize)) {
333         LOGD("abandon, failed to copy content");
334         return {ErrorCode::COPY_FAILED, 0};
335     }
336     return {ErrorCode::NO_ERR, valuePointerSize};
337 }
338 
SerializedSize() const339 size_t CacheData::SerializedSize() const
340 {
341     size_t size = Align4(sizeof(Header));
342     for (const ShaderPointer &p: shaderPointers_) {
343         std::shared_ptr <DataPointer> const &keyPointer = p.GetKeyPointer();
344         std::shared_ptr <DataPointer> const &valuePointer = p.GetValuePointer();
345         size += Align4(sizeof(ShaderData) + keyPointer->GetSize() + valuePointer->GetSize());
346     }
347     return size;
348 }
349 
Serialize(uint8_t * buffer,const size_t size) const350 int CacheData::Serialize(uint8_t *buffer, const size_t size) const
351 {
352     if (size < sizeof(Header)) {
353         LOGD("abandon because of insufficient buffer space.");
354         return -EINVAL;
355     }
356     Header *header = reinterpret_cast<Header *>(buffer);
357     header->numShaders_ = shaderPointers_.size();
358     size_t byteOffset = Align4(sizeof(Header));
359     size_t headSize = sizeof(ShaderData);
360 
361     uint8_t *byteBuffer = reinterpret_cast<uint8_t *>(buffer);
362     for (const ShaderPointer &p: shaderPointers_) {
363         std::shared_ptr<DataPointer> const &keyPointer = p.GetKeyPointer();
364         std::shared_ptr<DataPointer> const &valuePointer = p.GetValuePointer();
365         size_t keySize = keyPointer->GetSize();
366         size_t valueSize = valuePointer->GetSize();
367         size_t pairSize = sizeof(ShaderData) + keySize + valueSize;
368         size_t alignedSize = Align4(pairSize);
369         if (byteOffset + alignedSize > size) {
370             LOGD("abandon because of insufficient buffer space.");
371             return -EINVAL;
372         }
373 
374         ShaderData *shaderBuffer = reinterpret_cast<ShaderData *>(&byteBuffer[byteOffset]);
375         shaderBuffer->keySize_ = keySize;
376         shaderBuffer->valueSize_ = valueSize;
377         size_t sizeLeft = size - byteOffset - headSize;
378         if (memcpy_s(shaderBuffer->data_, sizeLeft, keyPointer->GetData(), keySize)) {
379             LOGD("abandon, failed to copy key");
380             return -EINVAL;
381         }
382         if (memcpy_s(shaderBuffer->data_ + keySize, sizeLeft - keySize, valuePointer->GetData(), valueSize)) {
383             LOGD("abandon, failed to copy value");
384             return -EINVAL;
385         }
386         if (alignedSize > pairSize) {
387             auto ret = memset_s(shaderBuffer->data_ + keySize + valueSize, alignedSize - pairSize, 0,
388                 alignedSize - pairSize);
389             if (ret != EOK) {
390                 LOGD("abandon, failed to memset_s");
391                 return -EINVAL;
392             }
393         }
394         byteOffset += alignedSize;
395     }
396     return 0;
397 }
398 
DeSerialize(uint8_t const * buffer,const size_t size)399 int CacheData::DeSerialize(uint8_t const *buffer, const size_t size)
400 {
401     shaderPointers_.clear();
402     if (size < sizeof(Header)) {
403         LOGD("abandon, not enough room for cache header");
404     }
405 
406     if (buffer == nullptr) {
407         LOGD("abandon, buffer is null");
408         return -EINVAL;
409     }
410     const Header *header = reinterpret_cast<const Header *>(buffer);
411     size_t numShaders = header->numShaders_;
412     size_t byteOffset = Align4(sizeof(Header));
413 
414     const uint8_t *byteBuffer = reinterpret_cast<const uint8_t *>(buffer);
415     for (size_t i = 0; i < numShaders; i++) {
416         if (byteOffset + sizeof(ShaderData) > size) {
417             shaderPointers_.clear();
418             LOGD("abandon because of insufficient buffer space");
419             return -EINVAL;
420         }
421         const ShaderData *shaderBuffer = reinterpret_cast<const ShaderData *>(&byteBuffer[byteOffset]);
422         size_t keySize = shaderBuffer->keySize_;
423         size_t valueSize = shaderBuffer->valueSize_;
424         size_t pairSize = sizeof(ShaderData) + keySize + valueSize;
425         size_t alignedSize = Align4(pairSize);
426         if (byteOffset + alignedSize > size) {
427             shaderPointers_.clear();
428             LOGD("abandon, not enough room for cache headers");
429             return -EINVAL;
430         }
431 
432         const uint8_t *data = shaderBuffer->data_;
433         Rewrite(data, keySize, data + keySize, valueSize);
434         byteOffset += alignedSize;
435     }
436     return 0;
437 }
438 
IfSizeValidate(const size_t newSize,const size_t addedSize) const439 bool CacheData::IfSizeValidate(const size_t newSize, const size_t addedSize) const
440 {
441     // check if size is ok and we don't neet to clean the shaders
442     if (newSize <= maxTotalSize_ || addedSize == 0) {
443         return true;
444     }
445     return false;
446 }
447 
IfSkipClean(const size_t addedSize) const448 bool CacheData::IfSkipClean(const size_t addedSize) const
449 {
450     // check if the new shader is still too large after cleaning
451     size_t maxPermittedSize = maxTotalSize_ - maxTotalSize_ / cleanLevel_;
452     if (addedSize > maxPermittedSize) {
453         LOGD("new shader is too large, abandon insert");
454         return true;
455     }
456     return false;
457 }
458 
IfCleanFinished()459 bool CacheData::IfCleanFinished()
460 {
461     if (!cleanThreshold_) {
462         RandClean(maxTotalSize_ / cleanLevel_);
463         return true;
464     } else {
465         LOGD("abandon, failed to clean the shaders");
466         return false;
467     }
468 }
469 
RandClean(const size_t cleanThreshold)470 void CacheData::RandClean(const size_t cleanThreshold)
471 {
472     if (cleanThreshold == 0) {
473         LOGD("CleanThreshold must be > 0");
474         return;
475     }
476     if (cleanThreshold_ == 0) {
477         if (!CleanInit()) {
478             return;
479         }
480     }
481     cleanThreshold_ = cleanThreshold;
482 
483     while (totalSize_ > cleanThreshold_) {
484         if (!StepClean()) {
485             break;
486         }
487     }
488 }
489 
CleanInit()490 bool CacheData::CleanInit()
491 {
492     auto now = std::chrono::steady_clock::now().time_since_epoch().count();
493     if (now < 0) {
494         LOGD("abandon, illegal negative now value");
495         return false;
496     }
497     unsigned long currentTime = static_cast<unsigned long>(now);
498     for (int indexRand = 0; indexRand < randLength_; ++indexRand) {
499         cleanInit_[indexRand] = (currentTime >> (indexRand * randShift_)) & 0xFFFF;
500     }
501     return true;
502 }
503 
StepClean()504 bool CacheData::StepClean()
505 {
506     long int randIndex = nrand48(cleanInit_);
507     if (randIndex < 0) {
508         LOGD("abandon, illegal negative randIndex value");
509         return false;
510     }
511     size_t sizeRandIndex = static_cast<size_t>(randIndex);
512     size_t currentSize = shaderPointers_.size();
513     if (currentSize == 0) {
514         LOGD("abandon, shader is empty, nothing to clean");
515         return false;
516     }
517     size_t removeIndex = sizeRandIndex % (currentSize);
518     if (!Clean(removeIndex)) {
519         LOGD("abandon, cleaned nothing");
520         return false;
521     }
522     return true;
523 }
524 
Clean(const size_t removeIndex)525 size_t CacheData::Clean(const size_t removeIndex)
526 {
527     if (removeIndex >= shaderPointers_.size()) {
528         LOGD("illegal shader index, abandon cleaning");
529         return 0;
530     }
531     const ShaderPointer &shader(shaderPointers_[removeIndex]);
532     size_t reducedSize = shader.GetKeyPointer()->GetSize() + shader.GetValuePointer()->GetSize();
533     totalSize_ -= reducedSize;
534     shaderPointers_.erase(shaderPointers_.begin() + removeIndex);
535     return reducedSize;
536 }
537 
CheckShaderCacheOverSoftLimit() const538 bool CacheData::CheckShaderCacheOverSoftLimit() const
539 {
540     return totalSize_ >= softLimit_;
541 }
542 
PurgeShaderCacheAfterAnimate(const std::function<bool (void)> & nextFrameHasArrived)543 void CacheData::PurgeShaderCacheAfterAnimate(const std::function<bool(void)>& nextFrameHasArrived)
544 {
545     if (!CleanInit()) {
546         return;
547     }
548     if (!nextFrameHasArrived) {
549         LOGD("nextFrame Func is Empty");
550         return;
551     }
552     const size_t cleanTarget = maxTotalSize_ / SHADER_CACHE_CLEAR_LEVEL;
553     int cleanTimes = 0;
554     while (totalSize_ > cleanTarget && (cleanTimes % CHECK_FRAME_FREQUENCY != 0 || !nextFrameHasArrived())) {
555         if (!StepClean()) {
556             break;
557         }
558         cleanTimes++;
559     }
560 }
561 
DataPointer(const void * data,size_t size,bool ifOccupy)562 CacheData::DataPointer::DataPointer(const void *data, size_t size, bool ifOccupy)
563     : pointer_(nullptr),
564     size_(size),
565     toFree_(ifOccupy)
566 {
567     if (ifOccupy) {
568         pointer_ = malloc(size);
569     } else {
570         pointer_ = data;
571     }
572 
573     if (data != nullptr && ifOccupy) {
574         if (memcpy_s(const_cast<void *>(pointer_), size, data, size)) {
575             LOGD("abandon: failed to copy data");
576             return;
577         }
578     }
579 }
580 
~DataPointer()581 CacheData::DataPointer::~DataPointer()
582 {
583     if (toFree_) {
584         free(const_cast<void *>(pointer_));
585         pointer_ = nullptr;
586     }
587 }
588 
ShaderPointer()589 CacheData::ShaderPointer::ShaderPointer() {}
590 
ShaderPointer(const std::shared_ptr<DataPointer> & key,const std::shared_ptr<DataPointer> & value)591 CacheData::ShaderPointer::ShaderPointer(const std::shared_ptr <DataPointer> &key,
592                                         const std::shared_ptr <DataPointer> &value)
593     : keyPointer_(key),
594     valuePointer_(value) {}
595 
ShaderPointer(const ShaderPointer & sp)596 CacheData::ShaderPointer::ShaderPointer(const ShaderPointer &sp)
597     : keyPointer_(sp.keyPointer_),
598     valuePointer_(sp.valuePointer_) {}
599 }   // namespace Rosen
600 }   // namespace OHOS