Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2015-2022 The Khronos Group Inc. |
| 2 | * Copyright (c) 2015-2022 Valve Corporation |
| 3 | * Copyright (c) 2015-2022 LunarG, Inc. |
| 4 | * Copyright (C) 2015-2022 Google Inc. |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 5 | * Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. |
| 6 | * |
| 7 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 8 | * you may not use this file except in compliance with the License. |
| 9 | * You may obtain a copy of the License at |
| 10 | * |
| 11 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 12 | * |
| 13 | * Unless required by applicable law or agreed to in writing, software |
| 14 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 16 | * See the License for the specific language governing permissions and |
| 17 | * limitations under the License. |
| 18 | * |
| 19 | * Author: Courtney Goeltzenleuchter <courtneygo@google.com> |
| 20 | * Author: Tobin Ehlis <tobine@google.com> |
| 21 | * Author: Chris Forbes <chrisf@ijw.co.nz> |
| 22 | * Author: Mark Lobodzinski <mark@lunarg.com> |
| 23 | * Author: Dave Houlton <daveh@lunarg.com> |
| 24 | * Author: John Zulauf <jzulauf@lunarg.com> |
| 25 | * Author: Tobias Hector <tobias.hector@amd.com> |
| 26 | * Author: Jeremy Gebben <jeremyg@lunarg.com> |
| 27 | */ |
| 28 | #include "image_state.h" |
Jeremy Gebben | 5d97074 | 2021-05-31 16:04:14 -0600 | [diff] [blame] | 29 | #include "pipeline_state.h" |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 30 | #include "descriptor_sets.h" |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 31 | #include "state_tracker.h" |
Jeremy Gebben | 4295bdf | 2021-09-09 12:34:07 -0600 | [diff] [blame] | 32 | #include <limits> |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 33 | |
| 34 | static VkImageSubresourceRange MakeImageFullRange(const VkImageCreateInfo &create_info) { |
| 35 | const auto format = create_info.format; |
| 36 | VkImageSubresourceRange init_range{0, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS}; |
| 37 | |
| 38 | #ifdef VK_USE_PLATFORM_ANDROID_KHR |
| 39 | const VkExternalFormatANDROID *external_format_android = LvlFindInChain<VkExternalFormatANDROID>(&create_info); |
| 40 | bool is_external_format_conversion = (external_format_android != nullptr && external_format_android->externalFormat != 0); |
| 41 | #else |
| 42 | bool is_external_format_conversion = false; |
| 43 | #endif |
| 44 | |
| 45 | if (FormatIsColor(format) || FormatIsMultiplane(format) || is_external_format_conversion) { |
| 46 | init_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // Normalization will expand this for multiplane |
| 47 | } else { |
| 48 | init_range.aspectMask = |
| 49 | (FormatHasDepth(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (FormatHasStencil(format) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0); |
| 50 | } |
| 51 | return NormalizeSubresourceRange(create_info, init_range); |
| 52 | } |
| 53 | |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 54 | static uint32_t ResolveRemainingLevels(const VkImageSubresourceRange *range, uint32_t mip_levels) { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 55 | // Return correct number of mip levels taking into account VK_REMAINING_MIP_LEVELS |
| 56 | uint32_t mip_level_count = range->levelCount; |
| 57 | if (range->levelCount == VK_REMAINING_MIP_LEVELS) { |
| 58 | mip_level_count = mip_levels - range->baseMipLevel; |
| 59 | } |
| 60 | return mip_level_count; |
| 61 | } |
| 62 | |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 63 | static uint32_t ResolveRemainingLayers(const VkImageSubresourceRange *range, uint32_t layers) { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 64 | // Return correct number of layers taking into account VK_REMAINING_ARRAY_LAYERS |
| 65 | uint32_t array_layer_count = range->layerCount; |
| 66 | if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) { |
| 67 | array_layer_count = layers - range->baseArrayLayer; |
| 68 | } |
| 69 | return array_layer_count; |
| 70 | } |
| 71 | |
| 72 | VkImageSubresourceRange NormalizeSubresourceRange(const VkImageCreateInfo &image_create_info, |
| 73 | const VkImageSubresourceRange &range) { |
| 74 | VkImageSubresourceRange norm = range; |
| 75 | norm.levelCount = ResolveRemainingLevels(&range, image_create_info.mipLevels); |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 76 | norm.layerCount = ResolveRemainingLayers(&range, image_create_info.arrayLayers); |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 77 | |
| 78 | // For multiplanar formats, IMAGE_ASPECT_COLOR is equivalent to adding the aspect of the individual planes |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 79 | if (FormatIsMultiplane(image_create_info.format)) { |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 80 | if (norm.aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) { |
| 81 | norm.aspectMask &= ~VK_IMAGE_ASPECT_COLOR_BIT; |
| 82 | norm.aspectMask |= (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT); |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 83 | if (FormatPlaneCount(image_create_info.format) > 2) { |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 84 | norm.aspectMask |= VK_IMAGE_ASPECT_PLANE_2_BIT; |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 85 | } |
| 86 | } |
| 87 | } |
| 88 | return norm; |
| 89 | } |
| 90 | |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 91 | static bool IsDepthSliced(const VkImageCreateInfo &image_create_info, const VkImageViewCreateInfo &create_info) { |
Jeremy Gebben | 7fad0db | 2022-08-02 13:52:09 -0600 | [diff] [blame] | 92 | auto kDepthSlicedFlags = VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT | VK_IMAGE_CREATE_2D_VIEW_COMPATIBLE_BIT_EXT; |
| 93 | return ((image_create_info.flags & kDepthSlicedFlags) != 0) && |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 94 | (create_info.viewType == VK_IMAGE_VIEW_TYPE_2D || create_info.viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY); |
| 95 | } |
| 96 | |
| 97 | VkImageSubresourceRange NormalizeSubresourceRange(const VkImageCreateInfo &image_create_info, |
| 98 | const VkImageViewCreateInfo &create_info) { |
| 99 | auto subres_range = create_info.subresourceRange; |
| 100 | |
| 101 | // if we're mapping a 3D image to a 2d image view, convert the view's subresource range to be compatible with the |
| 102 | // image's understanding of the world. From the VkImageSubresourceRange section of the Vulkan spec: |
| 103 | // |
| 104 | // When the VkImageSubresourceRange structure is used to select a subset of the slices of a 3D image’s mip level in |
| 105 | // order to create a 2D or 2D array image view of a 3D image created with VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, |
| 106 | // baseArrayLayer and layerCount specify the first slice index and the number of slices to include in the created |
| 107 | // image view. Such an image view can be used as a framebuffer attachment that refers only to the specified range |
| 108 | // of slices of the selected mip level. However, any layout transitions performed on such an attachment view during |
| 109 | // a render pass instance still apply to the entire subresource referenced which includes all the slices of the |
| 110 | // selected mip level. |
| 111 | // |
| 112 | if (IsDepthSliced(image_create_info, create_info)) { |
| 113 | subres_range.baseArrayLayer = 0; |
| 114 | subres_range.layerCount = 1; |
| 115 | } |
| 116 | return NormalizeSubresourceRange(image_create_info, subres_range); |
| 117 | } |
| 118 | |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 119 | static VkExternalMemoryHandleTypeFlags GetExternalHandleType(const VkImageCreateInfo *pCreateInfo) { |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 120 | const auto *external_memory_info = LvlFindInChain<VkExternalMemoryImageCreateInfo>(pCreateInfo->pNext); |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 121 | return external_memory_info ? external_memory_info->handleTypes : 0; |
| 122 | } |
| 123 | |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 124 | static VkSwapchainKHR GetSwapchain(const VkImageCreateInfo *pCreateInfo) { |
| 125 | const auto *swapchain_info = LvlFindInChain<VkImageSwapchainCreateInfoKHR>(pCreateInfo->pNext); |
| 126 | return swapchain_info ? swapchain_info->swapchain : VK_NULL_HANDLE; |
| 127 | } |
| 128 | |
| 129 | #ifdef VK_USE_PLATFORM_ANDROID_KHR |
| 130 | static uint64_t GetExternalFormat(const VkImageCreateInfo *info) { |
| 131 | const VkExternalFormatANDROID *ext_format_android = LvlFindInChain<VkExternalFormatANDROID>(info->pNext); |
| 132 | return ext_format_android ? ext_format_android->externalFormat : 0; |
| 133 | } |
| 134 | #else |
| 135 | static uint64_t GetExternalFormat(const VkImageCreateInfo *info) { return 0; } |
| 136 | #endif // VK_USE_PLATFORM_ANDROID_KHR |
| 137 | |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 138 | static IMAGE_STATE::MemoryReqs GetMemoryRequirements(const ValidationStateTracker *dev_data, VkImage img, |
| 139 | const VkImageCreateInfo *create_info, bool disjoint, bool is_external_ahb) { |
| 140 | IMAGE_STATE::MemoryReqs result{}; |
| 141 | // Record the memory requirements in case they won't be queried |
| 142 | // External AHB memory can't be queried until after memory is bound |
| 143 | if (!is_external_ahb) { |
| 144 | if (disjoint == false) { |
| 145 | DispatchGetImageMemoryRequirements(dev_data->device, img, &result[0]); |
| 146 | } else { |
| 147 | uint32_t plane_count = FormatPlaneCount(create_info->format); |
| 148 | static const std::array<VkImageAspectFlagBits, 3> aspects{VK_IMAGE_ASPECT_PLANE_0_BIT, VK_IMAGE_ASPECT_PLANE_1_BIT, |
| 149 | VK_IMAGE_ASPECT_PLANE_2_BIT}; |
| 150 | assert(plane_count <= aspects.size()); |
| 151 | auto image_plane_req = lvl_init_struct<VkImagePlaneMemoryRequirementsInfo>(); |
| 152 | auto mem_req_info2 = lvl_init_struct<VkImageMemoryRequirementsInfo2>(&image_plane_req); |
| 153 | mem_req_info2.image = img; |
| 154 | |
| 155 | for (uint32_t i = 0; i < plane_count; i++) { |
| 156 | auto mem_reqs2 = lvl_init_struct<VkMemoryRequirements2>(); |
| 157 | |
| 158 | image_plane_req.planeAspect = aspects[i]; |
| 159 | switch (dev_data->device_extensions.vk_khr_get_memory_requirements2) { |
| 160 | case kEnabledByApiLevel: |
| 161 | DispatchGetImageMemoryRequirements2(dev_data->device, &mem_req_info2, &mem_reqs2); |
| 162 | break; |
| 163 | case kEnabledByCreateinfo: |
| 164 | DispatchGetImageMemoryRequirements2KHR(dev_data->device, &mem_req_info2, &mem_reqs2); |
| 165 | break; |
| 166 | default: |
| 167 | // The VK_KHR_sampler_ycbcr_conversion extension requires VK_KHR_get_memory_requirements2, |
| 168 | // so validation of this vkCreateImage call should have already failed. |
| 169 | assert(false); |
| 170 | } |
| 171 | result[i] = mem_reqs2.memoryRequirements; |
| 172 | } |
| 173 | } |
| 174 | } |
| 175 | return result; |
| 176 | } |
| 177 | |
| 178 | static IMAGE_STATE::SparseReqs GetSparseRequirements(const ValidationStateTracker *dev_data, VkImage img, |
| 179 | const VkImageCreateInfo *create_info) { |
| 180 | IMAGE_STATE::SparseReqs result; |
| 181 | if (create_info->flags & VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT) { |
| 182 | uint32_t count = 0; |
| 183 | DispatchGetImageSparseMemoryRequirements(dev_data->device, img, &count, nullptr); |
| 184 | result.resize(count); |
| 185 | DispatchGetImageSparseMemoryRequirements(dev_data->device, img, &count, result.data()); |
| 186 | } |
| 187 | return result; |
| 188 | } |
| 189 | |
| 190 | static bool SparseMetaDataRequired(const IMAGE_STATE::SparseReqs &sparse_reqs) { |
| 191 | bool result = false; |
| 192 | for (const auto &req : sparse_reqs) { |
| 193 | if (req.formatProperties.aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) { |
| 194 | result = true; |
| 195 | break; |
| 196 | } |
| 197 | } |
| 198 | return result; |
| 199 | } |
Tony-LunarG | 285dbdc | 2022-07-15 09:42:54 -0600 | [diff] [blame] | 200 | #ifdef VK_USE_PLATFORM_METAL_EXT |
| 201 | static bool GetMetalExport(const VkImageCreateInfo *info, VkExportMetalObjectTypeFlagBitsEXT object_type_required) { |
| 202 | bool retval = false; |
| 203 | auto export_metal_object_info = LvlFindInChain<VkExportMetalObjectCreateInfoEXT>(info->pNext); |
| 204 | while (export_metal_object_info) { |
| 205 | if (export_metal_object_info->exportObjectType == object_type_required) { |
| 206 | retval = true; |
| 207 | break; |
| 208 | } |
| 209 | export_metal_object_info = LvlFindInChain<VkExportMetalObjectCreateInfoEXT>(export_metal_object_info->pNext); |
| 210 | } |
| 211 | return retval; |
| 212 | } |
| 213 | #endif // VK_USE_PLATFORM_METAL_EXT |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 214 | |
| 215 | IMAGE_STATE::IMAGE_STATE(const ValidationStateTracker *dev_data, VkImage img, const VkImageCreateInfo *pCreateInfo, |
Lionel Landwerlin | 21719f6 | 2021-12-09 11:40:09 +0200 | [diff] [blame] | 216 | VkFormatFeatureFlags2KHR ff) |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 217 | : BINDABLE(img, kVulkanObjectTypeImage, (pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != 0, |
| 218 | (pCreateInfo->flags & VK_IMAGE_CREATE_PROTECTED_BIT) == 0, GetExternalHandleType(pCreateInfo)), |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 219 | safe_create_info(pCreateInfo), |
| 220 | createInfo(*safe_create_info.ptr()), |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 221 | shared_presentable(false), |
| 222 | layout_locked(false), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 223 | ahb_format(GetExternalFormat(pCreateInfo)), |
| 224 | full_range{MakeImageFullRange(*pCreateInfo)}, |
| 225 | create_from_swapchain(GetSwapchain(pCreateInfo)), |
paul-lunarg | 4820fd1 | 2022-07-12 11:08:01 -0600 | [diff] [blame] | 226 | owned_by_swapchain(false), |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 227 | swapchain_image_index(0), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 228 | format_features(ff), |
| 229 | disjoint((pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0), |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 230 | requirements(GetMemoryRequirements(dev_data, img, pCreateInfo, disjoint, IsExternalAHB())), |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 231 | memory_requirements_checked{{false, false, false}}, |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 232 | sparse_requirements(GetSparseRequirements(dev_data, img, pCreateInfo)), |
| 233 | sparse_metadata_required(SparseMetaDataRequired(sparse_requirements)), |
| 234 | get_sparse_reqs_called(false), |
| 235 | sparse_metadata_bound(false), |
Tony-LunarG | 285dbdc | 2022-07-15 09:42:54 -0600 | [diff] [blame] | 236 | #ifdef VK_USE_PLATFORM_METAL_EXT |
| 237 | metal_image_export(GetMetalExport(pCreateInfo, VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT)), |
| 238 | metal_io_surface_export(GetMetalExport(pCreateInfo, VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT)), |
| 239 | #endif // VK_USE_PLATFORM_METAL_EXT |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 240 | subresource_encoder(full_range), |
| 241 | fragment_encoder(nullptr), |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 242 | store_device_as_workaround(dev_data->device) {} // TODO REMOVE WHEN encoder can be const |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 243 | |
Lionel Landwerlin | 21719f6 | 2021-12-09 11:40:09 +0200 | [diff] [blame] | 244 | IMAGE_STATE::IMAGE_STATE(const ValidationStateTracker *dev_data, VkImage img, const VkImageCreateInfo *pCreateInfo, |
| 245 | VkSwapchainKHR swapchain, uint32_t swapchain_index, VkFormatFeatureFlags2KHR ff) |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 246 | : BINDABLE(img, kVulkanObjectTypeImage, (pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) != 0, |
| 247 | (pCreateInfo->flags & VK_IMAGE_CREATE_PROTECTED_BIT) == 0, GetExternalHandleType(pCreateInfo)), |
| 248 | safe_create_info(pCreateInfo), |
| 249 | createInfo(*safe_create_info.ptr()), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 250 | shared_presentable(false), |
| 251 | layout_locked(false), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 252 | ahb_format(GetExternalFormat(pCreateInfo)), |
| 253 | full_range{MakeImageFullRange(*pCreateInfo)}, |
| 254 | create_from_swapchain(swapchain), |
paul-lunarg | 4820fd1 | 2022-07-12 11:08:01 -0600 | [diff] [blame] | 255 | owned_by_swapchain(true), |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 256 | swapchain_image_index(swapchain_index), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 257 | format_features(ff), |
| 258 | disjoint((pCreateInfo->flags & VK_IMAGE_CREATE_DISJOINT_BIT) != 0), |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 259 | requirements{}, |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 260 | memory_requirements_checked{false, false, false}, |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 261 | sparse_requirements{}, |
| 262 | sparse_metadata_required(false), |
| 263 | get_sparse_reqs_called(false), |
| 264 | sparse_metadata_bound(false), |
Tony-LunarG | 285dbdc | 2022-07-15 09:42:54 -0600 | [diff] [blame] | 265 | #ifdef VK_USE_PLATFORM_METAL_EXT |
| 266 | metal_image_export(GetMetalExport(pCreateInfo, VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT)), |
| 267 | metal_io_surface_export(GetMetalExport(pCreateInfo, VK_EXPORT_METAL_OBJECT_TYPE_METAL_IOSURFACE_BIT_EXT)), |
| 268 | #endif // VK_USE_PLATFORM_METAL_EXT |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 269 | subresource_encoder(full_range), |
| 270 | fragment_encoder(nullptr), |
Jeremy Gebben | bc9aacf | 2021-09-23 11:57:37 -0600 | [diff] [blame] | 271 | store_device_as_workaround(dev_data->device) { // TODO REMOVE WHEN encoder can be const |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 272 | fragment_encoder = |
| 273 | std::unique_ptr<const subresource_adapter::ImageRangeEncoder>(new subresource_adapter::ImageRangeEncoder(*this)); |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 274 | } |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 275 | |
Jeremy Gebben | 941e7fa | 2021-07-26 10:21:00 -0600 | [diff] [blame] | 276 | void IMAGE_STATE::Destroy() { |
Jeremy Gebben | 4a8881f | 2022-01-10 17:04:30 -0700 | [diff] [blame] | 277 | // NOTE: due to corner cases in aliased images, the layout_range_map MUST not be cleaned up here. |
| 278 | // If it is, bad local entries could be created by CMD_BUFFER_STATE::GetImageSubresourceLayoutMap() |
| 279 | // If an aliasing image was being destroyed (and layout_range_map was reset()), a nullptr keyed |
| 280 | // entry could get put into CMD_BUFFER_STATE::aliased_image_layout_map. |
Jeremy Gebben | 23cd4f2 | 2022-01-02 11:03:21 -0700 | [diff] [blame] | 281 | if (bind_swapchain) { |
| 282 | bind_swapchain->RemoveParent(this); |
| 283 | bind_swapchain = nullptr; |
| 284 | } |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 285 | BINDABLE::Destroy(); |
| 286 | } |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 287 | |
Jeremy Gebben | c9a2403 | 2021-11-02 11:36:08 -0600 | [diff] [blame] | 288 | void IMAGE_STATE::NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) { |
| 289 | BINDABLE::NotifyInvalidate(invalid_nodes, unlink); |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 290 | if (unlink) { |
Jeremy Gebben | 23cd4f2 | 2022-01-02 11:03:21 -0700 | [diff] [blame] | 291 | bind_swapchain = nullptr; |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 292 | } |
| 293 | } |
| 294 | |
| 295 | bool IMAGE_STATE::IsCreateInfoEqual(const VkImageCreateInfo &other_createInfo) const { |
| 296 | bool is_equal = (createInfo.sType == other_createInfo.sType) && (createInfo.flags == other_createInfo.flags); |
| 297 | is_equal = is_equal && IsImageTypeEqual(other_createInfo) && IsFormatEqual(other_createInfo); |
| 298 | is_equal = is_equal && IsMipLevelsEqual(other_createInfo) && IsArrayLayersEqual(other_createInfo); |
| 299 | is_equal = is_equal && IsUsageEqual(other_createInfo) && IsInitialLayoutEqual(other_createInfo); |
| 300 | is_equal = is_equal && IsExtentEqual(other_createInfo) && IsTilingEqual(other_createInfo); |
| 301 | is_equal = is_equal && IsSamplesEqual(other_createInfo) && IsSharingModeEqual(other_createInfo); |
| 302 | return is_equal && |
| 303 | ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) ? IsQueueFamilyIndicesEqual(other_createInfo) : true); |
| 304 | } |
| 305 | |
| 306 | // Check image compatibility rules for VK_NV_dedicated_allocation_image_aliasing |
| 307 | bool IMAGE_STATE::IsCreateInfoDedicatedAllocationImageAliasingCompatible(const VkImageCreateInfo &other_createInfo) const { |
| 308 | bool is_compatible = (createInfo.sType == other_createInfo.sType) && (createInfo.flags == other_createInfo.flags); |
| 309 | is_compatible = is_compatible && IsImageTypeEqual(other_createInfo) && IsFormatEqual(other_createInfo); |
| 310 | is_compatible = is_compatible && IsMipLevelsEqual(other_createInfo); |
| 311 | is_compatible = is_compatible && IsUsageEqual(other_createInfo) && IsInitialLayoutEqual(other_createInfo); |
| 312 | is_compatible = is_compatible && IsSamplesEqual(other_createInfo) && IsSharingModeEqual(other_createInfo); |
| 313 | is_compatible = is_compatible && |
| 314 | ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) ? IsQueueFamilyIndicesEqual(other_createInfo) : true); |
| 315 | is_compatible = is_compatible && IsTilingEqual(other_createInfo); |
| 316 | |
| 317 | is_compatible = is_compatible && createInfo.extent.width <= other_createInfo.extent.width && |
| 318 | createInfo.extent.height <= other_createInfo.extent.height && |
| 319 | createInfo.extent.depth <= other_createInfo.extent.depth && |
| 320 | createInfo.arrayLayers <= other_createInfo.arrayLayers; |
| 321 | return is_compatible; |
| 322 | } |
| 323 | |
| 324 | bool IMAGE_STATE::IsCompatibleAliasing(IMAGE_STATE *other_image_state) const { |
Jeremy Gebben | 82e11d5 | 2021-07-26 09:19:37 -0600 | [diff] [blame] | 325 | if (!IsSwapchainImage() && !other_image_state->IsSwapchainImage() && |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 326 | !(createInfo.flags & other_image_state->createInfo.flags & VK_IMAGE_CREATE_ALIAS_BIT)) { |
| 327 | return false; |
| 328 | } |
Jeremy Gebben | 6fbf824 | 2021-06-21 09:14:46 -0600 | [diff] [blame] | 329 | const auto binding = Binding(); |
| 330 | const auto other_binding = other_image_state->Binding(); |
Aitor Camacho | 3294edd | 2022-05-16 22:34:19 +0200 | [diff] [blame] | 331 | if ((create_from_swapchain == VK_NULL_HANDLE) && binding && other_binding && |
| 332 | (binding->memory_state == other_binding->memory_state) && (binding->memory_offset == other_binding->memory_offset) && |
| 333 | IsCreateInfoEqual(other_image_state->createInfo)) { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 334 | return true; |
| 335 | } |
Jeremy Gebben | 4a8881f | 2022-01-10 17:04:30 -0700 | [diff] [blame] | 336 | if (bind_swapchain && (bind_swapchain == other_image_state->bind_swapchain) && |
| 337 | (swapchain_image_index == other_image_state->swapchain_image_index)) { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 338 | return true; |
| 339 | } |
| 340 | return false; |
| 341 | } |
| 342 | |
Jeremy Gebben | 4a8881f | 2022-01-10 17:04:30 -0700 | [diff] [blame] | 343 | void IMAGE_STATE::SetInitialLayoutMap() { |
| 344 | if (layout_range_map) { |
| 345 | return; |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 346 | } |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 347 | if ((createInfo.flags & VK_IMAGE_CREATE_ALIAS_BIT) != 0) { |
Jeremy Gebben | 4a8881f | 2022-01-10 17:04:30 -0700 | [diff] [blame] | 348 | // Look for another aliasing image and point at its layout state. |
| 349 | // ObjectBindings() is thread safe since returns by value, and once |
| 350 | // the weak_ptr is successfully locked, the other image state won't |
| 351 | // be freed out from under us. |
Aitor Camacho | a597660 | 2022-06-03 21:00:39 +0200 | [diff] [blame] | 352 | for (auto const &memory_state : GetBoundMemoryStates()) { |
| 353 | for (auto &entry : memory_state->ObjectBindings()) { |
| 354 | if (entry.first.type == kVulkanObjectTypeImage) { |
| 355 | auto base_node = entry.second.lock(); |
| 356 | if (base_node) { |
| 357 | auto other_image = static_cast<IMAGE_STATE *>(base_node.get()); |
| 358 | if (other_image != this && other_image->IsCompatibleAliasing(this)) { |
| 359 | layout_range_map = other_image->layout_range_map; |
| 360 | break; |
| 361 | } |
Jeremy Gebben | 4a8881f | 2022-01-10 17:04:30 -0700 | [diff] [blame] | 362 | } |
| 363 | } |
| 364 | } |
| 365 | } |
| 366 | } else if (bind_swapchain) { |
| 367 | // Swapchains can also alias if multiple images are bound (or retrieved |
| 368 | // with vkGetSwapchainImages()) for a (single swapchain, index) pair. |
| 369 | // ObjectBindings() is thread safe since returns by value, and once |
| 370 | // the weak_ptr is successfully locked, the other image state won't |
| 371 | // be freed out from under us. |
| 372 | for (auto &entry : bind_swapchain->ObjectBindings()) { |
| 373 | if (entry.first.type == kVulkanObjectTypeImage) { |
| 374 | auto base_node = entry.second.lock(); |
| 375 | if (base_node) { |
| 376 | auto other_image = static_cast<IMAGE_STATE *>(base_node.get()); |
| 377 | if (other_image != this && other_image->IsCompatibleAliasing(this)) { |
| 378 | layout_range_map = other_image->layout_range_map; |
| 379 | break; |
| 380 | } |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 381 | } |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 382 | } |
| 383 | } |
| 384 | } |
Jeremy Gebben | 4a8881f | 2022-01-10 17:04:30 -0700 | [diff] [blame] | 385 | // ... otherwise set up the new map. |
| 386 | if (!layout_range_map) { |
| 387 | // set up the new map completely before making it available |
| 388 | auto new_map = std::make_shared<GlobalImageLayoutRangeMap>(subresource_encoder.SubresourceCount()); |
| 389 | auto range_gen = subresource_adapter::RangeGenerator(subresource_encoder); |
| 390 | for (; range_gen->non_empty(); ++range_gen) { |
| 391 | new_map->insert(new_map->end(), std::make_pair(*range_gen, createInfo.initialLayout)); |
| 392 | } |
| 393 | layout_range_map = std::move(new_map); |
| 394 | } |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 395 | } |
| 396 | |
| 397 | void IMAGE_STATE::SetSwapchain(std::shared_ptr<SWAPCHAIN_NODE> &swapchain, uint32_t swapchain_index) { |
Jeremy Gebben | 82e11d5 | 2021-07-26 09:19:37 -0600 | [diff] [blame] | 398 | assert(IsSwapchainImage()); |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 399 | bind_swapchain = swapchain; |
| 400 | swapchain_image_index = swapchain_index; |
| 401 | bind_swapchain->AddParent(this); |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 402 | } |
| 403 | |
| 404 | VkDeviceSize IMAGE_STATE::GetFakeBaseAddress() const { |
Jeremy Gebben | 82e11d5 | 2021-07-26 09:19:37 -0600 | [diff] [blame] | 405 | if (!IsSwapchainImage()) { |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 406 | return BINDABLE::GetFakeBaseAddress(); |
| 407 | } |
| 408 | if (!bind_swapchain) { |
| 409 | return 0; |
| 410 | } |
| 411 | return bind_swapchain->images[swapchain_image_index].fake_base_address; |
| 412 | } |
| 413 | |
Aitor Camacho | 089e125 | 2022-05-24 21:57:47 +0200 | [diff] [blame] | 414 | VkExtent3D IMAGE_STATE::GetSubresourceExtent(VkImageAspectFlags aspect_mask, uint32_t mip_level) const { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 415 | // Return zero extent if mip level doesn't exist |
Aitor Camacho | 089e125 | 2022-05-24 21:57:47 +0200 | [diff] [blame] | 416 | if (mip_level >= createInfo.mipLevels) { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 417 | return VkExtent3D{0, 0, 0}; |
| 418 | } |
| 419 | |
| 420 | // Don't allow mip adjustment to create 0 dim, but pass along a 0 if that's what subresource specified |
| 421 | VkExtent3D extent = createInfo.extent; |
| 422 | |
| 423 | // If multi-plane, adjust per-plane extent |
| 424 | if (FormatIsMultiplane(createInfo.format)) { |
Aitor Camacho | 089e125 | 2022-05-24 21:57:47 +0200 | [diff] [blame] | 425 | VkExtent2D divisors = FindMultiplaneExtentDivisors(createInfo.format, aspect_mask); |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 426 | extent.width /= divisors.width; |
| 427 | extent.height /= divisors.height; |
| 428 | } |
| 429 | |
| 430 | if (createInfo.flags & VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV) { |
Aitor Camacho | 089e125 | 2022-05-24 21:57:47 +0200 | [diff] [blame] | 431 | extent.width = (0 == extent.width ? 0 : std::max(2U, 1 + ((extent.width - 1) >> mip_level))); |
| 432 | extent.height = (0 == extent.height ? 0 : std::max(2U, 1 + ((extent.height - 1) >> mip_level))); |
| 433 | extent.depth = (0 == extent.depth ? 0 : std::max(2U, 1 + ((extent.depth - 1) >> mip_level))); |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 434 | } else { |
Aitor Camacho | 089e125 | 2022-05-24 21:57:47 +0200 | [diff] [blame] | 435 | extent.width = (0 == extent.width ? 0 : std::max(1U, extent.width >> mip_level)); |
| 436 | extent.height = (0 == extent.height ? 0 : std::max(1U, extent.height >> mip_level)); |
| 437 | extent.depth = (0 == extent.depth ? 0 : std::max(1U, extent.depth >> mip_level)); |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 438 | } |
| 439 | |
| 440 | // Image arrays have an effective z extent that isn't diminished by mip level |
| 441 | if (VK_IMAGE_TYPE_3D != createInfo.imageType) { |
| 442 | extent.depth = createInfo.arrayLayers; |
| 443 | } |
| 444 | |
| 445 | return extent; |
| 446 | } |
| 447 | |
Aitor Camacho | 089e125 | 2022-05-24 21:57:47 +0200 | [diff] [blame] | 448 | // Returns the effective extent of an image subresource, adjusted for mip level and array depth. |
| 449 | VkExtent3D IMAGE_STATE::GetSubresourceExtent(const VkImageSubresourceLayers &subresource) const { |
| 450 | return GetSubresourceExtent(subresource.aspectMask, subresource.mipLevel); |
| 451 | } |
| 452 | |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 453 | static VkSamplerYcbcrConversion GetSamplerConversion(const VkImageViewCreateInfo *ci) { |
| 454 | auto *conversion_info = LvlFindInChain<VkSamplerYcbcrConversionInfo>(ci->pNext); |
| 455 | return conversion_info ? conversion_info->conversion : VK_NULL_HANDLE; |
| 456 | } |
| 457 | |
| 458 | static VkImageUsageFlags GetInheritedUsage(const VkImageViewCreateInfo *ci, const IMAGE_STATE &image_state) { |
| 459 | auto usage_create_info = LvlFindInChain<VkImageViewUsageCreateInfo>(ci->pNext); |
| 460 | return (usage_create_info) ? usage_create_info->usage : image_state.createInfo.usage; |
| 461 | } |
| 462 | |
Tony-LunarG | 69604c4 | 2021-11-22 16:00:12 -0700 | [diff] [blame] | 463 | static float GetImageViewMinLod(const VkImageViewCreateInfo* ci) { |
| 464 | auto image_view_min_lod = LvlFindInChain<VkImageViewMinLodCreateInfoEXT>(ci->pNext); |
| 465 | return (image_view_min_lod) ? image_view_min_lod->minLod : 0.0f; |
| 466 | } |
| 467 | |
Tony-LunarG | ffb5b52 | 2022-06-15 15:49:27 -0600 | [diff] [blame] | 468 | #ifdef VK_USE_PLATFORM_METAL_EXT |
| 469 | static bool GetMetalExport(const VkImageViewCreateInfo *info) { |
| 470 | bool retval = false; |
| 471 | auto export_metal_object_info = LvlFindInChain<VkExportMetalObjectCreateInfoEXT>(info->pNext); |
| 472 | while (export_metal_object_info) { |
| 473 | if (export_metal_object_info->exportObjectType == VK_EXPORT_METAL_OBJECT_TYPE_METAL_TEXTURE_BIT_EXT) { |
| 474 | retval = true; |
| 475 | break; |
| 476 | } |
| 477 | export_metal_object_info = LvlFindInChain<VkExportMetalObjectCreateInfoEXT>(export_metal_object_info->pNext); |
| 478 | } |
| 479 | return retval; |
| 480 | } |
| 481 | #endif // VK_USE_PLATFORM_METAL_EXT |
| 482 | |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 483 | IMAGE_VIEW_STATE::IMAGE_VIEW_STATE(const std::shared_ptr<IMAGE_STATE> &im, VkImageView iv, const VkImageViewCreateInfo *ci, |
Lionel Landwerlin | 21719f6 | 2021-12-09 11:40:09 +0200 | [diff] [blame] | 484 | VkFormatFeatureFlags2KHR ff, const VkFilterCubicImageViewImageFormatPropertiesEXT &cubic_props) |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 485 | : BASE_NODE(iv, kVulkanObjectTypeImageView), |
ziga-lunarg | 857a651 | 2022-04-08 01:08:18 +0200 | [diff] [blame] | 486 | safe_create_info(ci), |
| 487 | create_info(*safe_create_info.ptr()), |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 488 | normalized_subresource_range(::NormalizeSubresourceRange(im->createInfo, *ci)), |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 489 | range_generator(im->subresource_encoder, normalized_subresource_range), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 490 | samples(im->createInfo.samples), |
| 491 | // When the image has a external format the views format must be VK_FORMAT_UNDEFINED and it is required to use a sampler |
| 492 | // Ycbcr conversion. Thus we can't extract any meaningful information from the format parameter. As a Sampler Ycbcr |
| 493 | // conversion must be used the shader type is always float. |
| 494 | descriptor_format_bits(im->HasAHBFormat() ? static_cast<unsigned>(DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT) |
| 495 | : DescriptorRequirementsBitsFromFormat(ci->format)), |
| 496 | samplerConversion(GetSamplerConversion(ci)), |
| 497 | filter_cubic_props(cubic_props), |
Tony-LunarG | 69604c4 | 2021-11-22 16:00:12 -0700 | [diff] [blame] | 498 | min_lod(GetImageViewMinLod(ci)), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 499 | format_features(ff), |
| 500 | inherited_usage(GetInheritedUsage(ci, *im)), |
Tony-LunarG | ffb5b52 | 2022-06-15 15:49:27 -0600 | [diff] [blame] | 501 | #ifdef VK_USE_PLATFORM_METAL_EXT |
| 502 | metal_imageview_export(GetMetalExport(ci)), |
| 503 | #endif |
Jeremy Gebben | 610d3a6 | 2022-01-01 12:53:17 -0700 | [diff] [blame] | 504 | image_state(im) {} |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 505 | |
| 506 | void IMAGE_VIEW_STATE::Destroy() { |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 507 | if (image_state) { |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 508 | image_state->RemoveParent(this); |
| 509 | image_state = nullptr; |
| 510 | } |
| 511 | BASE_NODE::Destroy(); |
| 512 | } |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 513 | |
Jeremy Gebben | 11a68a3 | 2021-07-29 11:59:22 -0600 | [diff] [blame] | 514 | bool IMAGE_VIEW_STATE::IsDepthSliced() const { return ::IsDepthSliced(image_state->createInfo, create_info); } |
| 515 | |
| 516 | VkOffset3D IMAGE_VIEW_STATE::GetOffset() const { |
| 517 | VkOffset3D result = {0, 0, 0}; |
| 518 | if (IsDepthSliced()) { |
| 519 | result.z = create_info.subresourceRange.baseArrayLayer; |
| 520 | } |
| 521 | return result; |
| 522 | } |
| 523 | |
| 524 | VkExtent3D IMAGE_VIEW_STATE::GetExtent() const { |
| 525 | VkExtent3D result = image_state->createInfo.extent; |
| 526 | if (IsDepthSliced()) { |
| 527 | result.depth = create_info.subresourceRange.layerCount; |
| 528 | } |
| 529 | return result; |
| 530 | } |
| 531 | |
ziga-lunarg | ff6485c | 2021-10-08 18:18:32 +0200 | [diff] [blame] | 532 | uint32_t IMAGE_VIEW_STATE::GetAttachmentLayerCount() const { |
| 533 | if (create_info.subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS && !IsDepthSliced()) { |
| 534 | return image_state->createInfo.arrayLayers; |
| 535 | } |
| 536 | return create_info.subresourceRange.layerCount; |
| 537 | } |
| 538 | |
Jeremy Gebben | bcba6d3 | 2021-07-16 11:41:41 -0600 | [diff] [blame] | 539 | static safe_VkImageCreateInfo GetImageCreateInfo(const VkSwapchainCreateInfoKHR *pCreateInfo) { |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 540 | auto image_ci = LvlInitStruct<VkImageCreateInfo>(); |
Jeremy Gebben | bcba6d3 | 2021-07-16 11:41:41 -0600 | [diff] [blame] | 541 | // Pull out the format list only. This stack variable will get copied onto the heap |
| 542 | // by the 'safe' constructor used to build the return value below. |
| 543 | VkImageFormatListCreateInfo fmt_info; |
| 544 | auto chain_fmt_info = LvlFindInChain<VkImageFormatListCreateInfo>(pCreateInfo->pNext); |
| 545 | if (chain_fmt_info) { |
| 546 | fmt_info = *chain_fmt_info; |
| 547 | fmt_info.pNext = nullptr; |
| 548 | image_ci.pNext = &fmt_info; |
| 549 | } else { |
| 550 | image_ci.pNext = nullptr; |
| 551 | } |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 552 | image_ci.flags = 0; // to be updated below |
| 553 | image_ci.imageType = VK_IMAGE_TYPE_2D; |
| 554 | image_ci.format = pCreateInfo->imageFormat; |
| 555 | image_ci.extent.width = pCreateInfo->imageExtent.width; |
| 556 | image_ci.extent.height = pCreateInfo->imageExtent.height; |
| 557 | image_ci.extent.depth = 1; |
| 558 | image_ci.mipLevels = 1; |
| 559 | image_ci.arrayLayers = pCreateInfo->imageArrayLayers; |
| 560 | image_ci.samples = VK_SAMPLE_COUNT_1_BIT; |
| 561 | image_ci.tiling = VK_IMAGE_TILING_OPTIMAL; |
| 562 | image_ci.usage = pCreateInfo->imageUsage; |
| 563 | image_ci.sharingMode = pCreateInfo->imageSharingMode; |
| 564 | image_ci.queueFamilyIndexCount = pCreateInfo->queueFamilyIndexCount; |
| 565 | image_ci.pQueueFamilyIndices = pCreateInfo->pQueueFamilyIndices; |
| 566 | image_ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 567 | |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 568 | if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR) { |
| 569 | image_ci.flags |= VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT; |
| 570 | } |
| 571 | if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) { |
| 572 | image_ci.flags |= VK_IMAGE_CREATE_PROTECTED_BIT; |
| 573 | } |
| 574 | if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { |
| 575 | image_ci.flags |= (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT); |
| 576 | } |
Jeremy Gebben | bcba6d3 | 2021-07-16 11:41:41 -0600 | [diff] [blame] | 577 | return safe_VkImageCreateInfo(&image_ci); |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 578 | } |
| 579 | |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 580 | SWAPCHAIN_NODE::SWAPCHAIN_NODE(ValidationStateTracker *dev_data_, const VkSwapchainCreateInfoKHR *pCreateInfo, |
| 581 | VkSwapchainKHR swapchain) |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 582 | : BASE_NODE(swapchain, kVulkanObjectTypeSwapchainKHR), |
| 583 | createInfo(pCreateInfo), |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 584 | shared_presentable(VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR == pCreateInfo->presentMode || |
| 585 | VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR == pCreateInfo->presentMode), |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 586 | image_create_info(GetImageCreateInfo(pCreateInfo)), |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 587 | dev_data(dev_data_) {} |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 588 | |
| 589 | void SWAPCHAIN_NODE::PresentImage(uint32_t image_index) { |
| 590 | if (image_index >= images.size()) return; |
Jeremy Gebben | 4295bdf | 2021-09-09 12:34:07 -0600 | [diff] [blame] | 591 | assert(acquired_images > 0); |
| 592 | acquired_images--; |
ziga-lunarg | 69aa72f | 2022-03-29 15:24:35 +0200 | [diff] [blame] | 593 | images[image_index].acquired = false; |
Jeremy Gebben | 4295bdf | 2021-09-09 12:34:07 -0600 | [diff] [blame] | 594 | if (shared_presentable) { |
| 595 | IMAGE_STATE *image_state = images[image_index].image_state; |
| 596 | if (image_state) { |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 597 | image_state->layout_locked = true; |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 598 | } |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 599 | } |
| 600 | } |
| 601 | |
| 602 | void SWAPCHAIN_NODE::AcquireImage(uint32_t image_index) { |
| 603 | if (image_index >= images.size()) return; |
| 604 | |
Jeremy Gebben | 4295bdf | 2021-09-09 12:34:07 -0600 | [diff] [blame] | 605 | assert(acquired_images < std::numeric_limits<uint32_t>::max()); |
ziga-lunarg | 69aa72f | 2022-03-29 15:24:35 +0200 | [diff] [blame] | 606 | acquired_images++; |
| 607 | images[image_index].acquired = true; |
Jeremy Gebben | 4295bdf | 2021-09-09 12:34:07 -0600 | [diff] [blame] | 608 | if (shared_presentable) { |
| 609 | IMAGE_STATE *image_state = images[image_index].image_state; |
| 610 | if (image_state) { |
| 611 | image_state->shared_presentable = shared_presentable; |
| 612 | } |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 613 | } |
| 614 | } |
| 615 | |
| 616 | void SWAPCHAIN_NODE::Destroy() { |
| 617 | for (auto &swapchain_image : images) { |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 618 | if (swapchain_image.image_state) { |
Jeremy Gebben | 8e59965 | 2021-10-20 12:10:33 -0600 | [diff] [blame] | 619 | RemoveParent(swapchain_image.image_state); |
Jeremy Gebben | 082a983 | 2021-10-28 13:40:11 -0600 | [diff] [blame] | 620 | dev_data->Destroy<IMAGE_STATE>(swapchain_image.image_state->image()); |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 621 | } |
Jeremy Gebben | 62c3bf4 | 2021-07-21 15:38:24 -0600 | [diff] [blame] | 622 | // NOTE: We don't have access to dev_data->fake_memory.Free() here, but it is currently a no-op |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 623 | } |
Jeremy Gebben | 5a542f5 | 2021-07-21 15:25:52 -0600 | [diff] [blame] | 624 | images.clear(); |
| 625 | if (surface) { |
| 626 | surface->RemoveParent(this); |
| 627 | surface = nullptr; |
| 628 | } |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 629 | BASE_NODE::Destroy(); |
| 630 | } |
| 631 | |
Jeremy Gebben | c9a2403 | 2021-11-02 11:36:08 -0600 | [diff] [blame] | 632 | void SWAPCHAIN_NODE::NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) { |
| 633 | BASE_NODE::NotifyInvalidate(invalid_nodes, unlink); |
Jeremy Gebben | b4d1701 | 2021-07-08 13:18:15 -0600 | [diff] [blame] | 634 | if (unlink) { |
Jeremy Gebben | 5a542f5 | 2021-07-21 15:25:52 -0600 | [diff] [blame] | 635 | surface = nullptr; |
Jeremy Gebben | 1dfbd17 | 2021-05-19 14:00:58 -0600 | [diff] [blame] | 636 | } |
| 637 | } |
Jeremy Gebben | 5a542f5 | 2021-07-21 15:25:52 -0600 | [diff] [blame] | 638 | |
| 639 | void SURFACE_STATE::Destroy() { |
| 640 | if (swapchain) { |
| 641 | swapchain = nullptr; |
| 642 | } |
| 643 | BASE_NODE::Destroy(); |
| 644 | } |
| 645 | |
| 646 | void SURFACE_STATE::RemoveParent(BASE_NODE *parent_node) { |
| 647 | if (swapchain == parent_node) { |
| 648 | swapchain = nullptr; |
| 649 | } |
| 650 | BASE_NODE::RemoveParent(parent_node); |
| 651 | } |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 652 | |
| 653 | void SURFACE_STATE::SetQueueSupport(VkPhysicalDevice phys_dev, uint32_t qfi, bool supported) { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 654 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 655 | assert(phys_dev); |
| 656 | GpuQueue key{phys_dev, qfi}; |
| 657 | gpu_queue_support_[key] = supported; |
| 658 | } |
| 659 | |
| 660 | bool SURFACE_STATE::GetQueueSupport(VkPhysicalDevice phys_dev, uint32_t qfi) const { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 661 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 662 | assert(phys_dev); |
| 663 | GpuQueue key{phys_dev, qfi}; |
| 664 | auto iter = gpu_queue_support_.find(key); |
| 665 | if (iter != gpu_queue_support_.end()) { |
| 666 | return iter->second; |
| 667 | } |
| 668 | VkBool32 supported = VK_FALSE; |
| 669 | DispatchGetPhysicalDeviceSurfaceSupportKHR(phys_dev, qfi, surface(), &supported); |
| 670 | gpu_queue_support_[key] = (supported == VK_TRUE); |
| 671 | return supported == VK_TRUE; |
| 672 | } |
| 673 | |
| 674 | void SURFACE_STATE::SetPresentModes(VkPhysicalDevice phys_dev, std::vector<VkPresentModeKHR> &&modes) { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 675 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 676 | assert(phys_dev); |
| 677 | present_modes_[phys_dev] = std::move(modes); |
| 678 | } |
| 679 | |
| 680 | std::vector<VkPresentModeKHR> SURFACE_STATE::GetPresentModes(VkPhysicalDevice phys_dev) const { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 681 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 682 | assert(phys_dev); |
| 683 | auto iter = present_modes_.find(phys_dev); |
| 684 | if (iter != present_modes_.end()) { |
| 685 | return iter->second; |
| 686 | } |
| 687 | std::vector<VkPresentModeKHR> result; |
| 688 | uint32_t count = 0; |
| 689 | DispatchGetPhysicalDeviceSurfacePresentModesKHR(phys_dev, surface(), &count, nullptr); |
| 690 | result.resize(count); |
| 691 | DispatchGetPhysicalDeviceSurfacePresentModesKHR(phys_dev, surface(), &count, result.data()); |
| 692 | return result; |
| 693 | } |
| 694 | |
| 695 | void SURFACE_STATE::SetFormats(VkPhysicalDevice phys_dev, std::vector<VkSurfaceFormatKHR> &&fmts) { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 696 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 697 | assert(phys_dev); |
| 698 | formats_[phys_dev] = std::move(fmts); |
| 699 | } |
| 700 | |
| 701 | std::vector<VkSurfaceFormatKHR> SURFACE_STATE::GetFormats(VkPhysicalDevice phys_dev) const { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 702 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 703 | assert(phys_dev); |
| 704 | auto iter = formats_.find(phys_dev); |
| 705 | if (iter != formats_.end()) { |
| 706 | return iter->second; |
| 707 | } |
| 708 | std::vector<VkSurfaceFormatKHR> result; |
| 709 | uint32_t count = 0; |
| 710 | DispatchGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, surface(), &count, nullptr); |
| 711 | result.resize(count); |
| 712 | DispatchGetPhysicalDeviceSurfaceFormatsKHR(phys_dev, surface(), &count, result.data()); |
| 713 | formats_[phys_dev] = result; |
| 714 | return result; |
| 715 | } |
| 716 | |
| 717 | void SURFACE_STATE::SetCapabilities(VkPhysicalDevice phys_dev, const VkSurfaceCapabilitiesKHR &caps) { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 718 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 719 | assert(phys_dev); |
| 720 | capabilities_[phys_dev] = caps; |
| 721 | } |
| 722 | |
| 723 | VkSurfaceCapabilitiesKHR SURFACE_STATE::GetCapabilities(VkPhysicalDevice phys_dev) const { |
Jeremy Gebben | 6c771d2 | 2022-01-01 12:30:15 -0700 | [diff] [blame] | 724 | auto guard = Lock(); |
Jeremy Gebben | 87b2e6b | 2021-10-20 11:21:40 -0600 | [diff] [blame] | 725 | assert(phys_dev); |
| 726 | auto iter = capabilities_.find(phys_dev); |
| 727 | if (iter != capabilities_.end()) { |
| 728 | return iter->second; |
| 729 | } |
| 730 | VkSurfaceCapabilitiesKHR result{}; |
| 731 | DispatchGetPhysicalDeviceSurfaceCapabilitiesKHR(phys_dev, surface(), &result); |
| 732 | capabilities_[phys_dev] = result; |
| 733 | return result; |
| 734 | } |