1 /*
2 * Copyright (c) 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 "surface_ohos_vulkan.h"
17
18 #include <iostream>
19 #include <vulkan_native_surface_ohos.h>
20 #include <vulkan_window.h>
21 #include <vulkan_proc_table.h>
22 #include <hilog/log.h>
23 #include <display_type.h>
24 #include "window.h"
25
26
27 #include "SkColor.h"
28 #include "native_buffer_inner.h"
29 #include "native_window.h"
30 #include "vulkan/vulkan_core.h"
31
32 #include "rs_vulkan_context.h"
33 #include "include/gpu/GrBackendSemaphore.h"
34
35
36 #include "engine_adapter/skia_adapter/skia_surface.h"
37
38 namespace OHOS {
39 namespace Rosen {
SurfaceOhosVulkan(const sptr<Surface> & producer)40 SurfaceOhosVulkan::SurfaceOhosVulkan(const sptr<Surface>& producer)
41 : SurfaceOhos(producer), frame_(nullptr)
42 {
43 }
44
~SurfaceOhosVulkan()45 SurfaceOhosVulkan::~SurfaceOhosVulkan()
46 {
47 frame_ = nullptr;
48 if (mNativeWindow_ != nullptr) {
49 DestoryNativeWindow(mNativeWindow_);
50 mNativeWindow_ = nullptr;
51 }
52 if (mVulkanWindow_ != nullptr) {
53 delete mVulkanWindow_;
54 mVulkanWindow_ = nullptr;
55 }
56 }
57
SetNativeWindowInfo(int32_t width,int32_t height)58 void SurfaceOhosVulkan::SetNativeWindowInfo(int32_t width, int32_t height)
59 {
60 uint64_t bufferUsage = BUFFER_USAGE_HW_RENDER | BUFFER_USAGE_HW_TEXTURE |
61 BUFFER_USAGE_HW_COMPOSER | BUFFER_USAGE_MEM_DMA;
62 NativeWindowHandleOpt(mNativeWindow_, SET_FORMAT, GRAPHIC_PIXEL_FMT_RGBA_8888);
63 #ifdef RS_ENABLE_AFBC
64 if (RSSystemProperties::GetAFBCEnabled()) {
65 int32_t format = 0;
66 NativeWindowHandleOpt(mNativeWindow_, GET_FORMAT, &format);
67 if (format == GRAPHIC_PIXEL_FMT_RGBA_8888) {
68 bufferUsage =
69 (BUFFER_USAGE_HW_RENDER | BUFFER_USAGE_HW_TEXTURE | BUFFER_USAGE_HW_COMPOSER | BUFFER_USAGE_MEM_DMA);
70 }
71 }
72 #endif
73
74 NativeWindowHandleOpt(mNativeWindow_, SET_USAGE, bufferUsage);
75 NativeWindowHandleOpt(mNativeWindow_, SET_BUFFER_GEOMETRY, width, height);
76 NativeWindowHandleOpt(mNativeWindow_, SET_COLOR_GAMUT, colorSpace_);
77 }
78
RequestFrame(int32_t width,int32_t height)79 std::unique_ptr<SurfaceFrame> SurfaceOhosVulkan::RequestFrame(int32_t width, int32_t height)
80 {
81 if (mNativeWindow_ == nullptr) {
82 mNativeWindow_ = CreateNativeWindowFromSurface(&producer_);
83 if (mNativeWindow_ == nullptr) {
84 LOGE("SurfaceOhosVulkan nativewindow is null");
85 return nullptr;
86 }
87 }
88
89 if (mVulkanWindow_ == nullptr) {
90 auto vulkan_surface_ohos = std::make_unique<vulkan::VulkanNativeSurfaceOHOS>(mNativeWindow_);
91 mVulkanWindow_ = new vulkan::VulkanWindow(std::move(vulkan_surface_ohos));
92 }
93
94 surface_ = std::make_shared<Drawing::Surface>();
95 #ifdef ENABLE_DDGR_OPTIMIZE
96 auto ddgrSurface = mVulkanWindow_->AcquireSurface();
97 if (!ddgrSurface) {
98 LOGE("SurfaceOhosVulkan: ddgrSurface or skSurface is null, return");
99 return nullptr;
100 }
101
102 if (!ddgrCanvas_) {
103 ddgrCanvas_ = std::make_shared<DDGR::DDGRCanvasV2>(*(mVulkanWindow_->GetDDGRContext()));
104 }
105 ddgrCanvas_->SetCurSurface(ddgrSurface);
106 ddgrCanvas_->BeginFrame();
107 surface_->GetImpl<Drawing::DDGRSurface>()->ImportDDGRSurface(ddgrSurface);
108 surface_->GetImpl<Drawing::DDGRSurface>()->SetGrContext(mVulkanWindow_->GetDDGRContext());
109 #else // ENABLE_DDGR_OPTIMIZE
110 sk_sp<SkSurface> skSurface = mVulkanWindow_->AcquireSurface();
111 surface_->GetImpl<Drawing::SkiaSurface>()->SetSkSurface(skSurface);
112 #endif // ENABLE_DDGR_OPTIMIZE
113
114 frame_ = std::make_unique<SurfaceFrameOhosVulkan>(surface_, width, height);
115
116 frame_->SetColorSpace(GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB);
117
118 NativeWindowHandleOpt(mNativeWindow_, SET_BUFFER_GEOMETRY, width, height);
119 NativeWindowHandleOpt(mNativeWindow_, SET_COLOR_GAMUT, frame_->GetColorSpace());
120
121 std::unique_ptr<SurfaceFrame> ret(std::move(frame_));
122 return ret;
123 }
124
CreateVkSemaphore(VkSemaphore * semaphore,RsVulkanContext & vkContext,NativeBufferUtils::NativeSurfaceInfo & nativeSurface)125 void SurfaceOhosVulkan::CreateVkSemaphore(
126 VkSemaphore* semaphore, RsVulkanContext& vkContext, NativeBufferUtils::NativeSurfaceInfo& nativeSurface)
127 {
128 VkSemaphoreCreateInfo semaphoreInfo;
129 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
130 semaphoreInfo.pNext = nullptr;
131 semaphoreInfo.flags = 0;
132 auto& rsInterface = vkContext.GetRsVulkanInterface();
133 rsInterface.vkCreateSemaphore(rsInterface.GetDevice(), &semaphoreInfo, nullptr, semaphore);
134
135 VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo;
136 importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
137 importSemaphoreFdInfo.pNext = nullptr;
138 importSemaphoreFdInfo.semaphore = *semaphore;
139 importSemaphoreFdInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
140 importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
141 importSemaphoreFdInfo.fd = nativeSurface.fence->Dup();
142 rsInterface.vkImportSemaphoreFdKHR(rsInterface.GetDevice(), &importSemaphoreFdInfo);
143 }
144
RequestNativeWindowBuffer(NativeWindowBuffer ** nativeWindowBuffer,int32_t width,int32_t height,int & fenceFd)145 int32_t SurfaceOhosVulkan::RequestNativeWindowBuffer(
146 NativeWindowBuffer** nativeWindowBuffer, int32_t width, int32_t height, int& fenceFd)
147 {
148 SetNativeWindowInfo(width, height);
149 struct timespec curTime = {0, 0};
150 clock_gettime(CLOCK_MONOTONIC, &curTime);
151 // 1000000000 is used for transfer second to nsec
152 uint64_t duration = static_cast<uint64_t>(curTime.tv_sec) * 1000000000 + static_cast<uint64_t>(curTime.tv_nsec);
153 NativeWindowHandleOpt(mNativeWindow_, SET_UI_TIMESTAMP, duration);
154
155 auto res = NativeWindowRequestBuffer(mNativeWindow_, nativeWindowBuffer, &fenceFd);
156 if (res != OHOS::GSERROR_OK) {
157 LOGE("RSSurfaceOhosVulkan: OH_NativeWindow_NativeWindowRequestBuffer failed %{public}d", res);
158 NativeWindowCancelBuffer(mNativeWindow_, *nativeWindowBuffer);
159 }
160 return res;
161 }
162
NativeRequestFrame(int32_t width,int32_t height)163 std::unique_ptr<SurfaceFrame> SurfaceOhosVulkan::NativeRequestFrame(int32_t width, int32_t height)
164 {
165 if (mNativeWindow_ == nullptr) {
166 mNativeWindow_ = CreateNativeWindowFromSurface(&producer_);
167 LOGI("RSSurfaceOhosVulkan: create native window");
168 }
169
170 if (drContext_ == nullptr) {
171 drContext_ = RsVulkanContext::GetSingleton().CreateDrawingContext();
172 }
173 if (!drContext_) {
174 LOGI("RSSurfaceOhosVulkan: skia context is nullptr");
175 return nullptr;
176 }
177
178 NativeWindowBuffer* nativeWindowBuffer = nullptr;
179 int fenceFd = -1;
180 if (RequestNativeWindowBuffer(&nativeWindowBuffer, width, height, fenceFd) != OHOS::GSERROR_OK) {
181 return nullptr;
182 }
183
184 surfaceList_.emplace_back(nativeWindowBuffer);
185 NativeBufferUtils::NativeSurfaceInfo& nativeSurface = surfaceMap_[nativeWindowBuffer];
186
187 if (nativeSurface.drawingSurface == nullptr) {
188 nativeSurface.window = mNativeWindow_;
189 nativeSurface.graphicColorGamut = colorSpace_;
190 if (!NativeBufferUtils::MakeFromNativeWindowBuffer(
191 drContext_, nativeWindowBuffer, nativeSurface, width, height)) {
192 LOGE("RSSurfaceOhosVulkan: MakeFromeNativeWindow failed");
193 NativeWindowCancelBuffer(mNativeWindow_, nativeWindowBuffer);
194 return nullptr;
195 }
196
197 if (!nativeSurface.drawingSurface) {
198 LOGE("RSSurfaceOhosVulkan: skSurface is null, return");
199 surfaceList_.pop_back();
200 return nullptr;
201 } else {
202 LOGI("RSSurfaceOhosVulkan: skSurface create success %{public}zu", surfaceMap_.size());
203 }
204 }
205
206 if (fenceFd >= 0) {
207 nativeSurface.fence = std::make_unique<SyncFence>(fenceFd);
208 auto status = nativeSurface.fence->GetStatus();
209 if (status != SIGNALED) {
210 auto& vkContext = RsVulkanContext::GetSingleton();
211 VkSemaphore semaphore;
212 CreateVkSemaphore(&semaphore, vkContext, nativeSurface);
213 nativeSurface.drawingSurface->Wait(1, semaphore);
214 }
215 }
216 frame_ = std::make_unique<SurfaceFrameOhosVulkan>(nativeSurface.drawingSurface, width, height);
217 frame_->SetColorSpace(GraphicColorGamut::GRAPHIC_COLOR_GAMUT_SRGB);
218 std::unique_ptr<SurfaceFrame> ret(std::move(frame_));
219 surface_ = nativeSurface.drawingSurface;
220 return ret;
221 }
222
FlushFrame(std::unique_ptr<SurfaceFrame> & frame)223 bool SurfaceOhosVulkan::FlushFrame(std::unique_ptr<SurfaceFrame>& frame)
224 {
225 if (drawingProxy_ == nullptr) {
226 LOGE("drawingProxy_ is nullptr, can not FlushFrame");
227 return false;
228 }
229 // gpu render flush
230 drawingProxy_->RenderFrame();
231 if (mVulkanWindow_ != nullptr) {
232 #ifdef ENABLE_DDGR_OPTIMIZE
233 mVulkanWindow_->SwapBuffers(ddgrCanvas_);
234 #else
235 mVulkanWindow_->SwapBuffers();
236 #endif
237 } else {
238 LOGE("mVulkanWindow_ is null");
239 }
240 return true;
241 }
242
NativeFlushFrame(std::unique_ptr<SurfaceFrame> & frame)243 bool SurfaceOhosVulkan::NativeFlushFrame(std::unique_ptr<SurfaceFrame> &frame)
244 {
245 if (drawingProxy_ == nullptr) {
246 LOGE("drawingProxy_ is nullptr, can not FlushFrame");
247 return false;
248 }
249 // gpu render flush
250 drawingProxy_->RenderFrame();
251
252 if (surfaceList_.empty()) {
253 return false;
254 }
255
256 if (!drContext_) {
257 LOGE("RSSurfaceOhosVulkan: FlushFrame mSkContext is nullptr");
258 return false;
259 }
260 auto& vkContext = RsVulkanContext::GetSingleton().GetRsVulkanInterface();
261
262 VkExportSemaphoreCreateInfo exportSemaphoreCreateInfo;
263 exportSemaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
264 exportSemaphoreCreateInfo.pNext = nullptr;
265 exportSemaphoreCreateInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
266
267 VkSemaphoreCreateInfo semaphoreInfo;
268 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
269 semaphoreInfo.pNext = &exportSemaphoreCreateInfo;
270 semaphoreInfo.flags = 0;
271 VkSemaphore semaphore;
272 vkContext.vkCreateSemaphore(vkContext.GetDevice(), &semaphoreInfo, nullptr, &semaphore);
273
274 GrBackendSemaphore backendSemaphore;
275 backendSemaphore.initVulkan(semaphore);
276
277 GrFlushInfo flushInfo;
278 flushInfo.fNumSemaphores = 1;
279 flushInfo.fSignalSemaphores = &backendSemaphore;
280
281 auto& surface = surfaceMap_[surfaceList_.front()];
282 Drawing::FlushInfo drawingFlushInfo;
283 drawingFlushInfo.backendSurfaceAccess = true;
284 drawingFlushInfo.numSemaphores = 1;
285 drawingFlushInfo.backendSemaphore = static_cast<void*>(&backendSemaphore);
286 surface.drawingSurface->Flush(&drawingFlushInfo);
287 drContext_->Submit();
288
289 int fenceFd = -1;
290
291 auto queue = vkContext.GetQueue();
292 if (vkContext.GetHardWareGrContext().get() == drContext_.get()) {
293 queue = vkContext.GetHardwareQueue();
294 }
295 auto err = RsVulkanContext::HookedVkQueueSignalReleaseImageOHOS(
296 queue, 1, &semaphore, surface.image, &fenceFd);
297 if (err != VK_SUCCESS) {
298 LOGE("RSSurfaceOhosVulkan QueueSignalReleaseImageOHOS failed %{public}d", err);
299 return false;
300 }
301
302 auto ret = NativeWindowFlushBuffer(surface.window, surface.nativeWindowBuffer, fenceFd, {});
303 if (ret != OHOS::GSERROR_OK) {
304 LOGE("RSSurfaceOhosVulkan NativeWindowFlushBuffer failed");
305 return false;
306 }
307 surfaceList_.pop_front();
308 vkContext.vkDestroySemaphore(vkContext.GetDevice(), semaphore, nullptr);
309 surface.fence.reset();
310 return true;
311 }
312
GetCanvas(std::unique_ptr<SurfaceFrame> & frame)313 Drawing::Canvas* SurfaceOhosVulkan::GetCanvas(std::unique_ptr<SurfaceFrame>& frame)
314 {
315 if (drawingProxy_ == nullptr) {
316 LOGE("drawingProxy_ is nullptr, can not GetCanvas");
317 return nullptr;
318 }
319 return drawingProxy_->AcquireDrCanvas(frame);
320 }
GetSkCanvas(std::unique_ptr<SurfaceFrame> & frame)321 SkCanvas* SurfaceOhosVulkan::GetSkCanvas(std::unique_ptr<SurfaceFrame>& frame)
322 {
323 if (drawingProxy_ == nullptr) {
324 LOGE("drawingProxy_ is nullptr, can not GetCanvas");
325 return nullptr;
326 }
327 return drawingProxy_->AcquireSkCanvas(frame);
328 }
329 } // namespace Rosen
330 } // namespace OHOS
331