18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci#include "swapchain_vk.h" 178bf80f4bSopenharmony_ci 188bf80f4bSopenharmony_ci#include <algorithm> 198bf80f4bSopenharmony_ci#include <cstddef> 208bf80f4bSopenharmony_ci#include <cstdint> 218bf80f4bSopenharmony_ci#include <vulkan/vulkan_core.h> 228bf80f4bSopenharmony_ci 238bf80f4bSopenharmony_ci#include <base/containers/vector.h> 248bf80f4bSopenharmony_ci#include <base/math/mathf.h> 258bf80f4bSopenharmony_ci#include <base/util/formats.h> 268bf80f4bSopenharmony_ci#include <core/intf_engine.h> 278bf80f4bSopenharmony_ci#include <render/device/gpu_resource_desc.h> 288bf80f4bSopenharmony_ci#include <render/namespace.h> 298bf80f4bSopenharmony_ci#include <render/vulkan/intf_device_vk.h> 308bf80f4bSopenharmony_ci 318bf80f4bSopenharmony_ci#include "util/log.h" 328bf80f4bSopenharmony_ci#include "vulkan/create_functions_vk.h" 338bf80f4bSopenharmony_ci#include "vulkan/device_vk.h" 348bf80f4bSopenharmony_ci#include "vulkan/validate_vk.h" 358bf80f4bSopenharmony_ci 368bf80f4bSopenharmony_ciusing namespace BASE_NS; 378bf80f4bSopenharmony_ci 388bf80f4bSopenharmony_ciRENDER_BEGIN_NAMESPACE() 398bf80f4bSopenharmony_cinamespace { 408bf80f4bSopenharmony_ciFormat GetValidDepthFormat(const DeviceVk& deviceVk) 418bf80f4bSopenharmony_ci{ 428bf80f4bSopenharmony_ci constexpr uint32_t PREFERRED_FORMAT_COUNT { 3 }; 438bf80f4bSopenharmony_ci constexpr Format preferredFormats[PREFERRED_FORMAT_COUNT] = { BASE_FORMAT_D24_UNORM_S8_UINT, BASE_FORMAT_D32_SFLOAT, 448bf80f4bSopenharmony_ci BASE_FORMAT_D16_UNORM }; 458bf80f4bSopenharmony_ci#ifndef NDEBUG 468bf80f4bSopenharmony_ci constexpr string_view PREFERRED_FORMAT_NAMES[PREFERRED_FORMAT_COUNT] = { "BASE_FORMAT_D24_UNORM_S8_UINT", 478bf80f4bSopenharmony_ci "BASE_FORMAT_D32_SFLOAT", "BASE_FORMAT_D16_UNORM" }; 488bf80f4bSopenharmony_ci#endif 498bf80f4bSopenharmony_ci Format finalFormat = BASE_FORMAT_UNDEFINED; 508bf80f4bSopenharmony_ci const auto& devPlat = deviceVk.GetPlatformInternalDataVk(); 518bf80f4bSopenharmony_ci for (uint32_t idx = 0; idx < PREFERRED_FORMAT_COUNT; ++idx) { 528bf80f4bSopenharmony_ci finalFormat = preferredFormats[idx]; 538bf80f4bSopenharmony_ci for (const auto& supportedDepthFormat : devPlat.supportedDepthFormats) { 548bf80f4bSopenharmony_ci if (finalFormat == supportedDepthFormat) { 558bf80f4bSopenharmony_ci#ifndef NDEBUG 568bf80f4bSopenharmony_ci PLUGIN_LOG_D( 578bf80f4bSopenharmony_ci "selected CORE_DEFAULT_BACKBUFFER format: %s", string(PREFERRED_FORMAT_NAMES[idx]).c_str()); 588bf80f4bSopenharmony_ci#endif 598bf80f4bSopenharmony_ci idx = PREFERRED_FORMAT_COUNT; 608bf80f4bSopenharmony_ci break; 618bf80f4bSopenharmony_ci } 628bf80f4bSopenharmony_ci } 638bf80f4bSopenharmony_ci } 648bf80f4bSopenharmony_ci return finalFormat; 658bf80f4bSopenharmony_ci} 668bf80f4bSopenharmony_ci 678bf80f4bSopenharmony_cistruct ColorInfo { 688bf80f4bSopenharmony_ci VkFormat format { VK_FORMAT_UNDEFINED }; 698bf80f4bSopenharmony_ci VkColorSpaceKHR colorSpace { VK_COLOR_SPACE_MAX_ENUM_KHR }; 708bf80f4bSopenharmony_ci}; 718bf80f4bSopenharmony_ci 728bf80f4bSopenharmony_ciVkFormat GetColorFormat(const uint32_t flags, const vector<VkSurfaceFormatKHR>& surfaceFormats) 738bf80f4bSopenharmony_ci{ 748bf80f4bSopenharmony_ci constexpr uint32_t preferredFormatCount { 4u }; 758bf80f4bSopenharmony_ci constexpr VkFormat srgbFormats[preferredFormatCount] = { VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB, 768bf80f4bSopenharmony_ci VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM }; 778bf80f4bSopenharmony_ci constexpr VkFormat nonSrgbFormats[preferredFormatCount] = { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM, 788bf80f4bSopenharmony_ci VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB }; 798bf80f4bSopenharmony_ci 808bf80f4bSopenharmony_ci const bool preferSrgbFormat = (flags & SwapchainFlagBits::CORE_SWAPCHAIN_SRGB_BIT); 818bf80f4bSopenharmony_ci const array_view<const VkFormat> formats = 828bf80f4bSopenharmony_ci (preferSrgbFormat) ? array_view<const VkFormat> { srgbFormats, preferredFormatCount } 838bf80f4bSopenharmony_ci : array_view<const VkFormat> { nonSrgbFormats, preferredFormatCount }; 848bf80f4bSopenharmony_ci 858bf80f4bSopenharmony_ci // If pSurfaceFormats includes just one entry, whose value for format is VK_FORMAT_UNDEFINED, 868bf80f4bSopenharmony_ci // surface has no preferred format. In this case, the application can use any valid VkFormat value. 878bf80f4bSopenharmony_ci if (surfaceFormats[0].format == VK_FORMAT_UNDEFINED && surfaceFormats.size() == 1) { 888bf80f4bSopenharmony_ci return VK_FORMAT_R8G8B8A8_SRGB; 898bf80f4bSopenharmony_ci } 908bf80f4bSopenharmony_ci 918bf80f4bSopenharmony_ci for (size_t idx = 0; idx < formats.size(); ++idx) { 928bf80f4bSopenharmony_ci for (size_t jdx = 0; jdx < surfaceFormats.size(); ++jdx) { 938bf80f4bSopenharmony_ci if (formats[idx] == surfaceFormats[jdx].format) { 948bf80f4bSopenharmony_ci return surfaceFormats[jdx].format; 958bf80f4bSopenharmony_ci } 968bf80f4bSopenharmony_ci } 978bf80f4bSopenharmony_ci } 988bf80f4bSopenharmony_ci return VK_FORMAT_UNDEFINED; 998bf80f4bSopenharmony_ci} 1008bf80f4bSopenharmony_ci 1018bf80f4bSopenharmony_ciColorInfo GetColorInfo(const VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, const uint32_t flags) 1028bf80f4bSopenharmony_ci{ 1038bf80f4bSopenharmony_ci // Pick a color format for the swapchain. 1048bf80f4bSopenharmony_ci uint32_t surfaceFormatsCount = 0; 1058bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, nullptr)); 1068bf80f4bSopenharmony_ci 1078bf80f4bSopenharmony_ci vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatsCount); 1088bf80f4bSopenharmony_ci VALIDATE_VK_RESULT( 1098bf80f4bSopenharmony_ci vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, surfaceFormats.data())); 1108bf80f4bSopenharmony_ci 1118bf80f4bSopenharmony_ci ColorInfo ci; 1128bf80f4bSopenharmony_ci ci.format = GetColorFormat(flags, surfaceFormats); 1138bf80f4bSopenharmony_ci ci.colorSpace = VK_COLOR_SPACE_MAX_ENUM_KHR; 1148bf80f4bSopenharmony_ci for (size_t idx = 0; idx < surfaceFormats.size(); ++idx) { 1158bf80f4bSopenharmony_ci if (surfaceFormats[idx].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { 1168bf80f4bSopenharmony_ci ci.colorSpace = surfaceFormats[idx].colorSpace; 1178bf80f4bSopenharmony_ci break; 1188bf80f4bSopenharmony_ci } 1198bf80f4bSopenharmony_ci } 1208bf80f4bSopenharmony_ci PLUGIN_ASSERT_MSG(ci.colorSpace != VK_COLOR_SPACE_MAX_ENUM_KHR, "colorspace not correct"); 1218bf80f4bSopenharmony_ci 1228bf80f4bSopenharmony_ci PLUGIN_ASSERT_MSG(ci.format != VK_FORMAT_UNDEFINED, "colorformat not correct"); 1238bf80f4bSopenharmony_ci PLUGIN_LOG_D("swapchainColorFormat: %u swapchainColorSpace %u", ci.format, ci.colorSpace); 1248bf80f4bSopenharmony_ci 1258bf80f4bSopenharmony_ci return ci; 1268bf80f4bSopenharmony_ci} 1278bf80f4bSopenharmony_ci 1288bf80f4bSopenharmony_ciVkPresentModeKHR GetPresentMode(const VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, const uint32_t flags) 1298bf80f4bSopenharmony_ci{ 1308bf80f4bSopenharmony_ci // Pick a present mode for the swapchain. 1318bf80f4bSopenharmony_ci uint32_t presentModeCount; 1328bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr)); 1338bf80f4bSopenharmony_ci 1348bf80f4bSopenharmony_ci vector<VkPresentModeKHR> presentModes(presentModeCount); 1358bf80f4bSopenharmony_ci VALIDATE_VK_RESULT( 1368bf80f4bSopenharmony_ci vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data())); 1378bf80f4bSopenharmony_ci 1388bf80f4bSopenharmony_ci VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; // FIFO must be supported by the specification. 1398bf80f4bSopenharmony_ci if ((flags & SwapchainFlagBits::CORE_SWAPCHAIN_VSYNC_BIT) != SwapchainFlagBits::CORE_SWAPCHAIN_VSYNC_BIT) { 1408bf80f4bSopenharmony_ci // immediate is really without vsync, but it might not be supported, so we also check for mailbox. 1418bf80f4bSopenharmony_ci if (std::any_of(presentModes.cbegin(), presentModes.cend(), 1428bf80f4bSopenharmony_ci [](const VkPresentModeKHR& supported) { return supported == VK_PRESENT_MODE_IMMEDIATE_KHR; })) { 1438bf80f4bSopenharmony_ci swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; 1448bf80f4bSopenharmony_ci } else if (std::any_of(presentModes.cbegin(), presentModes.cend(), 1458bf80f4bSopenharmony_ci [](const VkPresentModeKHR& supported) { return supported == VK_PRESENT_MODE_MAILBOX_KHR; })) { 1468bf80f4bSopenharmony_ci swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; 1478bf80f4bSopenharmony_ci } 1488bf80f4bSopenharmony_ci } 1498bf80f4bSopenharmony_ci 1508bf80f4bSopenharmony_ci#if (RENDER_DEV_ENABLED == 1) 1518bf80f4bSopenharmony_ci constexpr uint32_t strArraySize { 4 }; 1528bf80f4bSopenharmony_ci constexpr string_view presentModeStrings[strArraySize] = { 1538bf80f4bSopenharmony_ci "VK_PRESENT_MODE_IMMEDIATE_KHR", 1548bf80f4bSopenharmony_ci "VK_PRESENT_MODE_MAILBOX_KHR", 1558bf80f4bSopenharmony_ci "VK_PRESENT_MODE_FIFO_KHR", 1568bf80f4bSopenharmony_ci "VK_PRESENT_MODE_FIFO_RELAXED_KHR", 1578bf80f4bSopenharmony_ci }; 1588bf80f4bSopenharmony_ci 1598bf80f4bSopenharmony_ci PLUGIN_LOG_I("Available swapchain present modes:"); 1608bf80f4bSopenharmony_ci for (auto const presentMode : presentModes) { 1618bf80f4bSopenharmony_ci if ((uint32_t)presentMode < strArraySize) { 1628bf80f4bSopenharmony_ci PLUGIN_LOG_I(" %s", presentModeStrings[presentMode].data()); 1638bf80f4bSopenharmony_ci } 1648bf80f4bSopenharmony_ci } 1658bf80f4bSopenharmony_ci PLUGIN_LOG_I("Selected swapchain present modes:"); 1668bf80f4bSopenharmony_ci if ((uint32_t)swapchainPresentMode < strArraySize) { 1678bf80f4bSopenharmony_ci PLUGIN_LOG_I(" %s", presentModeStrings[swapchainPresentMode].data()); 1688bf80f4bSopenharmony_ci } 1698bf80f4bSopenharmony_ci#else 1708bf80f4bSopenharmony_ci PLUGIN_LOG_D("swapchainPresentMode: %x", swapchainPresentMode); 1718bf80f4bSopenharmony_ci#endif 1728bf80f4bSopenharmony_ci 1738bf80f4bSopenharmony_ci return swapchainPresentMode; 1748bf80f4bSopenharmony_ci} 1758bf80f4bSopenharmony_ci 1768bf80f4bSopenharmony_civoid ClampSwapchainExtent(const VkSurfaceCapabilitiesKHR& surfaceCapabilities, VkExtent2D& extent) 1778bf80f4bSopenharmony_ci{ 1788bf80f4bSopenharmony_ci extent.width = 1798bf80f4bSopenharmony_ci std::clamp(extent.width, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width); 1808bf80f4bSopenharmony_ci extent.height = 1818bf80f4bSopenharmony_ci std::clamp(extent.height, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height); 1828bf80f4bSopenharmony_ci 1838bf80f4bSopenharmony_ci PLUGIN_LOG_D("swapchainExtent: %u x %u", extent.width, extent.height); 1848bf80f4bSopenharmony_ci if ((extent.width == 0) || (extent.height == 0)) { 1858bf80f4bSopenharmony_ci PLUGIN_LOG_E( 1868bf80f4bSopenharmony_ci "zero sized swapchain cannot be created in vulkan (width: %u, height: %u)", extent.width, extent.height); 1878bf80f4bSopenharmony_ci PLUGIN_LOG_E("using 1x1 swapchain"); 1888bf80f4bSopenharmony_ci PLUGIN_ASSERT(false); 1898bf80f4bSopenharmony_ci extent.width = 1; 1908bf80f4bSopenharmony_ci extent.height = 1; 1918bf80f4bSopenharmony_ci } 1928bf80f4bSopenharmony_ci} 1938bf80f4bSopenharmony_ci 1948bf80f4bSopenharmony_ciconstexpr GpuImageDesc GetColorDesc( 1958bf80f4bSopenharmony_ci const uint32_t width, const uint32_t height, const Format format, const ImageUsageFlags imageUsageFlags) 1968bf80f4bSopenharmony_ci{ 1978bf80f4bSopenharmony_ci return { 1988bf80f4bSopenharmony_ci ImageType::CORE_IMAGE_TYPE_2D, // imageType 1998bf80f4bSopenharmony_ci ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, // imageViewType 2008bf80f4bSopenharmony_ci format, // format 2018bf80f4bSopenharmony_ci ImageTiling::CORE_IMAGE_TILING_OPTIMAL, // imageTiling 2028bf80f4bSopenharmony_ci imageUsageFlags, // usageFlags 2038bf80f4bSopenharmony_ci MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, // memoryPropertyFlags 2048bf80f4bSopenharmony_ci 0, // createFlags 2058bf80f4bSopenharmony_ci EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS | 2068bf80f4bSopenharmony_ci EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS, // engineCreationFlags 2078bf80f4bSopenharmony_ci width, // width 2088bf80f4bSopenharmony_ci height, // height 2098bf80f4bSopenharmony_ci 1, // depth 2108bf80f4bSopenharmony_ci 1, // mipCount 2118bf80f4bSopenharmony_ci 1, // layerCount 2128bf80f4bSopenharmony_ci SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT, // sampleCountFlags 2138bf80f4bSopenharmony_ci {}, // componentMapping 2148bf80f4bSopenharmony_ci }; 2158bf80f4bSopenharmony_ci} 2168bf80f4bSopenharmony_ci 2178bf80f4bSopenharmony_ciconstexpr GpuImageDesc GetDepthDesc(const uint32_t width, const uint32_t height, const Format format) 2188bf80f4bSopenharmony_ci{ 2198bf80f4bSopenharmony_ci return { 2208bf80f4bSopenharmony_ci ImageType::CORE_IMAGE_TYPE_2D, // imageType 2218bf80f4bSopenharmony_ci ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, // imageViewType 2228bf80f4bSopenharmony_ci format, // format 2238bf80f4bSopenharmony_ci ImageTiling::CORE_IMAGE_TILING_OPTIMAL, // imageTiling 2248bf80f4bSopenharmony_ci ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | 2258bf80f4bSopenharmony_ci ImageUsageFlagBits::CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | 2268bf80f4bSopenharmony_ci ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, // usageFlags 2278bf80f4bSopenharmony_ci MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | 2288bf80f4bSopenharmony_ci MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT, // memoryPropertyFlags 2298bf80f4bSopenharmony_ci 0, // createFlags 2308bf80f4bSopenharmony_ci EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, // engineCreationFlags 2318bf80f4bSopenharmony_ci width, // width 2328bf80f4bSopenharmony_ci height, // height 2338bf80f4bSopenharmony_ci 1, // depth 2348bf80f4bSopenharmony_ci 1, // mipCount 2358bf80f4bSopenharmony_ci 1, // layerCount 2368bf80f4bSopenharmony_ci SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT, // sampleCountFlags 2378bf80f4bSopenharmony_ci {}, // componentMapping 2388bf80f4bSopenharmony_ci }; 2398bf80f4bSopenharmony_ci} 2408bf80f4bSopenharmony_ci} // namespace 2418bf80f4bSopenharmony_ci 2428bf80f4bSopenharmony_ciSwapchainVk::SwapchainVk(Device& device, const SwapchainCreateInfo& swapchainCreateInfo) 2438bf80f4bSopenharmony_ci : device_(device), flags_(swapchainCreateInfo.swapchainFlags) 2448bf80f4bSopenharmony_ci{ 2458bf80f4bSopenharmony_ci const auto& devicePlatformData = (const DevicePlatformDataVk&)device_.GetPlatformData(); 2468bf80f4bSopenharmony_ci auto const physicalDevice = devicePlatformData.physicalDevice; 2478bf80f4bSopenharmony_ci // check for surface creation automatically 2488bf80f4bSopenharmony_ci if ((swapchainCreateInfo.surfaceHandle == 0) && swapchainCreateInfo.window.window) { 2498bf80f4bSopenharmony_ci CreateFunctionsVk::Window win; 2508bf80f4bSopenharmony_ci win.instance = swapchainCreateInfo.window.instance; 2518bf80f4bSopenharmony_ci win.window = swapchainCreateInfo.window.window; 2528bf80f4bSopenharmony_ci surface_ = CreateFunctionsVk::CreateSurface(devicePlatformData.instance, win); 2538bf80f4bSopenharmony_ci ownsSurface_ = true; 2548bf80f4bSopenharmony_ci } else { 2558bf80f4bSopenharmony_ci surface_ = VulkanHandleCast<VkSurfaceKHR>(swapchainCreateInfo.surfaceHandle); 2568bf80f4bSopenharmony_ci } 2578bf80f4bSopenharmony_ci 2588bf80f4bSopenharmony_ci if (surface_ != VK_NULL_HANDLE) { 2598bf80f4bSopenharmony_ci auto const vkDevice = devicePlatformData.device; 2608bf80f4bSopenharmony_ci 2618bf80f4bSopenharmony_ci // Sanity check that the device can use the surface. 2628bf80f4bSopenharmony_ci // NOTE: queuFamilyIndex hardcoded, should come via devicePlatformData? 2638bf80f4bSopenharmony_ci VkBool32 surfaceSupported = VK_FALSE; 2648bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, 0, surface_, &surfaceSupported)); 2658bf80f4bSopenharmony_ci PLUGIN_ASSERT_MSG(surfaceSupported != VK_FALSE, "physicalDevice doesn't support given surface"); 2668bf80f4bSopenharmony_ci 2678bf80f4bSopenharmony_ci const ColorInfo ci = GetColorInfo(physicalDevice, surface_, flags_); 2688bf80f4bSopenharmony_ci 2698bf80f4bSopenharmony_ci const VkPresentModeKHR swapchainPresentMode = GetPresentMode(physicalDevice, surface_, flags_); 2708bf80f4bSopenharmony_ci // Pick an extent, image count, and transform for the swapchain. 2718bf80f4bSopenharmony_ci VkSurfaceCapabilitiesKHR surfaceCapabilities; 2728bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface_, &surfaceCapabilities)); 2738bf80f4bSopenharmony_ci 2748bf80f4bSopenharmony_ci // NOTE: how do we handle the special case of 0xffffffffff which means the extent should be defined by the 2758bf80f4bSopenharmony_ci // swapchain? 2768bf80f4bSopenharmony_ci VkExtent2D swapchainExtent = surfaceCapabilities.currentExtent; 2778bf80f4bSopenharmony_ci ClampSwapchainExtent(surfaceCapabilities, swapchainExtent); 2788bf80f4bSopenharmony_ci plat_.swapchainImages.width = swapchainExtent.width; 2798bf80f4bSopenharmony_ci plat_.swapchainImages.height = swapchainExtent.height; 2808bf80f4bSopenharmony_ci 2818bf80f4bSopenharmony_ci const DeviceConfiguration deviceConfig = device_.GetDeviceConfiguration(); 2828bf80f4bSopenharmony_ci // surfaceCapabilities.maxImageCount of zero means that there is no limit 2838bf80f4bSopenharmony_ci const uint32_t imageCount = 2848bf80f4bSopenharmony_ci (surfaceCapabilities.maxImageCount == 0) 2858bf80f4bSopenharmony_ci ? (Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount)) 2868bf80f4bSopenharmony_ci : (Math::min(surfaceCapabilities.maxImageCount, 2878bf80f4bSopenharmony_ci Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount))); 2888bf80f4bSopenharmony_ci PLUGIN_LOG_D("swapchainImageCount: %u", imageCount); 2898bf80f4bSopenharmony_ci 2908bf80f4bSopenharmony_ci const VkSurfaceTransformFlagsKHR swapchainTransform = 2918bf80f4bSopenharmony_ci (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) 2928bf80f4bSopenharmony_ci ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR 2938bf80f4bSopenharmony_ci : surfaceCapabilities.currentTransform; 2948bf80f4bSopenharmony_ci 2958bf80f4bSopenharmony_ci const VkImageUsageFlags desiredUsageFlags = static_cast<VkImageUsageFlags>(swapchainCreateInfo.imageUsageFlags); 2968bf80f4bSopenharmony_ci const VkImageUsageFlags imageUsageFlags = desiredUsageFlags & surfaceCapabilities.supportedUsageFlags; 2978bf80f4bSopenharmony_ci PLUGIN_LOG_D("swapchain usage flags, selected: %u, desired: %u, capabilities: %u", imageUsageFlags, 2988bf80f4bSopenharmony_ci desiredUsageFlags, surfaceCapabilities.supportedUsageFlags); 2998bf80f4bSopenharmony_ci 3008bf80f4bSopenharmony_ci VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; 3018bf80f4bSopenharmony_ci if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { 3028bf80f4bSopenharmony_ci compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 3038bf80f4bSopenharmony_ci } 3048bf80f4bSopenharmony_ci 3058bf80f4bSopenharmony_ci VkSwapchainCreateInfoKHR const vkSwapchainCreateInfo { 3068bf80f4bSopenharmony_ci VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, // sType 3078bf80f4bSopenharmony_ci nullptr, // pNext 3088bf80f4bSopenharmony_ci 0, // flags 3098bf80f4bSopenharmony_ci surface_, // surface 3108bf80f4bSopenharmony_ci imageCount, // minImageCount 3118bf80f4bSopenharmony_ci ci.format, // imageFormat 3128bf80f4bSopenharmony_ci ci.colorSpace, // imageColorSpace 3138bf80f4bSopenharmony_ci swapchainExtent, // imageExtent 3148bf80f4bSopenharmony_ci 1, // imageArrayLayers 3158bf80f4bSopenharmony_ci imageUsageFlags, // imageUsage 3168bf80f4bSopenharmony_ci VK_SHARING_MODE_EXCLUSIVE, // imageSharingMode 3178bf80f4bSopenharmony_ci 0, // queueFamilyIndexCount 3188bf80f4bSopenharmony_ci nullptr, // pQueueFamilyIndices 3198bf80f4bSopenharmony_ci (VkSurfaceTransformFlagBitsKHR)swapchainTransform, // preTransform 3208bf80f4bSopenharmony_ci compositeAlpha, // compositeAlpha 3218bf80f4bSopenharmony_ci swapchainPresentMode, // presentMode 3228bf80f4bSopenharmony_ci VK_TRUE, // clipped 3238bf80f4bSopenharmony_ci VK_NULL_HANDLE, // oldSwapchain 3248bf80f4bSopenharmony_ci }; 3258bf80f4bSopenharmony_ci 3268bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfo, nullptr, &plat_.swapchain)); 3278bf80f4bSopenharmony_ci 3288bf80f4bSopenharmony_ci { 3298bf80f4bSopenharmony_ci uint32_t realImageCount = 0; 3308bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkGetSwapchainImagesKHR(vkDevice, // device 3318bf80f4bSopenharmony_ci plat_.swapchain, // swapchain 3328bf80f4bSopenharmony_ci &realImageCount, // pSwapchainImageCount 3338bf80f4bSopenharmony_ci nullptr)); // pSwapchainImages 3348bf80f4bSopenharmony_ci 3358bf80f4bSopenharmony_ci PLUGIN_LOG_D("swapchain realImageCount: %u", realImageCount); 3368bf80f4bSopenharmony_ci 3378bf80f4bSopenharmony_ci plat_.swapchainImages.images.resize(realImageCount); 3388bf80f4bSopenharmony_ci plat_.swapchainImages.imageViews.resize(realImageCount); 3398bf80f4bSopenharmony_ci plat_.swapchainImages.semaphores.resize(realImageCount); 3408bf80f4bSopenharmony_ci 3418bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkGetSwapchainImagesKHR(vkDevice, // device 3428bf80f4bSopenharmony_ci plat_.swapchain, // swapchain 3438bf80f4bSopenharmony_ci &realImageCount, // pSwapchainImageCount 3448bf80f4bSopenharmony_ci plat_.swapchainImages.images.data())); // pSwapchainImages 3458bf80f4bSopenharmony_ci 3468bf80f4bSopenharmony_ci constexpr VkComponentMapping componentMapping { 3478bf80f4bSopenharmony_ci VK_COMPONENT_SWIZZLE_IDENTITY, // r 3488bf80f4bSopenharmony_ci VK_COMPONENT_SWIZZLE_IDENTITY, // g 3498bf80f4bSopenharmony_ci VK_COMPONENT_SWIZZLE_IDENTITY, // b 3508bf80f4bSopenharmony_ci VK_COMPONENT_SWIZZLE_IDENTITY, // a 3518bf80f4bSopenharmony_ci }; 3528bf80f4bSopenharmony_ci constexpr VkImageSubresourceRange imageSubresourceRange { 3538bf80f4bSopenharmony_ci VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask 3548bf80f4bSopenharmony_ci 0, // baseMipLevel 3558bf80f4bSopenharmony_ci 1, // levelCount 3568bf80f4bSopenharmony_ci 0, // baseArrayLayer 3578bf80f4bSopenharmony_ci 1, // layerCount 3588bf80f4bSopenharmony_ci }; 3598bf80f4bSopenharmony_ci 3608bf80f4bSopenharmony_ci constexpr VkSemaphoreCreateFlags semaphoreCreateFlags { 0 }; 3618bf80f4bSopenharmony_ci const VkSemaphoreCreateInfo semaphoreCreateInfo { 3628bf80f4bSopenharmony_ci VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType 3638bf80f4bSopenharmony_ci nullptr, // pNext 3648bf80f4bSopenharmony_ci semaphoreCreateFlags, // flags 3658bf80f4bSopenharmony_ci }; 3668bf80f4bSopenharmony_ci for (uint32_t idx = 0; idx < plat_.swapchainImages.imageViews.size(); ++idx) { 3678bf80f4bSopenharmony_ci const VkImageViewCreateInfo imageViewCreateInfo { 3688bf80f4bSopenharmony_ci VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType 3698bf80f4bSopenharmony_ci nullptr, // pNext 3708bf80f4bSopenharmony_ci 0, // flags 3718bf80f4bSopenharmony_ci plat_.swapchainImages.images[idx], // image 3728bf80f4bSopenharmony_ci VK_IMAGE_VIEW_TYPE_2D, // viewType 3738bf80f4bSopenharmony_ci ci.format, // format 3748bf80f4bSopenharmony_ci componentMapping, // components 3758bf80f4bSopenharmony_ci imageSubresourceRange // subresourceRange; 3768bf80f4bSopenharmony_ci }; 3778bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkCreateImageView(vkDevice, // device 3788bf80f4bSopenharmony_ci &imageViewCreateInfo, // pCreateInfo 3798bf80f4bSopenharmony_ci nullptr, // pAllocator 3808bf80f4bSopenharmony_ci &plat_.swapchainImages.imageViews[idx])); // pView 3818bf80f4bSopenharmony_ci VALIDATE_VK_RESULT(vkCreateSemaphore(vkDevice, // device 3828bf80f4bSopenharmony_ci &semaphoreCreateInfo, // pCreateInfo 3838bf80f4bSopenharmony_ci nullptr, // pAllocator 3848bf80f4bSopenharmony_ci &plat_.swapchainImages.semaphores[idx])); // pSemaphore 3858bf80f4bSopenharmony_ci } 3868bf80f4bSopenharmony_ci } 3878bf80f4bSopenharmony_ci 3888bf80f4bSopenharmony_ci desc_ = GetColorDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, (Format)ci.format, 3898bf80f4bSopenharmony_ci (ImageUsageFlags)imageUsageFlags); 3908bf80f4bSopenharmony_ci 3918bf80f4bSopenharmony_ci if (flags_ & 0x2) { 3928bf80f4bSopenharmony_ci const Format depthFormat = GetValidDepthFormat((const DeviceVk&)device_); 3938bf80f4bSopenharmony_ci descDepthBuffer_ = GetDepthDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, depthFormat); 3948bf80f4bSopenharmony_ci } 3958bf80f4bSopenharmony_ci } else { 3968bf80f4bSopenharmony_ci PLUGIN_LOG_E("Invalid surface in swapchain creation"); 3978bf80f4bSopenharmony_ci } 3988bf80f4bSopenharmony_ci} 3998bf80f4bSopenharmony_ci 4008bf80f4bSopenharmony_ciSwapchainVk::~SwapchainVk() 4018bf80f4bSopenharmony_ci{ 4028bf80f4bSopenharmony_ci const auto& devicePlatformData = (const DevicePlatformDataVk&)device_.GetPlatformData(); 4038bf80f4bSopenharmony_ci const VkDevice device = devicePlatformData.device; 4048bf80f4bSopenharmony_ci for (auto const imageView : plat_.swapchainImages.imageViews) { 4058bf80f4bSopenharmony_ci if (imageView) { 4068bf80f4bSopenharmony_ci vkDestroyImageView(device, // device 4078bf80f4bSopenharmony_ci imageView, // imageView 4088bf80f4bSopenharmony_ci nullptr); // pAllocator 4098bf80f4bSopenharmony_ci } 4108bf80f4bSopenharmony_ci } 4118bf80f4bSopenharmony_ci for (const auto semaphore : plat_.swapchainImages.semaphores) { 4128bf80f4bSopenharmony_ci if (semaphore) { 4138bf80f4bSopenharmony_ci vkDestroySemaphore(device, // device 4148bf80f4bSopenharmony_ci semaphore, // semaphore 4158bf80f4bSopenharmony_ci nullptr); // pAllocator 4168bf80f4bSopenharmony_ci } 4178bf80f4bSopenharmony_ci } 4188bf80f4bSopenharmony_ci 4198bf80f4bSopenharmony_ci CreateFunctionsVk::DestroySwapchain(device, plat_.swapchain); 4208bf80f4bSopenharmony_ci if (ownsSurface_ && surface_) { 4218bf80f4bSopenharmony_ci CreateFunctionsVk::DestroySurface(devicePlatformData.instance, surface_); 4228bf80f4bSopenharmony_ci } 4238bf80f4bSopenharmony_ci} 4248bf80f4bSopenharmony_ci 4258bf80f4bSopenharmony_ciconst SwapchainPlatformDataVk& SwapchainVk::GetPlatformData() const 4268bf80f4bSopenharmony_ci{ 4278bf80f4bSopenharmony_ci return plat_; 4288bf80f4bSopenharmony_ci} 4298bf80f4bSopenharmony_ci 4308bf80f4bSopenharmony_ciconst GpuImageDesc& SwapchainVk::GetDesc() const 4318bf80f4bSopenharmony_ci{ 4328bf80f4bSopenharmony_ci return desc_; 4338bf80f4bSopenharmony_ci} 4348bf80f4bSopenharmony_ci 4358bf80f4bSopenharmony_ciconst GpuImageDesc& SwapchainVk::GetDescDepthBuffer() const 4368bf80f4bSopenharmony_ci{ 4378bf80f4bSopenharmony_ci return descDepthBuffer_; 4388bf80f4bSopenharmony_ci} 4398bf80f4bSopenharmony_ci 4408bf80f4bSopenharmony_ciuint32_t SwapchainVk::GetFlags() const 4418bf80f4bSopenharmony_ci{ 4428bf80f4bSopenharmony_ci return flags_; 4438bf80f4bSopenharmony_ci} 4448bf80f4bSopenharmony_ci 4458bf80f4bSopenharmony_ciSurfaceTransformFlags SwapchainVk::GetSurfaceTransformFlags() const 4468bf80f4bSopenharmony_ci{ 4478bf80f4bSopenharmony_ci return surfaceTransformFlags_; 4488bf80f4bSopenharmony_ci} 4498bf80f4bSopenharmony_ci 4508bf80f4bSopenharmony_ciuint64_t SwapchainVk::GetSurfaceHandle() const 4518bf80f4bSopenharmony_ci{ 4528bf80f4bSopenharmony_ci return VulkanHandleCast<uint64_t>(surface_); 4538bf80f4bSopenharmony_ci} 4548bf80f4bSopenharmony_ci 4558bf80f4bSopenharmony_ciuint32_t SwapchainVk::GetNextAcquireSwapchainSemaphoreIndex() const 4568bf80f4bSopenharmony_ci{ 4578bf80f4bSopenharmony_ci currSemaphoreIdx_ = (currSemaphoreIdx_ + 1) % plat_.swapchainImages.semaphores.size(); 4588bf80f4bSopenharmony_ci return currSemaphoreIdx_; 4598bf80f4bSopenharmony_ci} 4608bf80f4bSopenharmony_ciRENDER_END_NAMESPACE() 461