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