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 "rs_surface_ohos_vulkan.h"
17 
18 #include <memory>
19 #include "memory/rs_tag_tracker.h"
20 #include "native_buffer_inner.h"
21 #include "native_window.h"
22 #include "vulkan/vulkan_core.h"
23 #include "include/gpu/GrBackendSemaphore.h"
24 #include "include/gpu/GrDirectContext.h"
25 #include "platform/common/rs_log.h"
26 #include "window.h"
27 #include "platform/common/rs_system_properties.h"
28 #include "drawing/engine_adapter/skia_adapter/skia_gpu_context.h"
29 #include "engine_adapter/skia_adapter/skia_surface.h"
30 #include "rs_trace.h"
31 
32 namespace OHOS {
33 namespace Rosen {
34 
35 class RSTimer {
36 public:
GetNanoSeconds()37     static inline int64_t GetNanoSeconds()
38     {
39         struct timespec ts {};
40         clock_gettime(CLOCK_REALTIME, &ts);
41         return ts.tv_sec * NANO + ts.tv_nsec;
42     }
43 
RSTimer(const char * tag)44     explicit RSTimer(const char* tag): tag_(tag), timestamp_(GetNanoSeconds()) {}
45 
~RSTimer()46     ~RSTimer()
47     {
48         int64_t durationNS = GetNanoSeconds() - timestamp_;
49         int64_t durationMS = durationNS / MILLI;
50         if (durationMS > THRESHOLD) {
51             RS_LOGE("%{public}s task too long: %{public}" PRIu64" ms", tag_, durationMS);
52         }
53     }
54 
55 private:
56     const char* tag_;
57     const int64_t timestamp_;
58     static constexpr int64_t NANO = 1000000000LL;
59     static constexpr int64_t MILLI = 1000000LL;
60     static constexpr int64_t THRESHOLD = 50; //Jank 6
61 };
62 
RSSurfaceOhosVulkan(const sptr<Surface> & producer)63 RSSurfaceOhosVulkan::RSSurfaceOhosVulkan(const sptr<Surface>& producer) : RSSurfaceOhos(producer)
64 {
65     bufferUsage_ = BUFFER_USAGE_CPU_READ | BUFFER_USAGE_MEM_DMA;
66 }
67 
~RSSurfaceOhosVulkan()68 RSSurfaceOhosVulkan::~RSSurfaceOhosVulkan()
69 {
70     mSurfaceMap.clear();
71     mSurfaceList.clear();
72     DestoryNativeWindow(mNativeWindow);
73     mNativeWindow = nullptr;
74     if (mReservedFlushFd != -1) {
75         ::close(mReservedFlushFd);
76         mReservedFlushFd = -1;
77     }
78 }
79 
SetNativeWindowInfo(int32_t width,int32_t height,bool useAFBC,bool isProtected)80 void RSSurfaceOhosVulkan::SetNativeWindowInfo(int32_t width, int32_t height, bool useAFBC, bool isProtected)
81 {
82     if (width != mWidth || height != mHeight) {
83         for (auto &[key, val] : mSurfaceMap) {
84             NativeWindowCancelBuffer(mNativeWindow, key);
85         }
86         mSurfaceMap.clear();
87         mSurfaceList.clear();
88     }
89     NativeWindowHandleOpt(mNativeWindow, SET_FORMAT, pixelFormat_);
90 #ifdef RS_ENABLE_AFBC
91     if (RSSystemProperties::GetAFBCEnabled() && !isProtected) {
92         int32_t format = 0;
93         NativeWindowHandleOpt(mNativeWindow, GET_FORMAT, &format);
94         if (format == GRAPHIC_PIXEL_FMT_RGBA_8888 && useAFBC) {
95             bufferUsage_ =
96                 (BUFFER_USAGE_HW_RENDER | BUFFER_USAGE_HW_TEXTURE | BUFFER_USAGE_HW_COMPOSER | BUFFER_USAGE_MEM_DMA);
97         }
98     }
99 #endif
100 
101     if (isProtected) {
102         bufferUsage_ |= BUFFER_USAGE_PROTECTED;
103     } else {
104         bufferUsage_ &= (~BUFFER_USAGE_PROTECTED);
105     }
106     NativeWindowHandleOpt(mNativeWindow, SET_USAGE, bufferUsage_);
107     NativeWindowHandleOpt(mNativeWindow, SET_BUFFER_GEOMETRY, width, height);
108     NativeWindowHandleOpt(mNativeWindow, GET_BUFFER_GEOMETRY, &mHeight, &mWidth);
109     NativeWindowHandleOpt(mNativeWindow, SET_COLOR_GAMUT, colorSpace_);
110     NativeWindowHandleOpt(mNativeWindow, SET_TIMEOUT, timeOut_);
111 }
112 
113 
CreateVkSemaphore(VkSemaphore & semaphore,RsVulkanContext & vkContext,NativeBufferUtils::NativeSurfaceInfo & nativeSurface)114 void RSSurfaceOhosVulkan::CreateVkSemaphore(
115     VkSemaphore& semaphore, RsVulkanContext& vkContext, NativeBufferUtils::NativeSurfaceInfo& nativeSurface)
116 {
117     VkSemaphoreCreateInfo semaphoreInfo;
118     semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
119     semaphoreInfo.pNext = nullptr;
120     semaphoreInfo.flags = 0;
121     auto& vkInterface = vkContext.GetRsVulkanInterface();
122     auto res = vkInterface.vkCreateSemaphore(vkInterface.GetDevice(), &semaphoreInfo, nullptr, &semaphore);
123     if (res != VK_SUCCESS) {
124         ROSEN_LOGE("RSSurfaceOhosVulkan: CreateVkSemaphore vkCreateSemaphore failed %{public}d", res);
125         semaphore = VK_NULL_HANDLE;
126         nativeSurface.fence->Wait(-1);
127         return;
128     }
129 
130     VkImportSemaphoreFdInfoKHR importSemaphoreFdInfo;
131     importSemaphoreFdInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
132     importSemaphoreFdInfo.pNext = nullptr;
133     importSemaphoreFdInfo.semaphore = semaphore;
134     importSemaphoreFdInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
135     importSemaphoreFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
136     importSemaphoreFdInfo.fd = nativeSurface.fence->Dup();
137     res = vkInterface.vkImportSemaphoreFdKHR(vkInterface.GetDevice(), &importSemaphoreFdInfo);
138     if (res != VK_SUCCESS) {
139         ROSEN_LOGE("RSSurfaceOhosVulkan: CreateVkSemaphore vkImportSemaphoreFdKHR failed %{public}d", res);
140         vkInterface.vkDestroySemaphore(vkInterface.GetDevice(), semaphore, nullptr);
141         semaphore = VK_NULL_HANDLE;
142         close(importSemaphoreFdInfo.fd);
143         nativeSurface.fence->Wait(-1);
144     }
145 }
146 
RequestNativeWindowBuffer(NativeWindowBuffer ** nativeWindowBuffer,int32_t width,int32_t height,int & fenceFd,bool useAFBC,bool isProtected)147 int32_t RSSurfaceOhosVulkan::RequestNativeWindowBuffer(NativeWindowBuffer** nativeWindowBuffer,
148     int32_t width, int32_t height, int& fenceFd, bool useAFBC, bool isProtected)
149 {
150     SetNativeWindowInfo(width, height, useAFBC, isProtected);
151     struct timespec curTime = {0, 0};
152     clock_gettime(CLOCK_MONOTONIC, &curTime);
153     // 1000000000 is used for transfer second to nsec
154     uint64_t duration = static_cast<uint64_t>(curTime.tv_sec) * 1000000000 + static_cast<uint64_t>(curTime.tv_nsec);
155     NativeWindowHandleOpt(mNativeWindow, SET_UI_TIMESTAMP, duration);
156 
157     auto res = NativeWindowRequestBuffer(mNativeWindow, nativeWindowBuffer, &fenceFd);
158     if (res != OHOS::GSERROR_OK) {
159         ROSEN_LOGE("RSSurfaceOhosVulkan: OH_NativeWindow_NativeWindowRequestBuffer failed %{public}d", res);
160         NativeWindowCancelBuffer(mNativeWindow, *nativeWindowBuffer);
161     }
162     return res;
163 }
164 
RequestFrame(int32_t width,int32_t height,uint64_t uiTimestamp,bool useAFBC,bool isProtected)165 std::unique_ptr<RSSurfaceFrame> RSSurfaceOhosVulkan::RequestFrame(
166     int32_t width, int32_t height, uint64_t uiTimestamp, bool useAFBC, bool isProtected)
167 {
168     if (mNativeWindow == nullptr) {
169         mNativeWindow = CreateNativeWindowFromSurface(&producer_);
170         ROSEN_LOGD("RSSurfaceOhosVulkan: create native window");
171     }
172 
173     if (!mSkContext) {
174         ROSEN_LOGE("RSSurfaceOhosVulkan: skia context is nullptr");
175         return nullptr;
176     }
177 
178     NativeWindowBuffer* nativeWindowBuffer = nullptr;
179     int fenceFd = -1;
180     if (RequestNativeWindowBuffer(&nativeWindowBuffer, width, height,
181         fenceFd, useAFBC, isProtected) != OHOS::GSERROR_OK) {
182         return nullptr;
183     }
184 
185     mSurfaceList.emplace_back(nativeWindowBuffer);
186     NativeBufferUtils::NativeSurfaceInfo& nativeSurface = mSurfaceMap[nativeWindowBuffer];
187     if (nativeSurface.drawingSurface == nullptr) {
188         NativeObjectReference(mNativeWindow);
189         nativeSurface.window = mNativeWindow;
190         nativeSurface.graphicColorGamut = colorSpace_;
191         if (!NativeBufferUtils::MakeFromNativeWindowBuffer(
192             mSkContext, nativeWindowBuffer, nativeSurface, width, height, isProtected)
193             || !nativeSurface.drawingSurface) {
194             ROSEN_LOGE("RSSurfaceOhosVulkan: skSurface is null, return");
195             mSurfaceList.pop_back();
196             NativeWindowCancelBuffer(mNativeWindow, nativeWindowBuffer);
197             if (fenceFd != -1) {
198                 close(fenceFd);
199                 fenceFd = -1;
200             }
201             mSurfaceMap.erase(nativeWindowBuffer);
202             return nullptr;
203         } else {
204             ROSEN_LOGD("RSSurfaceOhosVulkan: skSurface create success %{public}zu", mSurfaceMap.size());
205         }
206     }
207 
208     nativeSurface.drawingSurface->ClearDrawingArea();
209 
210     if (fenceFd >= 0) {
211         nativeSurface.fence = std::make_unique<SyncFence>(fenceFd);
212         auto status = nativeSurface.fence->GetStatus();
213         if (status != SIGNALED) {
214             auto& vkContext = RsVulkanContext::GetSingleton();
215             VkSemaphore semaphore = VK_NULL_HANDLE;
216             CreateVkSemaphore(semaphore, vkContext, nativeSurface);
217             if (semaphore != VK_NULL_HANDLE) {
218                 nativeSurface.drawingSurface->Wait(1, semaphore);
219             }
220         }
221     }
222     int32_t bufferAge;
223     if (nativeSurface.lastPresentedCount == -1) {
224         bufferAge = 0;
225     } else {
226         bufferAge = mPresentCount - nativeSurface.lastPresentedCount;
227     }
228     std::unique_ptr<RSSurfaceFrameOhosVulkan> frame =
229         std::make_unique<RSSurfaceFrameOhosVulkan>(nativeSurface.drawingSurface, width, height, bufferAge);
230     std::unique_ptr<RSSurfaceFrame> ret(std::move(frame));
231     mSkContext->BeginFrame();
232     return ret;
233 }
234 
GetCurrentBuffer()235 sptr<SurfaceBuffer> RSSurfaceOhosVulkan::GetCurrentBuffer()
236 {
237     if (mSurfaceList.empty()) {
238         return nullptr;
239     }
240     return mSurfaceList.back()->sfbuffer;
241 }
242 
SetUiTimeStamp(const std::unique_ptr<RSSurfaceFrame> & frame,uint64_t uiTimestamp)243 void RSSurfaceOhosVulkan::SetUiTimeStamp(const std::unique_ptr<RSSurfaceFrame>& frame, uint64_t uiTimestamp)
244 {
245 }
246 
FlushFrame(std::unique_ptr<RSSurfaceFrame> & frame,uint64_t uiTimestamp)247 bool RSSurfaceOhosVulkan::FlushFrame(std::unique_ptr<RSSurfaceFrame>& frame, uint64_t uiTimestamp)
248 {
249     if (mSurfaceList.empty()) {
250         return false;
251     }
252     auto& vkContext = RsVulkanContext::GetSingleton().GetRsVulkanInterface();
253 
254     VkSemaphore semaphore = vkContext.RequireSemaphore();
255 
256     GrBackendSemaphore backendSemaphore;
257     backendSemaphore.initVulkan(semaphore);
258 
259     if (mSurfaceMap.find(mSurfaceList.front()) == mSurfaceMap.end()) {
260         ROSEN_LOGE("RSSurfaceOhosVulkan Can not find drawingsurface");
261         return false;
262     }
263 
264     auto& surface = mSurfaceMap[mSurfaceList.front()];
265 
266     RSTagTracker tagTracker(mSkContext.get(), RSTagTracker::TAGTYPE::TAG_ACQUIRE_SURFACE);
267 
268     auto* callbackInfo = new RsVulkanInterface::CallbackSemaphoreInfo(vkContext, semaphore, -1);
269 
270     Drawing::FlushInfo drawingFlushInfo;
271     drawingFlushInfo.backendSurfaceAccess = true;
272     drawingFlushInfo.numSemaphores = 1;
273     drawingFlushInfo.backendSemaphore = static_cast<void*>(&backendSemaphore);
274     drawingFlushInfo.finishedProc = [](void *context) {
275         RsVulkanInterface::CallbackSemaphoreInfo::DestroyCallbackRefs(context);
276     };
277     drawingFlushInfo.finishedContext = callbackInfo;
278     {
279         RS_TRACE_NAME("Flush");
280         RSTimer timer("Flush");
281         surface.drawingSurface->Flush(&drawingFlushInfo);
282     }
283     {
284         RS_TRACE_NAME("Submit");
285         RSTimer timer("Submit");
286         mSkContext->Submit();
287         mSkContext->EndFrame();
288     }
289 
290     int fenceFd = -1;
291     if (mReservedFlushFd != -1) {
292         ::close(mReservedFlushFd);
293         mReservedFlushFd = -1;
294     }
295     auto queue = vkContext.GetQueue();
296     if (vkContext.GetHardWareGrContext().get() == mSkContext.get()) {
297         queue = vkContext.GetHardwareQueue();
298     }
299     auto err = RsVulkanContext::HookedVkQueueSignalReleaseImageOHOS(
300         queue, 1, &semaphore, surface.image, &fenceFd);
301     if (err != VK_SUCCESS) {
302         if (err == VK_ERROR_DEVICE_LOST) {
303             vkContext.DestroyAllSemaphoreFence();
304         }
305         RsVulkanInterface::CallbackSemaphoreInfo::DestroyCallbackRefs(callbackInfo);
306         callbackInfo = nullptr;
307         ROSEN_LOGE("RSSurfaceOhosVulkan QueueSignalReleaseImageOHOS failed %{public}d", err);
308         return false;
309     }
310     callbackInfo->mFenceFd = ::dup(fenceFd);
311     mReservedFlushFd = ::dup(fenceFd);
312 
313     auto ret = NativeWindowFlushBuffer(surface.window, surface.nativeWindowBuffer, fenceFd, {});
314     if (ret != OHOS::GSERROR_OK) {
315         RsVulkanInterface::CallbackSemaphoreInfo::DestroyCallbackRefs(callbackInfo);
316         callbackInfo = nullptr;
317         ROSEN_LOGE("RSSurfaceOhosVulkan NativeWindowFlushBuffer failed");
318         return false;
319     }
320     mSurfaceList.pop_front();
321     RsVulkanInterface::CallbackSemaphoreInfo::DestroyCallbackRefs(callbackInfo);
322     callbackInfo = nullptr;
323     surface.fence.reset();
324     surface.lastPresentedCount = mPresentCount;
325     mPresentCount++;
326     return true;
327 }
328 
SetColorSpace(GraphicColorGamut colorSpace)329 void RSSurfaceOhosVulkan::SetColorSpace(GraphicColorGamut colorSpace)
330 {
331     if (colorSpace != colorSpace_) {
332         colorSpace_ = colorSpace;
333         for (auto &[key, val] : mSurfaceMap) {
334             NativeWindowCancelBuffer(mNativeWindow, key);
335         }
336         mSurfaceMap.clear();
337         mSurfaceList.clear();
338     }
339 }
340 
SetSurfaceBufferUsage(uint64_t usage)341 void RSSurfaceOhosVulkan::SetSurfaceBufferUsage(uint64_t usage)
342 {
343     bufferUsage_ = usage;
344 }
345 
SetSurfacePixelFormat(int32_t pixelFormat)346 void RSSurfaceOhosVulkan::SetSurfacePixelFormat(int32_t pixelFormat)
347 {
348     if (pixelFormat != pixelFormat_) {
349         for (auto &[key, val] : mSurfaceMap) {
350             NativeWindowCancelBuffer(mNativeWindow, key);
351         }
352         mSurfaceMap.clear();
353         mSurfaceList.clear();
354     }
355     pixelFormat_ = pixelFormat;
356 }
357 
ClearBuffer()358 void RSSurfaceOhosVulkan::ClearBuffer()
359 {
360     if (producer_ != nullptr) {
361         ROSEN_LOGD("RSSurfaceOhosVulkan: Clear surface buffer!");
362         producer_->GoBackground();
363     }
364 }
365 
ResetBufferAge()366 void RSSurfaceOhosVulkan::ResetBufferAge()
367 {
368     ROSEN_LOGD("RSSurfaceOhosVulkan: Reset Buffer Age!");
369 }
370 
DupReservedFlushFd()371 int RSSurfaceOhosVulkan::DupReservedFlushFd()
372 {
373     if (mReservedFlushFd != -1) {
374         return ::dup(mReservedFlushFd);
375     }
376     return -1;
377 }
378 } // namespace Rosen
379 } // namespace OHOS
380