• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (auto format : formats) {
92         for (auto surfaceFormat : surfaceFormats) {
93             if (format == surfaceFormat.format) {
94                 return surfaceFormat.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 (auto& surfaceFormat : surfaceFormats) {
115         if (surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
116             ci.colorSpace = surfaceFormat.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_E("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 ((uint32_t)presentMode < strArraySize) {
162             PLUGIN_LOG_I("  %s", presentModeStrings[presentMode].data());
163         }
164     }
165     PLUGIN_LOG_I("Selected swapchain present modes:");
166     if ((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 { swapchainCreateInfo.window.instance, swapchainCreateInfo.window.window };
250         surface_ = CreateFunctionsVk::CreateSurface(devicePlatformData.instance, win);
251         ownsSurface_ = true;
252     } else {
253         surface_ = VulkanHandleCast<VkSurfaceKHR>(swapchainCreateInfo.surfaceHandle);
254     }
255 
256     if (surface_ != VK_NULL_HANDLE) {
257         auto const vkDevice = devicePlatformData.device;
258 
259         // Sanity check that the device can use the surface.
260         // NOTE: queuFamilyIndex hardcoded, should come via devicePlatformData?
261         VkBool32 surfaceSupported = VK_FALSE;
262         VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, 0, surface_, &surfaceSupported));
263         PLUGIN_ASSERT_MSG(surfaceSupported != VK_FALSE, "physicalDevice doesn't support given surface");
264 
265         const ColorInfo ci = GetColorInfo(physicalDevice, surface_, flags_);
266 
267         const VkPresentModeKHR swapchainPresentMode = GetPresentMode(physicalDevice, surface_, flags_);
268         // Pick an extent, image count, and transform for the swapchain.
269         VkSurfaceCapabilitiesKHR surfaceCapabilities;
270         VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface_, &surfaceCapabilities));
271 
272         // NOTE: how do we handle the special case of 0xffffffffff which means the extent should be defined by the
273         // swapchain?
274         VkExtent2D swapchainExtent = surfaceCapabilities.currentExtent;
275         ClampSwapchainExtent(surfaceCapabilities, swapchainExtent);
276         plat_.swapchainImages.width = swapchainExtent.width;
277         plat_.swapchainImages.height = swapchainExtent.height;
278 
279         const DeviceConfiguration deviceConfig = device_.GetDeviceConfiguration();
280         // surfaceCapabilities.maxImageCount of zero means that there is no limit
281         const uint32_t imageCount =
282             (surfaceCapabilities.maxImageCount == 0)
283                 ? (Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount))
284                 : (Math::min(surfaceCapabilities.maxImageCount,
285                    Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount)));
286         PLUGIN_LOG_D("swapchainImageCount: %u", imageCount);
287 
288         const VkSurfaceTransformFlagsKHR swapchainTransform =
289             (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
290                 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
291                 : surfaceCapabilities.currentTransform;
292 
293         const auto desiredUsageFlags = static_cast<VkImageUsageFlags>(swapchainCreateInfo.imageUsageFlags);
294         const VkImageUsageFlags imageUsageFlags = desiredUsageFlags & surfaceCapabilities.supportedUsageFlags;
295         PLUGIN_LOG_D("swapchain usage flags, selected: %u, desired: %u, capabilities: %u", imageUsageFlags,
296             desiredUsageFlags, surfaceCapabilities.supportedUsageFlags);
297 
298         VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
299         if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
300             compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
301         }
302 
303         VkSwapchainCreateInfoKHR const vkSwapchainCreateInfo {
304             VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,       // sType
305             nullptr,                                           // pNext
306             0,                                                 // flags
307             surface_,                                          // surface
308             imageCount,                                        // minImageCount
309             ci.format,                                         // imageFormat
310             ci.colorSpace,                                     // imageColorSpace
311             swapchainExtent,                                   // imageExtent
312             1,                                                 // imageArrayLayers
313             imageUsageFlags,                                   // imageUsage
314             VK_SHARING_MODE_EXCLUSIVE,                         // imageSharingMode
315             0,                                                 // queueFamilyIndexCount
316             nullptr,                                           // pQueueFamilyIndices
317             (VkSurfaceTransformFlagBitsKHR)swapchainTransform, // preTransform
318             compositeAlpha,                                    // compositeAlpha
319             swapchainPresentMode,                              // presentMode
320             VK_TRUE,                                           // clipped
321             VK_NULL_HANDLE,                                    // oldSwapchain
322         };
323 
324         VALIDATE_VK_RESULT(vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfo, nullptr, &plat_.swapchain));
325 
326         {
327             uint32_t realImageCount = 0;
328             VALIDATE_VK_RESULT(vkGetSwapchainImagesKHR(vkDevice, // device
329                 plat_.swapchain,                                 // swapchain
330                 &realImageCount,                                 // pSwapchainImageCount
331                 nullptr));                                       // pSwapchainImages
332 
333             PLUGIN_LOG_D("swapchain realImageCount: %u", realImageCount);
334 
335             plat_.swapchainImages.images.resize(realImageCount);
336             plat_.swapchainImages.imageViews.resize(realImageCount);
337             plat_.swapchainImages.semaphores.resize(realImageCount);
338 
339             VALIDATE_VK_RESULT(vkGetSwapchainImagesKHR(vkDevice, // device
340                 plat_.swapchain,                                 // swapchain
341                 &realImageCount,                                 // pSwapchainImageCount
342                 plat_.swapchainImages.images.data()));           // pSwapchainImages
343 
344             constexpr VkComponentMapping componentMapping {
345                 VK_COMPONENT_SWIZZLE_IDENTITY, // r
346                 VK_COMPONENT_SWIZZLE_IDENTITY, // g
347                 VK_COMPONENT_SWIZZLE_IDENTITY, // b
348                 VK_COMPONENT_SWIZZLE_IDENTITY, // a
349             };
350             constexpr VkImageSubresourceRange imageSubresourceRange {
351                 VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
352                 0,                         // baseMipLevel
353                 1,                         // levelCount
354                 0,                         // baseArrayLayer
355                 1,                         // layerCount
356             };
357 
358             constexpr VkSemaphoreCreateFlags semaphoreCreateFlags { 0 };
359             const VkSemaphoreCreateInfo semaphoreCreateInfo {
360                 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType
361                 nullptr,                                 // pNext
362                 semaphoreCreateFlags,                    // flags
363             };
364             for (uint32_t idx = 0; idx < plat_.swapchainImages.imageViews.size(); ++idx) {
365                 const VkImageViewCreateInfo imageViewCreateInfo {
366                     VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
367                     nullptr,                                  // pNext
368                     0,                                        // flags
369                     plat_.swapchainImages.images[idx],        // image
370                     VK_IMAGE_VIEW_TYPE_2D,                    // viewType
371                     ci.format,                                // format
372                     componentMapping,                         // components
373                     imageSubresourceRange                     // subresourceRange;
374                 };
375                 VALIDATE_VK_RESULT(vkCreateImageView(vkDevice, // device
376                     &imageViewCreateInfo,                      // pCreateInfo
377                     nullptr,                                   // pAllocator
378                     &plat_.swapchainImages.imageViews[idx]));  // pView
379                 VALIDATE_VK_RESULT(vkCreateSemaphore(vkDevice, // device
380                     &semaphoreCreateInfo,                      // pCreateInfo
381                     nullptr,                                   // pAllocator
382                     &plat_.swapchainImages.semaphores[idx]));  // pSemaphore
383             }
384         }
385 
386         desc_ = GetColorDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, (Format)ci.format,
387             (ImageUsageFlags)imageUsageFlags);
388 
389         if (flags_ & 0x2) {
390             const Format depthFormat = GetValidDepthFormat((const DeviceVk&)device_);
391             descDepthBuffer_ = GetDepthDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, depthFormat);
392         }
393     } else {
394         PLUGIN_LOG_E("Invalid surface in swapchain creation");
395     }
396 }
397 
~SwapchainVk()398 SwapchainVk::~SwapchainVk()
399 {
400     const auto& devicePlatformData = (const DevicePlatformDataVk&)device_.GetPlatformData();
401     const VkDevice device = devicePlatformData.device;
402     for (auto const imageView : plat_.swapchainImages.imageViews) {
403         if (imageView) {
404             vkDestroyImageView(device, // device
405                 imageView,             // imageView
406                 nullptr);              // pAllocator
407         }
408     }
409     for (const auto semaphore : plat_.swapchainImages.semaphores) {
410         if (semaphore) {
411             vkDestroySemaphore(device, // device
412                 semaphore,             // semaphore
413                 nullptr);              // pAllocator
414         }
415     }
416 
417     CreateFunctionsVk::DestroySwapchain(device, plat_.swapchain);
418     if (ownsSurface_ && surface_) {
419         CreateFunctionsVk::DestroySurface(devicePlatformData.instance, surface_);
420     }
421 }
422 
GetPlatformData() const423 const SwapchainPlatformDataVk& SwapchainVk::GetPlatformData() const
424 {
425     return plat_;
426 }
427 
GetDesc() const428 const GpuImageDesc& SwapchainVk::GetDesc() const
429 {
430     return desc_;
431 }
432 
GetDescDepthBuffer() const433 const GpuImageDesc& SwapchainVk::GetDescDepthBuffer() const
434 {
435     return descDepthBuffer_;
436 }
437 
GetFlags() const438 uint32_t SwapchainVk::GetFlags() const
439 {
440     return flags_;
441 }
442 
GetSurfaceTransformFlags() const443 SurfaceTransformFlags SwapchainVk::GetSurfaceTransformFlags() const
444 {
445     return surfaceTransformFlags_;
446 }
447 
GetSurfaceHandle() const448 uint64_t SwapchainVk::GetSurfaceHandle() const
449 {
450     return VulkanHandleCast<uint64_t>(surface_);
451 }
452 
GetNextAcquireSwapchainSemaphoreIndex() const453 uint32_t SwapchainVk::GetNextAcquireSwapchainSemaphoreIndex() const
454 {
455     currSemaphoreIdx_ = (currSemaphoreIdx_ + 1) % plat_.swapchainImages.semaphores.size();
456     return currSemaphoreIdx_;
457 }
458 RENDER_END_NAMESPACE()
459