1 /*
2 * Copyright (c) 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 "drawing_surface_utils.h"
17
18 #ifdef RS_ENABLE_VK
19 #include "platform/ohos/backend/native_buffer_utils.h"
20 #include "sync_fence.h"
21 #ifdef USE_M133_SKIA
22 #include "include/gpu/ganesh/vk/GrVkBackendSemaphore.h"
23 #endif
24 #endif
25
26 #include "utils/log.h"
27 #include "utils/system_properties.h"
28
29 namespace OHOS {
30 namespace Rosen {
31
32 static std::mutex g_surfaceMutex;
33 static std::unordered_map<Drawing::Surface*, std::pair<std::shared_ptr<Drawing::Surface>, EGLSurface>> g_eglSurfaceMap;
34 #ifdef RS_ENABLE_VK
35 static std::unordered_map<Drawing::Surface*, std::tuple<std::shared_ptr<Drawing::Surface>, Drawing::GPUContext*,
36 NativeBufferUtils::NativeSurfaceInfo*>> g_vulkanSurfaceMap_;
37 #endif
38
ColorTypeToGLFormat(Drawing::ColorType colorType)39 int ColorTypeToGLFormat(Drawing::ColorType colorType)
40 {
41 switch (colorType) {
42 case Drawing::ColorType::COLORTYPE_RGBA_8888:
43 return GL_RGBA8;
44 case Drawing::ColorType::COLORTYPE_ALPHA_8:
45 return GL_R8;
46 case Drawing::ColorType::COLORTYPE_RGB_565:
47 return GL_RGB565;
48 case Drawing::ColorType::COLORTYPE_ARGB_4444:
49 return GL_RGBA4;
50 default:
51 return GL_RGBA8;
52 }
53 }
54
55 #ifdef RS_ENABLE_VK
CreateVkSemaphore(VkSemaphore & semaphore,RsVulkanContext & vkContext,NativeBufferUtils::NativeSurfaceInfo & nativeSurface)56 void CreateVkSemaphore(VkSemaphore& semaphore, RsVulkanContext& vkContext,
57 NativeBufferUtils::NativeSurfaceInfo& nativeSurface)
58 {
59 VkSemaphoreCreateInfo semaphoreInfo;
60 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
61 semaphoreInfo.pNext = nullptr;
62 semaphoreInfo.flags = 0;
63 auto& vkInterface = vkContext.GetRsVulkanInterface();
64 auto res = vkInterface.vkCreateSemaphore(vkInterface.GetDevice(), &semaphoreInfo, nullptr, &semaphore);
65 if (res != VK_SUCCESS) {
66 LOGE("DrawingSurfaceUtils: CreateVkSemaphore vkCreateSemaphore failed %{public}d", res);
67 semaphore = VK_NULL_HANDLE;
68 nativeSurface.fence->Wait(-1);
69 return;
70 }
71
72 VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo;
73 importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
74 importSemaphoreFdInfo.pNext = nullptr;
75 importSemaphoreFdInfo.semaphore = semaphore;
76 importSemaphoreFdInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
77 importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
78 importSemaphoreFdInfo.fd = nativeSurface.fence->Dup();
79 res = vkInterface.vkImportSemaphoreFdKHR(vkInterface.GetDevice(), &importSemaphoreFdInfo);
80 if (res != VK_SUCCESS) {
81 LOGE("DrawingSurfaceUtils: CreateVkSemaphore vkImportSemaphoreFdKHR failed %{public}d", res);
82 vkInterface.vkDestroySemaphore(vkInterface.GetDevice(), semaphore, nullptr);
83 semaphore = VK_NULL_HANDLE;
84 close(importSemaphoreFdInfo.fd);
85 nativeSurface.fence->Wait(-1);
86 }
87 }
88
CreateVulkanWindowSurface(Drawing::GPUContext * gpuContext,const Drawing::ImageInfo & imageInfo,void * window)89 std::shared_ptr<Drawing::Surface> CreateVulkanWindowSurface(Drawing::GPUContext* gpuContext,
90 const Drawing::ImageInfo& imageInfo, void* window)
91 {
92 int fenceFd = -1;
93 NativeWindowBuffer* nativeWindowBuffer = nullptr;
94 OHNativeWindow *nativeWindow = reinterpret_cast<OHNativeWindow *>(window);
95 auto res = NativeWindowRequestBuffer(nativeWindow, &nativeWindowBuffer, &fenceFd);
96 if (res != OHOS::GSERROR_OK) {
97 LOGE("CreateVulkanWindowSurface: RequestBuffer failed %{public}d", res);
98 NativeWindowCancelBuffer(nativeWindow, nativeWindowBuffer);
99 return nullptr;
100 }
101
102 NativeBufferUtils::NativeSurfaceInfo* nativeSurface = new(std::nothrow) NativeBufferUtils::NativeSurfaceInfo();
103 if (nativeSurface == nullptr) {
104 LOGE("CreateVulkanWindowSurface: create nativeSurface failed!");
105 NativeWindowCancelBuffer(nativeWindow, nativeWindowBuffer);
106 if (fenceFd != -1) {
107 close(fenceFd);
108 fenceFd = -1;
109 }
110 return nullptr;
111 }
112
113 NativeObjectReference(nativeWindow);
114 nativeSurface->window = nativeWindow;
115 NativeObjectReference(nativeWindowBuffer);
116 nativeSurface->nativeWindowBuffer = nativeWindowBuffer;
117 std::shared_ptr<Drawing::Surface> surface = NativeBufferUtils::CreateFromNativeWindowBuffer(
118 gpuContext, imageInfo, *nativeSurface);
119 if (!surface) {
120 LOGE("CreateVulkanWindowSurface: create surface failed!");
121 NativeWindowCancelBuffer(nativeWindow, nativeWindowBuffer);
122 if (fenceFd != -1) {
123 close(fenceFd);
124 fenceFd = -1;
125 }
126 delete nativeSurface;
127 return nullptr;
128 }
129 surface->ClearDrawingArea();
130
131 if (fenceFd >= 0) {
132 nativeSurface->fence = std::make_unique<SyncFence>(fenceFd);
133 auto status = nativeSurface->fence->GetStatus();
134 if (status != SIGNALED) {
135 auto& vkContext = RsVulkanContext::GetSingleton();
136 VkSemaphore semaphore = VK_NULL_HANDLE;
137 CreateVkSemaphore(semaphore, vkContext, *nativeSurface);
138 if (semaphore != VK_NULL_HANDLE) {
139 surface->Wait(1, semaphore);
140 }
141 }
142 }
143
144 std::lock_guard<std::mutex> lock(g_surfaceMutex);
145 g_vulkanSurfaceMap_.insert({surface.get(), std::make_tuple(surface, gpuContext, nativeSurface)});
146 return surface;
147 }
148
FlushVulkanSurface(Drawing::Surface * surface)149 bool FlushVulkanSurface(Drawing::Surface* surface)
150 {
151 std::lock_guard<std::mutex> lock(g_surfaceMutex);
152 auto iter = g_vulkanSurfaceMap_.find(surface);
153 if (iter == g_vulkanSurfaceMap_.end()) {
154 LOGE("FlushVulkanSurface: Can not find surface, surface is valid!");
155 return false;
156 }
157
158 auto nativeSurface = std::get<2>(iter->second);
159 Drawing::GPUContext* gpuContext = std::get<1>(iter->second);
160 if (nativeSurface == nullptr) {
161 surface->FlushAndSubmit();
162 return true;
163 }
164
165 auto& vkContext = RsVulkanContext::GetSingleton().GetRsVulkanInterface();
166 VkSemaphore semaphore = vkContext.RequireSemaphore();
167
168 #ifdef USE_M133_SKIA
169 GrBackendSemaphore backendSemaphore = GrBackendSemaphores::MakeVk(semaphore);
170 #else
171 GrBackendSemaphore backendSemaphore;
172 backendSemaphore.initVulkan(semaphore);
173 #endif
174
175 auto* callbackInfo = new RsVulkanInterface::CallbackSemaphoreInfo(vkContext, semaphore, -1);
176
177 Drawing::FlushInfo drawingFlushInfo;
178 drawingFlushInfo.backendSurfaceAccess = true;
179 drawingFlushInfo.numSemaphores = 1;
180 drawingFlushInfo.backendSemaphore = static_cast<void*>(&backendSemaphore);
181 drawingFlushInfo.finishedProc = [](void *context) {
182 RsVulkanInterface::CallbackSemaphoreInfo::DestroyCallbackRefs(context);
183 };
184 drawingFlushInfo.finishedContext = callbackInfo;
185 {
186 surface->Flush(&drawingFlushInfo);
187 gpuContext->Submit();
188 }
189
190 int fenceFd = -1;
191 auto queue = vkContext.GetQueue();
192 auto err = RsVulkanContext::HookedVkQueueSignalReleaseImageOHOS(
193 queue, 1, &semaphore, nativeSurface->image, &fenceFd);
194 if (err != VK_SUCCESS) {
195 if (err == VK_ERROR_DEVICE_LOST) {
196 vkContext.DestroyAllSemaphoreFence();
197 }
198 RsVulkanInterface::CallbackSemaphoreInfo::DestroyCallbackRefs(callbackInfo);
199 callbackInfo = nullptr;
200 LOGE("FlushVulkanSurface: QueueSignalReleaseImageOHOS failed %{public}d", err);
201 return false;
202 }
203 callbackInfo->mFenceFd = ::dup(fenceFd);
204
205 auto ret = NativeWindowFlushBuffer(nativeSurface->window, nativeSurface->nativeWindowBuffer, fenceFd, {});
206 RsVulkanInterface::CallbackSemaphoreInfo::DestroyCallbackRefs(callbackInfo);
207 callbackInfo = nullptr;
208 if (ret != OHOS::GSERROR_OK) {
209 LOGE("FlushVulkanSurface NativeWindowFlushBuffer failed");
210 return false;
211 }
212 nativeSurface->fence.reset();
213 return true;
214 }
215 #endif
216
CreateFromWindow(Drawing::GPUContext * gpuContext,const Drawing::ImageInfo & imageInfo,void * window)217 std::shared_ptr<Drawing::Surface> DrawingSurfaceUtils::CreateFromWindow(Drawing::GPUContext* gpuContext,
218 const Drawing::ImageInfo& imageInfo, void* window)
219 {
220 if (Drawing::SystemProperties::IsUseGl()) {
221 std::shared_ptr<Drawing::GPUContext> context = DrawingGpuContextManager::GetInstance().Find(gpuContext);
222 if (context == nullptr) {
223 LOGE("CreateFromWindow: gpuContext is invalid!");
224 return nullptr;
225 }
226
227 std::shared_ptr<RenderContext> renderContext = DrawingGpuContextManager::GetInstance().GetRenderContext();
228 if (renderContext == nullptr) {
229 LOGE("CreateFromWindow: get renderContext failed.");
230 return nullptr;
231 }
232
233 EGLSurface eglSurface = renderContext->CreateEGLSurface(reinterpret_cast<EGLNativeWindowType>(window));
234 if (eglSurface == EGL_NO_SURFACE) {
235 LOGE("CreateFromWindow: create eglSurface failed, window is invalid.");
236 return nullptr;
237 }
238 renderContext->MakeCurrent(eglSurface);
239
240 Drawing::FrameBuffer bufferInfo;
241 bufferInfo.width = imageInfo.GetWidth();
242 bufferInfo.height = imageInfo.GetHeight();
243 bufferInfo.FBOID = 0;
244 bufferInfo.Format = ColorTypeToGLFormat(imageInfo.GetColorType());
245 bufferInfo.gpuContext = context;
246 bufferInfo.colorSpace = Drawing::ColorSpace::CreateSRGB();
247 bufferInfo.colorType = imageInfo.GetColorType();
248 std::shared_ptr<Drawing::Surface> surface = std::make_shared<Drawing::Surface>();
249 if (!surface->Bind(bufferInfo)) {
250 LOGE("CreateFromWindow: create surface failed.");
251 renderContext->DestroyEGLSurface(eglSurface);
252 renderContext->MakeCurrent(EGL_NO_SURFACE);
253 return nullptr;
254 }
255
256 std::lock_guard<std::mutex> lock(g_surfaceMutex);
257 g_eglSurfaceMap.insert({surface.get(), std::make_pair(surface, eglSurface)});
258 return surface;
259 }
260
261 #ifdef RS_ENABLE_VK
262 if (Drawing::SystemProperties::IsUseVulkan()) {
263 return CreateVulkanWindowSurface(gpuContext, imageInfo, window);
264 }
265 #endif
266 return nullptr;
267 }
268
FlushSurface(Drawing::Surface * surface)269 bool DrawingSurfaceUtils::FlushSurface(Drawing::Surface* surface)
270 {
271 if (Drawing::SystemProperties::IsUseGl()) {
272 if (surface != nullptr && surface->GetCanvas() != nullptr) {
273 surface->GetCanvas()->Flush();
274 }
275
276 std::shared_ptr<RenderContext> renderContext = DrawingGpuContextManager::GetInstance().GetRenderContext();
277 if (renderContext == nullptr) {
278 LOGE("FlushSurface: get renderContext failed.");
279 return false;
280 }
281
282 std::lock_guard<std::mutex> lock(g_surfaceMutex);
283 auto iter = g_eglSurfaceMap.find(surface);
284 if (iter == g_eglSurfaceMap.end()) {
285 LOGE("FlushSurface: surface is invalid!");
286 return false;
287 }
288
289 EGLSurface eglSurface = (iter->second).second;
290 if (eglSurface != EGL_NO_SURFACE) {
291 renderContext->SwapBuffers(eglSurface);
292 }
293 return true;
294 }
295
296 #ifdef RS_ENABLE_VK
297 if (Drawing::SystemProperties::IsUseVulkan()) {
298 return FlushVulkanSurface(surface);
299 }
300 #endif
301 return false;
302 }
303
InsertSurface(std::shared_ptr<Drawing::Surface> surface,Drawing::GPUContext * gpuContext)304 void DrawingSurfaceUtils::InsertSurface(std::shared_ptr<Drawing::Surface> surface, Drawing::GPUContext* gpuContext)
305 {
306 std::lock_guard<std::mutex> lock(g_surfaceMutex);
307 if (Drawing::SystemProperties::IsUseGl()) {
308 g_eglSurfaceMap.insert({surface.get(), std::make_pair(surface, EGL_NO_SURFACE)});
309 }
310
311 #ifdef RS_ENABLE_VK
312 if (Drawing::SystemProperties::IsUseVulkan()) {
313 g_vulkanSurfaceMap_.insert({surface.get(), std::make_tuple(surface, gpuContext, nullptr)});
314 }
315 #endif
316 }
317
RemoveSurface(Drawing::Surface * surface)318 void DrawingSurfaceUtils::RemoveSurface(Drawing::Surface* surface)
319 {
320 std::lock_guard<std::mutex> lock(g_surfaceMutex);
321 if (Drawing::SystemProperties::IsUseGl()) {
322 auto iter = g_eglSurfaceMap.find(surface);
323 if (iter == g_eglSurfaceMap.end()) {
324 return;
325 }
326 g_eglSurfaceMap.erase(iter);
327 }
328
329 #ifdef RS_ENABLE_VK
330 if (Drawing::SystemProperties::IsUseVulkan()) {
331 auto iter = g_vulkanSurfaceMap_.find(surface);
332 if (iter == g_vulkanSurfaceMap_.end()) {
333 return;
334 }
335
336 auto nativeSurface = std::get<2>(iter->second);
337 g_vulkanSurfaceMap_.erase(iter);
338 if (nativeSurface != nullptr) {
339 delete nativeSurface;
340 nativeSurface = nullptr;
341 }
342 }
343 #endif
344 }
345 } // namespace Rosen
346 } // namespace OHOS