• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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