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