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