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