1 /*
2  * Copyright (C) 2024 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 #ifndef RENDER_RESOURCE_CACHE_H
17 #define RENDER_RESOURCE_CACHE_H
18 
19 #include "base/render_base.h"
20 #include "base/cache/render_fifo_cache.h"
21 #include "graphic/render_general_program.h"
22 #include "render_mesh.h"
23 #include "graphic/render_texture.h"
24 
25 #define TEXTURE_CACHE_MAX_CAPACITY (800 * 1024 * 1024)
26 #define TEXTURE_CACHE_STABLE_CAPACITY (80 * 1024 * 1024)
27 
28 namespace OHOS {
29 namespace Media {
30 namespace Effect {
31 class RenderFrameBuffer;
32 using RenderFrameBufferPtr = std::shared_ptr<RenderFrameBuffer>;
33 class RenderEffectBase;
34 using RenderEffectBasePtr = std::shared_ptr<RenderEffectBase>;
35 
36 constexpr int TEX_WIDTH_TAG_POS = 48;
37 constexpr int TEX_HEIGHT_TAG_POS = 32;
38 constexpr int RESIZE_RATE = 2;
39 
40 class ResourceCache {
41 public:
~ResourceCache()42     ~ResourceCache()
43     {
44         texReleaseFlag = true;
45         DeleteAllShader();
46         DeleteAllMesh();
47     }
GetShader(const std::string name)48     RenderGeneralProgram *GetShader(const std::string name)
49     {
50         auto ite = shadersMap_.find(name);
51         if (ite == shadersMap_.end()) {
52             return nullptr;
53         }
54         return ite->second;
55     }
56 
GetMesh(const std::string name)57     RenderMesh *GetMesh(const std::string name)
58     {
59         auto ite = meshesMap_.find(name);
60         if (ite == meshesMap_.end()) {
61             return nullptr;
62         }
63         return ite->second;
64     }
65 
GetEffect(const std::string name)66     RenderEffectBasePtr GetEffect(const std::string name)
67     {
68         auto ite = effectMap_.find(name);
69         if (ite == effectMap_.end()) {
70             return nullptr;
71         }
72         return ite->second;
73     }
74 
AddShader(std::string name,RenderGeneralProgram * shader)75     void AddShader(std::string name, RenderGeneralProgram *shader)
76     {
77         shadersMap_[name] = shader;
78     }
79 
AddMesh(std::string name,RenderMesh * mesh)80     void AddMesh(std::string name, RenderMesh *mesh)
81     {
82         meshesMap_[name] = mesh;
83     }
84 
AddEffect(std::string name,RenderEffectBasePtr effect)85     void AddEffect(std::string name, RenderEffectBasePtr effect)
86     {
87         effectMap_[name] = effect;
88     }
89 
RemoveShader(std::string name)90     size_t RemoveShader(std::string name)
91     {
92         return shadersMap_.erase(name);
93     }
94 
RemoveMesh(std::string name)95     size_t RemoveMesh(std::string name)
96     {
97         return meshesMap_.erase(name);
98     }
99 
RemoveEffect(std::string name)100     size_t RemoveEffect(std::string name)
101     {
102         return effectMap_.erase(name);
103     }
104 
RequestTexture(RenderContext * ctx,GLsizei w,GLsizei h,GLenum interFmt)105     RenderTexturePtr RequestTexture(RenderContext *ctx, GLsizei w, GLsizei h, GLenum interFmt)
106     {
107         UINT64 tag = GetTexTag(w, h, interFmt);
108         RenderTexture *rawTex;
109         RenderTexturePtr tex;
110         bool isGot = disuseTexCache_.Take(tag, tex);
111         if (isGot) {
112             rawTex = tex.get();
113             tex.reset();
114         } else {
115             rawTex = new RenderTexture(ctx, w, h, interFmt);
116             rawTex->Init();
117         }
118         return RenderTexturePtr(rawTex, [this](auto *p) {
119             if (p) {
120                 RecycleTexture(dynamic_cast<RenderTexture *>(p));
121             }
122         });
123     }
124 
ResizeTexCache()125     void ResizeTexCache()
126     {
127         if (disuseTexCache_.Size() > TEXTURE_CACHE_STABLE_CAPACITY) {
128             texReleaseFlag = true;
129             disuseTexCache_.ReSize(disuseTexCache_.Size() / RESIZE_RATE, false);
130             texReleaseFlag = false;
131         }
132     }
133 
AddTexStage(int id,RenderTexturePtr tex)134     void AddTexStage(int id, RenderTexturePtr tex)
135     {
136         namedTexCache_.insert_or_assign(id, tex);
137     }
138 
GetTexStage(int id)139     RenderTexturePtr GetTexStage(int id)
140     {
141         auto ite = namedTexCache_.find(id);
142         if (ite != namedTexCache_.end()) {
143             return ite->second;
144         }
145         return nullptr;
146     }
147 
RemoveTexStage(int id)148     void RemoveTexStage(int id)
149     {
150         auto ite = namedTexCache_.find(id);
151         if (ite != namedTexCache_.end()) {
152             namedTexCache_.erase(ite);
153         }
154     }
155 
AddTexGlobalCache(std::string id,RenderTexturePtr tex)156     void AddTexGlobalCache(std::string id, RenderTexturePtr tex)
157     {
158         texGlobalCache_.insert_or_assign(id, tex);
159     }
160 
GetTexGlobalCache(const std::string id)161     RenderTexturePtr GetTexGlobalCache(const std::string id)
162     {
163         auto ite = texGlobalCache_.find(id);
164         if (ite != texGlobalCache_.end()) {
165             return ite->second;
166         }
167         return nullptr;
168     }
169 
RemoveTexGlobalCache(const std::string id)170     void RemoveTexGlobalCache(const std::string id)
171     {
172         auto ite = texGlobalCache_.find(id);
173         if (ite != texGlobalCache_.end()) {
174             texGlobalCache_.erase(ite);
175         }
176     }
177 
178 private:
RecycleTexture(RenderTexture * tex)179     void RecycleTexture(RenderTexture *tex)
180     {
181         UINT64 tag = GetTexTag(tex->Width(), tex->Height(), tex->Format());
182         auto func = [this](RenderTexture *p) {
183             if (texReleaseFlag && p) {
184                 p->Release();
185                 delete p;
186             }
187         };
188         texReleaseFlag = true;
189         disuseTexCache_.Put(tag, RenderTexturePtr(tex, func));
190         texReleaseFlag = false;
191     }
192 
193     bool texReleaseFlag{ false };
194     std::unordered_map<std::string, RenderGeneralProgram *> shadersMap_;
195     std::unordered_map<std::string, RenderMesh *> meshesMap_;
196     RenderFifoCache<UINT64, RenderTexturePtr, TextureSizeMeasurer> disuseTexCache_{TEXTURE_CACHE_MAX_CAPACITY};
197     std::unordered_map<int, RenderTexturePtr> namedTexCache_;
198     std::unordered_map<std::string, RenderTexturePtr> texGlobalCache_;
199     std::unordered_map<std::string, RenderEffectBasePtr> effectMap_;
200 
DeleteAllShader()201     void DeleteAllShader()
202     {
203         std::unordered_map<std::string, RenderGeneralProgram *>::iterator iter = shadersMap_.begin();
204         while (iter != shadersMap_.end()) {
205             iter->second->Release();
206             ++iter;
207         }
208         shadersMap_.clear();
209     }
210 
DeleteAllMesh()211     void DeleteAllMesh()
212     {
213         std::unordered_map<std::string, RenderMesh *>::iterator iter = meshesMap_.begin();
214         while (iter != meshesMap_.end()) {
215             delete iter->second;
216             iter->second = nullptr;
217             meshesMap_.erase(iter++);
218         }
219     }
220 
GetTexTag(GLsizei w,GLsizei h,GLenum interFmt)221     UINT64 GetTexTag(GLsizei w, GLsizei h, GLenum interFmt)
222     {
223         return ((UINT64)interFmt & 0xffffffff) | (((UINT64)h & 0xffff) << TEX_HEIGHT_TAG_POS) |
224             (((UINT64)w & 0xffff) << TEX_WIDTH_TAG_POS);
225     }
226 };
227 } // namespace Effect
228 } // namespace Media
229 } // namespace OHOS
230 #endif