• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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) ? &regions[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(&region->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