1 /*
2 * Copyright (c) 2022-2025 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 #ifdef USE_M133_SKIA
24 #include "include/gpu/ganesh/vk/GrVkBackendSurface.h"
25 #else
26 #include "include/gpu/GrBackendSurface.h"
27 #endif
28 #include "pipeline/hardware_thread/rs_hardware_thread.h"
29 #include "pipeline/rs_task_dispatcher.h"
30 #include "rs_trace.h"
31 #include "common/rs_optional_trace.h"
32 #include "params/rs_surface_render_params.h"
33
34 #ifdef USE_M133_SKIA
35 #include "src/gpu/ganesh/gl/GrGLDefines.h"
36 #else
37 #include "src/gpu/gl/GrGLDefines.h"
38 #endif
39
40 namespace OHOS {
41 namespace Rosen {
42 namespace {
WaitAcquireFence(const sptr<SyncFence> & acquireFence)43 void WaitAcquireFence(const sptr<SyncFence>& acquireFence)
44 {
45 if (acquireFence == nullptr) {
46 return;
47 }
48 acquireFence->Wait(3000); // 3000ms
49 }
50
51 constexpr size_t MAX_CACHE_SIZE = 16;
52 constexpr size_t MAX_CACHE_SIZE_FOR_REUSE = 40;
53 static const bool ENABLE_VKIMAGE_DFX = system::GetBoolParameter("persist.graphic.enable_vkimage_dfx", false);
54 static const bool ENABLE_SEMAPHORE =
55 system::GetBoolParameter("persist.sys.graphic.rs_vkimgmgr_enable_semaphore", true);
56
57 #define DFX_LOG(enableDfx, format, ...) \
58 ((enableDfx) ? (void) HILOG_ERROR(LOG_CORE, format, ##__VA_ARGS__) : (void) 0)
59 #define DFX_LOGD(enableDfx, format, ...) \
60 ((enableDfx) ? (void) HILOG_ERROR(LOG_CORE, format, ##__VA_ARGS__) : \
61 (void) HILOG_DEBUG(LOG_CORE, format, ##__VA_ARGS__))
62 }
63
~VkImageResource()64 VkImageResource::~VkImageResource()
65 {
66 NativeBufferUtils::DeleteVkImage(mVulkanCleanupHelper);
67 DestroyNativeWindowBuffer(mNativeWindowBuffer);
68 }
69
Create(sptr<OHOS::SurfaceBuffer> buffer)70 std::shared_ptr<VkImageResource> VkImageResource::Create(sptr<OHOS::SurfaceBuffer> buffer)
71 {
72 if (buffer == nullptr) {
73 ROSEN_LOGE("VkImageResource::Create buffer is nullptr");
74 return nullptr;
75 }
76 auto width = buffer->GetSurfaceBufferWidth();
77 auto height = buffer->GetSurfaceBufferHeight();
78 NativeWindowBuffer* nativeWindowBuffer = CreateNativeWindowBufferFromSurfaceBuffer(&buffer);
79 bool isProtected = (buffer->GetUsage() & BUFFER_USAGE_PROTECTED) != 0;
80 auto backendTexture = NativeBufferUtils::MakeBackendTextureFromNativeBuffer(nativeWindowBuffer,
81 width, height, isProtected);
82 if (!backendTexture.IsValid() || !backendTexture.GetTextureInfo().GetVKTextureInfo()) {
83 DestroyNativeWindowBuffer(nativeWindowBuffer);
84 return nullptr;
85 }
86 return std::make_unique<VkImageResource>(
87 nativeWindowBuffer,
88 backendTexture,
89 new NativeBufferUtils::VulkanCleanupHelper(RsVulkanContext::GetSingleton(),
90 backendTexture.GetTextureInfo().GetVKTextureInfo()->vkImage,
91 backendTexture.GetTextureInfo().GetVKTextureInfo()->vkAlloc.memory));
92 }
93
WaitVKSemaphore(Drawing::Surface * drawingSurface,const sptr<SyncFence> & acquireFence)94 bool RSVkImageManager::WaitVKSemaphore(Drawing::Surface *drawingSurface, const sptr<SyncFence>& acquireFence)
95 {
96 if (drawingSurface == nullptr || acquireFence == nullptr) {
97 return false;
98 }
99
100 VkSemaphore semaphore = VK_NULL_HANDLE;
101 VkSemaphoreCreateInfo semaphoreInfo;
102 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
103 semaphoreInfo.pNext = nullptr;
104 semaphoreInfo.flags = 0;
105 auto& vkInterface = RsVulkanContext::GetSingleton().GetRsVulkanInterface();
106 auto res = vkInterface.vkCreateSemaphore(vkInterface.GetDevice(), &semaphoreInfo, nullptr, &semaphore);
107 if (res != VK_SUCCESS) {
108 ROSEN_LOGE("RSVkImageManager: CreateVkSemaphore vkCreateSemaphore failed %{public}d", res);
109 return false;
110 }
111
112 VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo;
113 importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
114 importSemaphoreFdInfo.pNext = nullptr;
115 importSemaphoreFdInfo.semaphore = semaphore;
116 importSemaphoreFdInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
117 importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
118 importSemaphoreFdInfo.fd = acquireFence->Dup();
119 res = vkInterface.vkImportSemaphoreFdKHR(vkInterface.GetDevice(), &importSemaphoreFdInfo);
120 if (res != VK_SUCCESS) {
121 ROSEN_LOGE("RSVkImageManager: CreateVkSemaphore vkImportSemaphoreFdKHR failed %{public}d", res);
122 vkInterface.vkDestroySemaphore(vkInterface.GetDevice(), semaphore, nullptr);
123 close(importSemaphoreFdInfo.fd);
124 return false;
125 }
126
127 drawingSurface->Wait(1, semaphore); // 1 means only one VKSemaphore need to wait
128 return true;
129 }
130
MapVkImageFromSurfaceBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,const sptr<SyncFence> & acquireFence,pid_t threadIndex,Drawing::Surface * drawingSurface)131 std::shared_ptr<VkImageResource> RSVkImageManager::MapVkImageFromSurfaceBuffer(
132 const sptr<OHOS::SurfaceBuffer>& buffer,
133 const sptr<SyncFence>& acquireFence,
134 pid_t threadIndex, Drawing::Surface *drawingSurface)
135 {
136 if (buffer == nullptr) {
137 ROSEN_LOGE("RSVkImageManager::MapVkImageFromSurfaceBuffer buffer is nullptr");
138 return nullptr;
139 }
140 if (!ENABLE_SEMAPHORE || !WaitVKSemaphore(drawingSurface, acquireFence)) {
141 WaitAcquireFence(acquireFence);
142 }
143 std::lock_guard<std::mutex> lock(opMutex_);
144 bool isProtectedCondition = (buffer->GetUsage() & BUFFER_USAGE_PROTECTED) ||
145 RsVulkanContext::GetSingleton().GetIsProtected();
146 auto bufferId = buffer->GetSeqNum();
147 if (isProtectedCondition || imageCacheSeqs_.find(bufferId) == imageCacheSeqs_.end()) {
148 RS_TRACE_NAME_FMT("create vkImage, bufferId=%u", bufferId);
149 return NewImageCacheFromBuffer(buffer, threadIndex, isProtectedCondition);
150 } else {
151 RS_TRACE_NAME_FMT("find cache vkImage, bufferId=%u", bufferId);
152 return imageCacheSeqs_[bufferId];
153 }
154 }
155
CreateImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer> buffer,const sptr<SyncFence> & acquireFence)156 std::shared_ptr<VkImageResource> RSVkImageManager::CreateImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer> buffer,
157 const sptr<SyncFence>& acquireFence)
158 {
159 WaitAcquireFence(acquireFence);
160 if (buffer == nullptr) {
161 ROSEN_LOGE("RSVkImageManager::CreateImageCacheFromBuffer buffer is nullptr");
162 return nullptr;
163 }
164 auto bufferId = buffer->GetSeqNum();
165 auto imageCache = VkImageResource::Create(buffer);
166 if (imageCache == nullptr) {
167 ROSEN_LOGE(
168 "RSVkImageManager::CreateImageCacheFromBuffer: failed to create ImageCache for buffer id %{public}d.",
169 bufferId);
170 return nullptr;
171 }
172 return imageCache;
173 }
174
NewImageCacheFromBuffer(const sptr<OHOS::SurfaceBuffer> & buffer,pid_t threadIndex,bool isProtectedCondition)175 std::shared_ptr<VkImageResource> RSVkImageManager::NewImageCacheFromBuffer(
176 const sptr<OHOS::SurfaceBuffer>& buffer, pid_t threadIndex, bool isProtectedCondition)
177 {
178 if (buffer == nullptr) {
179 ROSEN_LOGE("RSVkImageManager::NewImageCacheFromBuffer buffer is nullptr");
180 return {};
181 }
182 auto bufferId = buffer->GetSeqNum();
183 auto deleteFlag = buffer->GetBufferDeleteFromCacheFlag();
184 auto imageCache = VkImageResource::Create(buffer);
185 if (imageCache == nullptr) {
186 ROSEN_LOGE("RSVkImageManager::NewImageCacheFromBuffer: failed to create ImageCache for buffer id %{public}d.",
187 bufferId);
188 return {};
189 }
190
191 size_t imageCacheSeqSize = imageCacheSeqs_.size();
192 DFX_LOGD(ENABLE_VKIMAGE_DFX, "RSVkImageManagerDfx: create image, bufferId=%{public}u, threadIndex=%{public}d, "
193 "deleteFlag=%{public}d, isProtected=%{public}d,cacheSeq=%{public}lu",
194 bufferId, threadIndex, deleteFlag, isProtectedCondition, imageCacheSeqSize);
195 RS_TRACE_NAME_FMT("RSVkImageManagerDfx: create image, bufferId=%u, "
196 "deleteFlag=%d, isProtected=%d, cacheSeq=%lu",
197 bufferId, deleteFlag, isProtectedCondition, imageCacheSeqSize);
198 imageCache->SetThreadIndex(threadIndex);
199 imageCache->SetBufferDeleteFromCacheFlag(deleteFlag);
200 if (isProtectedCondition) {
201 return imageCache;
202 }
203
204 RS_LOGD("RSVkImageManager::NewImageCacheFromBuffer %{public}u", bufferId);
205 if (imageCacheSeqSize < MAX_CACHE_SIZE_FOR_REUSE) {
206 imageCacheSeqs_.emplace(bufferId, imageCache);
207 }
208
209 return imageCache;
210 }
211
UnMapImageFromSurfaceBuffer(int32_t seqNum)212 void RSVkImageManager::UnMapImageFromSurfaceBuffer(int32_t seqNum)
213 {
214 DFX_LOG(ENABLE_VKIMAGE_DFX, "RSVkImageManagerDfx: tryUnmapImage, bufferId=%{public}u", seqNum);
215 pid_t threadIndex = UNI_RENDER_THREAD_INDEX;
216 {
217 std::lock_guard<std::mutex> lock(opMutex_);
218 if (imageCacheSeqs_.count(seqNum) == 0) {
219 return;
220 }
221 threadIndex = imageCacheSeqs_[seqNum]->GetThreadIndex();
222 }
223 auto func = [this, seqNum]() {
224 std::lock_guard<std::mutex> lock(opMutex_);
225 auto iter = imageCacheSeqs_.find(seqNum);
226 if (iter == imageCacheSeqs_.end()) {
227 return;
228 }
229 RS_TRACE_NAME_FMT("RSVkImageManagerDfx: unmap image, bufferId=%u", seqNum);
230 imageCacheSeqs_.erase(iter);
231 DFX_LOGD(ENABLE_VKIMAGE_DFX, "RSVkImageManagerDfx: UnmapImage, bufferId=%{public}u, "
232 "cacheSeq=[%{public}lu]",
233 seqNum, imageCacheSeqs_.size());
234 };
235 DFX_LOGD(ENABLE_VKIMAGE_DFX, "RSVkImageManagerDfx: findImageToUnmap, bufferId=%{public}u", seqNum);
236 RSTaskDispatcher::GetInstance().PostTask(threadIndex, func);
237 }
238
DumpVkImageInfo(std::string & dumpString)239 void RSVkImageManager::DumpVkImageInfo(std::string &dumpString)
240 {
241 std::lock_guard<std::mutex> lock(opMutex_);
242 dumpString.append("\n---------RSVkImageManager-DumpVkImageInfo-Begin----------\n");
243 dumpString.append("imageCacheSeqs size: " + std::to_string(imageCacheSeqs_.size()) + "\n");
244 for (auto iter = imageCacheSeqs_.begin(); iter != imageCacheSeqs_.end(); ++iter) {
245 dumpString.append("vkimageinfo: bufferId=" + std::to_string(iter->first) +
246 ", threadIndex=" + std::to_string(iter->second->GetThreadIndex()) +
247 ", deleteFlag=" + std::to_string(iter->second->GetBufferDeleteFromCacheFlag()) + "\n");
248 }
249 dumpString.append("\n---------RSVkImageManager-DumpVkImageInfo-End----------\n");
250 }
251
CreateImageFromBuffer(RSPaintFilterCanvas & canvas,const BufferDrawParam & params,const std::shared_ptr<Drawing::ColorSpace> & drawingColorSpace)252 std::shared_ptr<Drawing::Image> RSVkImageManager::CreateImageFromBuffer(
253 RSPaintFilterCanvas& canvas, const BufferDrawParam& params,
254 const std::shared_ptr<Drawing::ColorSpace>& drawingColorSpace)
255 {
256 const sptr<SurfaceBuffer>& buffer = params.buffer;
257 const sptr<SyncFence>& acquireFence = params.acquireFence;
258 const pid_t threadIndex = params.threadIndex;
259 const Drawing::AlphaType alphaType = params.alphaType;
260
261 auto image = std::make_shared<Drawing::Image>();
262 if (buffer == nullptr) {
263 RS_LOGE("RSVkImageManager::CreateImageFromBuffer: buffer is nullptr");
264 return nullptr;
265 }
266 auto imageCache = MapVkImageFromSurfaceBuffer(buffer,
267 acquireFence, threadIndex, canvas.GetSurface());
268 if (imageCache == nullptr) {
269 RS_LOGE("RSVkImageManager::MapImageFromSurfaceBuffer failed!");
270 return nullptr;
271 }
272 if (buffer != nullptr && buffer->GetBufferDeleteFromCacheFlag()) {
273 RS_LOGD_IF(DEBUG_COMPOSER, " - Buffer %{public}u marked for deletion from cache, unmapping",
274 buffer->GetSeqNum());
275 UnMapImageFromSurfaceBuffer(buffer->GetSeqNum());
276 }
277 auto bitmapFormat = RSBaseRenderUtil::GenerateDrawingBitmapFormat(buffer, alphaType);
278 auto screenColorSpace = RSBaseRenderEngine::GetCanvasColorSpace(canvas);
279 if (screenColorSpace && drawingColorSpace &&
280 drawingColorSpace->IsSRGB() != screenColorSpace->IsSRGB()) {
281 bitmapFormat.alphaType = Drawing::AlphaType::ALPHATYPE_OPAQUE;
282 }
283 RS_LOGD_IF(DEBUG_COMPOSER, " - Generated bitmap format: colorType = %{public}d, alphaType = %{public}d",
284 bitmapFormat.colorType, bitmapFormat.alphaType);
285 auto surfaceOrigin = Drawing::TextureOrigin::TOP_LEFT;
286 RS_LOGD_IF(DEBUG_COMPOSER, " - Texture origin: %{public}d", static_cast<int>(surfaceOrigin));
287 auto contextDrawingVk = canvas.GetGPUContext();
288 if (contextDrawingVk == nullptr) {
289 RS_LOGE("contextDrawingVk is nullptr.");
290 return nullptr;
291 }
292 auto& backendTexture = imageCache->GetBackendTexture();
293 if (!image->BuildFromTexture(*contextDrawingVk, backendTexture.GetTextureInfo(),
294 surfaceOrigin, bitmapFormat, drawingColorSpace,
295 NativeBufferUtils::DeleteVkImage, imageCache->RefCleanupHelper())) {
296 RS_LOGE("RSVkImageManager::CreateImageFromBuffer: backendTexture is not valid!!!");
297 return nullptr;
298 }
299 return image;
300 }
301
GetIntersectImage(Drawing::RectI & imgCutRect,const std::shared_ptr<Drawing::GPUContext> & context,const sptr<OHOS::SurfaceBuffer> & buffer,const sptr<SyncFence> & acquireFence,pid_t threadIndex)302 std::shared_ptr<Drawing::Image> RSVkImageManager::GetIntersectImage(Drawing::RectI& imgCutRect,
303 const std::shared_ptr<Drawing::GPUContext>& context, const sptr<OHOS::SurfaceBuffer>& buffer,
304 const sptr<SyncFence>& acquireFence, pid_t threadIndex)
305 {
306 if (buffer == nullptr) {
307 ROSEN_LOGE("RSVkImageManager::GetIntersectImageFromVK context or buffer is nullptr!");
308 return nullptr;
309 }
310 auto imageCache = CreateImageCacheFromBuffer(buffer, acquireFence);
311 if (imageCache == nullptr) {
312 ROSEN_LOGE("RSVkImageManager::GetIntersectImageFromVK imageCache == nullptr!");
313 return nullptr;
314 }
315 auto& backendTexture = imageCache->GetBackendTexture();
316 Drawing::BitmapFormat bitmapFormat = RSBaseRenderUtil::GenerateDrawingBitmapFormat(buffer);
317
318 std::shared_ptr<Drawing::Image> layerImage = std::make_shared<Drawing::Image>();
319 if (!layerImage->BuildFromTexture(*context, backendTexture.GetTextureInfo(),
320 Drawing::TextureOrigin::TOP_LEFT, bitmapFormat, nullptr,
321 NativeBufferUtils::DeleteVkImage, imageCache->RefCleanupHelper())) {
322 ROSEN_LOGE("RSVkImageManager::GetIntersectImageFromVK image BuildFromTexture failed.");
323 return nullptr;
324 }
325
326 std::shared_ptr<Drawing::Image> cutDownImage = std::make_shared<Drawing::Image>();
327 bool res = cutDownImage->BuildSubset(layerImage, imgCutRect, *context);
328 if (!res) {
329 ROSEN_LOGE("RSVkImageManager::GetIntersectImageFromVK cutDownImage BuildSubset failed.");
330 return nullptr;
331 }
332 return cutDownImage;
333 }
334 } // namespace Rosen
335 } // namespace OHOS