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