1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "swapchain_vk.h"
17 
18 #include <algorithm>
19 #include <cstddef>
20 #include <cstdint>
21 #include <vulkan/vulkan_core.h>
22 
23 #include <base/containers/vector.h>
24 #include <base/math/mathf.h>
25 #include <base/util/formats.h>
26 #include <core/intf_engine.h>
27 #include <render/device/gpu_resource_desc.h>
28 #include <render/namespace.h>
29 #include <render/vulkan/intf_device_vk.h>
30 
31 #include "util/log.h"
32 #include "vulkan/create_functions_vk.h"
33 #include "vulkan/device_vk.h"
34 #include "vulkan/validate_vk.h"
35 
36 using namespace BASE_NS;
37 
38 RENDER_BEGIN_NAMESPACE()
39 namespace {
GetValidDepthFormat(const DeviceVk & deviceVk)40 Format GetValidDepthFormat(const DeviceVk& deviceVk)
41 {
42     constexpr uint32_t PREFERRED_FORMAT_COUNT { 3 };
43     constexpr Format preferredFormats[PREFERRED_FORMAT_COUNT] = { BASE_FORMAT_D24_UNORM_S8_UINT, BASE_FORMAT_D32_SFLOAT,
44         BASE_FORMAT_D16_UNORM };
45 #ifndef NDEBUG
46     constexpr string_view PREFERRED_FORMAT_NAMES[PREFERRED_FORMAT_COUNT] = { "BASE_FORMAT_D24_UNORM_S8_UINT",
47         "BASE_FORMAT_D32_SFLOAT", "BASE_FORMAT_D16_UNORM" };
48 #endif
49     Format finalFormat = BASE_FORMAT_UNDEFINED;
50     const auto& devPlat = deviceVk.GetPlatformInternalDataVk();
51     for (uint32_t idx = 0; idx < PREFERRED_FORMAT_COUNT; ++idx) {
52         finalFormat = preferredFormats[idx];
53         for (const auto& supportedDepthFormat : devPlat.supportedDepthFormats) {
54             if (finalFormat == supportedDepthFormat) {
55 #ifndef NDEBUG
56                 PLUGIN_LOG_D(
57                     "selected CORE_DEFAULT_BACKBUFFER format: %s", string(PREFERRED_FORMAT_NAMES[idx]).c_str());
58 #endif
59                 idx = PREFERRED_FORMAT_COUNT;
60                 break;
61             }
62         }
63     }
64     return finalFormat;
65 }
66 
67 struct ColorInfo {
68     VkFormat format { VK_FORMAT_UNDEFINED };
69     VkColorSpaceKHR colorSpace { VK_COLOR_SPACE_MAX_ENUM_KHR };
70 };
71 
GetColorFormat(const uint32_t flags,const vector<VkSurfaceFormatKHR> & surfaceFormats)72 VkFormat GetColorFormat(const uint32_t flags, const vector<VkSurfaceFormatKHR>& surfaceFormats)
73 {
74     constexpr uint32_t preferredFormatCount { 4u };
75     constexpr VkFormat srgbFormats[preferredFormatCount] = { VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB,
76         VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM };
77     constexpr VkFormat nonSrgbFormats[preferredFormatCount] = { VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8A8_UNORM,
78         VK_FORMAT_R8G8B8A8_SRGB, VK_FORMAT_B8G8R8A8_SRGB };
79 
80     const bool preferSrgbFormat = (flags & SwapchainFlagBits::CORE_SWAPCHAIN_SRGB_BIT);
81     const array_view<const VkFormat> formats =
82         (preferSrgbFormat) ? array_view<const VkFormat> { srgbFormats, preferredFormatCount }
83                            : array_view<const VkFormat> { nonSrgbFormats, preferredFormatCount };
84 
85     // If pSurfaceFormats includes just one entry, whose value for format is VK_FORMAT_UNDEFINED,
86     // surface has no preferred format. In this case, the application can use any valid VkFormat value.
87     if (surfaceFormats[0].format == VK_FORMAT_UNDEFINED && surfaceFormats.size() == 1) {
88         return VK_FORMAT_R8G8B8A8_SRGB;
89     }
90 
91     for (size_t idx = 0; idx < formats.size(); ++idx) {
92         for (size_t jdx = 0; jdx < surfaceFormats.size(); ++jdx) {
93             if (formats[idx] == surfaceFormats[jdx].format) {
94                 return surfaceFormats[jdx].format;
95             }
96         }
97     }
98     return VK_FORMAT_UNDEFINED;
99 }
100 
GetColorInfo(const VkPhysicalDevice physicalDevice,const VkSurfaceKHR surface,const uint32_t flags)101 ColorInfo GetColorInfo(const VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, const uint32_t flags)
102 {
103     // Pick a color format for the swapchain.
104     uint32_t surfaceFormatsCount = 0;
105     VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, nullptr));
106 
107     vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatsCount);
108     VALIDATE_VK_RESULT(
109         vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, surfaceFormats.data()));
110 
111     ColorInfo ci;
112     ci.format = GetColorFormat(flags, surfaceFormats);
113     ci.colorSpace = VK_COLOR_SPACE_MAX_ENUM_KHR;
114     for (size_t idx = 0; idx < surfaceFormats.size(); ++idx) {
115         if (surfaceFormats[idx].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
116             ci.colorSpace = surfaceFormats[idx].colorSpace;
117             break;
118         }
119     }
120     PLUGIN_ASSERT_MSG(ci.colorSpace != VK_COLOR_SPACE_MAX_ENUM_KHR, "colorspace not correct");
121 
122     PLUGIN_ASSERT_MSG(ci.format != VK_FORMAT_UNDEFINED, "colorformat not correct");
123     PLUGIN_LOG_D("swapchainColorFormat: %u swapchainColorSpace %u", ci.format, ci.colorSpace);
124 
125     return ci;
126 }
127 
GetPresentMode(const VkPhysicalDevice physicalDevice,const VkSurfaceKHR surface,const uint32_t flags)128 VkPresentModeKHR GetPresentMode(const VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, const uint32_t flags)
129 {
130     // Pick a present mode for the swapchain.
131     uint32_t presentModeCount;
132     VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr));
133 
134     vector<VkPresentModeKHR> presentModes(presentModeCount);
135     VALIDATE_VK_RESULT(
136         vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()));
137 
138     VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; // FIFO must be supported by the specification.
139     if ((flags & SwapchainFlagBits::CORE_SWAPCHAIN_VSYNC_BIT) != SwapchainFlagBits::CORE_SWAPCHAIN_VSYNC_BIT) {
140         // immediate is really without vsync, but it might not be supported, so we also check for mailbox.
141         if (std::any_of(presentModes.cbegin(), presentModes.cend(),
142                 [](const VkPresentModeKHR& supported) { return supported == VK_PRESENT_MODE_IMMEDIATE_KHR; })) {
143             swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
144         } else if (std::any_of(presentModes.cbegin(), presentModes.cend(),
145                        [](const VkPresentModeKHR& supported) { return supported == VK_PRESENT_MODE_MAILBOX_KHR; })) {
146             swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
147         }
148     }
149 
150 #if (RENDER_DEV_ENABLED == 1)
151     constexpr uint32_t strArraySize { 4 };
152     constexpr string_view presentModeStrings[strArraySize] = {
153         "VK_PRESENT_MODE_IMMEDIATE_KHR",
154         "VK_PRESENT_MODE_MAILBOX_KHR",
155         "VK_PRESENT_MODE_FIFO_KHR",
156         "VK_PRESENT_MODE_FIFO_RELAXED_KHR",
157     };
158 
159     PLUGIN_LOG_I("Available swapchain present modes:");
160     for (auto const presentMode : presentModes) {
161         if (static_cast<uint32_t>(presentMode) < strArraySize) {
162             PLUGIN_LOG_I("  %s", presentModeStrings[presentMode].data());
163         }
164     }
165     PLUGIN_LOG_I("Selected swapchain present modes:");
166     if (static_cast<uint32_t>(swapchainPresentMode) < strArraySize) {
167         PLUGIN_LOG_I("  %s", presentModeStrings[swapchainPresentMode].data());
168     }
169 #else
170     PLUGIN_LOG_D("swapchainPresentMode: %x", swapchainPresentMode);
171 #endif
172 
173     return swapchainPresentMode;
174 }
175 
ClampSwapchainExtent(const VkSurfaceCapabilitiesKHR & surfaceCapabilities,VkExtent2D & extent)176 void ClampSwapchainExtent(const VkSurfaceCapabilitiesKHR& surfaceCapabilities, VkExtent2D& extent)
177 {
178     extent.width =
179         std::clamp(extent.width, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width);
180     extent.height =
181         std::clamp(extent.height, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height);
182 
183     PLUGIN_LOG_D("swapchainExtent: %u x %u", extent.width, extent.height);
184     if ((extent.width == 0) || (extent.height == 0)) {
185         PLUGIN_LOG_E(
186             "zero sized swapchain cannot be created in vulkan (width: %u, height: %u)", extent.width, extent.height);
187         PLUGIN_LOG_E("using 1x1 swapchain");
188         PLUGIN_ASSERT(false);
189         extent.width = 1;
190         extent.height = 1;
191     }
192 }
193 
GetColorDesc(const uint32_t width,const uint32_t height,const Format format,const ImageUsageFlags imageUsageFlags)194 constexpr GpuImageDesc GetColorDesc(
195     const uint32_t width, const uint32_t height, const Format format, const ImageUsageFlags imageUsageFlags)
196 {
197     return {
198         ImageType::CORE_IMAGE_TYPE_2D,                                 // imageType
199         ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,                        // imageViewType
200         format,                                                        // format
201         ImageTiling::CORE_IMAGE_TILING_OPTIMAL,                        // imageTiling
202         imageUsageFlags,                                               // usageFlags
203         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, // memoryPropertyFlags
204         0,                                                             // createFlags
205         EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS |
206             EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS, // engineCreationFlags
207         width,                                                                                    // width
208         height,                                                                                   // height
209         1,                                                                                        // depth
210         1,                                                                                        // mipCount
211         1,                                                                                        // layerCount
212         SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,                                             // sampleCountFlags
213         {},                                                                                       // componentMapping
214     };
215 }
216 
GetDepthDesc(const uint32_t width,const uint32_t height,const Format format)217 constexpr GpuImageDesc GetDepthDesc(const uint32_t width, const uint32_t height, const Format format)
218 {
219     return {
220         ImageType::CORE_IMAGE_TYPE_2D,          // imageType
221         ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, // imageViewType
222         format,                                 // format
223         ImageTiling::CORE_IMAGE_TILING_OPTIMAL, // imageTiling
224         ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
225             ImageUsageFlagBits::CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
226             ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, // usageFlags
227         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
228             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,    // memoryPropertyFlags
229         0,                                                                        // createFlags
230         EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, // engineCreationFlags
231         width,                                                                    // width
232         height,                                                                   // height
233         1,                                                                        // depth
234         1,                                                                        // mipCount
235         1,                                                                        // layerCount
236         SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,                             // sampleCountFlags
237         {},                                                                       // componentMapping
238     };
239 }
240 } // namespace
241 
SwapchainVk(Device & device,const SwapchainCreateInfo & swapchainCreateInfo)242 SwapchainVk::SwapchainVk(Device& device, const SwapchainCreateInfo& swapchainCreateInfo)
243     : device_(device), flags_(swapchainCreateInfo.swapchainFlags)
244 {
245     const auto& devicePlatformData = (const DevicePlatformDataVk&)device_.GetPlatformData();
246     auto const physicalDevice = devicePlatformData.physicalDevice;
247     // check for surface creation automatically
248     if ((swapchainCreateInfo.surfaceHandle == 0) && swapchainCreateInfo.window.window) {
249         CreateFunctionsVk::Window win;
250         win.instance = swapchainCreateInfo.window.instance;
251         win.window = swapchainCreateInfo.window.window;
252         surface_ = CreateFunctionsVk::CreateSurface(devicePlatformData.instance, win);
253         ownsSurface_ = true;
254     } else {
255         surface_ = VulkanHandleCast<VkSurfaceKHR>(swapchainCreateInfo.surfaceHandle);
256     }
257 
258     if (surface_ != VK_NULL_HANDLE) {
259         auto const vkDevice = devicePlatformData.device;
260 
261         // Sanity check that the device can use the surface.
262         // NOTE: queuFamilyIndex hardcoded, should come via devicePlatformData?
263         VkBool32 surfaceSupported = VK_FALSE;
264         VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, 0, surface_, &surfaceSupported));
265         PLUGIN_ASSERT_MSG(surfaceSupported != VK_FALSE, "physicalDevice doesn't support given surface");
266 
267         const ColorInfo ci = GetColorInfo(physicalDevice, surface_, flags_);
268 
269         const VkPresentModeKHR swapchainPresentMode = GetPresentMode(physicalDevice, surface_, flags_);
270         // Pick an extent, image count, and transform for the swapchain.
271         VkSurfaceCapabilitiesKHR surfaceCapabilities;
272         VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface_, &surfaceCapabilities));
273 
274         // NOTE: how do we handle the special case of 0xffffffffff which means the extent should be defined by the
275         // swapchain?
276         VkExtent2D swapchainExtent = surfaceCapabilities.currentExtent;
277         ClampSwapchainExtent(surfaceCapabilities, swapchainExtent);
278         plat_.swapchainImages.width = swapchainExtent.width;
279         plat_.swapchainImages.height = swapchainExtent.height;
280 
281         const DeviceConfiguration deviceConfig = device_.GetDeviceConfiguration();
282         // surfaceCapabilities.maxImageCount of zero means that there is no limit
283         const uint32_t imageCount =
284             (surfaceCapabilities.maxImageCount == 0)
285                 ? (Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount))
286                 : (Math::min(surfaceCapabilities.maxImageCount,
287                     Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount)));
288         PLUGIN_LOG_D("swapchainImageCount: %u", imageCount);
289 
290         const VkSurfaceTransformFlagsKHR swapchainTransform =
291             (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
292                 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
293                 : surfaceCapabilities.currentTransform;
294 
295         const VkImageUsageFlags desiredUsageFlags = static_cast<VkImageUsageFlags>(swapchainCreateInfo.imageUsageFlags);
296         const VkImageUsageFlags imageUsageFlags = desiredUsageFlags & surfaceCapabilities.supportedUsageFlags;
297         PLUGIN_LOG_D("swapchain usage flags, selected: %u, desired: %u, capabilities: %u", imageUsageFlags,
298             desiredUsageFlags, surfaceCapabilities.supportedUsageFlags);
299 
300         VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
301         if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
302             compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
303         }
304 
305         VkSwapchainCreateInfoKHR const vkSwapchainCreateInfo {
306             VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,       // sType
307             nullptr,                                           // pNext
308             0,                                                 // flags
309             surface_,                                          // surface
310             imageCount,                                        // minImageCount
311             ci.format,                                         // imageFormat
312             ci.colorSpace,                                     // imageColorSpace
313             swapchainExtent,                                   // imageExtent
314             1,                                                 // imageArrayLayers
315             imageUsageFlags,                                   // imageUsage
316             VK_SHARING_MODE_EXCLUSIVE,                         // imageSharingMode
317             0,                                                 // queueFamilyIndexCount
318             nullptr,                                           // pQueueFamilyIndices
319             (VkSurfaceTransformFlagBitsKHR)swapchainTransform, // preTransform
320             compositeAlpha,                                    // compositeAlpha
321             swapchainPresentMode,                              // presentMode
322             VK_TRUE,                                           // clipped
323             VK_NULL_HANDLE,                                    // oldSwapchain
324         };
325 
326         VALIDATE_VK_RESULT(vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfo, nullptr, &plat_.swapchain));
327 
328         {
329             uint32_t realImageCount = 0;
330             VALIDATE_VK_RESULT(vkGetSwapchainImagesKHR(vkDevice, // device
331                 plat_.swapchain,                                 // swapchain
332                 &realImageCount,                                 // pSwapchainImageCount
333                 nullptr));                                       // pSwapchainImages
334 
335             PLUGIN_LOG_D("swapchain realImageCount: %u", realImageCount);
336 
337             plat_.swapchainImages.images.resize(realImageCount);
338             plat_.swapchainImages.imageViews.resize(realImageCount);
339             plat_.swapchainImages.semaphores.resize(realImageCount);
340 
341             VALIDATE_VK_RESULT(vkGetSwapchainImagesKHR(vkDevice, // device
342                 plat_.swapchain,                                 // swapchain
343                 &realImageCount,                                 // pSwapchainImageCount
344                 plat_.swapchainImages.images.data()));           // pSwapchainImages
345 
346             constexpr VkComponentMapping componentMapping {
347                 VK_COMPONENT_SWIZZLE_IDENTITY, // r
348                 VK_COMPONENT_SWIZZLE_IDENTITY, // g
349                 VK_COMPONENT_SWIZZLE_IDENTITY, // b
350                 VK_COMPONENT_SWIZZLE_IDENTITY, // a
351             };
352             constexpr VkImageSubresourceRange imageSubresourceRange {
353                 VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
354                 0,                         // baseMipLevel
355                 1,                         // levelCount
356                 0,                         // baseArrayLayer
357                 1,                         // layerCount
358             };
359 
360             constexpr VkSemaphoreCreateFlags semaphoreCreateFlags { 0 };
361             const VkSemaphoreCreateInfo semaphoreCreateInfo {
362                 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType
363                 nullptr,                                 // pNext
364                 semaphoreCreateFlags,                    // flags
365             };
366             for (uint32_t idx = 0; idx < plat_.swapchainImages.imageViews.size(); ++idx) {
367                 const VkImageViewCreateInfo imageViewCreateInfo {
368                     VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
369                     nullptr,                                  // pNext
370                     0,                                        // flags
371                     plat_.swapchainImages.images[idx],        // image
372                     VK_IMAGE_VIEW_TYPE_2D,                    // viewType
373                     ci.format,                                // format
374                     componentMapping,                         // components
375                     imageSubresourceRange                     // subresourceRange;
376                 };
377                 VALIDATE_VK_RESULT(vkCreateImageView(vkDevice, // device
378                     &imageViewCreateInfo,                      // pCreateInfo
379                     nullptr,                                   // pAllocator
380                     &plat_.swapchainImages.imageViews[idx]));  // pView
381                 VALIDATE_VK_RESULT(vkCreateSemaphore(vkDevice, // device
382                     &semaphoreCreateInfo,                      // pCreateInfo
383                     nullptr,                                   // pAllocator
384                     &plat_.swapchainImages.semaphores[idx]));  // pSemaphore
385             }
386         }
387 
388         desc_ = GetColorDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, (Format)ci.format,
389             (ImageUsageFlags)imageUsageFlags);
390 
391         if (flags_ & 0x2) {
392             const Format depthFormat = GetValidDepthFormat((const DeviceVk&)device_);
393             descDepthBuffer_ = GetDepthDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, depthFormat);
394         }
395     } else {
396         PLUGIN_LOG_E("Invalid surface in swapchain creation");
397     }
398 }
399 
~SwapchainVk()400 SwapchainVk::~SwapchainVk()
401 {
402     const auto& devicePlatformData = (const DevicePlatformDataVk&)device_.GetPlatformData();
403     const VkDevice device = devicePlatformData.device;
404     for (auto const imageView : plat_.swapchainImages.imageViews) {
405         if (imageView) {
406             vkDestroyImageView(device, // device
407                 imageView,             // imageView
408                 nullptr);              // pAllocator
409         }
410     }
411     for (const auto semaphore : plat_.swapchainImages.semaphores) {
412         if (semaphore) {
413             vkDestroySemaphore(device, // device
414                 semaphore,             // semaphore
415                 nullptr);              // pAllocator
416         }
417     }
418 
419     CreateFunctionsVk::DestroySwapchain(device, plat_.swapchain);
420     if (ownsSurface_ && surface_) {
421         CreateFunctionsVk::DestroySurface(devicePlatformData.instance, surface_);
422     }
423 }
424 
GetPlatformData() const425 const SwapchainPlatformDataVk& SwapchainVk::GetPlatformData() const
426 {
427     return plat_;
428 }
429 
GetDesc() const430 const GpuImageDesc& SwapchainVk::GetDesc() const
431 {
432     return desc_;
433 }
434 
GetDescDepthBuffer() const435 const GpuImageDesc& SwapchainVk::GetDescDepthBuffer() const
436 {
437     return descDepthBuffer_;
438 }
439 
GetFlags() const440 uint32_t SwapchainVk::GetFlags() const
441 {
442     return flags_;
443 }
444 
GetSurfaceTransformFlags() const445 SurfaceTransformFlags SwapchainVk::GetSurfaceTransformFlags() const
446 {
447     return surfaceTransformFlags_;
448 }
449 
GetSurfaceHandle() const450 uint64_t SwapchainVk::GetSurfaceHandle() const
451 {
452     return VulkanHandleCast<uint64_t>(surface_);
453 }
454 
GetNextAcquireSwapchainSemaphoreIndex() const455 uint32_t SwapchainVk::GetNextAcquireSwapchainSemaphoreIndex() const
456 {
457     currSemaphoreIdx_ = (currSemaphoreIdx_ + 1) % plat_.swapchainImages.semaphores.size();
458     return currSemaphoreIdx_;
459 }
460 RENDER_END_NAMESPACE()
461