• 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 
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     constexpr VkFormat hdrFormats[] = { VK_FORMAT_A2B10G10R10_UNORM_PACK32, VK_FORMAT_A2R10G10B10_UNORM_PACK32,
80         VK_FORMAT_R16G16B16A16_SFLOAT };
81 
82     // If pSurfaceFormats includes just one entry, whose value for format is VK_FORMAT_UNDEFINED,
83     // surface has no preferred format. In this case, the application can use any valid VkFormat value.
84     if (surfaceFormats[0].format == VK_FORMAT_UNDEFINED && surfaceFormats.size() == 1) {
85         return VK_FORMAT_R8G8B8A8_SRGB;
86     }
87 
88     if (flags & SwapchainFlagBits::CORE_SWAPCHAIN_HDR_BIT) {
89         for (auto format : hdrFormats) {
90             for (auto surfaceFormat : surfaceFormats) {
91                 if (format == surfaceFormat.format) {
92                     return surfaceFormat.format;
93                 }
94             }
95         }
96     }
97     const bool preferSrgbFormat = (flags & SwapchainFlagBits::CORE_SWAPCHAIN_SRGB_BIT);
98     const array_view<const VkFormat> formats =
99         (preferSrgbFormat) ? array_view<const VkFormat> { srgbFormats } : array_view<const VkFormat> { nonSrgbFormats };
100 
101     for (auto format : formats) {
102         for (auto surfaceFormat : surfaceFormats) {
103             if (format == surfaceFormat.format) {
104                 return surfaceFormat.format;
105             }
106         }
107     }
108     return VK_FORMAT_UNDEFINED;
109 }
110 
GetColorInfo(const VkPhysicalDevice physicalDevice,const VkSurfaceKHR surface,const uint32_t flags)111 ColorInfo GetColorInfo(const VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, const uint32_t flags)
112 {
113     // Pick a color format for the swapchain.
114     uint32_t surfaceFormatsCount = 0;
115     VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, nullptr));
116 
117     vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatsCount);
118     VALIDATE_VK_RESULT(
119         vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatsCount, surfaceFormats.data()));
120 
121     ColorInfo ci;
122     ci.format = GetColorFormat(flags, surfaceFormats);
123     ci.colorSpace = VK_COLOR_SPACE_MAX_ENUM_KHR;
124     for (auto& surfaceFormat : surfaceFormats) {
125         if (surfaceFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
126             ci.colorSpace = surfaceFormat.colorSpace;
127             break;
128         }
129     }
130     PLUGIN_ASSERT_MSG(ci.colorSpace != VK_COLOR_SPACE_MAX_ENUM_KHR, "colorspace not correct");
131 
132     PLUGIN_ASSERT_MSG(ci.format != VK_FORMAT_UNDEFINED, "colorformat not correct");
133     PLUGIN_LOG_D("swapchainColorFormat: %u swapchainColorSpace %u", ci.format, ci.colorSpace);
134 
135     return ci;
136 }
137 
GetPresentMode(const VkPhysicalDevice physicalDevice,const VkSurfaceKHR surface,const uint32_t flags)138 VkPresentModeKHR GetPresentMode(const VkPhysicalDevice physicalDevice, const VkSurfaceKHR surface, const uint32_t flags)
139 {
140     // Pick a present mode for the swapchain.
141     uint32_t presentModeCount;
142     VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr));
143 
144     vector<VkPresentModeKHR> presentModes(presentModeCount);
145     VALIDATE_VK_RESULT(
146         vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()));
147 
148     VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; // FIFO must be supported by the specification.
149     if ((flags & SwapchainFlagBits::CORE_SWAPCHAIN_VSYNC_BIT) != SwapchainFlagBits::CORE_SWAPCHAIN_VSYNC_BIT) {
150         // immediate is really without vsync, but it might not be supported, so we also check for mailbox.
151         if (std::any_of(presentModes.cbegin(), presentModes.cend(),
152                 [](const VkPresentModeKHR& supported) { return supported == VK_PRESENT_MODE_IMMEDIATE_KHR; })) {
153             swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
154         } else if (std::any_of(presentModes.cbegin(), presentModes.cend(),
155                        [](const VkPresentModeKHR& supported) { return supported == VK_PRESENT_MODE_MAILBOX_KHR; })) {
156             swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
157         }
158     }
159 
160 #if (RENDER_DEV_ENABLED == 1)
161     constexpr uint32_t strArraySize { 4 };
162     constexpr string_view presentModeStrings[strArraySize] = {
163         "VK_PRESENT_MODE_IMMEDIATE_KHR",
164         "VK_PRESENT_MODE_MAILBOX_KHR",
165         "VK_PRESENT_MODE_FIFO_KHR",
166         "VK_PRESENT_MODE_FIFO_RELAXED_KHR",
167     };
168 
169     PLUGIN_LOG_I("Available swapchain present modes:");
170     for (auto const presentMode : presentModes) {
171         if ((uint32_t)presentMode < strArraySize) {
172             PLUGIN_LOG_I("  %s", presentModeStrings[presentMode].data());
173         }
174     }
175     PLUGIN_LOG_I("Selected swapchain present modes:");
176     if ((uint32_t)swapchainPresentMode < strArraySize) {
177         PLUGIN_LOG_I("  %s", presentModeStrings[swapchainPresentMode].data());
178     }
179 #else
180     PLUGIN_LOG_D("swapchainPresentMode: %x", swapchainPresentMode);
181 #endif
182 
183     return swapchainPresentMode;
184 }
185 
ClampSwapchainExtent(const VkSurfaceCapabilitiesKHR & surfaceCapabilities,VkExtent2D & extent)186 void ClampSwapchainExtent(const VkSurfaceCapabilitiesKHR& surfaceCapabilities, VkExtent2D& extent)
187 {
188     extent.width =
189         std::clamp(extent.width, surfaceCapabilities.minImageExtent.width, surfaceCapabilities.maxImageExtent.width);
190     extent.height =
191         std::clamp(extent.height, surfaceCapabilities.minImageExtent.height, surfaceCapabilities.maxImageExtent.height);
192 
193     PLUGIN_LOG_D("swapchainExtent: %u x %u", extent.width, extent.height);
194     if ((extent.width == 0) || (extent.height == 0)) {
195         PLUGIN_LOG_E(
196             "zero sized swapchain cannot be created in vulkan (width: %u, height: %u)", extent.width, extent.height);
197         PLUGIN_LOG_E("using 1x1 swapchain");
198         PLUGIN_ASSERT(false);
199         extent.width = 1;
200         extent.height = 1;
201     }
202 }
203 
GetColorDesc(const uint32_t width,const uint32_t height,const Format format,const ImageUsageFlags imageUsageFlags)204 constexpr GpuImageDesc GetColorDesc(
205     const uint32_t width, const uint32_t height, const Format format, const ImageUsageFlags imageUsageFlags)
206 {
207     return {
208         ImageType::CORE_IMAGE_TYPE_2D,                                 // imageType
209         ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,                        // imageViewType
210         format,                                                        // format
211         ImageTiling::CORE_IMAGE_TILING_OPTIMAL,                        // imageTiling
212         imageUsageFlags,                                               // usageFlags
213         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, // memoryPropertyFlags
214         0,                                                             // createFlags
215         EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS |
216             EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS, // engineCreationFlags
217         width,                                                                                    // width
218         height,                                                                                   // height
219         1,                                                                                        // depth
220         1,                                                                                        // mipCount
221         1,                                                                                        // layerCount
222         SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,                                             // sampleCountFlags
223         {},                                                                                       // componentMapping
224     };
225 }
226 
GetDepthDesc(const uint32_t width,const uint32_t height,const Format format)227 constexpr GpuImageDesc GetDepthDesc(const uint32_t width, const uint32_t height, const Format format)
228 {
229     return {
230         ImageType::CORE_IMAGE_TYPE_2D,          // imageType
231         ImageViewType::CORE_IMAGE_VIEW_TYPE_2D, // imageViewType
232         format,                                 // format
233         ImageTiling::CORE_IMAGE_TILING_OPTIMAL, // imageTiling
234         ImageUsageFlagBits::CORE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
235             ImageUsageFlagBits::CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
236             ImageUsageFlagBits::CORE_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT, // usageFlags
237         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
238             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT,    // memoryPropertyFlags
239         0,                                                                        // createFlags
240         EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS, // engineCreationFlags
241         width,                                                                    // width
242         height,                                                                   // height
243         1,                                                                        // depth
244         1,                                                                        // mipCount
245         1,                                                                        // layerCount
246         SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,                             // sampleCountFlags
247         {},                                                                       // componentMapping
248     };
249 }
250 
LogAndUpdateResultError(const VkResult newResult,VkResult & result)251 inline void LogAndUpdateResultError(const VkResult newResult, VkResult& result)
252 {
253     if (newResult != VK_SUCCESS) {
254         PLUGIN_LOG_E("vulkan result is not VK_SUCCESS : %d", (int32_t)newResult);
255         result = newResult;
256     }
257 }
258 } // namespace
259 
SwapchainVk(Device & device,const SwapchainCreateInfo & swapchainCreateInfo)260 SwapchainVk::SwapchainVk(Device& device, const SwapchainCreateInfo& swapchainCreateInfo)
261     : device_(device), flags_(swapchainCreateInfo.swapchainFlags)
262 {
263     const auto& devicePlatformData = (const DevicePlatformDataVk&)device_.GetPlatformData();
264     auto const physicalDevice = devicePlatformData.physicalDevice;
265     // check for surface creation automatically
266     if ((swapchainCreateInfo.surfaceHandle == 0) && swapchainCreateInfo.window.window) {
267         CreateFunctionsVk::Window win { swapchainCreateInfo.window.instance, swapchainCreateInfo.window.window };
268         surface_ = CreateFunctionsVk::CreateSurface(devicePlatformData.instance, win);
269         ownsSurface_ = true;
270     } else {
271         surface_ = VulkanHandleCast<VkSurfaceKHR>(swapchainCreateInfo.surfaceHandle);
272     }
273 
274     if (surface_ != VK_NULL_HANDLE) {
275         auto const vkDevice = devicePlatformData.device;
276 
277         // Sanity check that the device can use the surface.
278         // NOTE: queuFamilyIndex hardcoded, should come via devicePlatformData?
279         VkBool32 surfaceSupported = VK_FALSE;
280         VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, 0, surface_, &surfaceSupported));
281         PLUGIN_ASSERT_MSG(surfaceSupported != VK_FALSE, "physicalDevice doesn't support given surface");
282 
283         const ColorInfo ci = GetColorInfo(physicalDevice, surface_, flags_);
284 
285         const VkPresentModeKHR swapchainPresentMode = GetPresentMode(physicalDevice, surface_, flags_);
286         // Pick an extent, image count, and transform for the swapchain.
287         VkSurfaceCapabilitiesKHR surfaceCapabilities;
288         VALIDATE_VK_RESULT(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface_, &surfaceCapabilities));
289 
290         // NOTE: how do we handle the special case of 0xffffffffff which means the extent should be defined by the
291         // swapchain?
292         VkExtent2D swapchainExtent = surfaceCapabilities.currentExtent;
293         ClampSwapchainExtent(surfaceCapabilities, swapchainExtent);
294         plat_.swapchainImages.width = swapchainExtent.width;
295         plat_.swapchainImages.height = swapchainExtent.height;
296 
297         const DeviceConfiguration deviceConfig = device_.GetDeviceConfiguration();
298         // surfaceCapabilities.maxImageCount of zero means that there is no limit
299         const uint32_t imageCount =
300             (surfaceCapabilities.maxImageCount == 0)
301                 ? (Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount))
302                 : (Math::min(surfaceCapabilities.maxImageCount,
303                              Math::max(surfaceCapabilities.minImageCount, deviceConfig.swapchainImageCount)));
304         PLUGIN_LOG_D("swapchainImageCount: %u", imageCount);
305 
306         const VkSurfaceTransformFlagsKHR swapchainTransform =
307             (surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
308                 ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR
309                 : surfaceCapabilities.currentTransform;
310 
311         const auto desiredUsageFlags = static_cast<VkImageUsageFlags>(swapchainCreateInfo.imageUsageFlags);
312         const VkImageUsageFlags imageUsageFlags = desiredUsageFlags & surfaceCapabilities.supportedUsageFlags;
313         PLUGIN_LOG_D("swapchain usage flags, selected: %u, desired: %u, capabilities: %u", imageUsageFlags,
314             desiredUsageFlags, surfaceCapabilities.supportedUsageFlags);
315 
316         VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
317         if (surfaceCapabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
318             compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
319         }
320 
321         VkSwapchainCreateInfoKHR const vkSwapchainCreateInfo {
322             VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,       // sType
323             nullptr,                                           // pNext
324             0,                                                 // flags
325             surface_,                                          // surface
326             imageCount,                                        // minImageCount
327             ci.format,                                         // imageFormat
328             ci.colorSpace,                                     // imageColorSpace
329             swapchainExtent,                                   // imageExtent
330             1,                                                 // imageArrayLayers
331             imageUsageFlags,                                   // imageUsage
332             VK_SHARING_MODE_EXCLUSIVE,                         // imageSharingMode
333             0,                                                 // queueFamilyIndexCount
334             nullptr,                                           // pQueueFamilyIndices
335             (VkSurfaceTransformFlagBitsKHR)swapchainTransform, // preTransform
336             compositeAlpha,                                    // compositeAlpha
337             swapchainPresentMode,                              // presentMode
338             VK_TRUE,                                           // clipped
339             VK_NULL_HANDLE,                                    // oldSwapchain
340         };
341 
342         VkResult mainResult = VK_SUCCESS;
343         {
344             VkResult result = vkCreateSwapchainKHR(vkDevice, &vkSwapchainCreateInfo, nullptr, &plat_.swapchain);
345             LogAndUpdateResultError(result, mainResult);
346         }
347         if (mainResult == VK_SUCCESS) {
348             uint32_t realImageCount = 0;
349             VkResult result = vkGetSwapchainImagesKHR(vkDevice, // device
350                 plat_.swapchain,                                // swapchain
351                 &realImageCount,                                // pSwapchainImageCount
352                 nullptr);                                       // pSwapchainImages
353             LogAndUpdateResultError(result, mainResult);
354 
355             PLUGIN_LOG_D("swapchain realImageCount: %u", realImageCount);
356 
357             plat_.swapchainImages.images.resize(realImageCount);
358             plat_.swapchainImages.imageViews.resize(realImageCount);
359             plat_.swapchainImages.semaphores.resize(realImageCount);
360 
361             result = vkGetSwapchainImagesKHR(vkDevice, // device
362                 plat_.swapchain,                       // swapchain
363                 &realImageCount,                       // pSwapchainImageCount
364                 plat_.swapchainImages.images.data());  // pSwapchainImages
365             LogAndUpdateResultError(result, mainResult);
366 
367             constexpr VkComponentMapping componentMapping {
368                 VK_COMPONENT_SWIZZLE_IDENTITY, // r
369                 VK_COMPONENT_SWIZZLE_IDENTITY, // g
370                 VK_COMPONENT_SWIZZLE_IDENTITY, // b
371                 VK_COMPONENT_SWIZZLE_IDENTITY, // a
372             };
373             constexpr VkImageSubresourceRange imageSubresourceRange {
374                 VK_IMAGE_ASPECT_COLOR_BIT, // aspectMask
375                 0,                         // baseMipLevel
376                 1,                         // levelCount
377                 0,                         // baseArrayLayer
378                 1,                         // layerCount
379             };
380 
381             constexpr VkSemaphoreCreateFlags semaphoreCreateFlags { 0 };
382             const VkSemaphoreCreateInfo semaphoreCreateInfo {
383                 VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, // sType
384                 nullptr,                                 // pNext
385                 semaphoreCreateFlags,                    // flags
386             };
387             for (uint32_t idx = 0; idx < plat_.swapchainImages.imageViews.size(); ++idx) {
388                 const VkImageViewCreateInfo imageViewCreateInfo {
389                     VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, // sType
390                     nullptr,                                  // pNext
391                     0,                                        // flags
392                     plat_.swapchainImages.images[idx],        // image
393                     VK_IMAGE_VIEW_TYPE_2D,                    // viewType
394                     ci.format,                                // format
395                     componentMapping,                         // components
396                     imageSubresourceRange                     // subresourceRange;
397                 };
398                 result = vkCreateImageView(vkDevice,         // device
399                     &imageViewCreateInfo,                    // pCreateInfo
400                     nullptr,                                 // pAllocator
401                     &plat_.swapchainImages.imageViews[idx]); // pView
402                 LogAndUpdateResultError(result, mainResult);
403 
404                 result = vkCreateSemaphore(vkDevice,         // device
405                     &semaphoreCreateInfo,                    // pCreateInfo
406                     nullptr,                                 // pAllocator
407                     &plat_.swapchainImages.semaphores[idx]); // pSemaphore
408                 LogAndUpdateResultError(result, mainResult);
409             }
410         }
411 
412         desc_ = GetColorDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, (Format)ci.format,
413             (ImageUsageFlags)imageUsageFlags);
414 
415         if (flags_ & 0x2) {
416             const Format depthFormat = GetValidDepthFormat((const DeviceVk&)device_);
417             descDepthBuffer_ = GetDepthDesc(plat_.swapchainImages.width, plat_.swapchainImages.height, depthFormat);
418         }
419 
420         if (mainResult != VK_SUCCESS) {
421             valid_ = false;
422         }
423     } else {
424         PLUGIN_LOG_E("Invalid surface in swapchain creation");
425         valid_ = false;
426     }
427 }
428 
~SwapchainVk()429 SwapchainVk::~SwapchainVk()
430 {
431     const auto& devicePlatformData = (const DevicePlatformDataVk&)device_.GetPlatformData();
432     const VkDevice device = devicePlatformData.device;
433     for (auto const imageView : plat_.swapchainImages.imageViews) {
434         if (imageView) {
435             vkDestroyImageView(device, // device
436                 imageView,             // imageView
437                 nullptr);              // pAllocator
438         }
439     }
440     for (const auto semaphore : plat_.swapchainImages.semaphores) {
441         if (semaphore) {
442             vkDestroySemaphore(device, // device
443                 semaphore,             // semaphore
444                 nullptr);              // pAllocator
445         }
446     }
447 
448     CreateFunctionsVk::DestroySwapchain(device, plat_.swapchain);
449     if (ownsSurface_ && surface_) {
450         CreateFunctionsVk::DestroySurface(devicePlatformData.instance, surface_);
451     }
452 }
453 
GetPlatformData() const454 const SwapchainPlatformDataVk& SwapchainVk::GetPlatformData() const
455 {
456     return plat_;
457 }
458 
GetDesc() const459 const GpuImageDesc& SwapchainVk::GetDesc() const
460 {
461     return desc_;
462 }
463 
GetDescDepthBuffer() const464 const GpuImageDesc& SwapchainVk::GetDescDepthBuffer() const
465 {
466     return descDepthBuffer_;
467 }
468 
GetFlags() const469 uint32_t SwapchainVk::GetFlags() const
470 {
471     return flags_;
472 }
473 
GetSurfaceTransformFlags() const474 SurfaceTransformFlags SwapchainVk::GetSurfaceTransformFlags() const
475 {
476     return surfaceTransformFlags_;
477 }
478 
GetSurfaceHandle() const479 uint64_t SwapchainVk::GetSurfaceHandle() const
480 {
481     return VulkanHandleCast<uint64_t>(surface_);
482 }
483 
GetNextAcquireSwapchainSemaphoreIndex() const484 uint32_t SwapchainVk::GetNextAcquireSwapchainSemaphoreIndex() const
485 {
486     currSemaphoreIdx_ = (currSemaphoreIdx_ + 1) % plat_.swapchainImages.semaphores.size();
487     return currSemaphoreIdx_;
488 }
489 
IsValid() const490 bool SwapchainVk::IsValid() const
491 {
492     return valid_;
493 }
494 RENDER_END_NAMESPACE()
495