• 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 
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