1 /*
2 * Copyright (c) 2022 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 #include "swapchain.h"
16 #include <algorithm>
17 #include <vector>
18 #include <unordered_set>
19 #include <unordered_map>
20 #include <new>
21 #include <malloc.h>
22 #include <native_window.h>
23 #include <window.h>
24 #include <native_buffer.h>
25 #include <wrapper_log.h>
26 #include <graphic_common.h>
27 #include "vulkan/vk_ohos_native_buffer.h"
28 #include <securec.h>
29
30 namespace vulkan {
31 namespace driver {
32 namespace {
33 constexpr uint32_t MIN_BUFFER_SIZE = 3;
34 }
35 struct Surface {
36 NativeWindow* window;
37 VkSwapchainKHR swapchainHandle;
38 int32_t consumerUsage;
39 };
40
41 using namespace OHOS;
42
43 struct Swapchain {
Swapchainvulkan::driver::Swapchain44 Swapchain(Surface& surface, uint32_t numImages, VkPresentModeKHR presentMode, int preTransform)
45 : surface(surface), numImages(numImages), mailboxMode(presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
46 preTransform(preTransform), frameTimestampsEnabled(false),
47 shared(presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
48 presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {}
49
50 Surface& surface;
51 uint32_t numImages;
52 bool mailboxMode;
53 int preTransform;
54 bool frameTimestampsEnabled;
55 bool shared;
56
57 struct Image {
Imagevulkan::driver::Swapchain::Image58 Image() : image(VK_NULL_HANDLE), buffer(nullptr), requestFence(-1), releaseFence(-1), requested(false) {}
59 VkImage image;
60 NativeWindowBuffer* buffer;
61 int requestFence;
62 int releaseFence;
63 bool requested;
64 } images[32];
65 };
66
DefaultAllocate(void *,size_t size,size_t alignment,VkSystemAllocationScope)67 VKAPI_ATTR void* DefaultAllocate(void*, size_t size, size_t alignment, VkSystemAllocationScope)
68 {
69 void* ptr = nullptr;
70 // Vulkan requires 'alignment' to be a power of two, but posix_memalign
71 // additionally requires that it be at least sizeof(void*).
72 int ret = posix_memalign(&ptr, std::max(alignment, sizeof(void*)), size);
73 return ret == 0 ? ptr : nullptr;
74 }
75
DefaultReallocate(void *,void * ptr,size_t size,size_t alignment,VkSystemAllocationScope)76 VKAPI_ATTR void* DefaultReallocate(void*, void* ptr, size_t size, size_t alignment, VkSystemAllocationScope)
77 {
78 if (size == 0) {
79 free(ptr);
80 return nullptr;
81 }
82
83 size_t oldSize = ptr ? malloc_usable_size(ptr) : 0;
84 if (size <= oldSize) {
85 return ptr;
86 }
87
88 void* newPtr = nullptr;
89 if (posix_memalign(&newPtr, std::max(alignment, sizeof(void*)), size) != 0) {
90 return nullptr;
91 }
92
93 if (ptr) {
94 auto ret = memcpy_s(newPtr, size, ptr, oldSize);
95 if (ret != EOK) {
96 return nullptr;
97 }
98 free(ptr);
99 }
100 return newPtr;
101 }
102
DefaultFree(void *,void * ptr)103 VKAPI_ATTR void DefaultFree(void*, void* ptr)
104 {
105 free(ptr);
106 }
107
GetDefaultAllocator()108 const VkAllocationCallbacks& GetDefaultAllocator()
109 {
110 static const VkAllocationCallbacks kDefaultAllocCallbacks = {
111 .pUserData = nullptr,
112 .pfnAllocation = DefaultAllocate,
113 .pfnReallocation = DefaultReallocate,
114 .pfnFree = DefaultFree,
115 };
116
117 return kDefaultAllocCallbacks;
118 }
119
HandleFromSurface(Surface * surface)120 VkSurfaceKHR HandleFromSurface(Surface* surface)
121 {
122 return VkSurfaceKHR(reinterpret_cast<uint64_t>(surface));
123 }
124
SurfaceFromHandle(VkSurfaceKHR handle)125 Surface* SurfaceFromHandle(VkSurfaceKHR handle)
126 {
127 return reinterpret_cast<Surface*>(handle);
128 }
129
SwapchainFromHandle(VkSwapchainKHR handle)130 Swapchain* SwapchainFromHandle(VkSwapchainKHR handle)
131 {
132 return reinterpret_cast<Swapchain*>(handle);
133 }
134
HandleFromSwapchain(Swapchain * swapchain)135 VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain)
136 {
137 return VkSwapchainKHR(reinterpret_cast<uint64_t>(swapchain));
138 }
139
CreateOHOSSurfaceOpenHarmony(VkInstance instance,const VkOHOSSurfaceCreateInfoOpenHarmony * pCreateInfo,const VkAllocationCallbacks * allocator,VkSurfaceKHR * outSurface)140 VKAPI_ATTR VkResult CreateOHOSSurfaceOpenHarmony(VkInstance instance,
141 const VkOHOSSurfaceCreateInfoOpenHarmony* pCreateInfo,
142 const VkAllocationCallbacks* allocator,
143 VkSurfaceKHR* outSurface)
144 {
145 if (!allocator) {
146 allocator = &vulkan::driver::GetDefaultAllocator();
147 }
148 void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Surface), alignof(Surface),
149 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
150 if (!mem) {
151 return VK_ERROR_OUT_OF_HOST_MEMORY;
152 }
153
154 Surface* surface = new (mem) Surface;
155 surface->window = pCreateInfo->window;
156 surface->swapchainHandle = VK_NULL_HANDLE;
157 int32_t res = NativeWindowHandleOpt(pCreateInfo->window, GET_USAGE, &(surface->consumerUsage));
158
159 if (surface->consumerUsage == 0) {
160 WLOGE("native window get usage failed, error num : %{public}d", res);
161 surface->~Surface();
162 allocator->pfnFree(allocator->pUserData, surface);
163 return VK_ERROR_SURFACE_LOST_KHR;
164 }
165
166 *outSurface = HandleFromSurface(surface);
167 return VK_SUCCESS;
168 }
169
170
DestroySurfaceKHR(VkInstance instance,VkSurfaceKHR surfaceHandle,const VkAllocationCallbacks * allocator)171 VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surfaceHandle,
172 const VkAllocationCallbacks* allocator)
173 {
174 Surface* surface = SurfaceFromHandle(surfaceHandle);
175 if (!surface) {
176 return;
177 }
178
179 surface->~Surface();
180 if (!allocator) {
181 allocator = &vulkan::driver::GetDefaultAllocator();
182 }
183 allocator->pfnFree(allocator->pUserData, surface);
184 }
185
186 VKAPI_ATTR
GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice,uint32_t,VkSurfaceKHR,VkBool32 * supported)187 VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice, uint32_t, VkSurfaceKHR, VkBool32* supported)
188 {
189 *supported = VK_TRUE;
190 return VK_SUCCESS;
191 }
192
193 VKAPI_ATTR
GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice,VkSurfaceKHR surface,VkSurfaceCapabilitiesKHR * capabilities)194 VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice, VkSurfaceKHR surface,
195 VkSurfaceCapabilitiesKHR* capabilities)
196 {
197 int width = 0;
198 int height = 0;
199 uint32_t maxBufferCount = 10;
200 if (surface != VK_NULL_HANDLE) {
201 NativeWindow* window = SurfaceFromHandle(surface)->window;
202 int err = NativeWindowHandleOpt(window, GET_BUFFER_GEOMETRY, &height, &width);
203 if (err != OHOS::GSERROR_OK) {
204 WLOGE("NATIVE_WINDOW_DEFAULT_WIDTH query failed: (%{public}d)", err);
205 return VK_ERROR_SURFACE_LOST_KHR;
206 }
207 maxBufferCount = window->surface->GetQueueSize();
208 }
209
210 capabilities->minImageCount = std::min(maxBufferCount, MIN_BUFFER_SIZE);
211 capabilities->maxImageCount = maxBufferCount;
212 capabilities->currentExtent = VkExtent2D {static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
213 capabilities->minImageExtent = VkExtent2D {1, 1};
214 capabilities->maxImageExtent = VkExtent2D {4096, 4096};
215 capabilities->maxImageArrayLayers = 1;
216 capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
217 capabilities->supportedUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
218 VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
219 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
220 return VK_SUCCESS;
221 }
222
223
224 VKAPI_ATTR
GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev,VkSurfaceKHR surfaceHandle,uint32_t * count,VkSurfaceFormatKHR * formats)225 VkResult GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice pdev, VkSurfaceKHR surfaceHandle, uint32_t* count,
226 VkSurfaceFormatKHR* formats)
227 {
228 std::vector<VkSurfaceFormatKHR> allFormats = {{VK_FORMAT_R8G8B8A8_UNORM, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR},
229 {VK_FORMAT_R8G8B8A8_SRGB, VK_COLOR_SPACE_SRGB_NONLINEAR_KHR}};
230 VkResult result = VK_SUCCESS;
231 if (formats) {
232 uint32_t transferCount = allFormats.size();
233 if (transferCount > *count) {
234 transferCount = *count;
235 result = VK_INCOMPLETE;
236 }
237 std::copy(allFormats.begin(), allFormats.begin() + transferCount, formats);
238 *count = transferCount;
239 } else {
240 *count = allFormats.size();
241 }
242
243 return result;
244 }
245
246 VKAPI_ATTR
GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev,VkSurfaceKHR surface,uint32_t * count,VkPresentModeKHR * modes)247 VkResult GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice pdev, VkSurfaceKHR surface, uint32_t* count,
248 VkPresentModeKHR* modes)
249 {
250 std::vector<VkPresentModeKHR> presentModes;
251 presentModes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
252 presentModes.push_back(VK_PRESENT_MODE_FIFO_KHR);
253
254 VkPhysicalDevicePresentationPropertiesOpenHarmony present_properties;
255 QueryPresentationProperties(pdev, &present_properties);
256 if (present_properties.sharedImage) {
257 presentModes.push_back(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR);
258 presentModes.push_back(VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR);
259 }
260
261 uint32_t numModes = uint32_t(presentModes.size());
262 VkResult result = VK_SUCCESS;
263 if (modes) {
264 if (*count < numModes) {
265 result = VK_INCOMPLETE;
266 }
267 *count = std::min(*count, numModes);
268 std::copy_n(presentModes.data(), *count, modes);
269 } else {
270 *count = numModes;
271 }
272 return result;
273 }
274
275 VKAPI_ATTR
GetSwapchainImagesKHR(VkDevice,VkSwapchainKHR swapchainHandle,uint32_t * count,VkImage * images)276 VkResult GetSwapchainImagesKHR(VkDevice, VkSwapchainKHR swapchainHandle, uint32_t* count, VkImage* images)
277 {
278 const Swapchain& swapchain = *SwapchainFromHandle(swapchainHandle);
279 if (images == nullptr) {
280 *count = swapchain.numImages;
281 return VK_SUCCESS;
282 }
283
284 VkResult result = VK_SUCCESS;
285 uint32_t numImages = swapchain.numImages;
286 if (*count < swapchain.numImages) {
287 numImages = *count;
288 result = VK_INCOMPLETE;
289 }
290 for (uint32_t i = 0; i < numImages; i++) {
291 images[i] = swapchain.images[i].image;
292 }
293 *count = numImages;
294 return result;
295 }
296
GetPixelFormat(VkFormat format)297 GraphicPixelFormat GetPixelFormat(VkFormat format)
298 {
299 GraphicPixelFormat nativeFormat = GRAPHIC_PIXEL_FMT_RGBA_8888;
300 switch (format) {
301 case VK_FORMAT_R8G8B8A8_UNORM:
302 case VK_FORMAT_R8G8B8A8_SRGB:
303 nativeFormat = GRAPHIC_PIXEL_FMT_RGBA_8888;
304 break;
305 case VK_FORMAT_R5G6B5_UNORM_PACK16:
306 nativeFormat = GRAPHIC_PIXEL_FMT_RGB_565;
307 break;
308 default:
309 WLOGE("unsupported swapchain format %{public}d", format);
310 break;
311 }
312 return nativeFormat;
313 }
314
GetColorDataspace(VkColorSpaceKHR colorspace)315 GraphicColorDataSpace GetColorDataspace(VkColorSpaceKHR colorspace)
316 {
317 switch (colorspace) {
318 case VK_COLOR_SPACE_SRGB_NONLINEAR_KHR:
319 return GRAPHIC_BT709_SRGB_FULL;
320 case VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT:
321 return GRAPHIC_DCI_P3_GAMMA26_FULL;
322 case VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT:
323 return GRAPHIC_BT709_LINEAR_EXTENDED;
324 case VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT:
325 return GRAPHIC_BT709_SRGB_EXTENDED;
326 case VK_COLOR_SPACE_DCI_P3_LINEAR_EXT:
327 return GRAPHIC_DCI_P3_LINEAR_FULL;
328 case VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT:
329 return GRAPHIC_DCI_P3_GAMMA26_FULL;
330 case VK_COLOR_SPACE_BT709_LINEAR_EXT:
331 return GRAPHIC_BT709_LINEAR_FULL;
332 case VK_COLOR_SPACE_BT709_NONLINEAR_EXT:
333 return GRAPHIC_BT709_SRGB_FULL;
334 case VK_COLOR_SPACE_BT2020_LINEAR_EXT:
335 return GRAPHIC_BT2020_LINEAR_FULL;
336 case VK_COLOR_SPACE_HDR10_ST2084_EXT:
337 return GRAPHIC_BT2020_ST2084_FULL;
338 case VK_COLOR_SPACE_DOLBYVISION_EXT:
339 return GRAPHIC_BT2020_ST2084_FULL;
340 case VK_COLOR_SPACE_HDR10_HLG_EXT:
341 return GRAPHIC_BT2020_HLG_FULL;
342 case VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT:
343 return static_cast<GraphicColorDataSpace>(
344 GRAPHIC_GAMUT_ADOBE_RGB | GRAPHIC_TRANSFORM_FUNC_LINEAR | GRAPHIC_PRECISION_FULL);
345 case VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT:
346 return GRAPHIC_ADOBE_RGB_GAMMA22_FULL;
347 default:
348 return GRAPHIC_COLOR_DATA_SPACE_UNKNOWN;
349 }
350 }
351
IsFencePending(int fd)352 static bool IsFencePending(int fd)
353 {
354 return false;
355 }
356
ReleaseSwapchainImage(VkDevice device,NativeWindow * window,int releaseFence,Swapchain::Image & image,bool deferIfPending)357 void ReleaseSwapchainImage(VkDevice device, NativeWindow* window, int releaseFence, Swapchain::Image& image,
358 bool deferIfPending)
359 {
360 if (image.requested) {
361 if (releaseFence >= 0) {
362 if (image.requestFence >= 0) {
363 close(image.requestFence);
364 }
365 } else {
366 releaseFence = image.requestFence;
367 }
368 image.requestFence = -1;
369
370 if (window) {
371 NativeWindowCancelBuffer(window, image.buffer);
372 } else {
373 if (releaseFence >= 0) {
374 close(releaseFence);
375 }
376 }
377 image.requested = false;
378 }
379
380 if (deferIfPending && IsFencePending(image.releaseFence)) {
381 return;
382 }
383
384 if (image.releaseFence >= 0) {
385 close(image.releaseFence);
386 image.releaseFence = -1;
387 }
388
389 if (image.image) {
390 vulkan::driver::DestroyImage(device, image.image, nullptr);
391 image.image = VK_NULL_HANDLE;
392 }
393 }
394
ReleaseSwapchain(VkDevice device,Swapchain * swapchain)395 void ReleaseSwapchain(VkDevice device, Swapchain* swapchain)
396 {
397 if (swapchain->surface.swapchainHandle != HandleFromSwapchain(swapchain)) {
398 return;
399 }
400
401 for (uint32_t i = 0; i < swapchain->numImages; i++) {
402 if (!swapchain->images[i].requested) {
403 ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i], true);
404 }
405 }
406 swapchain->surface.swapchainHandle = VK_NULL_HANDLE;
407 }
408
TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform)409 int TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform)
410 {
411 return ROTATE_NONE;
412 }
413
DestroySwapchainInternal(VkDevice device,VkSwapchainKHR swapchainHandle,const VkAllocationCallbacks * allocator)414 static void DestroySwapchainInternal(VkDevice device, VkSwapchainKHR swapchainHandle,
415 const VkAllocationCallbacks* allocator)
416 {
417 Swapchain* swapchain = SwapchainFromHandle(swapchainHandle);
418 if (!swapchain) {
419 return;
420 }
421
422 bool active = swapchain->surface.swapchainHandle == swapchainHandle;
423 NativeWindow* window = active ? swapchain->surface.window : nullptr;
424
425 for (uint32_t i = 0; i < swapchain->numImages; i++) {
426 ReleaseSwapchainImage(device, window, -1, swapchain->images[i], false);
427 }
428
429 if (active) {
430 swapchain->surface.swapchainHandle = VK_NULL_HANDLE;
431 }
432
433 if (!allocator) {
434 allocator = &vulkan::driver::GetDefaultAllocator();
435 }
436
437 swapchain->~Swapchain();
438 allocator->pfnFree(allocator->pUserData, swapchain);
439 }
440
SetWindowInfo(const VkSwapchainCreateInfoKHR * createInfo,int32_t * numImages)441 VKAPI_ATTR VkResult SetWindowInfo(const VkSwapchainCreateInfoKHR* createInfo, int32_t* numImages)
442 {
443 GraphicPixelFormat pixelFormat = GetPixelFormat(createInfo->imageFormat);
444 Surface& surface = *SurfaceFromHandle(createInfo->surface);
445
446 NativeWindow* window = surface.window;
447 int err = NativeWindowHandleOpt(window, SET_FORMAT, pixelFormat);
448 if (err != OHOS::GSERROR_OK) {
449 WLOGE("native_window_set_buffers_format(%{public}d) failed: (%{public}d)", pixelFormat, err);
450 return VK_ERROR_SURFACE_LOST_KHR;
451 }
452
453 err = NativeWindowHandleOpt(window, SET_BUFFER_GEOMETRY,
454 static_cast<int>(createInfo->imageExtent.width),
455 static_cast<int>(createInfo->imageExtent.height));
456 if (err != OHOS::GSERROR_OK) {
457 WLOGE("native_window_set_buffers_dimensions(%{public}d,%{public}d) failed: (%{public}d)",
458 createInfo->imageExtent.width, createInfo->imageExtent.height, err);
459 return VK_ERROR_SURFACE_LOST_KHR;
460 }
461
462 if (createInfo->presentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR ||
463 createInfo->presentMode == VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR) {
464 *numImages = 1;
465 }
466
467 uint64_t native_usage = OHOS::BUFFER_USAGE_CPU_READ | OHOS::BUFFER_USAGE_CPU_WRITE | OHOS::BUFFER_USAGE_MEM_DMA;
468 err = NativeWindowHandleOpt(window, SET_USAGE, native_usage);
469 if (err != OHOS::GSERROR_OK) {
470 WLOGE("native_window_set_buffer_count(%{public}d) failed: (%{public}d)", *numImages, err);
471 return VK_ERROR_SURFACE_LOST_KHR;
472 }
473 return VK_SUCCESS;
474 }
475
SetSwapchainCreateInfo(VkDevice device,const VkSwapchainCreateInfoKHR * createInfo,int32_t * numImages)476 VKAPI_ATTR VkResult SetSwapchainCreateInfo(VkDevice device, const VkSwapchainCreateInfoKHR* createInfo,
477 int32_t* numImages)
478 {
479 GraphicColorDataSpace color_data_space = GetColorDataspace(createInfo->imageColorSpace);
480 if (color_data_space == GRAPHIC_COLOR_DATA_SPACE_UNKNOWN) {
481 return VK_ERROR_INITIALIZATION_FAILED;
482 }
483 if (createInfo->oldSwapchain != VK_NULL_HANDLE) {
484 ReleaseSwapchain(device, SwapchainFromHandle(createInfo->oldSwapchain));
485 }
486
487 return SetWindowInfo(createInfo, numImages);
488 }
489
InitImageCreateInfo(const VkSwapchainCreateInfoKHR * createInfo,VkImageCreateInfo * imageCreate)490 void InitImageCreateInfo(const VkSwapchainCreateInfoKHR* createInfo, VkImageCreateInfo* imageCreate)
491 {
492 imageCreate->sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
493 imageCreate->flags = 0u;
494 imageCreate->imageType = VK_IMAGE_TYPE_2D;
495 imageCreate->format = createInfo->imageFormat;
496 imageCreate->extent = {0, 0, 1};
497 imageCreate->mipLevels = 1;
498 imageCreate->arrayLayers = 1;
499 imageCreate->samples = VK_SAMPLE_COUNT_1_BIT;
500 imageCreate->tiling = VK_IMAGE_TILING_OPTIMAL;
501 imageCreate->usage = createInfo->imageUsage;
502 imageCreate->sharingMode = createInfo->imageSharingMode;
503 imageCreate->queueFamilyIndexCount = createInfo->queueFamilyIndexCount;
504 imageCreate->pQueueFamilyIndices = createInfo->pQueueFamilyIndices;
505 }
506
507
CreateImages(int32_t & numImages,Swapchain * swapchain,const VkSwapchainCreateInfoKHR * createInfo,VkImageCreateInfo & imageCreate,VkDevice device)508 VKAPI_ATTR VkResult CreateImages(int32_t& numImages, Swapchain* swapchain, const VkSwapchainCreateInfoKHR* createInfo,
509 VkImageCreateInfo& imageCreate, VkDevice device)
510 {
511 Surface& surface = *SurfaceFromHandle(createInfo->surface);
512 NativeWindow* window = surface.window;
513 if (createInfo->oldSwapchain != VK_NULL_HANDLE) {
514 WLOGI("recreate swapchain ,clean buffer queue");
515 window->surface->CleanCache();
516 }
517 VkResult result = VK_SUCCESS;
518 for (int32_t i = 0; i < numImages; i++) {
519 Swapchain::Image& img = swapchain->images[i];
520
521 NativeWindowBuffer* buffer;
522 int err = NativeWindowRequestBuffer(window, &buffer, &img.requestFence);
523 if (err != OHOS::GSERROR_OK) {
524 WLOGE("dequeueBuffer[%{public}u] failed: (%{public}d)", i, err);
525 result = VK_ERROR_SURFACE_LOST_KHR;
526 break;
527 }
528 img.buffer = buffer;
529 img.requested = true;
530 imageCreate.extent = VkExtent3D {static_cast<uint32_t>(img.buffer->sfbuffer->GetSurfaceBufferWidth()),
531 static_cast<uint32_t>(img.buffer->sfbuffer->GetSurfaceBufferHeight()), 1};
532 ((VkNativeBufferOpenHarmony*)(imageCreate.pNext))->handle = img.buffer->sfbuffer->GetBufferHandle();
533 result = vulkan::driver::CreateImage(device, &imageCreate, nullptr, &img.image);
534 if (result != VK_SUCCESS) {
535 WLOGD("vkCreateImage native buffer failed: %{public}u", result);
536 break;
537 }
538 }
539
540 WLOGD("swapchain init shared %{public}d", swapchain->shared);
541 for (int32_t i = 0; i < numImages; i++) {
542 Swapchain::Image& img = swapchain->images[i];
543 if (img.requested) {
544 if (!swapchain->shared) {
545 NativeWindowCancelBuffer(window, img.buffer);
546 img.requestFence = -1;
547 img.requested = false;
548 }
549 }
550 }
551 return result;
552 }
553
CreateSwapchainKHR(VkDevice device,const VkSwapchainCreateInfoKHR * createInfo,const VkAllocationCallbacks * allocator,VkSwapchainKHR * swapchainHandle)554 VKAPI_ATTR VkResult CreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* createInfo,
555 const VkAllocationCallbacks* allocator, VkSwapchainKHR* swapchainHandle)
556 {
557 Surface& surface = *SurfaceFromHandle(createInfo->surface);
558 if (surface.swapchainHandle != createInfo->oldSwapchain) {
559 return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
560 }
561
562 int32_t numImages = static_cast<int32_t>(MIN_BUFFER_SIZE);
563 VkResult result = SetSwapchainCreateInfo(device, createInfo, &numImages);
564 if (result != VK_SUCCESS) {
565 return result;
566 }
567 if (!allocator) {
568 allocator = &vulkan::driver::GetDefaultAllocator();
569 }
570
571 void* mem = allocator->pfnAllocation(allocator->pUserData, sizeof(Swapchain), alignof(Swapchain),
572 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
573 if (!mem) {
574 return VK_ERROR_OUT_OF_HOST_MEMORY;
575 }
576
577 Swapchain* swapchain = new (mem) Swapchain(surface, numImages, createInfo->presentMode,
578 TranslateVulkanToNativeTransform(createInfo->preTransform));
579 VkSwapchainImageCreateInfoOpenHarmony swapchainImageCreate = {
580 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_OPENHARMONY,
581 .pNext = nullptr,
582 };
583 VkNativeBufferOpenHarmony imageNativeBuffer = {
584 .sType = VK_STRUCTURE_TYPE_NATIVE_BUFFER_OPENHARMONY,
585 .pNext = &swapchainImageCreate,
586 };
587
588 VkImageCreateInfo imageCreate = {
589 .pNext = &imageNativeBuffer,
590 };
591
592 InitImageCreateInfo(createInfo, &imageCreate);
593 result = CreateImages(numImages, swapchain, createInfo, imageCreate, device);
594 if (result != VK_SUCCESS) {
595 DestroySwapchainInternal(device, HandleFromSwapchain(swapchain), allocator);
596 return result;
597 }
598
599 surface.swapchainHandle = HandleFromSwapchain(swapchain);
600 *swapchainHandle = surface.swapchainHandle;
601 return VK_SUCCESS;
602 }
603
604 VKAPI_ATTR
DestroySwapchainKHR(VkDevice device,VkSwapchainKHR swapchainHandle,const VkAllocationCallbacks * allocator)605 void DestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchainHandle,
606 const VkAllocationCallbacks* allocator)
607 {
608 DestroySwapchainInternal(device, swapchainHandle, allocator);
609 }
610
611
AcquireNextImageKHR(VkDevice device,VkSwapchainKHR swapchainHandle,uint64_t timeout,VkSemaphore semaphore,VkFence vkFence,uint32_t * imageIndex)612 VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchainHandle, uint64_t timeout,
613 VkSemaphore semaphore, VkFence vkFence, uint32_t* imageIndex)
614 {
615 Swapchain& swapchain = *SwapchainFromHandle(swapchainHandle);
616 NativeWindow* nativeWindow = swapchain.surface.window;
617 VkResult result;
618
619 if (swapchain.surface.swapchainHandle != swapchainHandle) {
620 return VK_ERROR_OUT_OF_DATE_KHR;
621 }
622
623 if (swapchain.shared) {
624 *imageIndex = 0;
625 result = vulkan::driver::SetNativeFenceFdOpenHarmony(device, -1, semaphore, vkFence);
626 return result;
627 }
628
629 NativeWindowBuffer* nativeWindowBuffer;
630 int fence;
631 int32_t ret = NativeWindowRequestBuffer(nativeWindow, &nativeWindowBuffer, &fence);
632 if (ret != OHOS::GSERROR_OK) {
633 WLOGE("dequeueBuffer failed: (%{public}d)", ret);
634 return VK_ERROR_SURFACE_LOST_KHR;
635 }
636
637 uint32_t index = 0;
638 while (index < swapchain.numImages) {
639 if (swapchain.images[index].buffer->sfbuffer == nativeWindowBuffer->sfbuffer) {
640 swapchain.images[index].requested = true;
641 swapchain.images[index].requestFence = fence;
642 break;
643 }
644 index++;
645 }
646
647 if (index == swapchain.numImages) {
648 WLOGE("dequeueBuffer returned unrecognized buffer");
649 if (NativeWindowCancelBuffer(nativeWindow, nativeWindowBuffer) != OHOS::GSERROR_OK) {
650 WLOGE("NativeWindowCancelBuffer failed: (%{public}d)", ret);
651 }
652 return VK_ERROR_OUT_OF_DATE_KHR;
653 }
654
655 result = vulkan::driver::SetNativeFenceFdOpenHarmony(device, -1, semaphore, vkFence);
656 if (result != VK_SUCCESS) {
657 if (NativeWindowCancelBuffer(nativeWindow, nativeWindowBuffer) != OHOS::GSERROR_OK) {
658 WLOGE("NativeWindowCancelBuffer failed: (%{public}d)", ret);
659 }
660 swapchain.images[index].requested = false;
661 swapchain.images[index].requestFence = -1;
662 return result;
663 }
664
665 *imageIndex = index;
666 return VK_SUCCESS;
667 }
668
669 VKAPI_ATTR
AcquireNextImage2KHR(VkDevice device,const VkAcquireNextImageInfoKHR * pAcquireInfo,uint32_t * pImageIndex)670 VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex)
671 {
672 return AcquireNextImageKHR(device, pAcquireInfo->swapchain, pAcquireInfo->timeout,
673 pAcquireInfo->semaphore, pAcquireInfo->fence, pImageIndex);
674 }
675
GetPresentRegion(const VkPresentRegionKHR * regions,const Swapchain & swapchain,uint32_t index)676 const VkPresentRegionKHR* GetPresentRegion(
677 const VkPresentRegionKHR* regions, const Swapchain& swapchain, uint32_t index)
678 {
679 return (regions && !swapchain.mailboxMode) ? ®ions[index] : nullptr;
680 }
681
GetReleaseFence(VkQueue queue,const VkPresentInfoKHR * presentInfo,Swapchain::Image & img,int32_t & fence)682 VkResult GetReleaseFence(VkQueue queue, const VkPresentInfoKHR* presentInfo,
683 Swapchain::Image& img, int32_t &fence)
684 {
685 VkResult result = vulkan::driver::GetNativeFenceFdOpenHarmony(queue, presentInfo->waitSemaphoreCount,
686 presentInfo->pWaitSemaphores, img.image, &fence);
687 if (img.releaseFence >= 0) {
688 close(img.releaseFence);
689 img.releaseFence = -1;
690 }
691 if (fence >= 0) {
692 img.releaseFence = dup(fence);
693 }
694
695 return result;
696 }
697
GetRegionRect(const VkAllocationCallbacks * defaultAllocator,struct Region::Rect ** rects,int32_t rectangleCount)698 struct Region::Rect* GetRegionRect(
699 const VkAllocationCallbacks* defaultAllocator, struct Region::Rect** rects, int32_t rectangleCount)
700 {
701 return static_cast<struct Region::Rect*>(
702 defaultAllocator->pfnReallocation(
703 defaultAllocator->pUserData, *rects,
704 sizeof(Region::Rect) * rectangleCount,
705 alignof(Region::Rect), VK_SYSTEM_ALLOCATION_SCOPE_COMMAND));
706 }
707
InitRegionRect(const VkRectLayerKHR * layer,struct Region::Rect * rect)708 void InitRegionRect(const VkRectLayerKHR* layer, struct Region::Rect* rect)
709 {
710 rect->x = layer->offset.x;
711 rect->y = layer->offset.y;
712 rect->w = layer->extent.width;
713 rect->h = layer->extent.height;
714 }
715
GetPresentRegions(const VkPresentInfoKHR * presentInfo)716 const VkPresentRegionKHR* GetPresentRegions(const VkPresentInfoKHR* presentInfo)
717 {
718 const VkPresentRegionsKHR* presentRegions = nullptr;
719 const VkPresentRegionsKHR* nextRegions = reinterpret_cast<const VkPresentRegionsKHR*>(presentInfo->pNext);
720 while (nextRegions != nullptr) {
721 if (nextRegions->sType == VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR) {
722 presentRegions = nextRegions;
723 }
724 nextRegions = reinterpret_cast<const VkPresentRegionsKHR*>(nextRegions->pNext);
725 }
726
727 if (presentRegions == nullptr) {
728 return nullptr;
729 } else {
730 return presentRegions->pRegions;
731 }
732 }
733
FlushBuffer(const VkPresentRegionKHR * region,struct Region::Rect * rects,Swapchain & swapchain,Swapchain::Image & img,int32_t fence)734 VkResult FlushBuffer(const VkPresentRegionKHR* region, struct Region::Rect* rects,
735 Swapchain& swapchain, Swapchain::Image& img, int32_t fence)
736 {
737 const VkAllocationCallbacks* defaultAllocator = &vulkan::driver::GetDefaultAllocator();
738 Region localRegion;
739 if (memset_s(&localRegion, sizeof(localRegion), 0, sizeof(Region)) != EOK) {
740 return VK_ERROR_SURFACE_LOST_KHR;
741 }
742 if (region != nullptr) {
743 int32_t rectangleCount = region->rectangleCount;
744 if (rectangleCount > 0) {
745 struct Region::Rect* tmpRects = GetRegionRect(defaultAllocator, &rects, rectangleCount);
746 if (tmpRects != nullptr) {
747 rects = tmpRects;
748 } else {
749 rectangleCount = 0;
750 }
751 }
752 for (int32_t r = 0; r < rectangleCount; ++r) {
753 InitRegionRect(®ion->pRectangles[r], &rects[r]);
754 }
755
756 localRegion.rects = rects;
757 localRegion.rectNumber = rectangleCount;
758 }
759 NativeWindow* window = swapchain.surface.window;
760 // the acquire fence will be close by BufferQueue module
761 int err = NativeWindowFlushBuffer(window, img.buffer, fence, localRegion);
762 VkResult scResult = VK_SUCCESS;
763 if (err != OHOS::GSERROR_OK) {
764 WLOGE("queueBuffer failed: (%{public}d)", err);
765 scResult = VK_ERROR_SURFACE_LOST_KHR;
766 } else {
767 if (img.requestFence >= 0) {
768 close(img.requestFence);
769 img.requestFence = -1;
770 }
771 img.requested = false;
772 }
773
774 if (swapchain.shared && scResult == VK_SUCCESS) {
775 NativeWindowBuffer* buffer = nullptr;
776 int releaseFence = -1;
777 err = NativeWindowRequestBuffer(window, &buffer, &releaseFence);
778 if (err != OHOS::GSERROR_OK) {
779 scResult = VK_ERROR_SURFACE_LOST_KHR;
780 } else if (img.buffer != buffer) {
781 scResult = VK_ERROR_SURFACE_LOST_KHR;
782 } else {
783 img.requestFence = releaseFence;
784 img.requested = true;
785 }
786 }
787 return scResult;
788 }
789
QueuePresentKHR(VkQueue queue,const VkPresentInfoKHR * presentInfo)790 VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* presentInfo)
791 {
792 VkResult ret = VK_SUCCESS;
793
794 const VkPresentRegionKHR* regions = GetPresentRegions(presentInfo);
795 const VkAllocationCallbacks* defaultAllocator = &vulkan::driver::GetDefaultAllocator();
796 struct Region::Rect* rects = nullptr;
797
798 for (uint32_t i = 0; i < presentInfo->swapchainCount; i++) {
799 Swapchain& swapchain = *(reinterpret_cast<Swapchain*>(presentInfo->pSwapchains[i]));
800 Swapchain::Image& img = swapchain.images[presentInfo->pImageIndices[i]];
801 const VkPresentRegionKHR* region = GetPresentRegion(regions, swapchain, i);
802 int32_t fence = -1;
803 ret = GetReleaseFence(queue, presentInfo, img, fence);
804 if (swapchain.surface.swapchainHandle == presentInfo->pSwapchains[i]) {
805 if (ret == VK_SUCCESS) {
806 ret = FlushBuffer(region, rects, swapchain, img, fence);
807 } else {
808 ReleaseSwapchain(nullptr, &swapchain);
809 }
810 } else {
811 WLOGE("QueuePresentKHR swapchainHandle != pSwapchains[%{public}d]", i);
812 ReleaseSwapchainImage(nullptr, nullptr, fence, img, true);
813 ret = VK_ERROR_OUT_OF_DATE_KHR;
814 }
815
816 if (presentInfo->pResults) {
817 presentInfo->pResults[i] = ret;
818 }
819 }
820 if (rects != nullptr) {
821 defaultAllocator->pfnFree(defaultAllocator->pUserData, rects);
822 }
823 return ret;
824 }
825 } // namespace driver
826 } // namespace vulkan
827