Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2019 The Khronos Group Inc.
      2  * Copyright (c) 2015-2019 Valve Corporation
      3  * Copyright (c) 2015-2019 LunarG, Inc.
      4  * Copyright (C) 2015-2019 Google Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Courtney Goeltzenleuchter <courtneygo (at) google.com>
     19  * Author: Tobin Ehlis <tobine (at) google.com>
     20  * Author: Chris Forbes <chrisf (at) ijw.co.nz>
     21  * Author: Mark Lobodzinski <mark (at) lunarg.com>
     22  * Author: Dave Houlton <daveh (at) lunarg.com>
     23  */
     24 #ifndef CORE_VALIDATION_TYPES_H_
     25 #define CORE_VALIDATION_TYPES_H_
     26 
     27 #include "hash_vk_types.h"
     28 #include "vk_safe_struct.h"
     29 #include "vulkan/vulkan.h"
     30 #include "vk_layer_logging.h"
     31 #include "vk_object_types.h"
     32 #include "vk_extension_helper.h"
     33 #include "vk_typemap_helper.h"
     34 #include "convert_to_renderpass2.h"
     35 #include <atomic>
     36 #include <functional>
     37 #include <list>
     38 #include <map>
     39 #include <memory>
     40 #include <set>
     41 #include <string.h>
     42 #include <unordered_map>
     43 #include <unordered_set>
     44 #include <vector>
     45 #include <memory>
     46 #include <list>
     47 
     48 #ifdef VK_USE_PLATFORM_ANDROID_KHR
     49 #include "android_ndk_types.h"
     50 #endif  // VK_USE_PLATFORM_ANDROID_KHR
     51 
     52 class CoreChecks;
     53 typedef CoreChecks layer_data;
     54 typedef CoreChecks instance_layer_data;
     55 
     56 // Fwd declarations -- including descriptor_set.h creates an ugly include loop
     57 namespace cvdescriptorset {
     58 class DescriptorSetLayoutDef;
     59 class DescriptorSetLayout;
     60 class DescriptorSet;
     61 }  // namespace cvdescriptorset
     62 
     63 struct GLOBAL_CB_NODE;
     64 
     65 enum CALL_STATE {
     66     UNCALLED,       // Function has not been called
     67     QUERY_COUNT,    // Function called once to query a count
     68     QUERY_DETAILS,  // Function called w/ a count to query details
     69 };
     70 
     71 class BASE_NODE {
     72    public:
     73     // Track when object is being used by an in-flight command buffer
     74     std::atomic_int in_use;
     75     // Track command buffers that this object is bound to
     76     //  binding initialized when cmd referencing object is bound to command buffer
     77     //  binding removed when command buffer is reset or destroyed
     78     // When an object is destroyed, any bound cbs are set to INVALID
     79     std::unordered_set<GLOBAL_CB_NODE *> cb_bindings;
     80 
     81     BASE_NODE() { in_use.store(0); };
     82 };
     83 
     84 // Track command pools and their command buffers
     85 struct COMMAND_POOL_NODE : public BASE_NODE {
     86     VkCommandPoolCreateFlags createFlags;
     87     uint32_t queueFamilyIndex;
     88     // Cmd buffers allocated from this pool
     89     std::unordered_set<VkCommandBuffer> commandBuffers;
     90 };
     91 
     92 // Utilities for barriers and the commmand pool
     93 template <typename Barrier>
     94 static bool IsTransferOp(const Barrier *barrier) {
     95     return barrier->srcQueueFamilyIndex != barrier->dstQueueFamilyIndex;
     96 }
     97 
     98 template <typename Barrier, bool assume_transfer = false>
     99 static bool TempIsReleaseOp(const COMMAND_POOL_NODE *pool, const Barrier *barrier) {
    100     return (assume_transfer || IsTransferOp(barrier)) && (pool->queueFamilyIndex == barrier->srcQueueFamilyIndex);
    101 }
    102 
    103 template <typename Barrier, bool assume_transfer = false>
    104 static bool IsAcquireOp(const COMMAND_POOL_NODE *pool, const Barrier *barrier) {
    105     return (assume_transfer || IsTransferOp(barrier)) && (pool->queueFamilyIndex == barrier->dstQueueFamilyIndex);
    106 }
    107 
    108 inline bool IsSpecial(const uint32_t queue_family_index) {
    109     return (queue_family_index == VK_QUEUE_FAMILY_EXTERNAL_KHR) || (queue_family_index == VK_QUEUE_FAMILY_FOREIGN_EXT);
    110 }
    111 
    112 // Generic wrapper for vulkan objects
    113 struct VK_OBJECT {
    114     uint64_t handle;
    115     VulkanObjectType type;
    116 };
    117 
    118 inline bool operator==(VK_OBJECT a, VK_OBJECT b) NOEXCEPT { return a.handle == b.handle && a.type == b.type; }
    119 
    120 namespace std {
    121 template <>
    122 struct hash<VK_OBJECT> {
    123     size_t operator()(VK_OBJECT obj) const NOEXCEPT { return hash<uint64_t>()(obj.handle) ^ hash<uint32_t>()(obj.type); }
    124 };
    125 }  // namespace std
    126 
    127 // Flags describing requirements imposed by the pipeline on a descriptor. These
    128 // can't be checked at pipeline creation time as they depend on the Image or
    129 // ImageView bound.
    130 enum descriptor_req {
    131     DESCRIPTOR_REQ_VIEW_TYPE_1D = 1 << VK_IMAGE_VIEW_TYPE_1D,
    132     DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY = 1 << VK_IMAGE_VIEW_TYPE_1D_ARRAY,
    133     DESCRIPTOR_REQ_VIEW_TYPE_2D = 1 << VK_IMAGE_VIEW_TYPE_2D,
    134     DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY = 1 << VK_IMAGE_VIEW_TYPE_2D_ARRAY,
    135     DESCRIPTOR_REQ_VIEW_TYPE_3D = 1 << VK_IMAGE_VIEW_TYPE_3D,
    136     DESCRIPTOR_REQ_VIEW_TYPE_CUBE = 1 << VK_IMAGE_VIEW_TYPE_CUBE,
    137     DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY = 1 << VK_IMAGE_VIEW_TYPE_CUBE_ARRAY,
    138 
    139     DESCRIPTOR_REQ_ALL_VIEW_TYPE_BITS = (1 << (VK_IMAGE_VIEW_TYPE_END_RANGE + 1)) - 1,
    140 
    141     DESCRIPTOR_REQ_SINGLE_SAMPLE = 2 << VK_IMAGE_VIEW_TYPE_END_RANGE,
    142     DESCRIPTOR_REQ_MULTI_SAMPLE = DESCRIPTOR_REQ_SINGLE_SAMPLE << 1,
    143 
    144     DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT = DESCRIPTOR_REQ_MULTI_SAMPLE << 1,
    145     DESCRIPTOR_REQ_COMPONENT_TYPE_SINT = DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT << 1,
    146     DESCRIPTOR_REQ_COMPONENT_TYPE_UINT = DESCRIPTOR_REQ_COMPONENT_TYPE_SINT << 1,
    147 };
    148 
    149 struct DESCRIPTOR_POOL_STATE : BASE_NODE {
    150     VkDescriptorPool pool;
    151     uint32_t maxSets;        // Max descriptor sets allowed in this pool
    152     uint32_t availableSets;  // Available descriptor sets in this pool
    153 
    154     safe_VkDescriptorPoolCreateInfo createInfo;
    155     std::unordered_set<cvdescriptorset::DescriptorSet *> sets;  // Collection of all sets in this pool
    156     std::map<uint32_t, uint32_t> maxDescriptorTypeCount;        // Max # of descriptors of each type in this pool
    157     std::map<uint32_t, uint32_t> availableDescriptorTypeCount;  // Available # of descriptors of each type in this pool
    158 
    159     DESCRIPTOR_POOL_STATE(const VkDescriptorPool pool, const VkDescriptorPoolCreateInfo *pCreateInfo)
    160         : pool(pool),
    161           maxSets(pCreateInfo->maxSets),
    162           availableSets(pCreateInfo->maxSets),
    163           createInfo(pCreateInfo),
    164           maxDescriptorTypeCount(),
    165           availableDescriptorTypeCount() {
    166         // Collect maximums per descriptor type.
    167         for (uint32_t i = 0; i < createInfo.poolSizeCount; ++i) {
    168             uint32_t typeIndex = static_cast<uint32_t>(createInfo.pPoolSizes[i].type);
    169             // Same descriptor types can appear several times
    170             maxDescriptorTypeCount[typeIndex] += createInfo.pPoolSizes[i].descriptorCount;
    171             availableDescriptorTypeCount[typeIndex] = maxDescriptorTypeCount[typeIndex];
    172         }
    173     }
    174 };
    175 
    176 // Generic memory binding struct to track objects bound to objects
    177 struct MEM_BINDING {
    178     VkDeviceMemory mem;
    179     VkDeviceSize offset;
    180     VkDeviceSize size;
    181 };
    182 
    183 struct BufferBinding {
    184     VkBuffer buffer;
    185     VkDeviceSize size;
    186     VkDeviceSize offset;
    187 };
    188 
    189 struct IndexBufferBinding : BufferBinding {
    190     VkIndexType index_type;
    191 };
    192 
    193 inline bool operator==(MEM_BINDING a, MEM_BINDING b) NOEXCEPT { return a.mem == b.mem && a.offset == b.offset && a.size == b.size; }
    194 
    195 namespace std {
    196 template <>
    197 struct hash<MEM_BINDING> {
    198     size_t operator()(MEM_BINDING mb) const NOEXCEPT {
    199         auto intermediate = hash<uint64_t>()(reinterpret_cast<uint64_t &>(mb.mem)) ^ hash<uint64_t>()(mb.offset);
    200         return intermediate ^ hash<uint64_t>()(mb.size);
    201     }
    202 };
    203 }  // namespace std
    204 
    205 // Superclass for bindable object state (currently images and buffers)
    206 class BINDABLE : public BASE_NODE {
    207    public:
    208     bool sparse;  // Is this object being bound with sparse memory or not?
    209     // Non-sparse binding data
    210     MEM_BINDING binding;
    211     // Memory requirements for this BINDABLE
    212     VkMemoryRequirements requirements;
    213     // bool to track if memory requirements were checked
    214     bool memory_requirements_checked;
    215     // Sparse binding data, initially just tracking MEM_BINDING per mem object
    216     //  There's more data for sparse bindings so need better long-term solution
    217     // TODO : Need to update solution to track all sparse binding data
    218     std::unordered_set<MEM_BINDING> sparse_bindings;
    219 
    220     std::unordered_set<VkDeviceMemory> bound_memory_set_;
    221 
    222     BINDABLE()
    223         : sparse(false), binding{}, requirements{}, memory_requirements_checked(false), sparse_bindings{}, bound_memory_set_{} {};
    224 
    225     // Update the cached set of memory bindings.
    226     // Code that changes binding.mem or sparse_bindings must call UpdateBoundMemorySet()
    227     void UpdateBoundMemorySet() {
    228         bound_memory_set_.clear();
    229         if (!sparse) {
    230             bound_memory_set_.insert(binding.mem);
    231         } else {
    232             for (auto sb : sparse_bindings) {
    233                 bound_memory_set_.insert(sb.mem);
    234             }
    235         }
    236     }
    237 
    238     // Return unordered set of memory objects that are bound
    239     // Instead of creating a set from scratch each query, return the cached one
    240     const std::unordered_set<VkDeviceMemory> &GetBoundMemory() const { return bound_memory_set_; }
    241 };
    242 
    243 class BUFFER_STATE : public BINDABLE {
    244    public:
    245     VkBuffer buffer;
    246     VkBufferCreateInfo createInfo;
    247     BUFFER_STATE(VkBuffer buff, const VkBufferCreateInfo *pCreateInfo) : buffer(buff), createInfo(*pCreateInfo) {
    248         if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
    249             uint32_t *pQueueFamilyIndices = new uint32_t[createInfo.queueFamilyIndexCount];
    250             for (uint32_t i = 0; i < createInfo.queueFamilyIndexCount; i++) {
    251                 pQueueFamilyIndices[i] = pCreateInfo->pQueueFamilyIndices[i];
    252             }
    253             createInfo.pQueueFamilyIndices = pQueueFamilyIndices;
    254         }
    255 
    256         if (createInfo.flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) {
    257             sparse = true;
    258         }
    259     };
    260 
    261     BUFFER_STATE(BUFFER_STATE const &rh_obj) = delete;
    262 
    263     ~BUFFER_STATE() {
    264         if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
    265             delete[] createInfo.pQueueFamilyIndices;
    266             createInfo.pQueueFamilyIndices = nullptr;
    267         }
    268     };
    269 };
    270 
    271 class BUFFER_VIEW_STATE : public BASE_NODE {
    272    public:
    273     VkBufferView buffer_view;
    274     VkBufferViewCreateInfo create_info;
    275     BUFFER_VIEW_STATE(VkBufferView bv, const VkBufferViewCreateInfo *ci) : buffer_view(bv), create_info(*ci){};
    276     BUFFER_VIEW_STATE(const BUFFER_VIEW_STATE &rh_obj) = delete;
    277 };
    278 
    279 struct SAMPLER_STATE : public BASE_NODE {
    280     VkSampler sampler;
    281     VkSamplerCreateInfo createInfo;
    282     VkSamplerYcbcrConversion samplerConversion = VK_NULL_HANDLE;
    283 
    284     SAMPLER_STATE(const VkSampler *ps, const VkSamplerCreateInfo *pci) : sampler(*ps), createInfo(*pci) {
    285         auto *conversionInfo = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(pci->pNext);
    286         if (conversionInfo) samplerConversion = conversionInfo->conversion;
    287     }
    288 };
    289 
    290 class IMAGE_STATE : public BINDABLE {
    291    public:
    292     VkImage image;
    293     VkImageCreateInfo createInfo;
    294     bool valid;                   // If this is a swapchain image backing memory track valid here as it doesn't have DEVICE_MEM_INFO
    295     bool acquired;                // If this is a swapchain image, has it been acquired by the app.
    296     bool shared_presentable;      // True for a front-buffered swapchain image
    297     bool layout_locked;           // A front-buffered image that has been presented can never have layout transitioned
    298     bool get_sparse_reqs_called;  // Track if GetImageSparseMemoryRequirements() has been called for this image
    299     bool sparse_metadata_required;  // Track if sparse metadata aspect is required for this image
    300     bool sparse_metadata_bound;     // Track if sparse metadata aspect is bound to this image
    301     bool imported_ahb;              // True if image was imported from an Android Hardware Buffer
    302     bool has_ahb_format;            // True if image was created with an external Android format
    303     uint64_t ahb_format;            // External Android format, if provided
    304     std::vector<VkSparseImageMemoryRequirements> sparse_requirements;
    305     IMAGE_STATE(VkImage img, const VkImageCreateInfo *pCreateInfo)
    306         : image(img),
    307           createInfo(*pCreateInfo),
    308           valid(false),
    309           acquired(false),
    310           shared_presentable(false),
    311           layout_locked(false),
    312           get_sparse_reqs_called(false),
    313           sparse_metadata_required(false),
    314           sparse_metadata_bound(false),
    315           imported_ahb(false),
    316           has_ahb_format(false),
    317           ahb_format(0),
    318           sparse_requirements{} {
    319         if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
    320             uint32_t *pQueueFamilyIndices = new uint32_t[createInfo.queueFamilyIndexCount];
    321             for (uint32_t i = 0; i < createInfo.queueFamilyIndexCount; i++) {
    322                 pQueueFamilyIndices[i] = pCreateInfo->pQueueFamilyIndices[i];
    323             }
    324             createInfo.pQueueFamilyIndices = pQueueFamilyIndices;
    325         }
    326 
    327         if (createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) {
    328             sparse = true;
    329         }
    330     };
    331 
    332     IMAGE_STATE(IMAGE_STATE const &rh_obj) = delete;
    333 
    334     ~IMAGE_STATE() {
    335         if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
    336             delete[] createInfo.pQueueFamilyIndices;
    337             createInfo.pQueueFamilyIndices = nullptr;
    338         }
    339     };
    340 };
    341 
    342 class IMAGE_VIEW_STATE : public BASE_NODE {
    343    public:
    344     VkImageView image_view;
    345     VkImageViewCreateInfo create_info;
    346     VkSamplerYcbcrConversion samplerConversion;  // Handle of the ycbcr sampler conversion the image was created with, if any
    347     IMAGE_VIEW_STATE(VkImageView iv, const VkImageViewCreateInfo *ci)
    348         : image_view(iv), create_info(*ci), samplerConversion(VK_NULL_HANDLE) {
    349         auto *conversionInfo = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(create_info.pNext);
    350         if (conversionInfo) samplerConversion = conversionInfo->conversion;
    351     };
    352     IMAGE_VIEW_STATE(const IMAGE_VIEW_STATE &rh_obj) = delete;
    353 };
    354 
    355 struct MemRange {
    356     VkDeviceSize offset;
    357     VkDeviceSize size;
    358 };
    359 
    360 struct MEMORY_RANGE {
    361     uint64_t handle;
    362     bool image;   // True for image, false for buffer
    363     bool linear;  // True for buffers and linear images
    364     VkDeviceMemory memory;
    365     VkDeviceSize start;
    366     VkDeviceSize size;
    367     VkDeviceSize end;  // Store this pre-computed for simplicity
    368     // Set of ptrs to every range aliased with this one
    369     std::unordered_set<MEMORY_RANGE *> aliases;
    370 };
    371 
    372 // Data struct for tracking memory object
    373 struct DEVICE_MEM_INFO : public BASE_NODE {
    374     void *object;  // Dispatchable object used to create this memory (device of swapchain)
    375     VkDeviceMemory mem;
    376     VkMemoryAllocateInfo alloc_info;
    377     bool is_dedicated;
    378     VkBuffer dedicated_buffer;
    379     VkImage dedicated_image;
    380     bool is_export;
    381     VkExternalMemoryHandleTypeFlags export_handle_type_flags;
    382     std::unordered_set<VK_OBJECT> obj_bindings;               // objects bound to this memory
    383     std::unordered_map<uint64_t, MEMORY_RANGE> bound_ranges;  // Map of object to its binding range
    384     // Convenience vectors image/buff handles to speed up iterating over images or buffers independently
    385     std::unordered_set<uint64_t> bound_images;
    386     std::unordered_set<uint64_t> bound_buffers;
    387 
    388     MemRange mem_range;
    389     void *shadow_copy_base;    // Base of layer's allocation for guard band, data, and alignment space
    390     void *shadow_copy;         // Pointer to start of guard-band data before mapped region
    391     uint64_t shadow_pad_size;  // Size of the guard-band data before and after actual data. It MUST be a
    392                                // multiple of limits.minMemoryMapAlignment
    393     void *p_driver_data;       // Pointer to application's actual memory
    394 
    395     DEVICE_MEM_INFO(void *disp_object, const VkDeviceMemory in_mem, const VkMemoryAllocateInfo *p_alloc_info)
    396         : object(disp_object),
    397           mem(in_mem),
    398           alloc_info(*p_alloc_info),
    399           is_dedicated(false),
    400           dedicated_buffer(VK_NULL_HANDLE),
    401           dedicated_image(VK_NULL_HANDLE),
    402           is_export(false),
    403           export_handle_type_flags(0),
    404           mem_range{},
    405           shadow_copy_base(0),
    406           shadow_copy(0),
    407           shadow_pad_size(0),
    408           p_driver_data(0){};
    409 };
    410 
    411 class SWAPCHAIN_NODE {
    412    public:
    413     safe_VkSwapchainCreateInfoKHR createInfo;
    414     VkSwapchainKHR swapchain;
    415     std::vector<VkImage> images;
    416     bool retired = false;
    417     bool shared_presentable = false;
    418     CALL_STATE vkGetSwapchainImagesKHRState = UNCALLED;
    419     uint32_t get_swapchain_image_count = 0;
    420     SWAPCHAIN_NODE(const VkSwapchainCreateInfoKHR *pCreateInfo, VkSwapchainKHR swapchain)
    421         : createInfo(pCreateInfo), swapchain(swapchain) {}
    422 };
    423 
    424 class IMAGE_CMD_BUF_LAYOUT_NODE {
    425    public:
    426     IMAGE_CMD_BUF_LAYOUT_NODE() = default;
    427     IMAGE_CMD_BUF_LAYOUT_NODE(VkImageLayout initialLayoutInput, VkImageLayout layoutInput)
    428         : initialLayout(initialLayoutInput), layout(layoutInput) {}
    429 
    430     VkImageLayout initialLayout;
    431     VkImageLayout layout;
    432 };
    433 
    434 // Store the DAG.
    435 struct DAGNode {
    436     uint32_t pass;
    437     std::vector<uint32_t> prev;
    438     std::vector<uint32_t> next;
    439 };
    440 
    441 struct RENDER_PASS_STATE : public BASE_NODE {
    442     VkRenderPass renderPass;
    443     safe_VkRenderPassCreateInfo2KHR createInfo;
    444     std::vector<std::vector<uint32_t>> self_dependencies;
    445     std::vector<DAGNode> subpassToNode;
    446     std::unordered_map<uint32_t, bool> attachment_first_read;
    447 
    448     RENDER_PASS_STATE(VkRenderPassCreateInfo2KHR const *pCreateInfo) : createInfo(pCreateInfo) {}
    449     RENDER_PASS_STATE(VkRenderPassCreateInfo const *pCreateInfo) { ConvertVkRenderPassCreateInfoToV2KHR(pCreateInfo, &createInfo); }
    450 };
    451 
    452 // vkCmd tracking -- complete as of header 1.0.68
    453 // please keep in "none, then sorted" order
    454 // Note: grepping vulkan.h for VKAPI_CALL.*vkCmd will return all functions except vkEndCommandBuffer
    455 
    456 enum CMD_TYPE {
    457     CMD_NONE,
    458     CMD_BEGINQUERY,
    459     CMD_BEGINRENDERPASS,
    460     CMD_BEGINRENDERPASS2KHR,
    461     CMD_BINDDESCRIPTORSETS,
    462     CMD_BINDINDEXBUFFER,
    463     CMD_BINDPIPELINE,
    464     CMD_BINDSHADINGRATEIMAGE,
    465     CMD_BINDVERTEXBUFFERS,
    466     CMD_BLITIMAGE,
    467     CMD_CLEARATTACHMENTS,
    468     CMD_CLEARCOLORIMAGE,
    469     CMD_CLEARDEPTHSTENCILIMAGE,
    470     CMD_COPYBUFFER,
    471     CMD_COPYBUFFERTOIMAGE,
    472     CMD_COPYIMAGE,
    473     CMD_COPYIMAGETOBUFFER,
    474     CMD_COPYQUERYPOOLRESULTS,
    475     CMD_DEBUGMARKERBEGINEXT,
    476     CMD_DEBUGMARKERENDEXT,
    477     CMD_DEBUGMARKERINSERTEXT,
    478     CMD_DISPATCH,
    479     CMD_DISPATCHBASEKHX,
    480     CMD_DISPATCHINDIRECT,
    481     CMD_DRAW,
    482     CMD_DRAWINDEXED,
    483     CMD_DRAWINDEXEDINDIRECT,
    484     CMD_DRAWINDEXEDINDIRECTCOUNTAMD,
    485     CMD_DRAWINDEXEDINDIRECTCOUNTKHR,
    486     CMD_DRAWINDIRECT,
    487     CMD_DRAWINDIRECTCOUNTAMD,
    488     CMD_DRAWINDIRECTCOUNTKHR,
    489     CMD_DRAWMESHTASKSNV,
    490     CMD_DRAWMESHTASKSINDIRECTNV,
    491     CMD_DRAWMESHTASKSINDIRECTCOUNTNV,
    492     CMD_ENDCOMMANDBUFFER,  // Should be the last command in any RECORDED cmd buffer
    493     CMD_ENDQUERY,
    494     CMD_ENDRENDERPASS,
    495     CMD_ENDRENDERPASS2KHR,
    496     CMD_EXECUTECOMMANDS,
    497     CMD_FILLBUFFER,
    498     CMD_NEXTSUBPASS,
    499     CMD_NEXTSUBPASS2KHR,
    500     CMD_PIPELINEBARRIER,
    501     CMD_PROCESSCOMMANDSNVX,
    502     CMD_PUSHCONSTANTS,
    503     CMD_PUSHDESCRIPTORSETKHR,
    504     CMD_PUSHDESCRIPTORSETWITHTEMPLATEKHR,
    505     CMD_RESERVESPACEFORCOMMANDSNVX,
    506     CMD_RESETEVENT,
    507     CMD_RESETQUERYPOOL,
    508     CMD_RESOLVEIMAGE,
    509     CMD_SETBLENDCONSTANTS,
    510     CMD_SETDEPTHBIAS,
    511     CMD_SETDEPTHBOUNDS,
    512     CMD_SETDEVICEMASKKHX,
    513     CMD_SETDISCARDRECTANGLEEXT,
    514     CMD_SETEVENT,
    515     CMD_SETEXCLUSIVESCISSOR,
    516     CMD_SETLINEWIDTH,
    517     CMD_SETSAMPLELOCATIONSEXT,
    518     CMD_SETSCISSOR,
    519     CMD_SETSTENCILCOMPAREMASK,
    520     CMD_SETSTENCILREFERENCE,
    521     CMD_SETSTENCILWRITEMASK,
    522     CMD_SETVIEWPORT,
    523     CMD_SETVIEWPORTSHADINGRATEPALETTE,
    524     CMD_SETVIEWPORTWSCALINGNV,
    525     CMD_UPDATEBUFFER,
    526     CMD_WAITEVENTS,
    527     CMD_WRITETIMESTAMP,
    528 };
    529 
    530 enum CB_STATE {
    531     CB_NEW,                 // Newly created CB w/o any cmds
    532     CB_RECORDING,           // BeginCB has been called on this CB
    533     CB_RECORDED,            // EndCB has been called on this CB
    534     CB_INVALID_COMPLETE,    // had a complete recording, but was since invalidated
    535     CB_INVALID_INCOMPLETE,  // fouled before recording was completed
    536 };
    537 
    538 // CB Status -- used to track status of various bindings on cmd buffer objects
    539 typedef VkFlags CBStatusFlags;
    540 enum CBStatusFlagBits {
    541     // clang-format off
    542     CBSTATUS_NONE                   = 0x00000000,   // No status is set
    543     CBSTATUS_LINE_WIDTH_SET         = 0x00000001,   // Line width has been set
    544     CBSTATUS_DEPTH_BIAS_SET         = 0x00000002,   // Depth bias has been set
    545     CBSTATUS_BLEND_CONSTANTS_SET    = 0x00000004,   // Blend constants state has been set
    546     CBSTATUS_DEPTH_BOUNDS_SET       = 0x00000008,   // Depth bounds state object has been set
    547     CBSTATUS_STENCIL_READ_MASK_SET  = 0x00000010,   // Stencil read mask has been set
    548     CBSTATUS_STENCIL_WRITE_MASK_SET = 0x00000020,   // Stencil write mask has been set
    549     CBSTATUS_STENCIL_REFERENCE_SET  = 0x00000040,   // Stencil reference has been set
    550     CBSTATUS_VIEWPORT_SET           = 0x00000080,
    551     CBSTATUS_SCISSOR_SET            = 0x00000100,
    552     CBSTATUS_INDEX_BUFFER_BOUND     = 0x00000200,   // Index buffer has been set
    553     CBSTATUS_EXCLUSIVE_SCISSOR_SET  = 0x00000400,
    554     CBSTATUS_SHADING_RATE_PALETTE_SET = 0x00000800,
    555     CBSTATUS_ALL_STATE_SET          = 0x00000DFF,   // All state set (intentionally exclude index buffer)
    556     // clang-format on
    557 };
    558 
    559 struct QueryObject {
    560     VkQueryPool pool;
    561     uint32_t index;
    562 };
    563 
    564 inline bool operator==(const QueryObject &query1, const QueryObject &query2) {
    565     return (query1.pool == query2.pool && query1.index == query2.index);
    566 }
    567 
    568 namespace std {
    569 template <>
    570 struct hash<QueryObject> {
    571     size_t operator()(QueryObject query) const throw() {
    572         return hash<uint64_t>()((uint64_t)(query.pool)) ^ hash<uint32_t>()(query.index);
    573     }
    574 };
    575 }  // namespace std
    576 
    577 struct DrawData {
    578     std::vector<BufferBinding> vertex_buffer_bindings;
    579 };
    580 
    581 struct ImageSubresourcePair {
    582     VkImage image;
    583     bool hasSubresource;
    584     VkImageSubresource subresource;
    585 };
    586 
    587 inline bool operator==(const ImageSubresourcePair &img1, const ImageSubresourcePair &img2) {
    588     if (img1.image != img2.image || img1.hasSubresource != img2.hasSubresource) return false;
    589     return !img1.hasSubresource ||
    590            (img1.subresource.aspectMask == img2.subresource.aspectMask && img1.subresource.mipLevel == img2.subresource.mipLevel &&
    591             img1.subresource.arrayLayer == img2.subresource.arrayLayer);
    592 }
    593 
    594 namespace std {
    595 template <>
    596 struct hash<ImageSubresourcePair> {
    597     size_t operator()(ImageSubresourcePair img) const throw() {
    598         size_t hashVal = hash<uint64_t>()(reinterpret_cast<uint64_t &>(img.image));
    599         hashVal ^= hash<bool>()(img.hasSubresource);
    600         if (img.hasSubresource) {
    601             hashVal ^= hash<uint32_t>()(reinterpret_cast<uint32_t &>(img.subresource.aspectMask));
    602             hashVal ^= hash<uint32_t>()(img.subresource.mipLevel);
    603             hashVal ^= hash<uint32_t>()(img.subresource.arrayLayer);
    604         }
    605         return hashVal;
    606     }
    607 };
    608 }  // namespace std
    609 
    610 // Canonical dictionary for PushConstantRanges
    611 using PushConstantRangesDict = hash_util::Dictionary<PushConstantRanges>;
    612 using PushConstantRangesId = PushConstantRangesDict::Id;
    613 
    614 // Canonical dictionary for the pipeline layout's layout of descriptorsetlayouts
    615 using DescriptorSetLayoutDef = cvdescriptorset::DescriptorSetLayoutDef;
    616 using DescriptorSetLayoutId = std::shared_ptr<const DescriptorSetLayoutDef>;
    617 using PipelineLayoutSetLayoutsDef = std::vector<DescriptorSetLayoutId>;
    618 using PipelineLayoutSetLayoutsDict =
    619     hash_util::Dictionary<PipelineLayoutSetLayoutsDef, hash_util::IsOrderedContainer<PipelineLayoutSetLayoutsDef>>;
    620 using PipelineLayoutSetLayoutsId = PipelineLayoutSetLayoutsDict::Id;
    621 
    622 // Defines/stores a compatibility defintion for set N
    623 // The "layout layout" must store at least set+1 entries, but only the first set+1 are considered for hash and equality testing
    624 // Note: the "cannonical" data are referenced by Id, not including handle or device specific state
    625 // Note: hash and equality only consider layout_id entries [0, set] for determining uniqueness
    626 struct PipelineLayoutCompatDef {
    627     uint32_t set;
    628     PushConstantRangesId push_constant_ranges;
    629     PipelineLayoutSetLayoutsId set_layouts_id;
    630     PipelineLayoutCompatDef(const uint32_t set_index, const PushConstantRangesId pcr_id, const PipelineLayoutSetLayoutsId sl_id)
    631         : set(set_index), push_constant_ranges(pcr_id), set_layouts_id(sl_id) {}
    632     size_t hash() const;
    633     bool operator==(const PipelineLayoutCompatDef &other) const;
    634 };
    635 
    636 // Canonical dictionary for PipelineLayoutCompat records
    637 using PipelineLayoutCompatDict = hash_util::Dictionary<PipelineLayoutCompatDef, hash_util::HasHashMember<PipelineLayoutCompatDef>>;
    638 using PipelineLayoutCompatId = PipelineLayoutCompatDict::Id;
    639 
    640 // Store layouts and pushconstants for PipelineLayout
    641 struct PIPELINE_LAYOUT_NODE {
    642     VkPipelineLayout layout;
    643     std::vector<std::shared_ptr<cvdescriptorset::DescriptorSetLayout const>> set_layouts;
    644     PushConstantRangesId push_constant_ranges;
    645     std::vector<PipelineLayoutCompatId> compat_for_set;
    646 
    647     PIPELINE_LAYOUT_NODE() : layout(VK_NULL_HANDLE), set_layouts{}, push_constant_ranges{}, compat_for_set{} {}
    648 
    649     void reset() {
    650         layout = VK_NULL_HANDLE;
    651         set_layouts.clear();
    652         push_constant_ranges.reset();
    653         compat_for_set.clear();
    654     }
    655 };
    656 
    657 static inline bool CompatForSet(uint32_t set, const std::vector<PipelineLayoutCompatId> &a,
    658                                 const std::vector<PipelineLayoutCompatId> &b) {
    659     bool result = (set < a.size()) && (set < b.size()) && (a[set] == b[set]);
    660     return result;
    661 }
    662 
    663 static inline bool CompatForSet(uint32_t set, const PIPELINE_LAYOUT_NODE *a, const PIPELINE_LAYOUT_NODE *b) {
    664     // Intentionally have a result variable to simplify debugging
    665     bool result = a && b && CompatForSet(set, a->compat_for_set, b->compat_for_set);
    666     return result;
    667 }
    668 
    669 class PIPELINE_STATE : public BASE_NODE {
    670    public:
    671     VkPipeline pipeline;
    672     safe_VkGraphicsPipelineCreateInfo graphicsPipelineCI;
    673     // Hold shared ptr to RP in case RP itself is destroyed
    674     std::shared_ptr<RENDER_PASS_STATE> rp_state;
    675     safe_VkComputePipelineCreateInfo computePipelineCI;
    676     safe_VkRayTracingPipelineCreateInfoNV raytracingPipelineCI;
    677     // Flag of which shader stages are active for this pipeline
    678     uint32_t active_shaders;
    679     uint32_t duplicate_shaders;
    680     // Capture which slots (set#->bindings) are actually used by the shaders of this pipeline
    681     std::unordered_map<uint32_t, std::map<uint32_t, descriptor_req>> active_slots;
    682     // Vtx input info (if any)
    683     std::vector<VkVertexInputBindingDescription> vertex_binding_descriptions_;
    684     std::vector<VkVertexInputAttributeDescription> vertex_attribute_descriptions_;
    685     std::unordered_map<uint32_t, uint32_t> vertex_binding_to_index_map_;
    686     std::vector<VkPipelineColorBlendAttachmentState> attachments;
    687     bool blendConstantsEnabled;  // Blend constants enabled for any attachments
    688     PIPELINE_LAYOUT_NODE pipeline_layout;
    689     VkPrimitiveTopology topology_at_rasterizer;
    690 
    691     // Default constructor
    692     PIPELINE_STATE()
    693         : pipeline{},
    694           graphicsPipelineCI{},
    695           rp_state(nullptr),
    696           computePipelineCI{},
    697           raytracingPipelineCI{},
    698           active_shaders(0),
    699           duplicate_shaders(0),
    700           active_slots(),
    701           vertex_binding_descriptions_(),
    702           vertex_attribute_descriptions_(),
    703           vertex_binding_to_index_map_(),
    704           attachments(),
    705           blendConstantsEnabled(false),
    706           pipeline_layout(),
    707           topology_at_rasterizer{} {}
    708 
    709     void initGraphicsPipeline(const VkGraphicsPipelineCreateInfo *pCreateInfo, std::shared_ptr<RENDER_PASS_STATE> &&rpstate) {
    710         bool uses_color_attachment = false;
    711         bool uses_depthstencil_attachment = false;
    712         if (pCreateInfo->subpass < rpstate->createInfo.subpassCount) {
    713             const auto &subpass = rpstate->createInfo.pSubpasses[pCreateInfo->subpass];
    714 
    715             for (uint32_t i = 0; i < subpass.colorAttachmentCount; ++i) {
    716                 if (subpass.pColorAttachments[i].attachment != VK_ATTACHMENT_UNUSED) {
    717                     uses_color_attachment = true;
    718                     break;
    719                 }
    720             }
    721 
    722             if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
    723                 uses_depthstencil_attachment = true;
    724             }
    725         }
    726         graphicsPipelineCI.initialize(pCreateInfo, uses_color_attachment, uses_depthstencil_attachment);
    727         // Make sure compute pipeline is null
    728         VkComputePipelineCreateInfo emptyComputeCI = {};
    729         computePipelineCI.initialize(&emptyComputeCI);
    730         for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
    731             const VkPipelineShaderStageCreateInfo *pPSSCI = &pCreateInfo->pStages[i];
    732             this->duplicate_shaders |= this->active_shaders & pPSSCI->stage;
    733             this->active_shaders |= pPSSCI->stage;
    734         }
    735         if (graphicsPipelineCI.pVertexInputState) {
    736             const auto pVICI = graphicsPipelineCI.pVertexInputState;
    737             if (pVICI->vertexBindingDescriptionCount) {
    738                 this->vertex_binding_descriptions_ = std::vector<VkVertexInputBindingDescription>(
    739                     pVICI->pVertexBindingDescriptions, pVICI->pVertexBindingDescriptions + pVICI->vertexBindingDescriptionCount);
    740 
    741                 this->vertex_binding_to_index_map_.reserve(pVICI->vertexBindingDescriptionCount);
    742                 for (uint32_t i = 0; i < pVICI->vertexBindingDescriptionCount; ++i) {
    743                     this->vertex_binding_to_index_map_[pVICI->pVertexBindingDescriptions[i].binding] = i;
    744                 }
    745             }
    746             if (pVICI->vertexAttributeDescriptionCount) {
    747                 this->vertex_attribute_descriptions_ = std::vector<VkVertexInputAttributeDescription>(
    748                     pVICI->pVertexAttributeDescriptions,
    749                     pVICI->pVertexAttributeDescriptions + pVICI->vertexAttributeDescriptionCount);
    750             }
    751         }
    752         if (graphicsPipelineCI.pColorBlendState) {
    753             const auto pCBCI = graphicsPipelineCI.pColorBlendState;
    754             if (pCBCI->attachmentCount) {
    755                 this->attachments = std::vector<VkPipelineColorBlendAttachmentState>(pCBCI->pAttachments,
    756                                                                                      pCBCI->pAttachments + pCBCI->attachmentCount);
    757             }
    758         }
    759         if (graphicsPipelineCI.pInputAssemblyState) {
    760             topology_at_rasterizer = graphicsPipelineCI.pInputAssemblyState->topology;
    761         }
    762         rp_state = rpstate;
    763     }
    764 
    765     void initComputePipeline(const VkComputePipelineCreateInfo *pCreateInfo) {
    766         computePipelineCI.initialize(pCreateInfo);
    767         // Make sure gfx pipeline is null
    768         VkGraphicsPipelineCreateInfo emptyGraphicsCI = {};
    769         graphicsPipelineCI.initialize(&emptyGraphicsCI, false, false);
    770         switch (computePipelineCI.stage.stage) {
    771             case VK_SHADER_STAGE_COMPUTE_BIT:
    772                 this->active_shaders |= VK_SHADER_STAGE_COMPUTE_BIT;
    773                 break;
    774             default:
    775                 // TODO : Flag error
    776                 break;
    777         }
    778     }
    779     void initRayTracingPipelineNV(const VkRayTracingPipelineCreateInfoNV *pCreateInfo) {
    780         raytracingPipelineCI.initialize(pCreateInfo);
    781         // Make sure gfx and compute pipeline is null
    782         VkGraphicsPipelineCreateInfo emptyGraphicsCI = {};
    783         VkComputePipelineCreateInfo emptyComputeCI = {};
    784         computePipelineCI.initialize(&emptyComputeCI);
    785         graphicsPipelineCI.initialize(&emptyGraphicsCI, false, false);
    786         switch (raytracingPipelineCI.pStages->stage) {
    787             case VK_SHADER_STAGE_RAYGEN_BIT_NV:
    788                 this->active_shaders |= VK_SHADER_STAGE_RAYGEN_BIT_NV;
    789                 break;
    790             case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
    791                 this->active_shaders |= VK_SHADER_STAGE_ANY_HIT_BIT_NV;
    792                 break;
    793             case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
    794                 this->active_shaders |= VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
    795                 break;
    796             case VK_SHADER_STAGE_MISS_BIT_NV:
    797                 this->active_shaders = VK_SHADER_STAGE_MISS_BIT_NV;
    798                 break;
    799             case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
    800                 this->active_shaders = VK_SHADER_STAGE_INTERSECTION_BIT_NV;
    801                 break;
    802             case VK_SHADER_STAGE_CALLABLE_BIT_NV:
    803                 this->active_shaders |= VK_SHADER_STAGE_CALLABLE_BIT_NV;
    804                 break;
    805             default:
    806                 // TODO : Flag error
    807                 break;
    808         }
    809     }
    810 };
    811 
    812 // Track last states that are bound per pipeline bind point (Gfx & Compute)
    813 struct LAST_BOUND_STATE {
    814     LAST_BOUND_STATE() { reset(); }  // must define default constructor for portability reasons
    815     PIPELINE_STATE *pipeline_state;
    816     VkPipelineLayout pipeline_layout;
    817     // Track each set that has been bound
    818     // Ordered bound set tracking where index is set# that given set is bound to
    819     std::vector<cvdescriptorset::DescriptorSet *> boundDescriptorSets;
    820     std::unique_ptr<cvdescriptorset::DescriptorSet> push_descriptor_set;
    821     // one dynamic offset per dynamic descriptor bound to this CB
    822     std::vector<std::vector<uint32_t>> dynamicOffsets;
    823     std::vector<PipelineLayoutCompatId> compat_id_for_set;
    824 
    825     void reset() {
    826         pipeline_state = nullptr;
    827         pipeline_layout = VK_NULL_HANDLE;
    828         boundDescriptorSets.clear();
    829         push_descriptor_set = nullptr;
    830         dynamicOffsets.clear();
    831         compat_id_for_set.clear();
    832     }
    833 };
    834 
    835 // Types to store queue family ownership (QFO) Transfers
    836 
    837 // Common to image and buffer memory barriers
    838 template <typename Handle, typename Barrier>
    839 struct QFOTransferBarrierBase {
    840     using HandleType = Handle;
    841     using BarrierType = Barrier;
    842     struct Tag {};
    843     HandleType handle = VK_NULL_HANDLE;
    844     uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    845     uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
    846 
    847     QFOTransferBarrierBase() = default;
    848     QFOTransferBarrierBase(const BarrierType &barrier, const HandleType &resource_handle)
    849         : handle(resource_handle),
    850           srcQueueFamilyIndex(barrier.srcQueueFamilyIndex),
    851           dstQueueFamilyIndex(barrier.dstQueueFamilyIndex) {}
    852 
    853     hash_util::HashCombiner base_hash_combiner() const {
    854         hash_util::HashCombiner hc;
    855         hc << srcQueueFamilyIndex << dstQueueFamilyIndex << handle;
    856         return hc;
    857     }
    858 
    859     bool operator==(const QFOTransferBarrierBase &rhs) const {
    860         return (srcQueueFamilyIndex == rhs.srcQueueFamilyIndex) && (dstQueueFamilyIndex == rhs.dstQueueFamilyIndex) &&
    861                (handle == rhs.handle);
    862     }
    863 };
    864 
    865 template <typename Barrier>
    866 struct QFOTransferBarrier {};
    867 
    868 // Image barrier specific implementation
    869 template <>
    870 struct QFOTransferBarrier<VkImageMemoryBarrier> : public QFOTransferBarrierBase<VkImage, VkImageMemoryBarrier> {
    871     using BaseType = QFOTransferBarrierBase<VkImage, VkImageMemoryBarrier>;
    872     VkImageLayout oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    873     VkImageLayout newLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    874     VkImageSubresourceRange subresourceRange;
    875 
    876     QFOTransferBarrier() = default;
    877     QFOTransferBarrier(const BarrierType &barrier)
    878         : BaseType(barrier, barrier.image),
    879           oldLayout(barrier.oldLayout),
    880           newLayout(barrier.newLayout),
    881           subresourceRange(barrier.subresourceRange) {}
    882     size_t hash() const {
    883         // Ignoring the layout information for the purpose of the hash, as we're interested in QFO release/acquisition w.r.t.
    884         // the subresource affected, an layout transitions are current validated on another path
    885         auto hc = base_hash_combiner() << subresourceRange;
    886         return hc.Value();
    887     }
    888     bool operator==(const QFOTransferBarrier<BarrierType> &rhs) const {
    889         // Ignoring layout w.r.t. equality. See comment in hash above.
    890         return (static_cast<BaseType>(*this) == static_cast<BaseType>(rhs)) && (subresourceRange == rhs.subresourceRange);
    891     }
    892     // TODO: codegen a comprehensive complie time type -> string (and or other traits) template family
    893     static const char *BarrierName() { return "VkImageMemoryBarrier"; }
    894     static const char *HandleName() { return "VkImage"; }
    895     // UNASSIGNED-VkImageMemoryBarrier-image-00001 QFO transfer image barrier must not duplicate QFO recorded in command buffer
    896     static const char *ErrMsgDuplicateQFOInCB() { return "UNASSIGNED-VkImageMemoryBarrier-image-00001"; }
    897     // UNASSIGNED-VkImageMemoryBarrier-image-00002 QFO transfer image barrier must not duplicate QFO submitted in batch
    898     static const char *ErrMsgDuplicateQFOInSubmit() { return "UNASSIGNED-VkImageMemoryBarrier-image-00002"; }
    899     // UNASSIGNED-VkImageMemoryBarrier-image-00003 QFO transfer image barrier must not duplicate QFO submitted previously
    900     static const char *ErrMsgDuplicateQFOSubmitted() { return "UNASSIGNED-VkImageMemoryBarrier-image-00003"; }
    901     // UNASSIGNED-VkImageMemoryBarrier-image-00004 QFO acquire image barrier must have matching QFO release submitted previously
    902     static const char *ErrMsgMissingQFOReleaseInSubmit() { return "UNASSIGNED-VkImageMemoryBarrier-image-00004"; }
    903 };
    904 
    905 // Buffer barrier specific implementation
    906 template <>
    907 struct QFOTransferBarrier<VkBufferMemoryBarrier> : public QFOTransferBarrierBase<VkBuffer, VkBufferMemoryBarrier> {
    908     using BaseType = QFOTransferBarrierBase<VkBuffer, VkBufferMemoryBarrier>;
    909     VkDeviceSize offset = 0;
    910     VkDeviceSize size = 0;
    911     QFOTransferBarrier(const VkBufferMemoryBarrier &barrier)
    912         : BaseType(barrier, barrier.buffer), offset(barrier.offset), size(barrier.size) {}
    913     size_t hash() const {
    914         auto hc = base_hash_combiner() << offset << size;
    915         return hc.Value();
    916     }
    917     bool operator==(const QFOTransferBarrier<BarrierType> &rhs) const {
    918         return (static_cast<BaseType>(*this) == static_cast<BaseType>(rhs)) && (offset == rhs.offset) && (size == rhs.size);
    919     }
    920     static const char *BarrierName() { return "VkBufferMemoryBarrier"; }
    921     static const char *HandleName() { return "VkBuffer"; }
    922     // UNASSIGNED-VkImageMemoryBarrier-buffer-00001 QFO transfer buffer barrier must not duplicate QFO recorded in command buffer
    923     static const char *ErrMsgDuplicateQFOInCB() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00001"; }
    924     // UNASSIGNED-VkBufferMemoryBarrier-buffer-00002 QFO transfer buffer barrier must not duplicate QFO submitted in batch
    925     static const char *ErrMsgDuplicateQFOInSubmit() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00002"; }
    926     // UNASSIGNED-VkBufferMemoryBarrier-buffer-00003 QFO transfer buffer barrier must not duplicate QFO submitted previously
    927     static const char *ErrMsgDuplicateQFOSubmitted() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00003"; }
    928     // UNASSIGNED-VkBufferMemoryBarrier-buffer-00004 QFO acquire buffer barrier must have matching QFO release submitted previously
    929     static const char *ErrMsgMissingQFOReleaseInSubmit() { return "UNASSIGNED-VkBufferMemoryBarrier-buffer-00004"; }
    930 };
    931 
    932 template <typename Barrier>
    933 using QFOTransferBarrierHash = hash_util::HasHashMember<QFOTransferBarrier<Barrier>>;
    934 
    935 // Command buffers store the set of barriers recorded
    936 template <typename Barrier>
    937 using QFOTransferBarrierSet = std::unordered_set<QFOTransferBarrier<Barrier>, QFOTransferBarrierHash<Barrier>>;
    938 template <typename Barrier>
    939 struct QFOTransferBarrierSets {
    940     QFOTransferBarrierSet<Barrier> release;
    941     QFOTransferBarrierSet<Barrier> acquire;
    942     void Reset() {
    943         acquire.clear();
    944         release.clear();
    945     }
    946 };
    947 
    948 // The layer_data stores the map of pending release barriers
    949 template <typename Barrier>
    950 using GlobalQFOTransferBarrierMap =
    951     std::unordered_map<typename QFOTransferBarrier<Barrier>::HandleType, QFOTransferBarrierSet<Barrier>>;
    952 
    953 // Submit queue uses the Scoreboard to track all release/acquire operations in a batch.
    954 template <typename Barrier>
    955 using QFOTransferCBScoreboard =
    956     std::unordered_map<QFOTransferBarrier<Barrier>, const GLOBAL_CB_NODE *, QFOTransferBarrierHash<Barrier>>;
    957 template <typename Barrier>
    958 struct QFOTransferCBScoreboards {
    959     QFOTransferCBScoreboard<Barrier> acquire;
    960     QFOTransferCBScoreboard<Barrier> release;
    961 };
    962 
    963 struct GpuDeviceMemoryBlock {
    964     VkBuffer buffer;
    965     VkDeviceMemory memory;
    966     uint32_t offset;
    967 };
    968 
    969 struct GpuBufferInfo {
    970     GpuDeviceMemoryBlock mem_block;
    971     VkDescriptorSet desc_set;
    972     VkDescriptorPool desc_pool;
    973     GpuBufferInfo(GpuDeviceMemoryBlock mem_block, VkDescriptorSet desc_set, VkDescriptorPool desc_pool)
    974         : mem_block(mem_block), desc_set(desc_set), desc_pool(desc_pool){};
    975 };
    976 
    977 // Cmd Buffer Wrapper Struct - TODO : This desperately needs its own class
    978 struct GLOBAL_CB_NODE : public BASE_NODE {
    979     VkCommandBuffer commandBuffer;
    980     VkCommandBufferAllocateInfo createInfo = {};
    981     VkCommandBufferBeginInfo beginInfo;
    982     VkCommandBufferInheritanceInfo inheritanceInfo;
    983     VkDevice device;  // device this CB belongs to
    984     bool hasDrawCmd;
    985     CB_STATE state;        // Track cmd buffer update state
    986     uint64_t submitCount;  // Number of times CB has been submitted
    987     typedef uint64_t ImageLayoutUpdateCount;
    988     ImageLayoutUpdateCount image_layout_change_count;  // The sequence number for changes to image layout (for cached validation)
    989     CBStatusFlags status;                              // Track status of various bindings on cmd buffer
    990     CBStatusFlags static_status;                       // All state bits provided by current graphics pipeline
    991                                                        // rather than dynamic state
    992     // Currently storing "lastBound" objects on per-CB basis
    993     //  long-term may want to create caches of "lastBound" states and could have
    994     //  each individual CMD_NODE referencing its own "lastBound" state
    995     // Store last bound state for Gfx & Compute pipeline bind points
    996     std::map<uint32_t, LAST_BOUND_STATE> lastBound;
    997 
    998     uint32_t viewportMask;
    999     uint32_t scissorMask;
   1000     VkRenderPassBeginInfo activeRenderPassBeginInfo;
   1001     RENDER_PASS_STATE *activeRenderPass;
   1002     VkSubpassContents activeSubpassContents;
   1003     uint32_t activeSubpass;
   1004     VkFramebuffer activeFramebuffer;
   1005     std::unordered_set<VkFramebuffer> framebuffers;
   1006     // Unified data structs to track objects bound to this command buffer as well as object
   1007     //  dependencies that have been broken : either destroyed objects, or updated descriptor sets
   1008     std::unordered_set<VK_OBJECT> object_bindings;
   1009     std::vector<VK_OBJECT> broken_bindings;
   1010 
   1011     QFOTransferBarrierSets<VkBufferMemoryBarrier> qfo_transfer_buffer_barriers;
   1012     QFOTransferBarrierSets<VkImageMemoryBarrier> qfo_transfer_image_barriers;
   1013 
   1014     std::unordered_set<VkEvent> waitedEvents;
   1015     std::vector<VkEvent> writeEventsBeforeWait;
   1016     std::vector<VkEvent> events;
   1017     std::unordered_map<QueryObject, std::unordered_set<VkEvent>> waitedEventsBeforeQueryReset;
   1018     std::unordered_map<QueryObject, bool> queryToStateMap;  // 0 is unavailable, 1 is available
   1019     std::unordered_set<QueryObject> activeQueries;
   1020     std::unordered_set<QueryObject> startedQueries;
   1021     std::unordered_map<ImageSubresourcePair, IMAGE_CMD_BUF_LAYOUT_NODE> imageLayoutMap;
   1022     std::unordered_map<VkEvent, VkPipelineStageFlags> eventToStageMap;
   1023     std::vector<DrawData> draw_data;
   1024     DrawData current_draw_data;
   1025     bool vertex_buffer_used;  // Track for perf warning to make sure any bound vtx buffer used
   1026     VkCommandBuffer primaryCommandBuffer;
   1027     // Track images and buffers that are updated by this CB at the point of a draw
   1028     std::unordered_set<VkImageView> updateImages;
   1029     std::unordered_set<VkBuffer> updateBuffers;
   1030     // If primary, the secondary command buffers we will call.
   1031     // If secondary, the primary command buffers we will be called by.
   1032     std::unordered_set<GLOBAL_CB_NODE *> linkedCommandBuffers;
   1033     // Validation functions run at primary CB queue submit time
   1034     std::vector<std::function<bool()>> queue_submit_functions;
   1035     // Validation functions run when secondary CB is executed in primary
   1036     std::vector<std::function<bool(GLOBAL_CB_NODE *, VkFramebuffer)>> cmd_execute_commands_functions;
   1037     std::unordered_set<VkDeviceMemory> memObjs;
   1038     std::vector<std::function<bool(VkQueue)>> eventUpdates;
   1039     std::vector<std::function<bool(VkQueue)>> queryUpdates;
   1040     std::unordered_set<cvdescriptorset::DescriptorSet *> validated_descriptor_sets;
   1041     // Contents valid only after an index buffer is bound (CBSTATUS_INDEX_BUFFER_BOUND set)
   1042     IndexBufferBinding index_buffer_binding;
   1043     // GPU Validation data
   1044     std::vector<GpuBufferInfo> gpu_buffer_list;
   1045 };
   1046 
   1047 static inline QFOTransferBarrierSets<VkImageMemoryBarrier> &GetQFOBarrierSets(
   1048     GLOBAL_CB_NODE *cb, const QFOTransferBarrier<VkImageMemoryBarrier>::Tag &type_tag) {
   1049     return cb->qfo_transfer_image_barriers;
   1050 }
   1051 static inline QFOTransferBarrierSets<VkBufferMemoryBarrier> &GetQFOBarrierSets(
   1052     GLOBAL_CB_NODE *cb, const QFOTransferBarrier<VkBufferMemoryBarrier>::Tag &type_tag) {
   1053     return cb->qfo_transfer_buffer_barriers;
   1054 }
   1055 
   1056 struct SEMAPHORE_WAIT {
   1057     VkSemaphore semaphore;
   1058     VkQueue queue;
   1059     uint64_t seq;
   1060 };
   1061 
   1062 struct CB_SUBMISSION {
   1063     CB_SUBMISSION(std::vector<VkCommandBuffer> const &cbs, std::vector<SEMAPHORE_WAIT> const &waitSemaphores,
   1064                   std::vector<VkSemaphore> const &signalSemaphores, std::vector<VkSemaphore> const &externalSemaphores,
   1065                   VkFence fence)
   1066         : cbs(cbs),
   1067           waitSemaphores(waitSemaphores),
   1068           signalSemaphores(signalSemaphores),
   1069           externalSemaphores(externalSemaphores),
   1070           fence(fence) {}
   1071 
   1072     std::vector<VkCommandBuffer> cbs;
   1073     std::vector<SEMAPHORE_WAIT> waitSemaphores;
   1074     std::vector<VkSemaphore> signalSemaphores;
   1075     std::vector<VkSemaphore> externalSemaphores;
   1076     VkFence fence;
   1077 };
   1078 
   1079 struct IMAGE_LAYOUT_NODE {
   1080     VkImageLayout layout;
   1081     VkFormat format;
   1082 };
   1083 
   1084 struct MT_FB_ATTACHMENT_INFO {
   1085     IMAGE_VIEW_STATE *view_state;
   1086     VkImage image;
   1087 };
   1088 
   1089 class FRAMEBUFFER_STATE : public BASE_NODE {
   1090    public:
   1091     VkFramebuffer framebuffer;
   1092     safe_VkFramebufferCreateInfo createInfo;
   1093     std::shared_ptr<RENDER_PASS_STATE> rp_state;
   1094 #ifdef FRAMEBUFFER_ATTACHMENT_STATE_CACHE
   1095     // TODO Re-enable attachment state cache once staleness protection is implemented
   1096     //      For staleness protection destoryed images and image view must invalidate the cached data and tag the framebuffer object
   1097     //      as no longer valid
   1098     std::vector<MT_FB_ATTACHMENT_INFO> attachments;
   1099 #endif
   1100     FRAMEBUFFER_STATE(VkFramebuffer fb, const VkFramebufferCreateInfo *pCreateInfo, std::shared_ptr<RENDER_PASS_STATE> &&rpstate)
   1101         : framebuffer(fb), createInfo(pCreateInfo), rp_state(rpstate){};
   1102 };
   1103 
   1104 struct shader_module;
   1105 struct DeviceExtensions;
   1106 
   1107 struct DeviceFeatures {
   1108     VkPhysicalDeviceFeatures core;
   1109     VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing;
   1110     VkPhysicalDevice8BitStorageFeaturesKHR eight_bit_storage;
   1111     VkPhysicalDeviceExclusiveScissorFeaturesNV exclusive_scissor;
   1112     VkPhysicalDeviceShadingRateImageFeaturesNV shading_rate_image;
   1113     VkPhysicalDeviceMeshShaderFeaturesNV mesh_shader;
   1114     VkPhysicalDeviceInlineUniformBlockFeaturesEXT inline_uniform_block;
   1115     VkPhysicalDeviceTransformFeedbackFeaturesEXT transform_feedback_features;
   1116     VkPhysicalDeviceFloat16Int8FeaturesKHR float16_int8;
   1117     VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT vtx_attrib_divisor_features;
   1118     VkPhysicalDeviceScalarBlockLayoutFeaturesEXT scalar_block_layout_features;
   1119     VkPhysicalDeviceBufferAddressFeaturesEXT buffer_address;
   1120 };
   1121 
   1122 enum RenderPassCreateVersion { RENDER_PASS_VERSION_1 = 0, RENDER_PASS_VERSION_2 = 1 };
   1123 
   1124 class GpuDeviceMemoryManager;
   1125 class GpuDescriptorSetManager;
   1126 struct ShaderTracker {
   1127     VkPipeline pipeline;
   1128     VkShaderModule shader_module;
   1129     std::vector<unsigned int> pgm;
   1130 };
   1131 struct GpuValidationState {
   1132     bool aborted;
   1133     bool reserve_binding_slot;
   1134     VkDescriptorSetLayout debug_desc_layout;
   1135     VkDescriptorSetLayout dummy_desc_layout;
   1136     uint32_t adjusted_max_desc_sets;
   1137     uint32_t desc_set_bind_index;
   1138     uint32_t unique_shader_module_id;
   1139     std::unordered_map<uint32_t, ShaderTracker> shader_map;
   1140     std::unique_ptr<GpuDeviceMemoryManager> memory_manager;
   1141     std::unique_ptr<GpuDescriptorSetManager> desc_set_manager;
   1142     VkCommandPool barrier_command_pool;
   1143     VkCommandBuffer barrier_command_buffer;
   1144 };
   1145 
   1146 enum BarrierOperationsType {
   1147     kAllAcquire,  // All Barrier operations are "ownership acquire" operations
   1148     kAllRelease,  // All Barrier operations are "ownership release" operations
   1149     kGeneral,     // Either no ownership operations or a mix of ownership operation types and/or non-ownership operations
   1150 };
   1151 
   1152 std::shared_ptr<cvdescriptorset::DescriptorSetLayout const> const GetDescriptorSetLayout(layer_data const *, VkDescriptorSetLayout);
   1153 
   1154 #endif  // CORE_VALIDATION_TYPES_H_
   1155