forked from KhronosGroup/Vulkan-ValidationLayers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimage_state.h
336 lines (280 loc) · 14.3 KB
/
image_state.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/* Copyright (c) 2015-2021 The Khronos Group Inc.
* Copyright (c) 2015-2021 Valve Corporation
* Copyright (c) 2015-2021 LunarG, Inc.
* Copyright (C) 2015-2021 Google Inc.
* Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Courtney Goeltzenleuchter <[email protected]>
* Author: Tobin Ehlis <[email protected]>
* Author: Chris Forbes <[email protected]>
* Author: Mark Lobodzinski <[email protected]>
* Author: Dave Houlton <[email protected]>
* Author: John Zulauf <[email protected]>
* Author: Tobias Hector <[email protected]>
* Author: Jeremy Gebben <[email protected]>
*/
#pragma once
#include "device_memory_state.h"
#include "image_layout_map.h"
#include "vk_format_utils.h"
class ValidationStateTracker;
class SURFACE_STATE;
class SWAPCHAIN_NODE;
static inline bool operator==(const VkImageSubresource &lhs, const VkImageSubresource &rhs) {
bool is_equal = (lhs.aspectMask == rhs.aspectMask) && (lhs.mipLevel == rhs.mipLevel) && (lhs.arrayLayer == rhs.arrayLayer);
return is_equal;
}
VkImageSubresourceRange NormalizeSubresourceRange(const VkImageCreateInfo &image_create_info, const VkImageSubresourceRange &range);
VkImageSubresourceRange NormalizeSubresourceRange(const VkImageCreateInfo &image_create_info,
const VkImageViewCreateInfo &view_create_info);
// Transfer VkImageSubresourceRange into VkImageSubresourceLayers struct
static inline VkImageSubresourceLayers LayersFromRange(const VkImageSubresourceRange &subresource_range) {
VkImageSubresourceLayers subresource_layers;
subresource_layers.aspectMask = subresource_range.aspectMask;
subresource_layers.baseArrayLayer = subresource_range.baseArrayLayer;
subresource_layers.layerCount = subresource_range.layerCount;
subresource_layers.mipLevel = subresource_range.baseMipLevel;
return subresource_layers;
}
// Transfer VkImageSubresourceLayers into VkImageSubresourceRange struct
static inline VkImageSubresourceRange RangeFromLayers(const VkImageSubresourceLayers &subresource_layers) {
VkImageSubresourceRange subresource_range;
subresource_range.aspectMask = subresource_layers.aspectMask;
subresource_range.baseArrayLayer = subresource_layers.baseArrayLayer;
subresource_range.layerCount = subresource_layers.layerCount;
subresource_range.baseMipLevel = subresource_layers.mipLevel;
subresource_range.levelCount = 1;
return subresource_range;
}
// State for VkImage objects.
// Parent -> child relationships in the object usage tree:
// 1. Normal images:
// IMAGE_STATE [1] -> [1] DEVICE_MEMORY_STATE
//
// 2. Sparse images:
// IMAGE_STATE [1] -> [N] DEVICE_MEMORY_STATE
//
// 3. VK_IMAGE_CREATE_ALIAS_BIT images:
// IMAGE_STATE [N] -> [1] DEVICE_MEMORY_STATE
// All other images using the same device memory are in the aliasing_images set.
//
// 4. Swapchain images
// IMAGE_STATE [N] -> [1] SWAPCHAIN_NODE
// All other images using the same swapchain and swapchain_image_index are in the aliasing_images set.
// Note that the images for *every* image_index will show up as parents of the swapchain,
// so swapchain_image_index values must be compared.
//
class IMAGE_STATE : public BINDABLE {
public:
const safe_VkImageCreateInfo safe_create_info;
const VkImageCreateInfo &createInfo;
bool shared_presentable; // True for a front-buffered swapchain image
bool layout_locked; // A front-buffered image that has been presented can never have layout transitioned
const uint64_t ahb_format; // External Android format, if provided
const VkImageSubresourceRange full_range; // The normalized ISR for all levels, layers, and aspects
const VkSwapchainKHR create_from_swapchain;
std::shared_ptr<SWAPCHAIN_NODE> bind_swapchain;
uint32_t swapchain_image_index;
const VkFormatFeatureFlags format_features;
// Need to memory requirments for each plane if image is disjoint
const bool disjoint; // True if image was created with VK_IMAGE_CREATE_DISJOINT_BIT
static constexpr int MAX_PLANES = 3;
using MemoryReqs = std::array<VkMemoryRequirements, MAX_PLANES>;
const MemoryReqs requirements;
std::array<bool, MAX_PLANES> memory_requirements_checked;
using SparseReqs = std::vector<VkSparseImageMemoryRequirements>;
const SparseReqs sparse_requirements;
const bool sparse_metadata_required; // Track if sparse metadata aspect is required for this image
bool get_sparse_reqs_called; // Track if GetImageSparseMemoryRequirements() has been called for this image
bool sparse_metadata_bound; // Track if sparse metadata aspect is bound to this image
const image_layout_map::Encoder subresource_encoder; // Subresource resolution encoder
std::unique_ptr<const subresource_adapter::ImageRangeEncoder> fragment_encoder; // Fragment resolution encoder
const VkDevice store_device_as_workaround; // TODO REMOVE WHEN encoder can be const
layer_data::unordered_set<IMAGE_STATE *> aliasing_images;
IMAGE_STATE(const ValidationStateTracker *dev_data, VkImage img, const VkImageCreateInfo *pCreateInfo, VkFormatFeatureFlags features);
IMAGE_STATE(const ValidationStateTracker *dev_data, VkImage img, const VkImageCreateInfo *pCreateInfo, VkSwapchainKHR swapchain,
uint32_t swapchain_index, VkFormatFeatureFlags features);
IMAGE_STATE(IMAGE_STATE const &rh_obj) = delete;
VkImage image() const { return handle_.Cast<VkImage>(); }
bool HasAHBFormat() const { return ahb_format != 0; }
bool IsCompatibleAliasing(IMAGE_STATE *other_image_state) const;
bool IsCreateInfoEqual(const VkImageCreateInfo &other_createInfo) const;
bool IsCreateInfoDedicatedAllocationImageAliasingCompatible(const VkImageCreateInfo &other_createInfo) const;
bool IsSwapchainImage() const { return create_from_swapchain != VK_NULL_HANDLE; }
inline bool IsImageTypeEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.imageType == other_createInfo.imageType;
}
inline bool IsFormatEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.format == other_createInfo.format;
}
inline bool IsMipLevelsEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.mipLevels == other_createInfo.mipLevels;
}
inline bool IsUsageEqual(const VkImageCreateInfo &other_createInfo) const { return createInfo.usage == other_createInfo.usage; }
inline bool IsSamplesEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.samples == other_createInfo.samples;
}
inline bool IsTilingEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.tiling == other_createInfo.tiling;
}
inline bool IsArrayLayersEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.arrayLayers == other_createInfo.arrayLayers;
}
inline bool IsInitialLayoutEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.initialLayout == other_createInfo.initialLayout;
}
inline bool IsSharingModeEqual(const VkImageCreateInfo &other_createInfo) const {
return createInfo.sharingMode == other_createInfo.sharingMode;
}
inline bool IsExtentEqual(const VkImageCreateInfo &other_createInfo) const {
return (createInfo.extent.width == other_createInfo.extent.width) &&
(createInfo.extent.height == other_createInfo.extent.height) &&
(createInfo.extent.depth == other_createInfo.extent.depth);
}
inline bool IsQueueFamilyIndicesEqual(const VkImageCreateInfo &other_createInfo) const {
return (createInfo.queueFamilyIndexCount == other_createInfo.queueFamilyIndexCount) &&
(createInfo.queueFamilyIndexCount == 0 ||
memcmp(createInfo.pQueueFamilyIndices, other_createInfo.pQueueFamilyIndices,
createInfo.queueFamilyIndexCount * sizeof(createInfo.pQueueFamilyIndices[0])) == 0);
}
~IMAGE_STATE() {
if (!Destroyed()) {
Destroy();
}
}
void SetMemBinding(std::shared_ptr<DEVICE_MEMORY_STATE> &mem, VkDeviceSize memory_offset) override;
void SetSwapchain(std::shared_ptr<SWAPCHAIN_NODE> &swapchain, uint32_t swapchain_index);
VkDeviceSize GetFakeBaseAddress() const override;
void Destroy() override;
VkExtent3D GetSubresourceExtent(const VkImageSubresourceLayers &subresource) const;
VkImageSubresourceRange NormalizeSubresourceRange(const VkImageSubresourceRange &range) const {
return ::NormalizeSubresourceRange(createInfo, range);
}
protected:
void AddAliasingImage(IMAGE_STATE *bound_image);
void Unlink();
void NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) override;
};
// State for VkImageView objects.
// Parent -> child relationships in the object usage tree:
// IMAGE_VIEW_STATE [N] -> [1] IMAGE_STATE
class IMAGE_VIEW_STATE : public BASE_NODE {
public:
const VkImageViewCreateInfo create_info;
const VkImageSubresourceRange normalized_subresource_range;
const image_layout_map::RangeGenerator range_generator;
const VkSampleCountFlagBits samples;
const unsigned descriptor_format_bits;
const VkSamplerYcbcrConversion samplerConversion; // Handle of the ycbcr sampler conversion the image was created with, if any
const VkFilterCubicImageViewImageFormatPropertiesEXT filter_cubic_props;
const float min_lod;
const VkFormatFeatureFlags format_features;
const VkImageUsageFlags inherited_usage; // from spec #resources-image-inherited-usage
std::shared_ptr<IMAGE_STATE> image_state;
IMAGE_VIEW_STATE(const std::shared_ptr<IMAGE_STATE> &image_state, VkImageView iv, const VkImageViewCreateInfo *ci,
VkFormatFeatureFlags ff, const VkFilterCubicImageViewImageFormatPropertiesEXT &cubic_props);
IMAGE_VIEW_STATE(const IMAGE_VIEW_STATE &rh_obj) = delete;
VkImageView image_view() const { return handle_.Cast<VkImageView>(); }
virtual ~IMAGE_VIEW_STATE() {
if (!Destroyed()) {
Destroy();
}
}
bool OverlapSubresource(const IMAGE_VIEW_STATE &compare_view) const;
void Destroy() override;
bool IsDepthSliced() const;
VkOffset3D GetOffset() const;
VkExtent3D GetExtent() const;
};
struct SWAPCHAIN_IMAGE {
IMAGE_STATE *image_state = nullptr;
VkDeviceSize fake_base_address = 0;
bool acquired = false;
};
// State for VkSwapchainKHR objects.
// Parent -> child relationships in the object usage tree:
// SWAPCHAIN_NODE [N] -> [1] SURFACE_STATE
// However, only 1 swapchain for each surface can be !retired.
class SWAPCHAIN_NODE : public BASE_NODE {
public:
const safe_VkSwapchainCreateInfoKHR createInfo;
std::vector<SWAPCHAIN_IMAGE> images;
bool retired = false;
const bool shared_presentable;
uint32_t get_swapchain_image_count = 0;
uint64_t max_present_id = 0;
const safe_VkImageCreateInfo image_create_info;
std::shared_ptr<SURFACE_STATE> surface;
ValidationStateTracker *dev_data;
uint32_t acquired_images = 0;
SWAPCHAIN_NODE(ValidationStateTracker *dev_data, const VkSwapchainCreateInfoKHR *pCreateInfo, VkSwapchainKHR swapchain);
~SWAPCHAIN_NODE() {
if (!Destroyed()) {
Destroy();
}
}
VkSwapchainKHR swapchain() const { return handle_.Cast<VkSwapchainKHR>(); }
void PresentImage(uint32_t image_index);
void AcquireImage(uint32_t image_index);
void Destroy() override;
const NodeSet &ObjectBindings() const { return parent_nodes_; }
protected:
void NotifyInvalidate(const BASE_NODE::NodeList &invalid_nodes, bool unlink) override;
};
struct GpuQueue {
VkPhysicalDevice gpu;
uint32_t queue_family_index;
};
inline bool operator==(GpuQueue const &lhs, GpuQueue const &rhs) {
return (lhs.gpu == rhs.gpu && lhs.queue_family_index == rhs.queue_family_index);
}
namespace std {
template <>
struct hash<GpuQueue> {
size_t operator()(GpuQueue gq) const throw() {
return hash<uint64_t>()((uint64_t)(gq.gpu)) ^ hash<uint32_t>()(gq.queue_family_index);
}
};
} // namespace std
// State for VkSurfaceKHR objects.
// Parent -> child relationships in the object usage tree:
// SURFACE_STATE -> nothing
class SURFACE_STATE : public BASE_NODE {
public:
SURFACE_STATE(VkSurfaceKHR s) : BASE_NODE(s, kVulkanObjectTypeSurfaceKHR) {}
~SURFACE_STATE() {
if (!Destroyed()) {
Destroy();
}
}
VkSurfaceKHR surface() const { return handle_.Cast<VkSurfaceKHR>(); }
void Destroy() override;
VkImageCreateInfo GetImageCreateInfo() const;
void RemoveParent(BASE_NODE *parent_node) override;
void SetQueueSupport(VkPhysicalDevice phys_dev, uint32_t qfi, bool supported);
bool GetQueueSupport(VkPhysicalDevice phys_dev, uint32_t qfi) const;
void SetPresentModes(VkPhysicalDevice phys_dev, std::vector<VkPresentModeKHR> &&modes);
std::vector<VkPresentModeKHR> GetPresentModes(VkPhysicalDevice phys_dev) const;
void SetFormats(VkPhysicalDevice phys_dev, std::vector<VkSurfaceFormatKHR> &&fmts);
std::vector<VkSurfaceFormatKHR> GetFormats(VkPhysicalDevice phys_dev) const;
void SetCapabilities(VkPhysicalDevice phys_dev, const VkSurfaceCapabilitiesKHR &caps);
VkSurfaceCapabilitiesKHR GetCapabilities(VkPhysicalDevice phys_dev) const;
SWAPCHAIN_NODE *swapchain{nullptr};
private:
mutable layer_data::unordered_map<GpuQueue, bool> gpu_queue_support_;
mutable layer_data::unordered_map<VkPhysicalDevice, std::vector<VkPresentModeKHR>> present_modes_;
mutable layer_data::unordered_map<VkPhysicalDevice, std::vector<VkSurfaceFormatKHR>> formats_;
mutable layer_data::unordered_map<VkPhysicalDevice, VkSurfaceCapabilitiesKHR> capabilities_;
};