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