1 /*
2 * Copyright (c) 2022-2023 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 "rs_vk_image_manager.h"
17
18 #include <parameter.h>
19 #include <parameters.h>
20 #include "include/core/SkColorSpace.h"
21 #include "native_buffer_inner.h"
22 #include "platform/common/rs_log.h"
23 #include "include/gpu/GrBackendSurface.h"
24 #include "pipeline/hardware_thread/rs_hardware_thread.h"
25 #include "pipeline/rs_task_dispatcher.h"
26 #include "rs_trace.h"
27 #include "common/rs_optional_trace.h"
28 #include "params/rs_surface_render_params.h"
29
30 namespace OHOS {
31 namespace Rosen {
32 namespace {
WaitAcquireFence(const sptr<SyncFence> & acquireFence)33 void WaitAcquireFence(const sptr<SyncFence>& acquireFence)
34 {
35 if (acquireFence == nullptr) {
36 return;
37 }
38 acquireFence->Wait(3000); // 3000ms
39 }
40
41 constexpr size_t MAX_CACHE_SIZE = 16;
42 constexpr size_t MAX_CACHE_SIZE_FOR_VIRTUAL_SCREEN = 40;
43 static const bool ENABLE_VKIMAGE_DFX = system::GetBoolParameter("persist.graphic.enable_vkimage_dfx", false);
44
45 #define DFX_LOG(enableDfx, format, ...) \
46 ((enableDfx) ? (void) HILOG_ERROR(LOG_CORE, format, ##__VA_ARGS__) : (void) 0)
47 #define DFX_LOGD(enableDfx, format, ...) \
48 ((enableDfx) ? (void) HILOG_ERROR(LOG_CORE, format, ##__VA_ARGS__) : \
49 (void) HILOG_DEBUG(LOG_CORE, format, ##__VA_ARGS__))
50 }
51
~NativeVkImageRes()52 NativeVkImageRes::~NativeVkImageRes()
53 {
54 NativeBufferUtils::DeleteVkImage(mVulkanCleanupHelper);
55 DestroyNativeWindowBuffer(mNativeWindowBuffer);
56 }
57
Create(sptr<OHOS::SurfaceBuffer> buffer)58 std::shared_ptr<NativeVkImageRes> NativeVkImageRes::Create(sptr<OHOS::SurfaceBuffer> buffer)
59 {
60 if (buffer == nullptr) {
61 ROSEN_LOGE("NativeVkImageRes::Create buffer is nullptr");
62 return nullptr;
63 }
64 auto width = buffer->GetSurfaceBufferWidth();
65 auto height = buffer->GetSurfaceBufferHeight();
66 NativeWindowBuffer* nativeWindowBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&buffer);
67 bool isProtected = (buffer->GetUsage() & BUFFER_USAGE_PROTECTED) != 0;
68 auto backendTexture = NativeBufferUtils::MakeBackendTextureFromNativeBuffer(nativeWindowBuffer,
69 width, height, isProtected);
70 if (!backendTexture.IsValid() || !backendTexture.GetTextureInfo().GetVKTextureInfo()) {
71 DestroyNativeWindowBuffer(nativeWindowBuffer);
72 return nullptr;
73 }
74 return std::make_unique<NativeVkImageRes>(
75 nativeWindowBuffer,
76 backendTexture,
77 new NativeBufferUtils::VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
78 backendTexture.GetTextureInfo().GetVKTextureInfo()->vkImage,
79 backendTexture.GetTextureInfo().GetVKTextureInfo()->vkAlloc.memory));
80 }
81
MapVkImageFromSurfaceBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,const sptr<SyncFence> & acquireFence,pid_t threadIndex,ScreenId screenId)82 std::shared_ptr<NativeVkImageRes> RSVkImageManager::MapVkImageFromSurfaceBuffer(
83 const sptr<OHOS::SurfaceBuffer>& buffer,
84 const sptr<SyncFence>& acquireFence,
85 pid_t threadIndex, ScreenId screenId)
86 {
87 if (buffer == nullptr) {
88 ROSEN_LOGE("RSVkImageManager::MapVkImageFromSurfaceBuffer buffer is nullptr");
89 return nullptr;
90 }
91 WaitAcquireFence(acquireFence);
92 std::lock_guard<std::mutex> lock(opMutex_);
93 bool isProtectedCondition = (buffer->GetUsage() & BUFFER_USAGE_PROTECTED) ||
94 RsVulkanContext::GetSingleton().GetIsProtected();
95 auto bufferId = buffer->GetSeqNum();
96 if (isVirtualScreen(screenId) && !isProtectedCondition && threadIndex == RSUniRenderThread::Instance().GetTid()) {
97 if (imageCacheVirtualScreenSeqs_.find(bufferId) == imageCacheVirtualScreenSeqs_.end()) {
98 return NewImageCacheFromBuffer(buffer, threadIndex, isProtectedCondition, true);
99 }
100 RS_TRACE_NAME_FMT("find cache vkImage for VirScreen, bufferId=%u", bufferId);
101 return imageCacheVirtualScreenSeqs_[bufferId];
102 }
103
104 if (isProtectedCondition || imageCacheSeqs_.find(bufferId) == imageCacheSeqs_.end()) {
105 return NewImageCacheFromBuffer(buffer, threadIndex, isProtectedCondition);
106 } else {
107 return imageCacheSeqs_[bufferId];
108 }
109 }
110
CreateImageCacheFromBuffer(sptr<OHOS::SurfaceBuffer> buffer,const sptr<SyncFence> & acquireFence)111 std::shared_ptr<NativeVkImageRes> RSVkImageManager::CreateImageCacheFromBuffer(sptr<OHOS::SurfaceBuffer> buffer,
112 const sptr<SyncFence>& acquireFence)
113 {
114 WaitAcquireFence(acquireFence);
115 auto bufferId = buffer->GetSeqNum();
116 auto imageCache = NativeVkImageRes::Create(buffer);
117 if (imageCache == nullptr) {
118 ROSEN_LOGE(
119 "RSVkImageManager::CreateImageCacheFromBuffer: failed to create ImageCache for buffer id %{public}d.",
120 bufferId);
121 return nullptr;
122 }
123 return imageCache;
124 }
125
isVirtualScreen(ScreenId screenId)126 bool RSVkImageManager::isVirtualScreen(ScreenId screenId)
127 {
128 if (screenId == INVALID_SCREEN_ID) {
129 return false;
130 }
131
132 auto screenManager = CreateOrGetScreenManager();
133 if (!screenManager) {
134 return false;
135 }
136 RSScreenType type = UNKNOWN_TYPE_SCREEN;
137 if (screenManager->GetScreenType(screenId, type) != StatusCode::SUCCESS) {
138 return false;
139 }
140 return type == VIRTUAL_TYPE_SCREEN ? true : false;
141 }
142
NewImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,pid_t threadIndex,bool isProtectedCondition,bool isMatchVirtualScreen)143 std::shared_ptr<NativeVkImageRes> RSVkImageManager::NewImageCacheFromBuffer(
144 const sptr<OHOS::SurfaceBuffer>& buffer, pid_t threadIndex, bool isProtectedCondition, bool isMatchVirtualScreen)
145 {
146 auto bufferId = buffer->GetSeqNum();
147 auto deleteFlag = buffer->GetBufferDeleteFromCacheFlag();
148 auto imageCache = NativeVkImageRes::Create(buffer);
149 if (imageCache == nullptr) {
150 ROSEN_LOGE("RSVkImageManager::NewImageCacheFromBuffer: failed to create ImageCache for buffer id %{public}d.",
151 bufferId);
152 return {};
153 }
154
155 size_t imageCacheVirtualScreenSeqSize = imageCacheVirtualScreenSeqs_.size();
156 size_t imageCacheSeqSize = imageCacheSeqs_.size();
157 DFX_LOGD(ENABLE_VKIMAGE_DFX, "RSVkImageManagerDfx: create image, bufferId=%{public}u, threadIndex=%{public}d, "
158 "deleteFlag=%{public}d, isProtected=%{public}d, isVirtualScreen=%{public}d,cacheSeq=[%{public}lu, %{public}lu]",
159 bufferId, threadIndex, deleteFlag, isProtectedCondition, isMatchVirtualScreen,
160 imageCacheVirtualScreenSeqSize, imageCacheSeqSize);
161 RS_TRACE_NAME_FMT("RSVkImageManagerDfx: create image, bufferId=%u, "
162 "deleteFlag=%d, isProtected=%d, isVirtualScreen=%d,cacheSeq=[%lu, %lu]",
163 bufferId, deleteFlag, isProtectedCondition, isMatchVirtualScreen,
164 imageCacheVirtualScreenSeqSize, imageCacheSeqSize);
165 imageCache->SetThreadIndex(threadIndex);
166 imageCache->SetBufferDeleteFromCacheFlag(deleteFlag);
167 if (isProtectedCondition) {
168 return imageCache;
169 }
170
171 if (isMatchVirtualScreen) {
172 if (imageCacheVirtualScreenSeqSize <= MAX_CACHE_SIZE_FOR_VIRTUAL_SCREEN) {
173 imageCacheVirtualScreenSeqs_.emplace(bufferId, imageCache);
174 }
175 } else {
176 imageCacheSeqs_.emplace(bufferId, imageCache);
177 cacheQueue_.push(bufferId);
178 }
179 return imageCache;
180 }
181
ShrinkCachesIfNeeded()182 void RSVkImageManager::ShrinkCachesIfNeeded()
183 {
184 while (cacheQueue_.size() > MAX_CACHE_SIZE) {
185 const uint32_t id = cacheQueue_.front();
186 UnMapVkImageFromSurfaceBuffer(id);
187 cacheQueue_.pop();
188 }
189 }
190
UnMapVkImageFromSurfaceBuffer(uint32_t seqNum,bool isMatchVirtualScreen)191 void RSVkImageManager::UnMapVkImageFromSurfaceBuffer(uint32_t seqNum, bool isMatchVirtualScreen)
192 {
193 DFX_LOG(ENABLE_VKIMAGE_DFX,
194 "RSVkImageManagerDfx: tryUnmapImage, bufferId=%{public}u, isMatchVirtualScreen=%{public}d",
195 seqNum, isMatchVirtualScreen);
196 pid_t threadIndex = UNI_RENDER_THREAD_INDEX;
197 {
198 std::lock_guard<std::mutex> lock(opMutex_);
199 if (isMatchVirtualScreen) {
200 threadIndex = RSUniRenderThread::Instance().GetTid();
201 } else {
202 if (imageCacheSeqs_.count(seqNum) == 0) {
203 return;
204 }
205 threadIndex = imageCacheSeqs_[seqNum]->GetThreadIndex();
206 }
207 }
208 auto func = [this, seqNum, isMatchVirtualScreen]() {
209 {
210 std::lock_guard<std::mutex> lock(opMutex_);
211 if (isMatchVirtualScreen) {
212 auto iter = imageCacheVirtualScreenSeqs_.find(seqNum);
213 if (iter == imageCacheVirtualScreenSeqs_.end()) {
214 return;
215 }
216 imageCacheVirtualScreenSeqs_.erase(iter);
217 } else {
218 auto iter = imageCacheSeqs_.find(seqNum);
219 if (iter == imageCacheSeqs_.end()) {
220 return;
221 }
222 imageCacheSeqs_.erase(iter);
223 }
224 DFX_LOGD(ENABLE_VKIMAGE_DFX, "RSVkImageManagerDfx: UnmapImage, bufferId=%{public}u, "
225 "isMatchVirtualScreen=%{public}d, cacheSeq=[%{public}lu, %{public}lu]",
226 seqNum, isMatchVirtualScreen, imageCacheVirtualScreenSeqs_.size(), imageCacheSeqs_.size());
227 }
228 };
229 DFX_LOGD(ENABLE_VKIMAGE_DFX, "RSVkImageManagerDfx: findImageToUnmap, bufferId=%{public}u", seqNum);
230 RSTaskDispatcher::GetInstance().PostTask(threadIndex, func);
231 }
232
UnMapAllVkImageVirtualScreenCache()233 void RSVkImageManager::UnMapAllVkImageVirtualScreenCache()
234 {
235 auto func = [this]() {
236 std::lock_guard<std::mutex> lock(opMutex_);
237 (void)imageCacheVirtualScreenSeqs_.clear();
238 };
239 RSTaskDispatcher::GetInstance().PostTask(RSUniRenderThread::Instance().GetTid(), func);
240 }
241
DumpVkImageInfo(std::string & dumpString)242 void RSVkImageManager::DumpVkImageInfo(std::string &dumpString)
243 {
244 std::lock_guard<std::mutex> lock(opMutex_);
245 dumpString.append("\n---------RSVkImageManager-DumpVkImageInfo-Begin----------\n");
246 dumpString.append("imageCacheSeqs size: " + std::to_string(imageCacheSeqs_.size()) + "\n");
247 for (auto iter = imageCacheSeqs_.begin(); iter != imageCacheSeqs_.end(); ++iter) {
248 dumpString.append("vkimageinfo: bufferId=" + std::to_string(iter->first) +
249 ", threadIndex=" + std::to_string(iter->second->GetThreadIndex()) +
250 ", deleteFlag=" + std::to_string(iter->second->GetBufferDeleteFromCacheFlag()) + "\n");
251 }
252 dumpString.append("imageCacheVirtualScreenSeqs size: " +
253 std::to_string(imageCacheVirtualScreenSeqs_.size()) + "\n");
254 for (auto iter = imageCacheVirtualScreenSeqs_.begin(); iter != imageCacheVirtualScreenSeqs_.end(); ++iter) {
255 dumpString.append("vkimageinfo: bufferId=" + std::to_string(iter->first) +
256 ", threadIndex=" + std::to_string(iter->second->GetThreadIndex()) +
257 ", deleteFlag=" + std::to_string(iter->second->GetBufferDeleteFromCacheFlag()) + "\n");
258 }
259 dumpString.append("\n---------RSVkImageManager-DumpVkImageInfo-End----------\n");
260 }
261
262 } // namespace Rosen
263 } // namespace OHOS